=== SkyServers Product Sync for eMAG ===
Contributors: skyservers, freemius
Tags: emag, marketplace, sync, romania, ecommerce
Requires at least: 5.8
Tested up to: 7.1
Requires PHP: 7.4
Stable tag: 3.9.3
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Sync prices, stock and publish products from WooCommerce to eMAG Marketplace. Margin control, category mapping, and Buy Button tracking.

== Description ==

**SkyServers Product Sync for eMAG** connects your WooCommerce store to the eMAG Marketplace (Romania, Bulgaria, Hungary) and keeps your offers up to date automatically.

= Free Features =

* **Margin-based pricing** — set a global margin % or override per product. Prices are calculated from your WooCommerce ex-VAT price plus your chosen markup.
* **Min/Max margin protection** — block sync if the calculated price falls outside your safety bounds, preventing accidental underselling or eMAG price guard rejections.
* **Stock percentage control** — send only a fraction of your WooCommerce stock to eMAG (e.g., 50%). Rounded up, configurable globally and per product.
* **VAT-aware pricing** — reads WooCommerce tax classes (11%, 21%, etc.) and sends correct VAT info to eMAG via the cached vat/read API.
* **Scheduled auto-sync** — choose from 15 min, 30 min, hourly, 3h, 6h, 12h, or daily via WP-Cron.
* **Manual sync** — one-click full sync from the admin panel.
* **Bootstrap import** — import your existing eMAG offers, match them to WooCommerce products by SKU, and store offer IDs, VAT rates, and price bounds automatically.
* **Smart Bootstrap (preserve existing eMAG prices)** — if you already sell on eMAG, the importer can read each offer's current sale price and back-calculate the implied margin per product, storing it as an override. Your hand-tuned eMAG prices stay intact when sync starts; you control when to change them. Choose between this mode and the classic "apply global margin to everything" mode in the Setup wizard.
* **Per-product controls** — enable/disable sync, set custom margin, min/max margin, and stock % per product from a searchable list.
* **Minimum WC Stock buffer** — reserve safety stock that won't be sent to eMAG (send stock 0 to the marketplace when WooCommerce stock drops to your threshold).
* **Activity logs** — every sync action is logged with timestamp, product, action, result, and details. Filterable and prunable, with configurable retention from 7 to 365 days.
* **Setup wizard** — guided 5-step onboarding that auto-runs on first activation. Connects to eMAG, sets pricing/stock defaults, schedules sync, and bootstraps your existing offers. Can be re-run from the Help page. (Pro adds a 6th step for product publishing defaults.)

= Premium Features (requires license) =

* **Publish new products** from WooCommerce to eMAG — including warranty, resupply days, and Dry Run mode.
* **Category mapping** — map WooCommerce categories to eMAG categories (2,900+ categories imported).
* **Characteristics mapping** — auto-fill eMAG product attributes from WooCommerce product data.
* **Family type mapping** — assign eMAG family types to your product categories.
* **Buy Button rank tracking** — monitor your position (rank 1-4), number of competing offers, and best offer price.
* **EAN/Brand auto-detection** — scan your products for EAN/GTIN and brand meta keys.
* **Order import (webhook-first)** — incoming eMAG orders land in WooCommerce automatically once you register the callback URLs in your eMAG seller account. Manual import-by-id is also available for backfill. Status mapping is configurable. Optional auto-decrement of WC stock with idempotency guard against webhook retries.
* **AWB shipping integration** — issue AWB labels directly from the WooCommerce order edit screen. Print in A4, A5, A6, or ZPL with last-used auto-save. Sender/pickup address auto-detected from your eMAG account. Default OFF until you set the sender phone in Settings.
* **Email notifications** — per-event email alerts when sync fails, when a new eMAG order arrives, when an AWB is issued, **when your Buy Button rank drops from #1** (a competitor takes the top position on a product), and **when a competitor undercuts your price** below your configured threshold. Per-event subscription controls on a dedicated Notifications page, with throttling so you do not get spammed during a price war.
* **Auto-updates** — receive new versions directly through WordPress, delivered via the licensed update channel.
* **Priority support** — direct email support from the development team.
* **Free guided setup** — every new Pro customer gets a complimentary 1-2 hour onboarding video call. Email contact@sky-servers.com after activation to book it — we configure your eMAG API credentials, run the initial offer bootstrap, set up category mapping, and walk through your first sync together.

