3.5 KiB
Commerce analytics core
commerce is the product-centric analytics boundary of EUSRR. It does not
replace an operational CRM or warehouse. External and future internal systems
all supply records to the same canonical product model.
Stable model
Productis one sellable or stockable SKU.parentgroups variants.SourceRecordretains the latest raw payload with source provenance.ProductBindingmaps a source product/offer identifier toProduct.SaleandSaleLinecontain normalized product-level sales facts.Costcontains commissions, delivery, advertising and other expenses.StockSnapshotcontains point-in-time stock observations by source and warehouse.
Money is never aggregated across currencies. Returns are represented as a
Sale with event_type="return"; line values remain positive and analytics
applies the sign.
Integration contract
An adapter subclasses commerce.integrations.SourceAdapter, handles API
pagination internally and yields ExternalRecord objects. Register it in
adapter_registry, then invoke the Celery task commerce.sync_source.
Adapters must not store credentials in SourceSystem.metadata; secrets belong
in environment-backed configuration or a dedicated encrypted credential
store.
IntegrationConnection is that encrypted credential boundary for connections
created by employees. moysklad scans the complete paginated assortment,
aggregate stock, shipments and customer returns. wildberries reads the
current Finance API realization details and normalizes sales, returns,
commissions, acquiring, logistics, storage and deductions. Raw API payloads are
retained in SourceRecord before normalization. Repeated scans update the same
source identities and append stock observations.
Wildberries imports save the last rrdId after every non-empty page and continue
on the next scheduled run until the API returns HTTP 204, as required by the
provider contract. This avoids both duplicates and a worker sleep under the
provider's one-request-per-minute Finance API limit. After the initial history
is complete, each run rechecks the latest 30 days so report corrections replace
prior facts.
Celery Beat checks due connections every minute. Each connection stores whether automatic synchronization is enabled, its interval (15 minutes by default) and the next planned run; row locking and connection status prevent overlapping full scans. Both a Celery worker and Celery Beat must be running.
Imported cards are matched by an existing source binding, SKU or barcode. A
card that cannot be matched safely is created separately and can later be
merged into a canonical product through products/{id}/merge/; bindings and
normalized facts move with it.
Source-specific code must not create alternative product models. It stores the
raw payload first and then resolves a product through ProductBinding or
commerce.services.match_product before writing normalized facts.
API
The authenticated API is mounted at /api/v1/commerce/:
products/products/{id}/analytics/products/{id}/merge/connections/(test/andsync/actions)sync-runs/sources/product-bindings/sales/sale-lines/costs/stock-snapshots/
All employees may read. Writes require staff status or the corresponding Django model permission. The frontend management screen can bootstrap and correct normalized records manually; integrations should still write them through application services so raw provenance and idempotency are preserved.