=== CJ Live Shipping for WooCommerce ===
Contributors: genesispay
Requires at least: 6.7
Tested up to: 6.8
Requires PHP: 8.1
Stable tag: 0.2.3
License: GPLv3 or later

Destination-bound CJdropshipping freight quotes for WooCommerce.

== Description ==

This extension resolves each shippable WooCommerce line from its CJ SKU, checks
the warehouses that currently have inventory, and asks CJ for live freight to
the checkout destination. If CJ has no route or the supplier API cannot confirm
the price, checkout exposes no fallback shipping rate.

All items of a package ship from one warehouse that stocks every item. The
candidates are tried in this order: the destination country; then the US
before China for US addresses, otherwise China before the US; then any other
common warehouse alphabetically. CJ's EU and US warehouses mostly ship only
domestically, so when CJ reports no route from a candidate the next one is
tried (up to three, within the wait budget). Supplier errors are never
retried from another warehouse; they fail closed. A cart whose items share no
stocked warehouse, or that no candidate can route, gets no rate rather than a
split or guessed one.

CJ quotes a joint freight request for two different products as "no route"
even when each ships alone, because its warehouses are many supplier
warehouses. A package with two or more different products is therefore quoted
item by item and offered as at most two summed rates: Standard (each item's
cheapest route) and Express (each item's fastest route, shown only when it
arrives sooner). All items use the same warehouse: the first candidate from
which every item has a route. If there is none, checkout gets no rate.

CJ allows one API request per second per account. Every PHP worker reserves its
request slot through one shared database row, waits at most about nine seconds
per quote (including up to two retries after HTTP 429), and otherwise fails
closed. Variant lookups are cached for 24 hours, warehouse inventory and freight
quotes for 15 minutes.

Mixed catalogs: only CJ items are quoted. An item counts as a CJ item when its
SKU (the variation SKU, else the parent SKU) starts with "CJ" (any case); no CJ
call is needed to decide. Override it with the `mabit_cj_is_cj_item` filter,
which receives the default boolean and the WC_Product. A package without CJ
items is left entirely to your other shipping methods. A package that mixes CJ
and non-CJ items (for example BigBuy or Syncee products) gets no CJ rate, logs
`cj_mixed_package`, and keeps the other methods' rates; for such carts, split
packages per supplier (for example with the `woocommerce_cart_shipping_packages`
filter or a package-splitting plugin) so CJ quotes its own package. Only a
package made entirely of CJ items replaces the other rates and fails closed.

WooCommerce remains authoritative for tax and the final order total. GenesisPay
continues to receive the exact frozen WooCommerce order total.

== Installation ==

1. Install and activate this ZIP with WooCommerce active.
2. In WooCommerce > Settings > Integrations > CJ Live Shipping, enter a CJ API
   Key and enable live quotes.
3. Add "CJ live freight" to every shipping zone you sell to.
4. Remove the old flat-rate method from those zones after confirming one live
   quote. Keeping both is unnecessary; this plugin also suppresses fallback
   rates whenever its live method ran for the package.
5. Ensure every CJ-supplied product or variation has its CJ variant SKU in the
   WooCommerce SKU field.

== Changelog ==

= 0.2.3 =
* Fall back to the next common warehouse when CJ reports no route from the preferred one (up to three candidates, inside the wait budget; "no route" answers are cached for 15 minutes). Outside the US, China is now tried before the US. Errors and HTTP 429 still fail closed without fallback. Packages no candidate can route log `cj_no_route_any_origin` (replaces `cj_no_rates` and `cj_no_rates_item`).

= 0.2.2 =
* Only quote packages made entirely of CJ items (SKU starts with "CJ", overridable via the `mabit_cj_is_cj_item` filter), decided without calling CJ. Packages without CJ items are left to other methods untouched; mixed packages get no CJ rate, log `cj_mixed_package` once and keep other methods' rates. CJ-only packages still fail closed and suppress fallback rates.

= 0.2.1 =
* Quote packages with two or more different products item by item (CJ answers a joint request with no route) and offer a summed Standard rate plus an Express rate when it is strictly faster; any item without a route still fails closed (cj_no_rates_item). Single-item packages are unchanged.

= 0.2.0 =
* Share CJ's one-request-per-second allowance across all PHP workers through a database-backed request slot, with a bounded wait (about 9 s per quote) and up to two retries after HTTP 429; past the budget the quote fails closed.
* Quote mixed carts from a warehouse common to every item (destination country, then US, then China) instead of refusing every multi-origin cart; carts with no common warehouse still get no rate and log cj_no_common_origin.
* Cache freight per origin, destination, postcode prefix and item set for 15 minutes; variant lookups for 24 hours; inventory for 15 minutes.

= 0.1.9 =
* Fall back to the variant-SKU lookup when CJ rejects a product-SKU lookup with HTTP 400 and a failure reason (0.1.5 diagnostics had disabled that fallback).

= 0.1.8 =
* Resolve WooCommerce variations through their CJ parent product SKU, then select the exact variant SKU.

= 0.1.7 =
* Route product-SKU lookups through CJ's product query endpoint while retaining the variant endpoint fallback.

= 0.1.6 =
* Respect CJ's one-request-per-second API limit and parse product variant lists returned for product SKUs.

= 0.1.5 =
* Include CJ's sanitized failure reason in quote diagnostics without recording credentials or customer data.

= 0.1.4 =
* Prefer product-SKU lookup for CJ-imported WooCommerce products to avoid an unnecessary rate-limited request.

= 0.1.3 =
* Fall back from variant-SKU to product-SKU lookup when CJ rejects the first lookup shape.

= 0.1.2 =
* Record the failing CJ API stage and status without logging credentials or customer data.

= 0.1.1 =
* Use CJ's documented inventory endpoint and record safe quote diagnostics in WooCommerce logs.

= 0.1.0 =
* Add cached CJ token, variant, warehouse inventory and freight lookup.
* Prefer in-country inventory, then China, and refuse ambiguous multi-origin carts.
* Fail closed when a destination cannot be quoted.
