rerobe-js-orm 4.9.0 → 4.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,17 @@
1
+ type VariantOptions = {
2
+ [k: string]: string;
3
+ };
4
+ export default class ProductVariantHelpers {
5
+ static optionsLabel(options: VariantOptions | null | undefined, separator?: string): string;
6
+ static variantLabel(lineItem: any, separator?: string): string;
7
+ static resolveChosenVariant(product: any, { variantId, sku }?: {
8
+ variantId?: string;
9
+ sku?: string;
10
+ }): any;
11
+ static mapOptionsToAttributes(options: VariantOptions | null | undefined): {
12
+ size?: string;
13
+ standardSize?: string;
14
+ color?: string;
15
+ };
16
+ }
17
+ export {};
@@ -0,0 +1,90 @@
1
+ "use strict";
2
+ // Variant display + business logic — the single home for turning a chosen
3
+ // MULTIVARIANT variant into:
4
+ // (a) a human-readable label for cart / order / receipt surfaces,
5
+ // (b) concrete product attribute fields when cloning a variant into a
6
+ // standalone UNIQUE unit, and
7
+ // (c) the resolved variantInventory row a sale / clone refers to.
8
+ //
9
+ // Pure + dependency-free so backend, web, and mobile share one rule instead of
10
+ // each reimplementing the options join, the Shopify "Default Title" exclusion,
11
+ // and the find-by-id-then-sku fallback. `variantOptions` stays the source of
12
+ // truth for what was sold; mapOptionsToAttributes only mirrors the well-known
13
+ // axes onto filter attributes so a sold unit looks like a normal product.
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ // Shopify emits this placeholder title for products with no real variants; it
16
+ // should never render as a chosen variant.
17
+ const SHOPIFY_DEFAULT_TITLE = 'default title';
18
+ // Display default. Cart / order detail / receipt all use the middot; the legacy
19
+ // label printer keeps ProductSkuHelpers.describeVariantOptions (" / ").
20
+ const DEFAULT_SEPARATOR = ' · ';
21
+ class ProductVariantHelpers {
22
+ // Join a raw options map's values, e.g. { Size: 'M', Color: 'R' } -> "M · R".
23
+ // Empty/absent values are dropped. Returns '' for a non-object input.
24
+ static optionsLabel(options, separator = DEFAULT_SEPARATOR) {
25
+ if (!options || typeof options !== 'object' || Array.isArray(options)) {
26
+ return '';
27
+ }
28
+ return Object.keys(options)
29
+ .map((k) => String(options[k] == null ? '' : options[k]).trim())
30
+ .filter(Boolean)
31
+ .join(separator);
32
+ }
33
+ // Human-readable variant label for a line item / variant-bearing object.
34
+ // Prefers the chosen `variantOptions`, then a Shopify `variant.title` /
35
+ // `variantTitle` (ignoring the "Default Title" placeholder). Returns '' when
36
+ // there is no variant to show.
37
+ static variantLabel(lineItem, separator = DEFAULT_SEPARATOR) {
38
+ if (!lineItem || typeof lineItem !== 'object')
39
+ return '';
40
+ const fromOptions = this.optionsLabel(lineItem.variantOptions, separator);
41
+ if (fromOptions)
42
+ return fromOptions;
43
+ const title = (lineItem.variant && lineItem.variant.title) || lineItem.variantTitle || '';
44
+ const trimmed = String(title).trim();
45
+ if (trimmed && trimmed.toLowerCase() !== SHOPIFY_DEFAULT_TITLE) {
46
+ return trimmed;
47
+ }
48
+ return '';
49
+ }
50
+ // Resolve which variantInventory row a sale / clone refers to. Variants are
51
+ // identified by their stable `id`; sku is often null on POS-created variants,
52
+ // so id is primary and sku is the fallback. Returns null when unresolved.
53
+ static resolveChosenVariant(product, { variantId = '', sku = '' } = {}) {
54
+ const variants = product && Array.isArray(product.variantInventory) ? product.variantInventory : [];
55
+ const byId = variantId ? variants.find((v) => v && String(v.id || '') === String(variantId)) : null;
56
+ if (byId)
57
+ return byId;
58
+ const bySku = sku ? variants.find((v) => v && String(v.sku || '').trim() === String(sku).trim()) : null;
59
+ return bySku || null;
60
+ }
61
+ // Best-effort map of a variant's chosen options onto concrete product filter
62
+ // attributes, so a cloned single-unit product looks like a normal product to
63
+ // search / filtering / display. Only the well-known axes are mapped (size,
64
+ // color — English + Swedish keys, case-insensitive); unknown axes are left to
65
+ // `variantOptions`, which remains authoritative. Empty values never overwrite.
66
+ static mapOptionsToAttributes(options) {
67
+ const out = {};
68
+ if (!options || typeof options !== 'object' || Array.isArray(options)) {
69
+ return out;
70
+ }
71
+ Object.keys(options).forEach((rawKey) => {
72
+ const key = String(rawKey || '')
73
+ .trim()
74
+ .toLowerCase();
75
+ const value = String(options[rawKey] == null ? '' : options[rawKey]).trim();
76
+ if (!value)
77
+ return;
78
+ if (key === 'size' || key === 'storlek') {
79
+ out.size = value;
80
+ out.standardSize = value;
81
+ }
82
+ else if (key === 'color' || key === 'colour' || key === 'färg' || key === 'farg') {
83
+ out.color = value;
84
+ }
85
+ // Any other axis intentionally stays only in variantOptions.
86
+ });
87
+ return out;
88
+ }
89
+ }
90
+ exports.default = ProductVariantHelpers;
package/lib/index.d.ts CHANGED
@@ -50,11 +50,12 @@ import * as MarketplaceOrderHelpers from './helpers/marketplace/MarketplaceOrder
50
50
  import TaxHelpers from './helpers/TaxHelpers';
