rerobe-js-orm 4.8.7 → 4.9.0
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.
- package/lib/constants/marketplace-constants.d.ts +52 -0
- package/lib/constants/marketplace-constants.js +82 -0
- package/lib/constants/merchant-constants.d.ts +35 -0
- package/lib/constants/merchant-constants.js +35 -1
- package/lib/constants/product-constants.d.ts +6 -0
- package/lib/constants/product-constants.js +43 -1
- package/lib/constants/tax-constants.d.ts +19 -0
- package/lib/constants/tax-constants.js +70 -0
- package/lib/factories/Product/RetailProductFactory.d.ts +102 -0
- package/lib/factories/Product/RetailProductFactory.js +260 -0
- package/lib/form-states/Product/ProductFormState.d.ts +9 -0
- package/lib/form-states/Product/ProductFormState.js +46 -0
- package/lib/helpers/MarketplaceProductHelpers.d.ts +181 -0
- package/lib/helpers/MarketplaceProductHelpers.js +555 -0
- package/lib/helpers/OrderHelpers.d.ts +5 -2
- package/lib/helpers/OrderHelpers.js +18 -4
- package/lib/helpers/PricingHelpers.d.ts +29 -0
- package/lib/helpers/PricingHelpers.js +215 -0
- package/lib/helpers/ProductInventoryHelpers.d.ts +31 -0
- package/lib/helpers/ProductInventoryHelpers.js +66 -0
- package/lib/helpers/ProductSkuHelpers.d.ts +13 -0
- package/lib/helpers/ProductSkuHelpers.js +70 -0
- package/lib/helpers/TaxHelpers.d.ts +15 -0
- package/lib/helpers/TaxHelpers.js +76 -0
- package/lib/helpers/marketplace/CommissionPolicy.d.ts +20 -0
- package/lib/helpers/marketplace/CommissionPolicy.js +9 -0
- package/lib/helpers/marketplace/CommissionPolicyRegistry.d.ts +4 -0
- package/lib/helpers/marketplace/CommissionPolicyRegistry.js +21 -0
- package/lib/helpers/marketplace/EvenPerSellerStripeFeePolicy.d.ts +5 -0
- package/lib/helpers/marketplace/EvenPerSellerStripeFeePolicy.js +46 -0
- package/lib/helpers/marketplace/FeeAllocationPolicy.d.ts +10 -0
- package/lib/helpers/marketplace/FeeAllocationPolicy.js +36 -0
- package/lib/helpers/marketplace/FeeAllocationPolicyRegistry.d.ts +6 -0
- package/lib/helpers/marketplace/FeeAllocationPolicyRegistry.js +26 -0
- package/lib/helpers/marketplace/InventoryPolicy.d.ts +18 -0
- package/lib/helpers/marketplace/InventoryPolicy.js +7 -0
- package/lib/helpers/marketplace/InventoryPolicyRegistry.d.ts +4 -0
- package/lib/helpers/marketplace/InventoryPolicyRegistry.js +29 -0
- package/lib/helpers/marketplace/LineNetCommissionPolicy.d.ts +5 -0
- package/lib/helpers/marketplace/LineNetCommissionPolicy.js +25 -0
- package/lib/helpers/marketplace/MarketplaceErrors.d.ts +6 -0
- package/lib/helpers/marketplace/MarketplaceErrors.js +21 -0
- package/lib/helpers/marketplace/MarketplaceLedgerHelpers.d.ts +40 -0
- package/lib/helpers/marketplace/MarketplaceLedgerHelpers.js +120 -0
- package/lib/helpers/marketplace/MarketplaceLegacyAdapters.d.ts +53 -0
- package/lib/helpers/marketplace/MarketplaceLegacyAdapters.js +99 -0
- package/lib/helpers/marketplace/MarketplaceLineDisplayHelpers.d.ts +40 -0
- package/lib/helpers/marketplace/MarketplaceLineDisplayHelpers.js +125 -0
- package/lib/helpers/marketplace/MarketplaceOrderHelpers.d.ts +15 -0
- package/lib/helpers/marketplace/MarketplaceOrderHelpers.js +77 -0
- package/lib/helpers/marketplace/MultivariantLocationInventoryPolicy.d.ts +9 -0
- package/lib/helpers/marketplace/MultivariantLocationInventoryPolicy.js +60 -0
- package/lib/helpers/marketplace/OneOfAKindInventoryPolicy.d.ts +9 -0
- package/lib/helpers/marketplace/OneOfAKindInventoryPolicy.js +55 -0
- package/lib/helpers/marketplace/OriginalCommissionShareCommissionPolicy.d.ts +5 -0
- package/lib/helpers/marketplace/OriginalCommissionShareCommissionPolicy.js +26 -0
- package/lib/helpers/marketplace/ProportionalToLineNetPolicy.d.ts +5 -0
- package/lib/helpers/marketplace/ProportionalToLineNetPolicy.js +35 -0
- package/lib/helpers/marketplace/UntrackedStockInventoryPolicy.d.ts +7 -0
- package/lib/helpers/marketplace/UntrackedStockInventoryPolicy.js +23 -0
- package/lib/index.d.ts +18 -1
- package/lib/index.js +56 -1
- package/lib/models/Merchant.d.ts +86 -0
- package/lib/models/Merchant.js +86 -0
- package/lib/models/Product.d.ts +16 -0
- package/lib/models/Product.js +151 -0
- package/lib/types/merchant-types.d.ts +28 -0
- package/lib/types/pricing-types.d.ts +85 -0
- package/lib/types/pricing-types.js +5 -0
- package/lib/types/rerobe-order-types.d.ts +86 -0
- package/lib/types/rerobe-product-types.d.ts +19 -0
- package/package.json +1 -1
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Retail product factory. Lifts the four `build*Payload` helpers from
|
|
3
|
+
// `ribbn-web-app/components/admin/products-v2/RetailProductQuickEntry.tsx`
|
|
4
|
+
// into ORM as four pure factory methods that produce canonical
|
|
5
|
+
// seller-owned `Product` instances.
|
|
6
|
+
//
|
|
7
|
+
// Why this lives here:
|
|
8
|
+
// - The shape decisions (productClass, default status, default
|
|
9
|
+
// availableForSale, placeholder variant inventory, default
|
|
10
|
+
// reRobeCommission for marketplace sellers) are business logic, not
|
|
11
|
+
// UI plumbing — every surface that creates a retail product (web
|
|
12
|
+
// POS today, mobile / CSV uploader / backend service tomorrow)
|
|
13
|
+
// should produce the same shape.
|
|
14
|
+
// - Framework-agnostic: no Firestore, no React, no fetch. Persistence
|
|
15
|
+
// timestamps and the actual write are the caller's concern. Web
|
|
16
|
+
// keeps producing `serverTimestamp()` for `createdAtTimestamp` /
|
|
17
|
+
// `updatedAtTimestamp` and merging it into `factory.toObj()`.
|
|
18
|
+
// - Canonical marketplace shape: ownership is always seller-owned
|
|
19
|
+
// (`merchantId = vendorId = sellerMerchantId`,
|
|
20
|
+
// `merchants = [sellerMerchantId]`). Marketplace visibility for a
|
|
21
|
+
// parent is layered on top via
|
|
22
|
+
// `MarketplaceProductHelpers.upsertListing(...)` after construction
|
|
23
|
+
// — keeps this factory marketplace-aware-but-not-marketplace-coupled.
|
|
24
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
+
const product_constants_1 = require("../../constants/product-constants");
|
|
26
|
+
const marketplace_constants_1 = require("../../constants/marketplace-constants");
|
|
27
|
+
const MarketplaceProductHelpers_1 = require("../../helpers/MarketplaceProductHelpers");
|
|
28
|
+
const ProductInventoryHelpers_1 = require("../../helpers/ProductInventoryHelpers");
|
|
29
|
+
const ProductSkuHelpers_1 = require("../../helpers/ProductSkuHelpers");
|
|
30
|
+
const tax_constants_1 = require("../../constants/tax-constants");
|
|
31
|
+
const TaxHelpers_1 = require("../../helpers/TaxHelpers");
|
|
32
|
+
const Product_1 = require("../../models/Product");
|
|
33
|
+
class RetailProductFactory {
|
|
34
|
+
// ---- 4 public factory methods ----
|
|
35
|
+
static fromOneOfAKindClothing(input) {
|
|
36
|
+
const base = RetailProductFactory.buildBaseAttributes(input, product_constants_1.PRODUCT_CLASS_VALUES.UNIQUE);
|
|
37
|
+
const details = input.details || {};
|
|
38
|
+
const inventoryLocations = RetailProductFactory.buildInventoryLocationsForFixedQuantity(input.location, 1);
|
|
39
|
+
return new Product_1.default(Object.assign(Object.assign(Object.assign({}, base), RetailProductFactory.normalizeClothingDetails(details)), { quantity: 1, inventoryLocations }));
|
|
40
|
+
}
|
|
41
|
+
static fromMultivariantClothing(input) {
|
|
42
|
+
const base = RetailProductFactory.buildBaseAttributes(input, product_constants_1.PRODUCT_CLASS_VALUES.MULTIVARIANT);
|
|
43
|
+
const details = input.details || {};
|
|
44
|
+
const variantInventory = Array.isArray(input.variantInventory) ? input.variantInventory : [];
|
|
45
|
+
const aggregatedQuantity = RetailProductFactory.aggregateQuantityFromVariantInventory(variantInventory);
|
|
46
|
+
const inventoryLocations = RetailProductFactory.aggregateLocationsFromVariantInventory(variantInventory);
|
|
47
|
+
return new Product_1.default(Object.assign(Object.assign(Object.assign({}, base), RetailProductFactory.normalizeClothingDetails(details)), { variantInventory, quantity: aggregatedQuantity, inventoryLocations }));
|
|
48
|
+
}
|
|
49
|
+
static fromTrackedRetail(input) {
|
|
50
|
+
var _a, _b;
|
|
51
|
+
const base = RetailProductFactory.buildBaseAttributes(input, product_constants_1.PRODUCT_CLASS_VALUES.MULTIVARIANT);
|
|
52
|
+
const details = input.details || {};
|
|
53
|
+
const sku = base.sku;
|
|
54
|
+
const numericQuantity = RetailProductFactory.coerceNonNegativeQuantity(input.quantity);
|
|
55
|
+
const placeholderVariant = ProductInventoryHelpers_1.default.buildPlaceholderVariantInventory({
|
|
56
|
+
sku,
|
|
57
|
+
price: base.price,
|
|
58
|
+
taxable: input.variantTaxable || base.isTaxable,
|
|
59
|
+
quantity: numericQuantity,
|
|
60
|
+
locationId: (_a = input.location) === null || _a === void 0 ? void 0 : _a.locationId,
|
|
61
|
+
locationName: (_b = input.location) === null || _b === void 0 ? void 0 : _b.locationName,
|
|
62
|
+
continueSellingWhenOutOfStock: false,
|
|
63
|
+
});
|
|
64
|
+
const inventoryLocations = RetailProductFactory.buildInventoryLocationsForFixedQuantity(input.location, numericQuantity);
|
|
65
|
+
return new Product_1.default(Object.assign(Object.assign(Object.assign({}, base), RetailProductFactory.normalizeNonClothingDetails(details)), { variantInventory: placeholderVariant, inventoryLocations, quantity: numericQuantity }));
|
|
66
|
+
}
|
|
67
|
+
static fromUntrackedRetail(input) {
|
|
68
|
+
var _a, _b;
|
|
69
|
+
const base = RetailProductFactory.buildBaseAttributes(input, product_constants_1.PRODUCT_CLASS_VALUES.MULTIVARIANT);
|
|
70
|
+
const details = input.details || {};
|
|
71
|
+
const sku = base.sku;
|
|
72
|
+
const placeholderVariant = ProductInventoryHelpers_1.default.buildPlaceholderVariantInventory({
|
|
73
|
+
sku,
|
|
74
|
+
price: base.price,
|
|
75
|
+
taxable: base.isTaxable,
|
|
76
|
+
quantity: 0,
|
|
77
|
+
locationId: (_a = input.location) === null || _a === void 0 ? void 0 : _a.locationId,
|
|
78
|
+
locationName: (_b = input.location) === null || _b === void 0 ? void 0 : _b.locationName,
|
|
79
|
+
continueSellingWhenOutOfStock: true,
|
|
80
|
+
});
|
|
81
|
+
const inventoryLocations = RetailProductFactory.buildInventoryLocationsForFixedQuantity(input.location, 0);
|
|
82
|
+
return new Product_1.default(Object.assign(Object.assign(Object.assign({}, base), RetailProductFactory.normalizeNonClothingDetails(details)), { variantInventory: placeholderVariant, inventoryLocations, quantity: 0,
|
|
83
|
+
// Sentinel that signals the order processor / inventory policy to
|
|
84
|
+
// skip per-location decrements for this product.
|
|
85
|
+
stockStatus: marketplace_constants_1.STOCK_STATUSES.inStockUnlimited }));
|
|
86
|
+
}
|
|
87
|
+
// ---- Shared helpers (exposed as static so callers / tests can use them) ----
|
|
88
|
+
static resolveOwnership(ownership) {
|
|
89
|
+
const sellerMerchantId = String((ownership === null || ownership === void 0 ? void 0 : ownership.sellerMerchantId) || '').trim();
|
|
90
|
+
if (!sellerMerchantId) {
|
|
91
|
+
throw new Error('RetailProductFactory: ownership.sellerMerchantId is required');
|
|
92
|
+
}
|
|
93
|
+
const ownershipShape = MarketplaceProductHelpers_1.default.buildSellerProductOwnership({ sellerMerchantId });
|
|
94
|
+
return Object.assign(Object.assign({}, ownershipShape), { vendorName: (ownership === null || ownership === void 0 ? void 0 : ownership.sellerMerchantName) || '' });
|
|
95
|
+
}
|
|
96
|
+
static resolveDefaults(ownership) {
|
|
97
|
+
const isMarketplaceSeller = !!(ownership === null || ownership === void 0 ? void 0 : ownership.isMarketplaceSeller);
|
|
98
|
+
return {
|
|
99
|
+
status: isMarketplaceSeller ? product_constants_1.PRODUCT_STATES.listed : product_constants_1.PRODUCT_STATES.draft,
|
|
100
|
+
availableForSale: isMarketplaceSeller,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
static resolveAccounting(accounting, ownership) {
|
|
104
|
+
var _a, _b, _c;
|
|
105
|
+
const normalizedTaxCategory = TaxHelpers_1.default.normalizeTaxCategory(accounting === null || accounting === void 0 ? void 0 : accounting.taxCategory);
|
|
106
|
+
const isTaxable = (accounting === null || accounting === void 0 ? void 0 : accounting.isTaxable) !== undefined
|
|
107
|
+
? accounting.isTaxable
|
|
108
|
+
: normalizedTaxCategory === tax_constants_1.TAX_CATEGORIES.EXEMPT
|
|
109
|
+
? 'no'
|
|
110
|
+
: 'yes';
|
|
111
|
+
const reRobeCommission = (accounting === null || accounting === void 0 ? void 0 : accounting.reRobeCommission) !== undefined
|
|
112
|
+
? accounting.reRobeCommission
|
|
113
|
+
: (ownership === null || ownership === void 0 ? void 0 : ownership.isMarketplaceSeller)
|
|
114
|
+
? MarketplaceProductHelpers_1.default.defaultSellerCommission()
|
|
115
|
+
: undefined;
|
|
116
|
+
return {
|
|
117
|
+
price: String((_a = accounting === null || accounting === void 0 ? void 0 : accounting.price) !== null && _a !== void 0 ? _a : '').trim(),
|
|
118
|
+
taxCategory: String(normalizedTaxCategory),
|
|
119
|
+
isTaxable,
|
|
120
|
+
costPerItem: String((_b = accounting === null || accounting === void 0 ? void 0 : accounting.costPerItem) !== null && _b !== void 0 ? _b : '').trim(),
|
|
121
|
+
compareAtPrice: String((_c = accounting === null || accounting === void 0 ? void 0 : accounting.compareAtPrice) !== null && _c !== void 0 ? _c : '').trim(),
|
|
122
|
+
reRobeCommission,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
// ---- Private helpers ----
|
|
126
|
+
static buildBaseAttributes(input, productClass) {
|
|
127
|
+
const ownership = RetailProductFactory.resolveOwnership(input.ownership);
|
|
128
|
+
const defaults = RetailProductFactory.resolveDefaults(input.ownership);
|
|
129
|
+
const accounting = RetailProductFactory.resolveAccounting(input.accounting, input.ownership);
|
|
130
|
+
const sku = String(input.sku || '').trim() || ProductSkuHelpers_1.default.generateSku();
|
|
131
|
+
const title = String(input.title || '').trim();
|
|
132
|
+
const base = {
|
|
133
|
+
title,
|
|
134
|
+
sku,
|
|
135
|
+
productClass,
|
|
136
|
+
price: accounting.price,
|
|
137
|
+
taxCategory: accounting.taxCategory,
|
|
138
|
+
isTaxable: accounting.isTaxable,
|
|
139
|
+
costPerItem: accounting.costPerItem,
|
|
140
|
+
compareAtPrice: accounting.compareAtPrice,
|
|
141
|
+
vendorId: ownership.vendorId,
|
|
142
|
+
vendorName: ownership.vendorName,
|
|
143
|
+
merchantId: ownership.merchantId,
|
|
144
|
+
merchants: ownership.merchants,
|
|
145
|
+
status: defaults.status,
|
|
146
|
+
availableForSale: defaults.availableForSale,
|
|
147
|
+
imageUrls: Array.isArray(input.imageUrls) ? input.imageUrls : [],
|
|
148
|
+
coverPhotoUrl: input.coverPhotoUrl || '',
|
|
149
|
+
tags: Array.isArray(input.tags) ? input.tags : [],
|
|
150
|
+
};
|
|
151
|
+
if (accounting.reRobeCommission !== undefined) {
|
|
152
|
+
base.reRobeCommission = accounting.reRobeCommission;
|
|
153
|
+
}
|
|
154
|
+
return base;
|
|
155
|
+
}
|
|
156
|
+
static normalizeClothingDetails(details) {
|
|
157
|
+
const out = {};
|
|
158
|
+
if (details.brand !== undefined)
|
|
159
|
+
out.brand = details.brand;
|
|
160
|
+
if (details.gender !== undefined)
|
|
161
|
+
out.gender = details.gender;
|
|
162
|
+
if (details.productCategory !== undefined)
|
|
163
|
+
out.productCategory = details.productCategory;
|
|
164
|
+
if (details.productType !== undefined)
|
|
165
|
+
out.productType = details.productType;
|
|
166
|
+
if (details.color !== undefined)
|
|
167
|
+
out.color = details.color;
|
|
168
|
+
if (details.size !== undefined)
|
|
169
|
+
out.size = details.size;
|
|
170
|
+
if (details.productStyle !== undefined)
|
|
171
|
+
out.productStyle = details.productStyle;
|
|
172
|
+
if (details.materialComposition !== undefined)
|
|
173
|
+
out.materialComposition = details.materialComposition;
|
|
174
|
+
if (details.measurementCategory !== undefined)
|
|
175
|
+
out.measurementCategory = details.measurementCategory;
|
|
176
|
+
if (details.standardSize !== undefined)
|
|
177
|
+
out.standardSize = details.standardSize;
|
|
178
|
+
if (details.internationalSize !== undefined)
|
|
179
|
+
out.internationalSize = details.internationalSize;
|
|
180
|
+
if (details.condition !== undefined)
|
|
181
|
+
out.condition = details.condition;
|
|
182
|
+
if (details.conditionRemarks !== undefined)
|
|
183
|
+
out.conditionRemarks = details.conditionRemarks;
|
|
184
|
+
if (details.productRemarks !== undefined)
|
|
185
|
+
out.productRemarks = details.productRemarks;
|
|
186
|
+
if (details.careInstructions !== undefined)
|
|
187
|
+
out.careInstructions = details.careInstructions;
|
|
188
|
+
if (details.description !== undefined)
|
|
189
|
+
out.description = details.description;
|
|
190
|
+
return out;
|
|
191
|
+
}
|
|
192
|
+
static normalizeNonClothingDetails(details) {
|
|
193
|
+
const out = {};
|
|
194
|
+
if (details.brand !== undefined)
|
|
195
|
+
out.brand = details.brand;
|
|
196
|
+
if (details.productCategory !== undefined)
|
|
197
|
+
out.productCategory = details.productCategory;
|
|
198
|
+
if (details.description !== undefined)
|
|
199
|
+
out.description = details.description;
|
|
200
|
+
return out;
|
|
201
|
+
}
|
|
202
|
+
static buildInventoryLocationsForFixedQuantity(location, quantity) {
|
|
203
|
+
const locationId = String((location === null || location === void 0 ? void 0 : location.locationId) || '').trim();
|
|
204
|
+
if (!locationId)
|
|
205
|
+
return [];
|
|
206
|
+
const safeQty = RetailProductFactory.coerceNonNegativeQuantity(quantity);
|
|
207
|
+
return [
|
|
208
|
+
{
|
|
209
|
+
id: locationId,
|
|
210
|
+
name: (location === null || location === void 0 ? void 0 : location.locationName) || '',
|
|
211
|
+
incomingAmount: 0,
|
|
212
|
+
availableAmount: safeQty,
|
|
213
|
+
},
|
|
214
|
+
];
|
|
215
|
+
}
|
|
216
|
+
static coerceNonNegativeQuantity(value) {
|
|
217
|
+
const n = typeof value === 'number' ? value : Number(value);
|
|
218
|
+
if (!Number.isFinite(n))
|
|
219
|
+
return 0;
|
|
220
|
+
return Math.max(0, Math.floor(n));
|
|
221
|
+
}
|
|
222
|
+
// For multivariant clothing, sum availableAmount across every variant
|
|
223
|
+
// and every variant location so the parent `quantity` field stays in
|
|
224
|
+
// sync with the reality the inventory rows describe. Mirrors the
|
|
225
|
+
// aggregation `ProductFormState.aggregateInventoryLocationsFromVariants`
|
|
226
|
+
// does at edit time.
|
|
227
|
+
static aggregateQuantityFromVariantInventory(variantInventory) {
|
|
228
|
+
return variantInventory.reduce((acc, v) => {
|
|
229
|
+
const locations = Array.isArray(v === null || v === void 0 ? void 0 : v.locations) ? v.locations : [];
|
|
230
|
+
const variantSum = locations.reduce((lacc, loc) => lacc + (Number(loc === null || loc === void 0 ? void 0 : loc.availableAmount) || 0), 0);
|
|
231
|
+
return acc + variantSum;
|
|
232
|
+
}, 0);
|
|
233
|
+
}
|
|
234
|
+
// For multivariant clothing, project the parent `inventoryLocations`
|
|
235
|
+
// by summing per-location availableAmount across every variant. Matches
|
|
236
|
+
// the form-state aggregation rule one-for-one.
|
|
237
|
+
static aggregateLocationsFromVariantInventory(variantInventory) {
|
|
238
|
+
const acc = {};
|
|
239
|
+
variantInventory.forEach((v) => {
|
|
240
|
+
const locations = Array.isArray(v === null || v === void 0 ? void 0 : v.locations) ? v.locations : [];
|
|
241
|
+
locations.forEach((loc) => {
|
|
242
|
+
const id = String((loc === null || loc === void 0 ? void 0 : loc.id) || '').trim();
|
|
243
|
+
if (!id)
|
|
244
|
+
return;
|
|
245
|
+
if (!acc[id]) {
|
|
246
|
+
acc[id] = {
|
|
247
|
+
id,
|
|
248
|
+
name: (loc === null || loc === void 0 ? void 0 : loc.name) || '',
|
|
249
|
+
incomingAmount: 0,
|
|
250
|
+
availableAmount: 0,
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
acc[id].availableAmount = acc[id].availableAmount + (Number(loc === null || loc === void 0 ? void 0 : loc.availableAmount) || 0);
|
|
254
|
+
acc[id].incomingAmount = acc[id].incomingAmount + (Number(loc === null || loc === void 0 ? void 0 : loc.incomingAmount) || 0);
|
|
255
|
+
});
|
|
256
|
+
});
|
|
257
|
+
return Object.keys(acc).map((id) => acc[id]);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
exports.default = RetailProductFactory;
|
|
@@ -75,6 +75,15 @@ export default class ProductFormState extends FormState {
|
|
|
75
75
|
addAxisValue(axis: string, value: string): void;
|
|
76
76
|
removeAxisValue(axis: string, value: string): void;
|
|
77
77
|
reorderAxes(order: string[]): void;
|
|
78
|
+
applyVariantAxes(opts: {
|
|
79
|
+
axes: {
|
|
80
|
+
[axis: string]: string[];
|
|
81
|
+
};
|
|
82
|
+
defaults?: Partial<VariantInventory>;
|
|
83
|
+
}): void;
|
|
84
|
+
deriveAxesFromVariantInventory(): {
|
|
85
|
+
[axis: string]: string[];
|
|
86
|
+
};
|
|
78
87
|
upsertVariantByOptions(options: {
|
|
79
88
|
[k: string]: string;
|
|
80
89
|
}, patch: Partial<VariantInventory>): void;
|
|
@@ -790,6 +790,52 @@ class ProductFormState extends FormState_1.default {
|
|
|
790
790
|
this.variantAxes = next;
|
|
791
791
|
// No regen required; only presentation order
|
|
792
792
|
}
|
|
793
|
+
// Convenience wrapper used by retail entry surfaces that drive variants
|
|
794
|
+
// from a small number of axes (e.g. just Size + Color). Trims and
|
|
795
|
+
// dedupes axis values, drops empty axes, then runs the axis update +
|
|
796
|
+
// regenerate pipeline in one shot. Empty axes input is a no-op so the
|
|
797
|
+
// form-state stays untouched if the merchant clears the dropdowns.
|
|
798
|
+
applyVariantAxes(opts) {
|
|
799
|
+
const inputAxes = (opts === null || opts === void 0 ? void 0 : opts.axes) || {};
|
|
800
|
+
const cleaned = {};
|
|
801
|
+
Object.keys(inputAxes).forEach((axisName) => {
|
|
802
|
+
const values = Array.isArray(inputAxes[axisName]) ? inputAxes[axisName] : [];
|
|
803
|
+
const cleanedValues = Array.from(new Set(values.map((v) => String(v).trim()).filter(Boolean)));
|
|
804
|
+
if (cleanedValues.length > 0) {
|
|
805
|
+
cleaned[axisName] = cleanedValues;
|
|
806
|
+
}
|
|
807
|
+
});
|
|
808
|
+
this.setVariantAxes(cleaned);
|
|
809
|
+
this.generateVariantsFromAxes((opts === null || opts === void 0 ? void 0 : opts.defaults) || {});
|
|
810
|
+
}
|
|
811
|
+
// Reverse of applyVariantAxes — read the current variantInventory rows
|
|
812
|
+
// and project them back to a per-axis values map. Used by simplified
|
|
813
|
+
// retail flows to hydrate local axis dropdowns from a product loaded
|
|
814
|
+
// for editing. Preserves first-seen order so the UI doesn't reshuffle
|
|
815
|
+
// values across renders.
|
|
816
|
+
deriveAxesFromVariantInventory() {
|
|
817
|
+
var _a;
|
|
818
|
+
const variants = (((_a = this.fields.variantInventory) === null || _a === void 0 ? void 0 : _a.selectedValues) || []);
|
|
819
|
+
const acc = {};
|
|
820
|
+
const seen = {};
|
|
821
|
+
variants.forEach((v) => {
|
|
822
|
+
const opts = (v === null || v === void 0 ? void 0 : v.options) || {};
|
|
823
|
+
Object.keys(opts).forEach((axisName) => {
|
|
824
|
+
const value = String(opts[axisName] || '').trim();
|
|
825
|
+
if (!value)
|
|
826
|
+
return;
|
|
827
|
+
if (!acc[axisName]) {
|
|
828
|
+
acc[axisName] = [];
|
|
829
|
+
seen[axisName] = new Set();
|
|
830
|
+
}
|
|
831
|
+
if (!seen[axisName].has(value)) {
|
|
832
|
+
seen[axisName].add(value);
|
|
833
|
+
acc[axisName].push(value);
|
|
834
|
+
}
|
|
835
|
+
});
|
|
836
|
+
});
|
|
837
|
+
return acc;
|
|
838
|
+
}
|
|
793
839
|
upsertVariantByOptions(options, patch) {
|
|
794
840
|
const prev = this.getExistingVariantByOptions(options);
|
|
795
841
|
const id = (prev === null || prev === void 0 ? void 0 : prev.id) || this.utilities.makeRandId(28);
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { MarketplaceCommissionBasisValue, MarketplaceFeeAllocationBasisValue, MarketplaceListingStatusValue, MarketplaceRelationshipTypeValue } from '../constants/marketplace-constants';
|
|
2
|
+
import { CommissionPolicy } from './marketplace/CommissionPolicy';
|
|
3
|
+
import { FeeAllocationContext, FeeAllocationPolicy } from './marketplace/FeeAllocationPolicy';
|
|
4
|
+
import { InventoryAdjustmentParams, InventoryAdjustmentResult, InventoryPolicy } from './marketplace/InventoryPolicy';
|
|
5
|
+
export { CommissionPolicy, CommissionPolicyContext, CommissionPolicyFeeContext, CommissionPolicyResult, } from './marketplace/CommissionPolicy';
|
|
6
|
+
export { FeeAllocationContext, FeeAllocationPolicy } from './marketplace/FeeAllocationPolicy';
|
|
7
|
+
export { InventoryAdjustmentParams, InventoryAdjustmentResult, InventoryPolicy } from './marketplace/InventoryPolicy';
|
|
8
|
+
export { MarketplaceCommissionRateError, MarketplaceOwnershipError } from './marketplace/MarketplaceErrors';
|
|
9
|
+
type BuildMarketplaceListingParams = {
|
|
10
|
+
productMerchantId?: string;
|
|
11
|
+
listings?: {
|
|
12
|
+
parentMarketplaceId: string;
|
|
13
|
+
relationshipId: string;
|
|
14
|
+
relationshipType?: string;
|
|
15
|
+
status?: MarketplaceListingStatusValue | string;
|
|
16
|
+
listedAt?: number | null;
|
|
17
|
+
updatedAt?: number | null;
|
|
18
|
+
}[];
|
|
19
|
+
};
|
|
20
|
+
type VariantSelectionInput = {
|
|
21
|
+
variantId?: string;
|
|
22
|
+
options?: VariantOptions;
|
|
23
|
+
};
|
|
24
|
+
type BuildMarketplaceLineSnapshotParams = {
|
|
25
|
+
product: CompleteProduct;
|
|
26
|
+
parentMerchantId: string;
|
|
27
|
+
managedMerchantId?: string;
|
|
28
|
+
relationshipId: string;
|
|
29
|
+
sellerDisplayName?: string;
|
|
30
|
+
lineDisplayTitle?: string;
|
|
31
|
+
marketplaceCommissionRate: string | number;
|
|
32
|
+
originalProductCommissionRate?: string | number;
|
|
33
|
+
marketplaceCommissionBasis?: MarketplaceCommissionBasisValue | string;
|
|
34
|
+
quantity?: number;
|
|
35
|
+
currencyCode?: string;
|
|
36
|
+
discountAmount?: number;
|
|
37
|
+
taxAmount?: number;
|
|
38
|
+
stripeFeeAllocatedAmount?: number;
|
|
39
|
+
ribbnFeeAllocatedAmount?: number;
|
|
40
|
+
variantSelection?: VariantSelectionInput;
|
|
41
|
+
};
|
|
42
|
+
type MarketplaceRelationshipInput = {
|
|
43
|
+
documentId?: string;
|
|
44
|
+
parentMerchantId?: string;
|
|
45
|
+
childMerchantId?: string;
|
|
46
|
+
marketplaceCommission?: string | number;
|
|
47
|
+
marketplaceCommissionBasis?: MarketplaceCommissionBasisValue | string;
|
|
48
|
+
isActive?: boolean;
|
|
49
|
+
relationshipType?: string;
|
|
50
|
+
};
|
|
51
|
+
type BuildCanonicalMarketplaceListingPatchParams = {
|
|
52
|
+
product: CompleteProduct;
|
|
53
|
+
parentMerchantId: string;
|
|
54
|
+
relationshipId?: string;
|
|
55
|
+
relationshipType?: MarketplaceRelationshipTypeValue | string;
|
|
56
|
+
listingStatus?: MarketplaceListingStatusValue | string;
|
|
57
|
+
at?: number;
|
|
58
|
+
};
|
|
59
|
+
type BuildLineSnapshotFromListingParams = {
|
|
60
|
+
product: CompleteProduct;
|
|
61
|
+
parentMerchantId: string;
|
|
62
|
+
relationship?: MarketplaceRelationshipInput | null;
|
|
63
|
+
lineItem?: ReRobeOrderLineItem | any;
|
|
64
|
+
quantity?: number;
|
|
65
|
+
currencyCode?: string;
|
|
66
|
+
marketplaceCommissionRate?: string | number;
|
|
67
|
+
originalProductCommissionRate?: string | number;
|
|
68
|
+
marketplaceCommissionBasis?: MarketplaceCommissionBasisValue | string;
|
|
69
|
+
discountAmount?: number;
|
|
70
|
+
taxAmount?: number;
|
|
71
|
+
stripeFeeAllocatedAmount?: number;
|
|
72
|
+
ribbnFeeAllocatedAmount?: number;
|
|
73
|
+
variantSelection?: VariantSelectionInput;
|
|
74
|
+
};
|
|
75
|
+
type InventoryTransformParams = {
|
|
76
|
+
product: CompleteProduct;
|
|
77
|
+
variantId: string;
|
|
78
|
+
locationId?: string;
|
|
79
|
+
quantity?: number;
|
|
80
|
+
};
|
|
81
|
+
type ReturnAdjustmentParams = {
|
|
82
|
+
snapshot: MarketplaceLineSnapshot;
|
|
83
|
+
quantityReturned?: number;
|
|
84
|
+
};
|
|
85
|
+
type ApplyEffectiveCommissionToProductsParams = {
|
|
86
|
+
products: CompleteProduct[];
|
|
87
|
+
relationships?: MarketplaceRelationshipInput[];
|
|
88
|
+
contextMerchantId?: string;
|
|
89
|
+
};
|
|
90
|
+
type ApplyStripeFeeRecoupBumpToProductsParams = {
|
|
91
|
+
merchantId: string;
|
|
92
|
+
products: CompleteProduct[];
|
|
93
|
+
totalFeeAmount: number;
|
|
94
|
+
basis?: MarketplaceFeeAllocationBasisValue | string;
|
|
95
|
+
};
|
|
96
|
+
export default class MarketplaceProductHelpers {
|
|
97
|
+
static registerCommissionPolicy(policy: CommissionPolicy): void;
|
|
98
|
+
static getCommissionPolicy(basis: string): CommissionPolicy;
|
|
99
|
+
static hasCommissionPolicy(basis: string): boolean;
|
|
100
|
+
static emptyMarketplace(): ProductMarketplace;
|
|
101
|
+
static uniqueStrings(values?: any[]): string[];
|
|
102
|
+
static normalizeMarketplace(input?: any): ProductMarketplace;
|
|
103
|
+
static buildMarketplace({ productMerchantId, listings, }: BuildMarketplaceListingParams): ProductMarketplace;
|
|
104
|
+
static buildTypesenseFields(marketplace?: ProductMarketplace): {
|
|
105
|
+
marketplaceVisibleToMerchantIds: string[];
|
|
106
|
+
marketplaceParentMerchantIds: string[];
|
|
107
|
+
marketplaceRelationshipIds: string[];
|
|
108
|
+
isMarketplaceVisible: boolean;
|
|
109
|
+
};
|
|
110
|
+
static toRate(value: string | number | undefined | null): number;
|
|
111
|
+
static roundMoney(value: number): number;
|
|
112
|
+
static lineNetFromProduct(product: CompleteProduct, quantity?: number, variant?: MarketplaceVariantSnapshot): number;
|
|
113
|
+
static selectVariant(product: CompleteProduct, selection?: VariantSelectionInput): MarketplaceVariantSnapshot | null;
|
|
114
|
+
static buildLineSnapshot({ product, parentMerchantId, managedMerchantId, relationshipId, sellerDisplayName, lineDisplayTitle, marketplaceCommissionRate, originalProductCommissionRate, marketplaceCommissionBasis, quantity, currencyCode, discountAmount, taxAmount, stripeFeeAllocatedAmount, ribbnFeeAllocatedAmount, variantSelection, }: BuildMarketplaceLineSnapshotParams): MarketplaceLineSnapshot;
|
|
115
|
+
static deriveVariantSelectionFromLineItem(lineItem: any): VariantSelectionInput | undefined;
|
|
116
|
+
static buildLineSnapshotFromListing({ product, parentMerchantId, relationship, lineItem, quantity, currencyCode, marketplaceCommissionRate, originalProductCommissionRate, marketplaceCommissionBasis, discountAmount, taxAmount, stripeFeeAllocatedAmount, ribbnFeeAllocatedAmount, variantSelection, }: BuildLineSnapshotFromListingParams): MarketplaceLineSnapshot | null;
|
|
117
|
+
static prorateAmounts(amounts: MarketplaceLineAmounts, ratio: number): MarketplaceLineAmounts;
|
|
118
|
+
static buildReturnAdjustment({ snapshot, quantityReturned }: ReturnAdjustmentParams): MarketplaceReturnAdjustment;
|
|
119
|
+
static transformVariantInventory({ product, variantId, locationId, quantity }: InventoryTransformParams, direction: 'decrement' | 'restore'): VariantInventory[];
|
|
120
|
+
static decrementVariantInventory(params: InventoryTransformParams): VariantInventory[];
|
|
121
|
+
static restoreVariantInventory(params: InventoryTransformParams): VariantInventory[];
|
|
122
|
+
static registerInventoryPolicy(policy: InventoryPolicy, position?: 'append' | 'prepend'): void;
|
|
123
|
+
static findInventoryPolicy(product: CompleteProduct | null | undefined): InventoryPolicy | null;
|
|
124
|
+
static adjustInventory(product: CompleteProduct, params: InventoryAdjustmentParams, direction: 'decrement' | 'restore'): InventoryAdjustmentResult;
|
|
125
|
+
static adjustVariantInventoryForLine(product: CompleteProduct, { lineItem, variantId, locationId, defaultLocationId, quantity, }: {
|
|
126
|
+
lineItem?: any;
|
|
127
|
+
variantId?: string;
|
|
128
|
+
locationId?: string;
|
|
129
|
+
defaultLocationId?: string;
|
|
130
|
+
quantity?: number;
|
|
131
|
+
}, direction?: 'decrement' | 'restore'): InventoryAdjustmentResult;
|
|
132
|
+
static registerFeeAllocationPolicy(policy: FeeAllocationPolicy): void;
|
|
133
|
+
static getFeeAllocationPolicy(basis: string): FeeAllocationPolicy;
|
|
134
|
+
static allocateFee(context: FeeAllocationContext, basis?: MarketplaceFeeAllocationBasisValue | string): MarketplaceFeeAllocation[];
|
|
135
|
+
static allocateStripeFee(context: FeeAllocationContext): MarketplaceFeeAllocation[];
|
|
136
|
+
static allocateRibbnFee(context: FeeAllocationContext): MarketplaceFeeAllocation[];
|
|
137
|
+
static buildFeeBasketFromProducts({ merchantId, products, }: {
|
|
138
|
+
merchantId: string;
|
|
139
|
+
products: CompleteProduct[];
|
|
140
|
+
}): MarketplaceFeeBasketLine[];
|
|
141
|
+
static applyStripeFeeRecoupBumpToProducts({ merchantId, products, totalFeeAmount, basis, }: ApplyStripeFeeRecoupBumpToProductsParams): CompleteProduct[];
|
|
142
|
+
static upsertListing(marketplace: ProductMarketplace | undefined, parentMarketplaceId: string, partial?: Partial<ProductMarketplaceListing> & {
|
|
143
|
+
ownerMerchantId?: string;
|
|
144
|
+
}, options?: {
|
|
145
|
+
at?: number;
|
|
146
|
+
}): ProductMarketplace;
|
|
147
|
+
static pauseListing(marketplace: ProductMarketplace | undefined, parentMarketplaceId: string, options?: {
|
|
148
|
+
at?: number;
|
|
149
|
+
ownerMerchantId?: string;
|
|
150
|
+
}): ProductMarketplace;
|
|
151
|
+
static resumeListing(marketplace: ProductMarketplace | undefined, parentMarketplaceId: string, options?: {
|
|
152
|
+
at?: number;
|
|
153
|
+
ownerMerchantId?: string;
|
|
154
|
+
}): ProductMarketplace;
|
|
155
|
+
static removeListing(marketplace: ProductMarketplace | undefined, parentMarketplaceId: string, options?: {
|
|
156
|
+
at?: number;
|
|
157
|
+
ownerMerchantId?: string;
|
|
158
|
+
}): ProductMarketplace;
|
|
159
|
+
static buildCanonicalMarketplaceListingPatch({ product, parentMerchantId, relationshipId, relationshipType, listingStatus, at, }: BuildCanonicalMarketplaceListingPatchParams): {
|
|
160
|
+
marketplace: ProductMarketplace;
|
|
161
|
+
} | null;
|
|
162
|
+
static resolveEffectiveCommission(product: CompleteProduct | null | undefined, relationship: {
|
|
163
|
+
marketplaceCommission?: string | number;
|
|
164
|
+
isActive?: boolean;
|
|
165
|
+
relationshipType?: string;
|
|
166
|
+
parentMerchantId?: string;
|
|
167
|
+
} | null | undefined, contextMerchantId?: string): string;
|
|
168
|
+
static applyEffectiveCommissionToProducts({ products, relationships, contextMerchantId, }: ApplyEffectiveCommissionToProductsParams): CompleteProduct[];
|
|
169
|
+
static buildSellerProductOwnership(params: {
|
|
170
|
+
sellerMerchantId: string;
|
|
171
|
+
isActingAs?: boolean;
|
|
172
|
+
parentMerchantId?: string;
|
|
173
|
+
}): {
|
|
174
|
+
merchantId: string;
|
|
175
|
+
vendorId: string;
|
|
176
|
+
merchants: string[];
|
|
177
|
+
};
|
|
178
|
+
static defaultSellerCommission(): string;
|
|
179
|
+
static buildActAsTypesenseFilter(managedMerchantId: string): string;
|
|
180
|
+
static normalizeCommissionRate(value: string | number | null | undefined): string;
|
|
181
|
+
}
|