Diff -- /var/www/vhosts/3dshawn.com/repricer.3dshawn.com/MODS/RePricer/Marketplaces.pm
Diff

/var/www/vhosts/3dshawn.com/repricer.3dshawn.com/MODS/RePricer/Marketplaces.pm

added on local at 2026-07-01 21:47:12

Added
+153
lines
Removed
-0
lines
Context
0
unchanged
Blobs
from
to 26dd5d7bc97c
Restore this content →
Unified diff
Naive LCS-based line diff. Additions in emerald, deletions in rose. Both sides decompressed live from BLOB_STORE.
1package MODS::RePricer::Marketplaces;
2
3sub new {
4 my ($cls) = @_;
5 return bless {}, ref($cls) || $cls;
6}
7
8#======================================================================
9# RePricer -- marketplace registry.
10#
11# Single source of truth for which marketplaces RePricer supports as
12# repricing targets. Each entry describes the marketplace, how a seller
13# connects, and which adapter module implements the API plumbing.
14#
15# To add a new marketplace:
16# 1. Append an entry to @PLATFORMS.
17# 2. Drop a module at MODS/RePricer/Marketplaces/<Slug>.pm whose
18# package is MODS::RePricer::Marketplaces::<Slug> and which
19# implements the adapter contract:
20# new($self, $account) # $account = marketplace_accounts row
21# test_connection() # cheap call; { ok => 1 } or { error => '...' }
22# list_my_listings($opts) # paged seller's own listings
23# get_competitor_offers($product) # competitor pricing for one product
24# update_price($product, $cents) # push new price; { ok => 1, id => '...' }
25# refresh_token_if_needed() # for OAuth-based platforms
26# 3. marketplaces.cgi auto-picks up the new entry for the Connect UI.
27#======================================================================
28use strict;
29use warnings;
30
31our @PLATFORMS = (
32 {
33 slug => 'amazon',
34 name => 'Amazon',
35 tagline => 'The big one. Pricing + Listings APIs via SP-API; LWA OAuth.',
36 adapter => 'MODS::RePricer::Marketplaces::Amazon',
37 auth => 'oauth',
38 regions => [
39 { code => 'us', label => 'United States', marketplace_id => 'ATVPDKIKX0DER' },
40 { code => 'ca', label => 'Canada', marketplace_id => 'A2EUQ1WTGCTBG2' },
41 { code => 'mx', label => 'Mexico', marketplace_id => 'A1AM78C64UM0Y8' },
42 { code => 'uk', label => 'United Kingdom', marketplace_id => 'A1F83G8C2ARO7P' },
43 { code => 'de', label => 'Germany', marketplace_id => 'A1PA6795UKMFR9' },
44 { code => 'fr', label => 'France', marketplace_id => 'A13V1IB3VIYZZH' },
45 { code => 'it', label => 'Italy', marketplace_id => 'APJ6JRA9NG5V4' },
46 { code => 'es', label => 'Spain', marketplace_id => 'A1RKKUPIHCS9HS' },
47 { code => 'jp', label => 'Japan', marketplace_id => 'A1VC38T7YXB528' },
48 { code => 'au', label => 'Australia', marketplace_id => 'A39IBJ37TRP1C6' },
49 ],
50 signup_url => 'https://sell.amazon.com/',
51 developer_url=> 'https://developer-docs.amazon.com/sp-api/',
52 seller_plan_required => 'Professional ($39.99/mo)',
53 oauth_settings => {
54 client_id_key => 'amazon_lwa_client_id',
55 client_secret_key => 'amazon_lwa_client_secret',
56 app_id_key => 'amazon_sp_app_id',
57 refresh_url => 'https://api.amazon.com/auth/o2/token',
58 authorize_url => 'https://sellercentral.amazon.com/apps/authorize/consent',
59 callback_cgi => '/oauth_amazon.cgi',
60 scope => '', # SP-API doesn't use OAuth scopes; permissions come from app roles
61 },
62 icon => 'A',
63 accent => '#ff9900',
64 },
65 {
66 slug => 'ebay',
67 name => 'eBay',
68 tagline => 'Fixed-price Buy It Now listings. OAuth2; Sell + Browse APIs.',
69 adapter => 'MODS::RePricer::Marketplaces::EBay',
70 auth => 'oauth',
71 regions => [
72 { code => 'us', label => 'United States', marketplace_id => 'EBAY_US' },
73 { code => 'uk', label => 'United Kingdom', marketplace_id => 'EBAY_GB' },
74 { code => 'de', label => 'Germany', marketplace_id => 'EBAY_DE' },
75 { code => 'au', label => 'Australia', marketplace_id => 'EBAY_AU' },
76 { code => 'ca', label => 'Canada', marketplace_id => 'EBAY_CA' },
77 { code => 'fr', label => 'France', marketplace_id => 'EBAY_FR' },
78 { code => 'it', label => 'Italy', marketplace_id => 'EBAY_IT' },
79 { code => 'es', label => 'Spain', marketplace_id => 'EBAY_ES' },
80 ],
81 signup_url => 'https://www.ebay.com/sellercenter/sell',
82 developer_url=> 'https://developer.ebay.com/',
83 seller_plan_required => 'Any seller account (Free)',
84 oauth_settings => {
85 client_id_key => 'ebay_client_id',
86 client_secret_key => 'ebay_client_secret',
87 runame_key => 'ebay_runame', # eBay's "RuName" identifier for the redirect URI
88 refresh_url => 'https://api.ebay.com/identity/v1/oauth2/token',
89 authorize_url => 'https://auth.ebay.com/oauth2/authorize',
90 sandbox_authorize => 'https://auth.sandbox.ebay.com/oauth2/authorize',
91 callback_cgi => '/oauth_ebay.cgi',
92 scope => 'https://api.ebay.com/oauth/api_scope '
93 . 'https://api.ebay.com/oauth/api_scope/sell.inventory '
94 . 'https://api.ebay.com/oauth/api_scope/sell.marketing '
95 . 'https://api.ebay.com/oauth/api_scope/sell.account '
96 . 'https://api.ebay.com/oauth/api_scope/sell.fulfillment '
97 . 'https://api.ebay.com/oauth/api_scope/buy.browse',
98 },
99 icon => 'eB',
100 accent => '#e53238',
101 },
102 {
103 slug => 'walmart',
104 name => 'Walmart',
105 tagline => 'Walmart Marketplace. Consumer ID + RSA private-key signed requests.',
106 adapter => 'MODS::RePricer::Marketplaces::Walmart',
107 auth => 'api_key', # not OAuth -- seller pastes a Consumer ID + Private Key
108 regions => [
109 { code => 'us', label => 'United States', marketplace_id => 'WALMART_US' },
110 { code => 'ca', label => 'Canada', marketplace_id => 'WALMART_CA' },
111 { code => 'mx', label => 'Mexico', marketplace_id => 'WALMART_MX' },
112 ],
113 signup_url => 'https://marketplace.walmart.com/apply/',
114 developer_url=> 'https://developer.walmart.com/home/us-mp',
115 seller_plan_required => 'Walmart Marketplace seller (application-gated)',
116 oauth_settings => {
117 # No OAuth -- the "credentials" UI captures these per-account
118 # via marketplaces.cgi instead.
119 api_base_us => 'https://marketplace.walmartapis.com',
120 api_base_ca => 'https://marketplace.walmartapis.com/v3/ca',
121 },
122 icon => 'W',
123 accent => '#0071dc',
124 },
125);
126
127# Whole-list accessor for the dashboard.
128sub platforms { return @PLATFORMS; }
129
130# Look one up by slug. Returns undef if unknown.
131sub by_slug {
132 my ($slug) = @_;
133 foreach my $p (@PLATFORMS) {
134 return $p if $p->{slug} eq $slug;
135 }
136 return undef;
137}
138
139# Convenience: load and instantiate the right adapter for a given
140# marketplace_accounts row. Returns undef on missing platform or load
141# failure (eval-guarded).
142sub adapter_for {
143 my ($account) = @_;
144 return undef unless $account && $account->{platform};
145 my $p = by_slug($account->{platform});
146 return undef unless $p && $p->{adapter};
147 my $module = $p->{adapter};
148 my $loaded = eval "require $module; 1";
149 return undef unless $loaded;
150 return $module->new($account);
151}
152
1531;
Keyboard: j next diff k previous diff g top G bottom r restore c compile-check ? help