51
51
  import PricingHelpers from './helpers/PricingHelpers';
52
52
  import ProductSkuHelpers, { DEFAULT_SKU_LENGTH, SKU_ALPHABET } from './helpers/ProductSkuHelpers';
53
+ import ProductVariantHelpers from './helpers/ProductVariantHelpers';
53
54
  import ProductInventoryHelpers, { PLACEHOLDER_VARIANT_ID } from './helpers/ProductInventoryHelpers';
54
55
  import RetailProductFactory from './factories/Product/RetailProductFactory';
55
56
  import { FALLBACK_TAX_COUNTRY_CODE, TAX_CATEGORIES, TAX_CATEGORY_ALIASES, TAX_CATEGORY_BASE_LABELS, TAX_CATEGORY_RATES } from './constants/tax-constants';
56
57
  import { ADMIN_SIMPLIFIED_STATES, ADMIN_STATES, PRODUCT_CLASS_VALUES, PRODUCT_STATES, PRODUCT_STATE_LABELS, RETAIL_EDITABLE_PRODUCT_STATES, getProductStateLabel, getRetailEditableProductStateOptions } from './constants/product-constants';
57
- export { RibbnFile, ProductFromAlgoliaJSONDoc, ProductFromShopifyWebhookJSONDoc, ProductFromShopifyJSClientJSONDoc, ProductFormStateFactory, ProductCollectionFormStateFactory, ProductCollectionHelpers, SellRequestFormStateFactory, PickUpFormStateFactory, AddressFormStateFactory, UserFormStateFactory, UserFromShopifyWebhookJSONDoc, UserFromAuthTemplateMethod, DraftOrderFromMirakl, DraftOrderFromApp, ChatRoomFromNewUserSignUp, KlarnaSessionFactory, Product, ProductStateManager, Order, OrderFromShopifyWebhook, OrderFromShopifyAdminApi, OrderFromShopifyStorefrontApi, OrderFromApp, OrderFromTraderaEmail, OrderFormStateFactory, RefundFormStateFactory, PayoutAccount, PayoutAccountFormState, Merchant, MERCHANT_ACCOUNT_MODES, MERCHANT_ACCOUNT_CLASSES, MERCHANT_RELATIONSHIP_TYPES, MARKETPLACE_SELLER_CAPABILITIES, DEFAULT_MARKETPLACE_SELLER_CAPABILITIES, MerchantFormState, MerchantFormStateFactory, MerchantConfigAutomatedPayouts, MerchantConfigAutomatedPayoutsFormState, ReRobeProductHelpers, MarketplaceProductHelpers, MarketplaceLedgerHelpers, MarketplaceLegacyAdapters, MarketplaceLineDisplayHelpers, MarketplaceOrderHelpers, MARKETPLACE_LISTING_STATUSES, MARKETPLACE_COMMISSION_BASES, MARKETPLACE_RELATIONSHIP_TYPES, MARKETPLACE_FEE_TYPES, MARKETPLACE_FEE_ALLOCATION_BASES, MARKETPLACE_LEDGER_STATUSES, MARKETPLACE_INVENTORY_POLICY_KINDS, MARKETPLACE_SELLER_DEFAULT_COMMISSION, STOCK_STATUSES, DEFAULT_MARKETPLACE_LISTING_STATUS, DEFAULT_MARKETPLACE_COMMISSION_BASIS, DEFAULT_MARKETPLACE_RELATIONSHIP_TYPE, DEFAULT_STRIPE_FEE_ALLOCATION_BASIS, DEFAULT_RIBBN_FEE_ALLOCATION_BASIS, DEFAULT_MARKETPLACE_LEDGER_STATUS, User, AnalyticsHelpers, OrderHelpers, WebhookFormState, MerchantWebPage, ShopifyMerchantAccount, CustomerNotification, TaxHelpers, PricingHelpers, ProductSkuHelpers, ProductInventoryHelpers, RetailProductFactory, SKU_ALPHABET, DEFAULT_SKU_LENGTH, PLACEHOLDER_VARIANT_ID, TAX_CATEGORIES, TAX_CATEGORY_RATES, TAX_CATEGORY_BASE_LABELS, TAX_CATEGORY_ALIASES, FALLBACK_TAX_COUNTRY_CODE, PRODUCT_STATES, PRODUCT_STATE_LABELS, PRODUCT_CLASS_VALUES, ADMIN_STATES, ADMIN_SIMPLIFIED_STATES, RETAIL_EDITABLE_PRODUCT_STATES, getProductStateLabel, getRetailEditableProductStateOptions, };
58
+ export { RibbnFile, ProductFromAlgoliaJSONDoc, ProductFromShopifyWebhookJSONDoc, ProductFromShopifyJSClientJSONDoc, ProductFormStateFactory, ProductCollectionFormStateFactory, ProductCollectionHelpers, SellRequestFormStateFactory, PickUpFormStateFactory, AddressFormStateFactory, UserFormStateFactory, UserFromShopifyWebhookJSONDoc, UserFromAuthTemplateMethod, DraftOrderFromMirakl, DraftOrderFromApp, ChatRoomFromNewUserSignUp, KlarnaSessionFactory, Product, ProductStateManager, Order, OrderFromShopifyWebhook, OrderFromShopifyAdminApi, OrderFromShopifyStorefrontApi, OrderFromApp, OrderFromTraderaEmail, OrderFormStateFactory, RefundFormStateFactory, PayoutAccount, PayoutAccountFormState, Merchant, MERCHANT_ACCOUNT_MODES, MERCHANT_ACCOUNT_CLASSES, MERCHANT_RELATIONSHIP_TYPES, MARKETPLACE_SELLER_CAPABILITIES, DEFAULT_MARKETPLACE_SELLER_CAPABILITIES, MerchantFormState, MerchantFormStateFactory, MerchantConfigAutomatedPayouts, MerchantConfigAutomatedPayoutsFormState, ReRobeProductHelpers, MarketplaceProductHelpers, MarketplaceLedgerHelpers, MarketplaceLegacyAdapters, MarketplaceLineDisplayHelpers, MarketplaceOrderHelpers, MARKETPLACE_LISTING_STATUSES, MARKETPLACE_COMMISSION_BASES, MARKETPLACE_RELATIONSHIP_TYPES, MARKETPLACE_FEE_TYPES, MARKETPLACE_FEE_ALLOCATION_BASES, MARKETPLACE_LEDGER_STATUSES, MARKETPLACE_INVENTORY_POLICY_KINDS, MARKETPLACE_SELLER_DEFAULT_COMMISSION, STOCK_STATUSES, DEFAULT_MARKETPLACE_LISTING_STATUS, DEFAULT_MARKETPLACE_COMMISSION_BASIS, DEFAULT_MARKETPLACE_RELATIONSHIP_TYPE, DEFAULT_STRIPE_FEE_ALLOCATION_BASIS, DEFAULT_RIBBN_FEE_ALLOCATION_BASIS, DEFAULT_MARKETPLACE_LEDGER_STATUS, User, AnalyticsHelpers, OrderHelpers, WebhookFormState, MerchantWebPage, ShopifyMerchantAccount, CustomerNotification, TaxHelpers, PricingHelpers, ProductSkuHelpers, ProductVariantHelpers, ProductInventoryHelpers, RetailProductFactory, SKU_ALPHABET, DEFAULT_SKU_LENGTH, PLACEHOLDER_VARIANT_ID, TAX_CATEGORIES, TAX_CATEGORY_RATES, TAX_CATEGORY_BASE_LABELS, TAX_CATEGORY_ALIASES, FALLBACK_TAX_COUNTRY_CODE, PRODUCT_STATES, PRODUCT_STATE_LABELS, PRODUCT_CLASS_VALUES, ADMIN_STATES, ADMIN_SIMPLIFIED_STATES, RETAIL_EDITABLE_PRODUCT_STATES, getProductStateLabel, getRetailEditableProductStateOptions, };
58
59
  export type { PlaceholderVariantInput, PlaceholderVariantInventory, PlaceholderVariantLocation, } from './helpers/ProductInventoryHelpers';