[Upgrade to Premium](https://www.sky-servers.com/skyservers-product-sync-for-emag)

= How It Works =

1. Enter your eMAG API credentials (username + password) in the plugin settings.
2. Whitelist your server IP in your eMAG seller account.
3. Run the Bootstrap import to pull in your existing eMAG offers.
4. Configure your global margin, stock percentage, and sync schedule.
5. Enable sync per product and let the plugin do the rest.

= Requirements =

* WooCommerce 7.0 or higher
* PHP 7.4 or higher
* eMAG Marketplace seller account with API access
* Server IP whitelisted in eMAG seller settings

== Installation ==

1. Upload the plugin folder to `/wp-content/plugins/` or install via the WordPress plugin screen.
2. Activate the plugin through the 'Plugins' menu in WordPress.
3. Go to **eMAG Sync → Settings** and enter your eMAG API credentials.
4. Click **Test Connection** to verify your setup.
5. Run **Import from eMAG** to pull existing offers.
6. Configure margins and enable sync on your products.

== Frequently Asked Questions ==

= Does this plugin import orders from eMAG? =

Yes — order import is a Premium feature. The plugin registers two REST callback URLs that you paste into your eMAG seller account (Account → Technical details → Settings). Once eMAG fires a callback for a new or cancelled order, the plugin reads the payload, maps it to a `WC_Order`, and acknowledges it back to eMAG. Manual import-by-id is also provided for backfill. A configurable Dry Run mode lets you UAT the import flow against a live WooCommerce database without creating real orders.

= Can the plugin issue AWB shipping labels for eMAG orders? =

Yes — AWB issuance and printing are Premium features. Each imported eMAG order gets an "eMAG Shipping" meta box on the WooCommerce order edit screen. Click "Issue AWB" once your sender phone and pickup address are configured (Settings → Orders & AWB), and the plugin will request an AWB from eMAG, attach it to the order, and let you print in A4 / A5 / A6 / ZPL formats. The last-used format auto-saves as your default.

= What eMAG API endpoints does the plugin use? =

For sync: `product_offer/save`, `product_offer/read`, `vat/read`, `category/read`, `product_offer/count`. For orders (Premium): `order/read`, `order/count`, `order/acknowledge` plus the two webhook callback endpoints we expose. For AWB (Premium): `courier_accounts/read`, `addresses/read`, `awb/save`, `awb/read`. All built against the public eMAG Marketplace API v4.5.1 documentation.

= Is my eMAG password stored securely? =

Yes. Your API password is encrypted in the database using AES-256-CBC with a key derived from your WordPress AUTH_KEY constant and a freshly random initialization vector for each save. If you rotate AUTH_KEY (via wp-config.php), the plugin detects the resulting decryption failure on the next admin load, clears the corrupted credentials row, and shows you an admin notice asking you to re-enter the password.

= Can I sync only specific products? =

Yes. Each product has an individual sync toggle. Only products with sync enabled will be synchronised. Unmapped products (without an eMAG offer ID) are always skipped.

= Is the plugin compatible with WooCommerce HPOS (High Performance Order Storage)? =

Yes. Order lookups use `wc_get_orders()` so the active data store handles the query — works on both legacy CPT mode and HPOS authoritative-only mode (WC 8.2+). HPOS compatibility is also declared via `FeaturesUtil::declare_compatibility('custom_order_tables', __FILE__, true)`.

== External services ==

This plugin connects to two external services to deliver its core functionality. They are documented here as required by the WordPress.org Plugin Directory guidelines.

= eMAG Marketplace API =

This is the primary service the plugin integrates with. It is the public REST API operated by Dante International SA (the company behind the eMAG marketplace) for sellers to manage their offers, products, orders, and shipping labels programmatically.

* What it is used for: synchronising prices, stock levels, VAT rates, and product offers from your WooCommerce store to your eMAG seller account; bootstrapping your existing eMAG offer catalog into WooCommerce on first install. With the Premium add-on, also: publishing new products to eMAG, importing eMAG orders into WooCommerce via webhook callbacks, issuing AWB shipping labels, and tracking Buy Button rank.
* What data is sent: your eMAG API username and password (Basic Auth, transmitted over HTTPS); the product fields you choose to sync (SKU, price, stock, VAT rate, name, description, images, category, characteristics, EAN, brand); the eMAG order id when you receive a webhook callback or trigger a manual import.
* When data is sent: on the schedule you configure (15 min, 30 min, 1h, 3h, 6h, 12h, or daily); when you manually trigger Sync, Bootstrap, or Test Connection; when WooCommerce events fire (product save, order status change) and the Premium add-on is active; when eMAG fires an order callback to the plugin's REST endpoint.
* Privacy and Terms: the eMAG API is the official marketplace integration channel and requires that you have an active seller account and have agreed to the marketplace terms of service before any data flows. The Terms of Service document below is hosted in the seller-facing knowledge base and its full text is gated behind a marketplace login because it is a contractual agreement between eMAG and the seller; the page title and abstract are public.
* Terms of Service: https://marketplace.emag.ro/infocenter/emag-academy/cerinte-legale/termeni-si-conditii-pentru-utilizarea-api-pe-emag-marketplace/
* Privacy Policy: https://marketplace.emag.ro/infocenter/politica-de-confidentialitate/

= ipify.org =

A small, free public service that returns the requesting server's external IP address as plain text.

* What it is used for: the Help page has a "Detect server IP" button that calls ipify so you know which IP to whitelist in your eMAG seller account (eMAG requires server IP whitelisting before API calls are accepted). The plugin does not call ipify on any other code path.
* What data is sent: your server's IP address as the source of an outbound HTTP request (no payload, no PII, no plugin data). The request goes to https://api.ipify.org with no parameters.
* When data is sent: only when you explicitly click the "Detect server IP" button on the Help page. The plugin never calls ipify on a schedule, on activation, or in the background.
* Operating terms and privacy stance: ipify does not publish separate Terms of Service or Privacy Policy documents because it is a free, no-registration, no-authentication service that does not log or store IP queries. The single-page site at https://www.ipify.org/ explicitly states the operating terms (free for unlimited use, no rate limits beyond abuse protection) and the no-logging privacy stance. We disclose this here so users can make an informed decision about whether to use the "Detect server IP" button. The button is opt-in (manual click) and never fires automatically.
* Documentation: https://www.ipify.org/

== Languages ==

The admin interface is fully translated to:

* **English (en_US)** — native, source language
* **Romanian (ro_RO)** — full native translation
* **Bulgarian (bg_BG)** — full translation
* **Hungarian (hu_HU)** — full translation

All ~944 admin strings are translated in every locale shipped above. The Bulgarian and Hungarian translations are an initial machine-translated baseline — native speakers are very welcome to refine them at https://translate.wordpress.org/projects/wp-plugins/skyservers-product-sync-for-emag/ — WordPress.org will distribute approved contributions automatically to all users in your locale.

== Changelog ==

= 3.9.3 =
* New: "Publish ID offset" setting — keeps the internal ids of newly published products clear of offers already present in your eMAG account (created by another feed or integration), so publishing works smoothly on accounts with a pre-existing catalogue.
* New: publishing now verifies the internal id on eMAG before sending and reports a clear, actionable message when the id is already in use by another product.
* New: republishing a product that is already linked to an eMAG offer reuses its existing offer id.
* New Help section explaining the eMAG "part_number and name" rejection and how to resolve it.

= 3.9.2 =
* Compatibility: tested with WordPress 7.1.
* Fix: duplicating a product in WooCommerce no longer copies its eMAG mapping. Inherited mappings caused "Duplicate product found" batch errors and could overwrite the original offer's price and stock on eMAG.
* New: sync detects products sharing one eMAG offer id and blocks only the wrongly mapped ones, with a clear log message, instead of failing the whole batch.
* New: "Unlink from eMAG" action on the Products page, plus a one-click repair tool for existing duplicate mappings.
* Fix: the manual Buy Button tracking button now runs in the background — on large catalogs the previous synchronous request could exceed the server timeout and report "Request failed" even though tracking completed.

= 3.9.1 =
Maintenance release, internal reliability improvements.

= 3.9.0 =
Smart Bootstrap release. The Setup wizard now lets you pick how the initial import handles pricing: either apply your global margin to every matched product (the original behaviour) or preserve your existing eMAG prices by back-calculating the implied margin per product from each current offer. The new "preserve" mode is ideal for sellers who already have a hand-tuned catalogue on eMAG &mdash; your marketplace prices stay intact when sync starts, and you change them on your own schedule. Negative implied margins are flagged in the activity log so you spot loss-making offers immediately. Existing per-product margin overrides are never touched.

= 3.8.1 =
Multi-language release + marketing polish. Added full admin interface translations for Romanian (ro_RO, native), Bulgarian (bg_BG) and Hungarian (hu_HU), covering all ~944 user-facing strings in every locale. Expanded the Email notifications description to call out the Buy Button #1 rank-drop alert and the competitor-undercut alert, which were already supported but not previously documented. Documented the complimentary 1-2 hour onboarding video call available to every new Pro customer.



= 3.8.0 =
Scalability release. Sync now runs asynchronously in the background using WooCommerce's Action Scheduler instead of blocking the request. The Settings page Manual Sync and the Products page "Sync selected now" bulk action both open a real-time progress bar with ETA and a Cancel button, so the browser is free to navigate while a sync is in flight. Per-request batches dropped from 50 to 25 products and the per-request timeout grew from 20 to 30 seconds, with one automatic retry on transient eMAG timeouts &mdash; together this eliminates the intermittent cURL 28 failures that affected larger catalogues during eMAG marketplace peak hours. Stores with hundreds or thousands of products now sync reliably across multiple short-lived background jobs that resume cleanly after server restarts.

= 3.7.3 =
Compatibility metadata refresh after the WordPress 7.0 release (2026-05-20). Marked the plugin as tested up to WordPress 7.0. No code changes; functionality is identical to 3.7.2.

= 3.7.2 =
Stability and compliance improvements. No user-facing changes.

= 3.7.0 =
Sync schedule fully configurable on every plan: 15 minutes, 30 minutes, 1 hour, 3 hours, 6 hours, 12 hours, or daily. Activity log retention configurable from 7 to 365 days. Minimum WooCommerce Stock buffer editable on every install. Sync stability hardened with inter-batch throttling that stays under eMAG's 3 req/sec ceiling, a 30-second cooldown on cURL timeouts, and cascade-abort after two consecutive batch failures.

= 3.6.0 - 3.6.4 =
Removed the 25-product cap on the Free plan &mdash; product sync is now unlimited. Improved adherence to WordPress.org Plugin Directory guidelines.

= 3.5.0 - 3.5.8 =
WooCommerce HPOS (High Performance Order Storage) compatibility. Stronger encryption for the stored eMAG API password (random IV per encryption). AUTH_KEY rotation now self-heals with a clear admin notice. AWB issuance and order import are mutex-protected to prevent duplicate operations under heavy load. Translation template (.pot) added.

= 3.4.0 - 3.4.8 =
Setup wizard added &mdash; 5-step guided onboarding that runs on first activation. Test Connection now displays response latency. Brand and EAN source fields can be auto-detected.

= 3.3.0 - 3.3.5 =
AWB shipping label integration (Pro): manual issuance and printing directly from the WooCommerce order edit screen. Supports A4, A5, A6, and ZPL formats with last-used auto-save. Help page rewritten around new-seller first-run questions.

= 3.0.0 - 3.2.1 =
Webhook-first order import (Pro): incoming eMAG orders are pulled into WooCommerce automatically. Dry-run mode and manual import-by-id for backfill. eMAG order badge column in the WooCommerce Orders screen. Multi-region support: Romania, Bulgaria, Hungary. Freemius licensing introduced.

= 2.1.4 =
Product family type mapping (Pro). Characteristics mapping (Pro). 2,900+ eMAG categories imported. Buy Button rank tracking (Pro).

= 1.0.1 =
Initial release with price and stock sync, margin system, bootstrap import of existing eMAG offers, and activity logs.

== Screenshots ==

1. Setup wizard — get started in 5 steps with eMAG account, pricing, sync schedule and bootstrap import.
2. Built-in Help & Documentation page with quick start, troubleshooting and "Run setup wizard" shortcut.
3. General settings — global margin, min/max margin guards, stock percentage, price rounding and sync frequency.
4. Sync filters and eMAG API credentials — minimum price, max weight, SKU skip regex, multi-region (RO / BG / HU) and Test Connection.
5. Products list with per-product sync toggle, custom margin, min/max margin, stock %, eMAG offer ID and Buy Button rank.
6. PRO &ndash; Publish new products to eMAG Marketplace with bulk selection and dry-run validation (available in the Pro version).
7. PRO &ndash; Import eMAG orders into WooCommerce with configurable status mapping and dry-run mode (available in the Pro version).

== Upgrade Notice ==

= 3.9.3 =
Recommended for sellers whose eMAG account already contains offers created by another feed or integration: adds the Publish ID offset setting and a pre-publish id check so new products publish without conflicts.

= 3.9.2 =
Recommended for all sellers: prevents duplicated WooCommerce products from claiming the same eMAG offer (batch sync errors, silent offer overwrites) and adds an Unlink + repair tool.

= 3.9.1 =
Maintenance release, internal reliability improvements.
