rerobe-js-orm 4.5.1 → 4.5.3

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.
@@ -1,4 +1,5 @@
1
1
  import OrderFactory from './OrderFactory';
2
2
  export default class OrderFromShopifyWebhook extends OrderFactory {
3
3
  createOrder(order: ShopifyRestApiOrderObj): ReRobeOrderObj;
4
+ createOrderV2(order: any): ReRobeOrderObj;
4
5
  }
@@ -277,5 +277,112 @@ class OrderFromShopifyWebhook extends OrderFactory_1.default {
277
277
  shippingLine, state: Order_1.default.ORDER_STATES.completed, shippingType: orderHelpers.getShippingTypeFromShopifyObj(shipping_lines), paymentType: orderHelpers.getPaymentTypeUsingTags(tags), salesChannel: orderHelpers.getSalesChannelUsingTags(tags), tags: tags ? tags.split(', ') : [] }));
278
278
  return rerobeOrder.toObj();
279
279
  }
280
+ // Aligned with Shopify REST order payload that includes current_* fields
281
+ createOrderV2(order) {
282
+ const { id, name, financial_status, fulfillment_status, cancel_reason, created_at, processed_at, updated_at, currency, contact_email, email, shipping_address, line_items = [], discount_applications = [], shipping_lines = [], tax_lines = [], tags = '', cancelled_at, closed_at, order_number, current_subtotal_price_set, current_total_price_set, current_total_tax_set, current_total_discounts_set, current_shipping_price_set, } = order || {};
283
+ const moneyFromSet = (setObj) => {
284
+ const shop = setObj === null || setObj === void 0 ? void 0 : setObj.shop_money;
285
+ return shop
286
+ ? { amount: shop.amount, currencyCode: shop.currency_code }
287
+ : { amount: 0, currencyCode: currency || '' };
288
+ };
289
+ const subtotalPrice = moneyFromSet(current_subtotal_price_set);
290
+ const totalPrice = moneyFromSet(current_total_price_set);
291
+ const totalTax = moneyFromSet(current_total_tax_set);
292
+ const totalShippingPrice = moneyFromSet(current_shipping_price_set);
293
+ const totalDiscount = current_total_discounts_set
294
+ ? moneyFromSet(current_total_discounts_set)
295
+ : { amount: 0, currencyCode: currency || '' };
296
+ const shippingAddress = shipping_address
297
+ ? {
298
+ address1: shipping_address.address1,
299
+ address2: shipping_address.address2,
300
+ city: shipping_address.city,
301
+ country: shipping_address.country,
302
+ countryCode: shipping_address.country_code,
303
+ province: shipping_address.province,
304
+ zip: shipping_address.zip,
305
+ }
306
+ : null;
307
+ const lineItems = line_items.map((item) => ({
308
+ title: item.title,
309
+ quantity: item.quantity,
310
+ variant: {
311
+ id: item.variant_id ? `gid://shopify/ProductVariant/${item.variant_id}` : '',
312
+ title: item.variant_title || '',
313
+ image: { id: '', originalSrc: '' },
314
+ },
315
+ shopifyProductId: item.product_id ? `gid://shopify/Product/${item.product_id}` : null,
316
+ originalTotalPrice: moneyFromSet(item.price_set),
317
+ discountedTotalPrice: moneyFromSet(item.total_discount_set),
318
+ }));
319
+ const discountApplications = discount_applications.map((item) => ({
320
+ allocationMethod: item.allocation_method ? String(item.allocation_method).toUpperCase() : '',
321
+ targetSelection: item.target_selection ? String(item.target_selection).toUpperCase() : '',
322
+ targetType: item.target_type ? String(item.target_type).toUpperCase() : '',
323
+ value: { amount: item.value },
324
+ }));
325
+ const taxLinesV2 = tax_lines.map((item) => ({
326
+ rate: item.rate,
327
+ title: item.title,
328
+ priceSet: { amount: item.price, currencyCode: currency || '' },
329
+ }));
330
+ const shippingLine = shipping_lines && shipping_lines.length
331
+ ? {
332
+ id: '',
333
+ title: shipping_lines[0].title,
334
+ source: shipping_lines[0].source,
335
+ discountedPrice: moneyFromSet(shipping_lines[0].discounted_price_set),
336
+ originalPrice: moneyFromSet(shipping_lines[0].price_set),
337
+ taxLines: (shipping_lines[0].tax_lines || []).map((t) => ({
338
+ rate: t.rate,
339
+ title: t.title,
340
+ priceSet: { amount: t.price, currencyCode: currency || '' },
341
+ })),
342
+ }
343
+ : {
344
+ id: '',
345
+ title: '',
346
+ taxLines: [],
347
+ discountAllocations: [],
348
+ discountedPrice: { amount: 0 },
349
+ originalPrice: { amount: 0 },
350
+ source: '',
351
+ };
352
+ // @ts-ignore
353
+ const fulfillmentStatus = !fulfillment_status ? '' : fulfillmentStatusRestMapping[fulfillment_status];
354
+ const rerobeOrder = new Order_1.default({
355
+ id: orderHelpers.getOrderIdFromShopifyObj(order),
356
+ shopifyId: `gid://shopify/Order/${id}`,
357
+ shopifyOrderNumber: name ? Number(String(name).replace('#', '')) : order_number || 0,
358
+ name: name || '',
359
+ currencyCode: currency || '',
360
+ email: contact_email || email || '',
361
+ financialStatus: financial_status ? String(financial_status).toUpperCase() : '',
362
+ fulfillmentStatus,
363
+ cancelReason: cancel_reason ? String(cancel_reason).toUpperCase() : '',
364
+ createdAt: created_at,
365
+ processedAt: processed_at,
366
+ updatedAt: updated_at,
367
+ canceledAt: cancelled_at,
368
+ closedAt: closed_at,
369
+ orderNumber: order_number || 0,
370
+ shippingAddress,
371
+ lineItems,
372
+ subtotalPrice,
373
+ totalPrice,
374
+ totalTax,
375
+ totalShippingPrice,
376
+ totalDiscount,
377
+ discountApplications,
378
+ shippingLine,
379
+ tags: tags ? String(tags).split(', ').filter(Boolean) : [],
380
+ state: Order_1.default.ORDER_STATES.completed,
381
+ shippingType: orderHelpers.getShippingTypeFromShopifyObj(shipping_lines),
382
+ paymentType: orderHelpers.getPaymentTypeUsingTags(tags),
383
+ salesChannel: orderHelpers.getSalesChannelUsingTags(tags),
384
+ });
385
+ return rerobeOrder.toObj();
386
+ }
280
387
  }