59
60
  export type { RetailOwnershipInput, RetailAccountingInput, RetailLocationInput, ClothingDetailsInput, NonClothingDetailsInput, OneOfAKindClothingInput, MultivariantClothingInput, TrackedRetailInput, UntrackedRetailInput, } from './factories/Product/RetailProductFactory';
60
61
  export type { TaxCategoryValue } from './constants/tax-constants';
package/lib/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MARKETPLACE_FEE_ALLOCATION_BASES = exports.MARKETPLACE_FEE_TYPES = exports.MARKETPLACE_RELATIONSHIP_TYPES = exports.MARKETPLACE_COMMISSION_BASES = exports.MARKETPLACE_LISTING_STATUSES = exports.MarketplaceOrderHelpers = exports.MarketplaceLineDisplayHelpers = exports.MarketplaceLegacyAdapters = exports.MarketplaceLedgerHelpers = exports.MarketplaceProductHelpers = exports.ReRobeProductHelpers = exports.MerchantConfigAutomatedPayoutsFormState = exports.MerchantConfigAutomatedPayouts = exports.MerchantFormStateFactory = exports.MerchantFormState = exports.DEFAULT_MARKETPLACE_SELLER_CAPABILITIES = exports.MARKETPLACE_SELLER_CAPABILITIES = exports.MERCHANT_RELATIONSHIP_TYPES = exports.MERCHANT_ACCOUNT_CLASSES = exports.MERCHANT_ACCOUNT_MODES = exports.Merchant = exports.PayoutAccountFormState = exports.PayoutAccount = exports.RefundFormStateFactory = exports.OrderFormStateFactory = exports.OrderFromTraderaEmail = exports.OrderFromApp = exports.OrderFromShopifyStorefrontApi = exports.OrderFromShopifyAdminApi = exports.OrderFromShopifyWebhook = exports.Order = exports.ProductStateManager = exports.Product = exports.KlarnaSessionFactory = exports.ChatRoomFromNewUserSignUp = exports.DraftOrderFromApp = exports.DraftOrderFromMirakl = exports.UserFromAuthTemplateMethod = exports.UserFromShopifyWebhookJSONDoc = exports.UserFormStateFactory = exports.AddressFormStateFactory = exports.PickUpFormStateFactory = exports.SellRequestFormStateFactory = exports.ProductCollectionHelpers = exports.ProductCollectionFormStateFactory = exports.ProductFormStateFactory = exports.ProductFromShopifyJSClientJSONDoc = exports.ProductFromShopifyWebhookJSONDoc = exports.ProductFromAlgoliaJSONDoc = exports.RibbnFile = void 0;
4
- exports.getRetailEditableProductStateOptions = exports.getProductStateLabel = exports.RETAIL_EDITABLE_PRODUCT_STATES = exports.ADMIN_SIMPLIFIED_STATES = exports.ADMIN_STATES = exports.PRODUCT_CLASS_VALUES = exports.PRODUCT_STATE_LABELS = exports.PRODUCT_STATES = exports.FALLBACK_TAX_COUNTRY_CODE = exports.TAX_CATEGORY_ALIASES = exports.TAX_CATEGORY_BASE_LABELS = exports.TAX_CATEGORY_RATES = exports.TAX_CATEGORIES = exports.PLACEHOLDER_VARIANT_ID = exports.DEFAULT_SKU_LENGTH = exports.SKU_ALPHABET = exports.RetailProductFactory = exports.ProductInventoryHelpers = exports.ProductSkuHelpers = exports.PricingHelpers = exports.TaxHelpers = exports.CustomerNotification = exports.ShopifyMerchantAccount = exports.MerchantWebPage = exports.WebhookFormState = exports.OrderHelpers = exports.AnalyticsHelpers = exports.User = exports.DEFAULT_MARKETPLACE_LEDGER_STATUS = exports.DEFAULT_RIBBN_FEE_ALLOCATION_BASIS = exports.DEFAULT_STRIPE_FEE_ALLOCATION_BASIS = exports.DEFAULT_MARKETPLACE_RELATIONSHIP_TYPE = exports.DEFAULT_MARKETPLACE_COMMISSION_BASIS = exports.DEFAULT_MARKETPLACE_LISTING_STATUS = exports.STOCK_STATUSES = exports.MARKETPLACE_SELLER_DEFAULT_COMMISSION = exports.MARKETPLACE_INVENTORY_POLICY_KINDS = exports.MARKETPLACE_LEDGER_STATUSES = void 0;
4
+ exports.getRetailEditableProductStateOptions = exports.getProductStateLabel = exports.RETAIL_EDITABLE_PRODUCT_STATES = exports.ADMIN_SIMPLIFIED_STATES = exports.ADMIN_STATES = exports.PRODUCT_CLASS_VALUES = exports.PRODUCT_STATE_LABELS = exports.PRODUCT_STATES = exports.FALLBACK_TAX_COUNTRY_CODE = exports.TAX_CATEGORY_ALIASES = exports.TAX_CATEGORY_BASE_LABELS = exports.TAX_CATEGORY_RATES = exports.TAX_CATEGORIES = exports.PLACEHOLDER_VARIANT_ID = exports.DEFAULT_SKU_LENGTH = exports.SKU_ALPHABET = exports.RetailProductFactory = exports.ProductInventoryHelpers = exports.ProductVariantHelpers = exports.ProductSkuHelpers = exports.PricingHelpers = exports.TaxHelpers = exports.CustomerNotification = exports.ShopifyMerchantAccount = exports.MerchantWebPage = exports.WebhookFormState = exports.OrderHelpers = exports.AnalyticsHelpers = exports.User = exports.DEFAULT_MARKETPLACE_LEDGER_STATUS = exports.DEFAULT_RIBBN_FEE_ALLOCATION_BASIS = exports.DEFAULT_STRIPE_FEE_ALLOCATION_BASIS = exports.DEFAULT_MARKETPLACE_RELATIONSHIP_TYPE = exports.DEFAULT_MARKETPLACE_COMMISSION_BASIS = exports.DEFAULT_MARKETPLACE_LISTING_STATUS = exports.STOCK_STATUSES = exports.MARKETPLACE_SELLER_DEFAULT_COMMISSION = exports.MARKETPLACE_INVENTORY_POLICY_KINDS = exports.MARKETPLACE_LEDGER_STATUSES = void 0;
5
5
  const ProductFromShopifyJSClientJSONDoc_1 = require("./factories/Product/ProductFromShopifyJSClientJSONDoc");
