Bỏ qua để đến nội dung

Catalog — variant sell unit and pack

Nội dung này hiện chưa có sẵn bằng ngôn ngữ của bạn.

One product (items) can have many variations (item_variations / JSON variations[]). Retail vs wholesale pricing is driven by price channel on orders, not by duplicating catalog rows. Sell unit defaults from items.unit_id; each variation may override with its own unit_id or inherit when null. Pack size is stored per variation as units_per_pack (for example 24 for a case). An optional base variation link (base_variation_id, exposed as base_variant key in API payloads) supports reporting and conversion when pack size is known. Stock remains per variation; the platform does not auto-convert inventory between pack and base SKU.


ItemDetail
MigrationItemVariationUnitAndPack1783000000000apps/backend/src/database/migrations/1783000000000-ItemVariationUnitAndPack.ts
Tableitem_variations (prefixed table name via tp('item_variations') where the codebase applies table prefixes)
New columns (legacy field prefix fp(...))unit_id — nullable; references sell unit id; null means inherit product unit · units_per_pack — nullable decimal multiplier vs base SKU · base_variation_id — nullable self-FK
ConstraintFK_item_variations_base_variationON DELETE SET NULL

Run pending migrations for apps/backend against the target database. If the item_variations table does not exist, the migration skips column changes safely.


  • Entity: apps/backend/src/database/entities/item-variation.entity.tsunitId, unitsPerPack, baseVariationId, optional baseVariation relation.
  • API row builder: apps/backend/src/common/item-variation-unit.util.tsmapItemVariationEntityToApiRow, resolveVariationSellUnitId, variationBaseQuantity, payload parsers.
  • Sync from payloads: apps/backend/src/common/item-variation-sync.util.ts — reads unit_id, units_per_pack, base_variant / base_variation_key from each variation payload; persists columns; resolves base_variation_id from the base variant key in a follow-up pass.

Each object in variations on product detail (admin + vendor rebuild paths) includes fields such as:

FieldType (typical)Meaning
variantstringStable variation key / label
sku_code, sku_name, barcodestringIdentifiers
price, wholesale_price, stocknumberExisting catalog fields
unit_idstring | nullOverride unit id; null → use product unit_id
units_per_packnumber | nullPack multiplier; null if unset
base_variation_idnumber | nullPersisted FK after sync
base_variantstring | nullKey of linked base variation row (round-trip / forms)

Clients may send per variation row:

  • unit_id — optional string or empty / omitted to inherit
  • units_per_pack — optional positive number or null to clear
  • base_variant — optional string matching another row’s variant key

Exact request bodies remain defined in OpenAPI (npm run openapi:export) — see API endpoints catalog.


AreaImplementation notes
Vendor catalog detailapps/backend/src/modules/vendor/vendor-products.service.tsresolveVariationsForVendorDetail uses mapItemVariationEntityToApiRow.
Admin catalog detail / exportapps/backend/src/modules/admin/admin-products.service.ts — same mapping; export builds from full ItemVariationEntity rows where required.
POS item variantsapps/backend/src/modules/pos/pos.service.ts — variant rows expose unit_id, units_per_pack, base_variation_id where loaded from ItemVariationEntity.

  • Routes: /dashboard/products/create, /dashboard/products/:id/edit — variations tables include sell unit, units / pack, and base SKU (multi-variant only) via ProductVariationUnitPackCells.
  • Files: product-form-page.tsx, product-form.schema.ts, components/dashboard/products/ProductVariationUnitPackCells.tsx.
  • Copy: packages/shared/src/locales/vendor-product-form.ts (variantsTable keys for unit, inherit label, units per pack, base variant).
  • Admin product form exposes product-level unit_id; per-variation units per pack and base variant editors are not implemented yet. APIs still return variation fields — use vendor edit or raw API JSON as needed until UI parity lands.

Vendor detail screens may omit some variation breakdown fields; authoritative editing is on create / edit.

If POS or tooling reads catalog only from JSON blobs, extend packages/utils normalization so unit_id / units_per_pack propagate consistently alongside entity-backed paths.


  • apps/backend/src/common/item-variation-sync.util.spec.ts
  • apps/backend/src/common/item-variation-unit.util.spec.ts