281
388
  exports.default = OrderFromShopifyWebhook;
@@ -95,6 +95,28 @@ export default class ProductFormState extends FormState {
95
95
  }[];
96
96
  toRemove: string[];
97
97
  };
98
+ getVariantIds(): string[];
99
+ getVariantRows(): VariantInventory[];
100
+ bulkEditVariantFields(patch: Partial<VariantInventory>, selector?: {
101
+ ids?: string[];
102
+ predicate?: (v: VariantInventory) => boolean;
103
+ }): void;
104
+ bulkEditVariantLocationAmount(location: {
105
+ id: string;
106
+ name: string;
107
+ }, amount: number, options?: {
108
+ ids?: string[];
109
+ predicate?: (v: VariantInventory) => boolean;
110
+ mode?: 'set' | 'increment';
111
+ field?: 'availableAmount' | 'incomingAmount';
112
+ }): void;
113
+ bulkEditVariantSkus(updates: {
114
+ id?: string;
115
+ options?: {
116
+ [k: string]: string;
117
+ };
118
+ sku: string;
119
+ }[]): void;
98
120
  private aggregateInventoryLocationsFromVariants;
99
121
  private fieldFactory;
100
122
  }
@@ -837,6 +837,128 @@ class ProductFormState extends FormState_1.default {
837
837
  const toRemove = curRows.filter((r) => !nextKeySet.has(JSON.stringify(r.options || {}))).map((r) => r.id);
838
838
  return { toAdd, toRemove };
839
839
  }