6
6
  exports.ProductFromShopifyJSClientJSONDoc = ProductFromShopifyJSClientJSONDoc_1.default;
7
7
  const ProductFromAlgoliaJSONDoc_1 = require("./factories/Product/ProductFromAlgoliaJSONDoc");
@@ -126,6 +126,8 @@ const ProductSkuHelpers_1 = require("./helpers/ProductSkuHelpers");
126
126
  exports.ProductSkuHelpers = ProductSkuHelpers_1.default;
127
127
  Object.defineProperty(exports, "DEFAULT_SKU_LENGTH", { enumerable: true, get: function () { return ProductSkuHelpers_1.DEFAULT_SKU_LENGTH; } });
128
128
  Object.defineProperty(exports, "SKU_ALPHABET", { enumerable: true, get: function () { return ProductSkuHelpers_1.SKU_ALPHABET; } });
129
+ const ProductVariantHelpers_1 = require("./helpers/ProductVariantHelpers");
130
+ exports.ProductVariantHelpers = ProductVariantHelpers_1.default;
129
131
  const ProductInventoryHelpers_1 = require("./helpers/ProductInventoryHelpers");
130
132
  exports.ProductInventoryHelpers = ProductInventoryHelpers_1.default;
131
133
  Object.defineProperty(exports, "PLACEHOLDER_VARIANT_ID", { enumerable: true, get: function () { return ProductInventoryHelpers_1.PLACEHOLDER_VARIANT_ID; } });
