get_stock_quantity() on a never-managed product returns 0, which equaled
BC's inventory for out-of-stock items, so the "did the value change?"
guard treated it as no-op and never called set_manage_stock(true). The
product was left at WooCommerce's default stock_status of "instock" with
no quantity tracked - looked fine for in-stock items (real quantity forced
the block to run) but silently wrong for anything actually out of stock.
Now also runs whenever stock isn't managed yet, regardless of whether the
value looks unchanged. Also enables manage_stock at product creation time
so newly created products never sit in that ambiguous state to begin with.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The plugin only ever updated existing WooCommerce products - nothing
created new ones, so a category-filtered sync would just skip every BC
item without a matching product, no matter how the filter was configured.
Adds an opt-in "Create Missing Products" setting (default off, so existing
update-only behavior is unchanged unless explicitly enabled) that creates
a bare WC_Product_Simple (name, SKU from GTIN/number, configurable
draft/publish status) for unmatched BC items in the category-filtered
sync path, then runs it straight through the existing update_product()
call for stock/price/brand - no duplicated logic.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Two fixes bundled together:
1. Shrink CATEGORY_PAGE_SIZE from 100 to 25. Each item in a category page
can trigger several sequential BC calls (location stock, price lists,
brand/category lookup) beyond the page fetch itself - at 100 items/page
this measured 150-250+ seconds on live data, exceeding PHP's execution
limit and leaving the Action Scheduler action stuck "in-progress"
forever instead of completing or failing visibly.
2. BC's Item Category table has no parent-category field - confirmed via
the actual published CategProd endpoint (Code, Description only) and
the standard itemCategories entity (id, code, displayName only). The
original ItemCategoryHierarchy AL snippet assumed a Parent Category
field that doesn't exist. Switched to the standard /itemCategories API
for the brand display name (no custom endpoint needed for that part),
and replaced the BC-side parent-category walk with a WordPress-side
manual map (wbc_category_parent_map: "CODE=Parent Name" per line) for
the WooCommerce product category grouping, since BC has nothing to
offer there.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
When wbc_category_filter is set, sync now pages through BC's /items
endpoint filtered server-side by itemCategoryCode (or-chained eq - BC's
classic OData rejects the `in` operator) and matches each returned item to
a WooCommerce product locally via wc_get_product_id_by_sku(), instead of
querying BC once per WooCommerce product only to discard most of them.
Confirmed against live data that BC's `in` filter isn't supported here but
chained `eq ... or ...` is.
Also reorders find_bc_item_by_sku() to try GTIN/number before Item
Reference (ReferenciasArticulo). Empirically, on this catalog Reference_No
is always identical to Item_No, so the reference lookup never matched
anything the GTIN/number checks didn't already find - it was costing an
extra BC round trip on every single product for no benefit. Kept as a
last-resort fallback both directions (SKU->item and item->SKU) in case
that doesn't hold for some future item.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
as_enqueue_async_action() spreads the args array into separate positional
parameters on the hooked callback, it does not pass one combined array.
process_batch() was registered with accepted_args=1 and tried to read
$args['run_id']/$args['product_ids'] off what was actually just the run_id
string - the run_id comparison then always failed and every batch returned
immediately without doing any work, while Action Scheduler still marked
each action complete (no exception was thrown). Found by tracing why 896
queued batches all reported "complete" within seconds with zero products
actually synced.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Manual and scheduled sync previously processed every WooCommerce product
inline in a single PHP request/AJAX call, with several sequential BC API
calls per product. At real catalog sizes this exceeds PHP's
max_execution_time and the proxy's read timeout, surfacing as a 502 Bad
Gateway on "Sync Now".
Adds WBC_Batch_Sync, which queues the catalog in chunks of 25 via Action
Scheduler (bundled with WooCommerce) and processes them asynchronously.
The manual sync AJAX call now returns immediately after queuing, and the
admin UI polls for progress instead of waiting on one long request.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Filter product sync to an allow-list of BC item category codes
- Look up items by ReferenciasArticulo item reference before falling back to GTIN/item number
- Sync BC item category to product_brand and parent category to product_cat via a new ItemCategoryHierarchy endpoint
- Add on-demand push of product name/photo back to BC (product edit meta box + bulk action), including binary PATCH support for item pictures
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Uses wbc_location_code setting on all order lines including shipping.
Header-level location to be handled by BC extension post-processing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
PATCH salesOrders status to 'Released' after creation and line items.
Controlled by Auto-Release Order checkbox in Order Settings.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Search BC customers by taxRegistrationNumber (NIF/CIF from _nif meta)
- If NIF found in BC, use that customer; if not, create with NIF
- If no NIF on order, use configurable default customer number
- Add Default Customer Number setting in Order Settings tab
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
BC OData filter options are in English (Draft/Active/Inactive),
not the localized display values.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Source_Type (not Assign_to_Type), Status='Activo' and
Source_Type='Todos los clientes' (Spanish enum values from BC).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace broken itemLedgerEntries approach with custom ItemByLocation
OData V4 endpoint for location-specific stock. Add ListaPrecios
endpoint for price list sync (B2C regular, B2C_OF sale price) with
filters for active status and all-customers assignment.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reversed the product sync direction: instead of pulling all 60k+ items
from BC and matching against WooCommerce (600+ paginated API calls that
timeout), now iterates the ~100 WooCommerce products and queries BC for
each one by GTIN/item number (1-2 API calls per product).
Added Location Code setting (e.g. "ICP") to filter stock by BC location.
Uses Item Ledger Entries endpoint to sum per-location stock. Falls back
to total inventory if the endpoint is unavailable.
Also registered wbc_location_code in sync settings group and uninstall.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Native PHP plugin (no Composer) that syncs:
- Product stock and pricing from BC to WooCommerce (scheduled cron)
- Orders from WooCommerce to BC (on payment received)
- Auto-creates customers in BC from WooCommerce billing data
Product matching: WooCommerce SKU → BC Item Number, fallback to GTIN (EAN).
OAuth2 client credentials auth with encrypted secret storage.
Admin settings page with connection test, manual sync, and log viewer.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>