840
+ // UI: expose variant ids and rows
841
+ getVariantIds() {
842
+ return this.fields.variantInventory.selectedValues.map((v) => v.id);
843
+ }
844
+ getVariantRows() {
845
+ return this.fields.variantInventory.selectedValues.slice();
846
+ }
847
+ // Bulk edit user-mutable variant fields (excludes inventory locations and options/id)
848
+ bulkEditVariantFields(patch, selector) {
849
+ const allowedKeys = [
850
+ 'price',
851
+ 'compareAtPrice',
852
+ 'salePrice',
853
+ 'isOnSale',
854
+ 'sku',
855
+ 'taxable',
856
+ 'costPerItem',
857
+ 'continueSellingWhenOutOfStock',
858
+ ];
859
+ const rows = this.fields.variantInventory.selectedValues;
860
+ const shouldEdit = (v) => {
861
+ if ((selector === null || selector === void 0 ? void 0 : selector.ids) && selector.ids.length)
862
+ return selector.ids.includes(v.id);
863
+ if (selector === null || selector === void 0 ? void 0 : selector.predicate)
864
+ return !!selector.predicate(v);
865
+ return true; // default: all
866
+ };
867
+ rows.forEach((v, idx) => {
868
+ if (!shouldEdit(v))
869
+ return;
870
+ const next = Object.assign({}, v);
871
+ allowedKeys.forEach((k) => {
872
+ if (patch[k] !== undefined)
873
+ next[k] = patch[k];
874
+ });
875
+ this.fields.variantInventory.selectedValues[idx] = next;
876
+ });
877
+ // Recompute aggregates (locations unchanged, so totals stay the same but we keep logic consistent)
878
+ const totalQty = this.fields.variantInventory.selectedValues.reduce((acc, cur) => {
879
+ const locs = cur.locations;
880
+ const sum = Array.isArray(locs) ? locs.reduce((a, l) => a + (Number(l === null || l === void 0 ? void 0 : l.availableAmount) || 0), 0) : 0;
881
+ return acc + sum;
882
+ }, 0);
883
+ this.fields.quantity.inputValue = totalQty;
884
+ this.fields.availableForSale.selectedValue = totalQty > 0;
885
+ this.aggregateInventoryLocationsFromVariants();
886
+ }
887
+ // Bulk edit inventory amount for a specific location across selected variants
888
+ // mode: 'set' (default) to overwrite, 'increment' to add delta
889
+ bulkEditVariantLocationAmount(location, amount, options) {
890
+ const rows = this.fields.variantInventory.selectedValues;
891
+ const shouldEdit = (v) => {
892
+ if ((options === null || options === void 0 ? void 0 : options.ids) && options.ids.length)
893
+ return options.ids.includes(v.id);
894
+ if (options === null || options === void 0 ? void 0 : options.predicate)
895
+ return !!options.predicate(v);
896
+ return true; // default all
897
+ };
898
+ const mode = (options === null || options === void 0 ? void 0 : options.mode) || 'set';
899
+ const targetField = (options === null || options === void 0 ? void 0 : options.field) || 'availableAmount';
900
+ rows.forEach((v, idx) => {
901
+ if (!shouldEdit(v))
902
+ return;
903
+ const locs = (v.locations || []);
904
+ const existingIdx = locs.findIndex((l) => l && l.id === location.id);
905
+ if (existingIdx !== -1) {
906
+ const current = locs[existingIdx];
907
+ const nextVal = mode === 'increment' ? Number(current[targetField] || 0) + Number(amount) : Number(amount);
908
+ const updated = Object.assign(Object.assign({}, current), { [targetField]: nextVal });
909
+ locs.splice(existingIdx, 1, updated);
910
+ }
911
+ else {
912
+ const base = {
913
+ id: location.id,
914
+ name: location.name,
915
+ availableAmount: 0,
916
+ incomingAmount: 0,
917
+ };
918
+ base[targetField] = mode === 'increment' ? Number(amount) : Number(amount);
919
+ locs.push(base);
920
+ }
921
+ this.fields.variantInventory.selectedValues[idx] = Object.assign(Object.assign({}, v), { locations: locs });
922
+ });
923
+ // Recompute aggregates
924
+ const totalQty = this.fields.variantInventory.selectedValues.reduce((acc, cur) => {
925
+ const locs = cur.locations;
926
+ const sum = Array.isArray(locs) ? locs.reduce((a, l) => a + (Number(l === null || l === void 0 ? void 0 : l.availableAmount) || 0), 0) : 0;
927
+ return acc + sum;
928
+ }, 0);
929
+ this.fields.quantity.inputValue = totalQty;
930
+ this.fields.availableForSale.selectedValue = totalQty > 0;
931
+ this.aggregateInventoryLocationsFromVariants();
932
+ }
933
+ // Bulk edit SKUs per selected variant individually
934
+ bulkEditVariantSkus(updates) {
935
+ if (!Array.isArray(updates) || !updates.length)
936
+ return;
937
+ const rows = this.fields.variantInventory.selectedValues;
938
+ const indexById = {};
939
+ rows.forEach((v, i) => (indexById[v.id] = i));
940
+ updates.forEach((u) => {
941
+ let idx = -1;
942
+ if (u.id && indexById[u.id] !== undefined) {
943
+ idx = indexById[u.id];
944
+ }
945
+ else if (u.options) {
946
+ idx = rows.findIndex((v) => this.isSameOptions(v.options, u.options));
947
+ }
948
+ if (idx !== -1) {
949
+ const cur = rows[idx] || {};
950
+ this.fields.variantInventory.selectedValues[idx] = Object.assign(Object.assign({}, cur), { sku: u.sku });
951
+ }
952
+ });
953
+ // Aggregates unchanged but keep consistent calc
954
+ const totalQty = this.fields.variantInventory.selectedValues.reduce((acc, cur) => {
955
+ const locs = cur.locations;
956
+ const sum = Array.isArray(locs) ? locs.reduce((a, l) => a + (Number(l === null || l === void 0 ? void 0 : l.availableAmount) || 0), 0) : 0;
957
+ return acc + sum;
958
+ }, 0);
959
+ this.fields.quantity.inputValue = totalQty;
960
+ this.fields.availableForSale.selectedValue = totalQty > 0;
961
+ }
840
962
  aggregateInventoryLocationsFromVariants() {
841
963
  var _a;
842
964
  const variants = ((_a = this.fields.variantInventory) === null || _a === void 0 ? void 0 : _a.selectedValues) || [];
@@ -163,6 +163,9 @@ type VariantInventory = {
163
163
  isOnSale?: 'yes' | 'no';
164
164
  sku?: string;
165
165
  taxable?: 'yes' | 'no';
166
+ shopifyId?: string;
167
+ costPerItem?: string;
168
+ continueSellingWhenOutOfStock?: boolean;
166
169
  };
167
170
  type ProductSellStatusKeys = 'SELL_REQUEST_REVIEW' | 'REJECTED' | 'HOLD' | 'ACCEPTED' | 'DROP_OFF_AT_REROBE' | 'SHIP_TO_REROBE' | 'AT_HOME_PICK_UP' | 'QUALITY_CONTROL' | 'LISTED' | 'SOLD' | 'RETURNED' | 'SOLD_SELLER_TO_BE_PAID' | 'SOLD_SELLER_PAID' | 'HIDDEN' | 'BOOKED' | 'OPEN';
168
171
  type ProductPublishKeys = 'USER_PUBLISHED' | 'MERCHANT_PUBLISHED';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rerobe-js-orm",
3
- "version": "4.5.1",
3
+ "version": "4.5.3",
4
4
  "description": "ReRobe's Javascript ORM Framework",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",