@@ -24,6 +24,17 @@ export default class Product extends Base {
24
24
  getEffectiveSku(): string;
25
25
  getEffectiveVariantSku(variantId: string): string;
26
26
  describeVariant(variantId: string): string;
27
+ buildVariantCloneData({ chosenVariantId, chosenVariantSku, price, imageUrls, overrides, }?: {
28
+ chosenVariantId?: string;
29
+ chosenVariantSku?: string;
30
+ price?: string | number;
31
+ imageUrls?: string[];
32
+ overrides?: {
33
+ [k: string]: any;
34
+ };
35
+ }): {
36
+ [k: string]: any;
37
+ };
27
38
  diagnoseVariantInventory(): 'no_variants' | 'all_zero_qty' | 'ok';
28
39
  toProductInputObjForShopify(location?: string): any;
29
40
  toProductInputObjForShopifyV2(locationId: string, weightUnit?: string): any[];
@@ -8,6 +8,7 @@ const ReRobeProductHelpers_1 = require("../helpers/ReRobeProductHelpers");
8
8
  const MarketplaceProductHelpers_1 = require("../helpers/MarketplaceProductHelpers");
9
9
  const PricingHelpers_1 = require("../helpers/PricingHelpers");
10
10
  const ProductSkuHelpers_1 = require("../helpers/ProductSkuHelpers");
11
+ const ProductVariantHelpers_1 = require("../helpers/ProductVariantHelpers");
11
12
  class Product extends Base_1.default {
12
13
  constructor(props) {
13
14
  super();
@@ -255,6 +256,33 @@ class Product extends Base_1.default {
255
256
  return '';
256
257
  return ProductSkuHelpers_1.default.describeVariantOptions(variant.options || {});
257
258
  }
259
+ // Build the data for ONE concrete, single-unit clone of a chosen variant —
260
+ // a UNIQUE product carrying the variant's identity (options / sku / price)
261
+ // and back-linked to this parent so its stock can be decremented at sale
262
+ // time. The clone is HIDDEN until sold (kept out of the seller's catalog /
263
+ // counts; reaped by the abandoned-clone cron if the cart is dropped) and
264
+ // tagged `clonedProduct` + `variantClone`. The chosen options are also
265
+ // mirrored onto concrete filter attributes (size / color) so the unit looks
266
+ // like a normal product to search / display, while `variantOptions` stays
267
+ // authoritative.
268
+ //
269
+ // Pure: returns the clone's data object. The caller assigns a documentId and
270
+ // persists it (and may create N copies for quantity > 1).
271
+ buildVariantCloneData({ chosenVariantId = '', chosenVariantSku = '', price = '', imageUrls = [], overrides = {}, } = {}) {
272
+ const parent = this.toObj();
273
+ const chosenVariant = ProductVariantHelpers_1.default.resolveChosenVariant(parent, {
274
+ variantId: chosenVariantId,
275
+ sku: chosenVariantSku,
276
+ });
277
+ const variantOptions = (chosenVariant && chosenVariant.options) || {};
278
+ const resolvedPrice = price || (chosenVariant && chosenVariant.price) || parent.price || '0';
279
+ const resolvedImageUrls = Array.isArray(imageUrls) && imageUrls.length ? imageUrls : parent.imageUrls || [];
280
+ const resolvedSku = (chosenVariant && chosenVariant.sku) || parent.sku || '';
281
+ const systemTags = Array.isArray(parent.systemTags)
282
+ ? parent.systemTags.filter((tag) => tag !== 'templateProduct')
283
+ : [];
284
+ return Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, parent), { productClass: product_constants_1.PRODUCT_CLASS_VALUES.UNIQUE, variantInventory: [], status: product_constants_1.PRODUCT_STATES.hidden, systemTags: [...new Set([...systemTags, 'clonedProduct', 'variantClone'])], price: String(resolvedPrice), imageUrls: resolvedImageUrls, sku: resolvedSku }), ProductVariantHelpers_1.default.mapOptionsToAttributes(variantOptions)), { variantOptions, originalVariantProductId: parent.documentId || '', chosenVariantId: (chosenVariant && chosenVariant.id) || chosenVariantId || '', chosenVariantSku: resolvedSku, bookedTimestamp: null, openTimestamp: null }), overrides);
285
+ }
258
286
  // Diagnose whether a variant-inventory product is purchasable. Mirrors
259
287
  // the readiness gate the retail entry exposes as a confirm-before-save
260
288
  // dialog: a multivariant product with no variants generated yet, or
@@ -633,6 +661,10 @@ class Product extends Base_1.default {
633
661
  primaryAgeCategory: this.utilities.sanitizeString(this.filterAttributes.primaryAgeCategory),
634
662
  isOnSale: this.utilities.sanitizeString(this.consignmentAttributes.isOnSale),
635
663
  isTaxable: this.utilities.sanitizeString(this.attributes.isTaxable),
664
+ // Reduced-rate gross display in product lists needs the category (12% FOOD
665
+ // / 6% CULTURE etc.); without it the list defaults to STANDARD (25%) and
666
+ // over-states the listing price for reduced-rate products.
667
+ taxCategory: this.utilities.sanitizeString(this.attributes.taxCategory),
636
668
  merchants: this.utilities.sanitzeStringArr(this.attributes.merchants),
637
669
  merchantId: this.utilities.sanitizeString(this.attributes.merchantId),
638
670
  marketplaceVisibleToMerchantIds: marketplaceFields.marketplaceVisibleToMerchantIds,
@@ -324,6 +324,7 @@ type TypesenseProductObj = {
324
324
  primaryAgeCategory: string;
325
325
  isOnSale: string;
326
326
  isTaxable: string;
327
+ taxCategory: string;
327
328
  merchants: string[];
328
329
  merchantId: string;
329
330
  price: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rerobe-js-orm",
3
- "version": "4.9.0",
3
+ "version": "4.9.2",
4
4
  "description": "ReRobe's Javascript ORM Framework",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -21,7 +21,9 @@
21
21
  "type": "git",
22
22
  "url": "git+https://github.com/ReRobe/rerobe-object-factories.git"
23
23
  },
24
- "keywords": ["ribbn"],
24
+ "keywords": [
25
+ "ribbn"
26
+ ],
25
27
  "license": "ISC",
26
28
  "bugs": {
27
29
  "url": "https://github.com/ReRobe/rerobe-product/issues"