@pisell/pisellos 2.2.233 → 2.2.234
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/dist/modules/Order/index.d.ts +36 -1
- package/dist/modules/Order/index.js +496 -308
- package/dist/modules/Order/types.d.ts +11 -0
- package/dist/modules/Order/utils.d.ts +1 -0
- package/dist/modules/Order/utils.js +1 -1
- package/dist/server/index.d.ts +5 -0
- package/dist/server/index.js +855 -633
- package/dist/server/modules/order/index.d.ts +2 -0
- package/dist/server/modules/order/index.js +86 -32
- package/dist/solution/BaseSales/index.d.ts +6 -0
- package/dist/solution/BaseSales/index.js +240 -197
- package/dist/solution/BookingByStep/index.d.ts +1 -1
- package/dist/solution/BookingTicket/index.d.ts +38 -2
- package/dist/solution/BookingTicket/index.js +642 -313
- package/dist/solution/BookingTicket/types.d.ts +62 -0
- package/dist/solution/BookingTicket/types.js +30 -0
- package/dist/solution/BookingTicket/utils/addTimeAvailability.d.ts +35 -0
- package/dist/solution/BookingTicket/utils/addTimeAvailability.js +95 -0
- package/dist/solution/BookingTicket/utils/cartView.d.ts +9 -1
- package/dist/solution/BookingTicket/utils/cartView.js +76 -5
- package/dist/solution/BookingTicket/utils/exampleData.d.ts +123 -0
- package/dist/solution/BookingTicket/utils/exampleData.js +183 -0
- package/dist/solution/BookingTicket/utils/resolveBestAddTimePlan.d.ts +9 -13
- package/dist/solution/BookingTicket/utils/resolveBestAddTimePlan.js +42 -33
- package/lib/model/strategy/adapter/promotion/index.js +0 -49
- package/lib/modules/Order/index.d.ts +36 -1
- package/lib/modules/Order/index.js +98 -10
- package/lib/modules/Order/types.d.ts +11 -0
- package/lib/modules/Order/utils.d.ts +1 -0
- package/lib/modules/Order/utils.js +1 -1
- package/lib/server/index.d.ts +5 -0
- package/lib/server/index.js +224 -63
- package/lib/server/modules/order/index.d.ts +2 -0
- package/lib/server/modules/order/index.js +43 -1
- package/lib/solution/BaseSales/index.d.ts +6 -0
- package/lib/solution/BaseSales/index.js +20 -1
- package/lib/solution/BookingByStep/index.d.ts +1 -1
- package/lib/solution/BookingTicket/index.d.ts +38 -2
- package/lib/solution/BookingTicket/index.js +194 -3
- package/lib/solution/BookingTicket/types.d.ts +62 -0
- package/lib/solution/BookingTicket/utils/addTimeAvailability.d.ts +35 -0
- package/lib/solution/BookingTicket/utils/addTimeAvailability.js +125 -0
- package/lib/solution/BookingTicket/utils/cartView.d.ts +9 -1
- package/lib/solution/BookingTicket/utils/cartView.js +48 -2
- package/lib/solution/BookingTicket/utils/exampleData.d.ts +123 -0
- package/lib/solution/BookingTicket/utils/exampleData.js +0 -0
- package/lib/solution/BookingTicket/utils/resolveBestAddTimePlan.d.ts +9 -13
- package/lib/solution/BookingTicket/utils/resolveBestAddTimePlan.js +41 -28
- package/package.json +1 -1
|
@@ -2144,6 +2144,17 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
2144
2144
|
hasOrderProductLineNote(product) {
|
|
2145
2145
|
return typeof (product == null ? void 0 : product.note) === "string" && product.note.trim().length > 0;
|
|
2146
2146
|
}
|
|
2147
|
+
/**
|
|
2148
|
+
* 判断商品行是否显式绑定了 booking。
|
|
2149
|
+
*
|
|
2150
|
+
* @example
|
|
2151
|
+
* this.hasLinkedBookingUid({ metadata: { booking_uid: 'booking-1' } });
|
|
2152
|
+
*/
|
|
2153
|
+
hasLinkedBookingUid(product) {
|
|
2154
|
+
var _a;
|
|
2155
|
+
const bookingUid = (product == null ? void 0 : product.booking_uid) ?? ((_a = product == null ? void 0 : product.metadata) == null ? void 0 : _a.booking_uid);
|
|
2156
|
+
return bookingUid !== void 0 && bookingUid !== null && String(bookingUid) !== "";
|
|
2157
|
+
}
|
|
2147
2158
|
// ─── TempOrder: 商品 CRUD ───
|
|
2148
2159
|
/**
|
|
2149
2160
|
* 预约商品加车后的统一收尾:促销、折扣、summary 重算与持久化(批量拆行时只调用一次)。
|
|
@@ -2151,11 +2162,17 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
2151
2162
|
* @example
|
|
2152
2163
|
* await this.finalizeProductOrderMutation(tempOrder);
|
|
2153
2164
|
*/
|
|
2154
|
-
async finalizeProductOrderMutation(tempOrder) {
|
|
2165
|
+
async finalizeProductOrderMutation(tempOrder, options) {
|
|
2155
2166
|
this.syncTempOrderHolderFromBookings(tempOrder);
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2167
|
+
if (!(options == null ? void 0 : options.skipEditDiscountConfigRefresh)) {
|
|
2168
|
+
await this.ensureEditDiscountConfigForProductChange(tempOrder);
|
|
2169
|
+
}
|
|
2170
|
+
if (!(options == null ? void 0 : options.skipDiscountRecalculation)) {
|
|
2171
|
+
await this.applyPromotion();
|
|
2172
|
+
}
|
|
2173
|
+
if (!(options == null ? void 0 : options.skipDiscountRecalculation)) {
|
|
2174
|
+
this.applyDiscount();
|
|
2175
|
+
}
|
|
2159
2176
|
this.sanitizeTempOrderProducts(tempOrder);
|
|
2160
2177
|
await this.recalculateSummary({ createIfMissing: true });
|
|
2161
2178
|
this.persistTempOrder();
|
|
@@ -2168,7 +2185,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
2168
2185
|
* await this.appendProductLineToTempOrder(tempOrder, { product_id: 1, num: 1 }, booking);
|
|
2169
2186
|
*/
|
|
2170
2187
|
async appendProductLineToTempOrder(tempOrder, product, booking) {
|
|
2171
|
-
var _a;
|
|
2188
|
+
var _a, _b;
|
|
2172
2189
|
const linked = booking ? this.createLinkedProductAndBooking({ product, booking }) : null;
|
|
2173
2190
|
const productToAdd = (linked == null ? void 0 : linked.product) || product;
|
|
2174
2191
|
const incomingFingerprint = (0, import_utils3.buildProductLineFingerprint)(
|
|
@@ -2179,6 +2196,14 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
2179
2196
|
productToAdd,
|
|
2180
2197
|
(0, import_utils3.normalizeOrderProduct)(productToAdd)
|
|
2181
2198
|
);
|
|
2199
|
+
const incomingBookingUid = productToAdd.booking_uid ?? ((_a = productToAdd.metadata) == null ? void 0 : _a.booking_uid);
|
|
2200
|
+
if (incomingBookingUid !== void 0 && incomingBookingUid !== null && String(incomingBookingUid) !== "") {
|
|
2201
|
+
normalizedIncoming.booking_uid = String(incomingBookingUid);
|
|
2202
|
+
normalizedIncoming.metadata = {
|
|
2203
|
+
...normalizedIncoming.metadata || {},
|
|
2204
|
+
booking_uid: String(incomingBookingUid)
|
|
2205
|
+
};
|
|
2206
|
+
}
|
|
2182
2207
|
normalizedIncoming.discount_list = (0, import_utils.normalizeOrderProductDiscountList)(
|
|
2183
2208
|
normalizedIncoming.discount_list
|
|
2184
2209
|
);
|
|
@@ -2186,7 +2211,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
2186
2211
|
normalizedIncoming
|
|
2187
2212
|
);
|
|
2188
2213
|
const hasIncomingProductNote = this.hasOrderProductLineNote(normalizedIncoming);
|
|
2189
|
-
const
|
|
2214
|
+
const hasIncomingBookingUid = this.hasLinkedBookingUid(productToAdd) || this.hasLinkedBookingUid(normalizedIncoming);
|
|
2215
|
+
const shouldForceNewLine = !!booking || hasIncomingProductNote || hasIncomingBookingUid;
|
|
2190
2216
|
const matchedIndex = hasIncomingGoodPass || shouldForceNewLine ? -1 : tempOrder.products.findIndex((item) => {
|
|
2191
2217
|
if (this.hasGoodPassDiscount(item))
|
|
2192
2218
|
return false;
|
|
@@ -2232,10 +2258,10 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
2232
2258
|
booking_uid: linked.bookingUid
|
|
2233
2259
|
};
|
|
2234
2260
|
}
|
|
2235
|
-
tempOrder.products.
|
|
2261
|
+
tempOrder.products = [...tempOrder.products, normalizedIncoming];
|
|
2236
2262
|
} else {
|
|
2237
2263
|
const targetProduct = matchedProduct;
|
|
2238
|
-
const targetUid = (
|
|
2264
|
+
const targetUid = (_b = targetProduct.metadata) == null ? void 0 : _b.unique_identification_number;
|
|
2239
2265
|
const normalizedProduct = (0, import_utils.mergeOrderProductDisplayFields)(
|
|
2240
2266
|
targetProduct,
|
|
2241
2267
|
(0, import_utils3.normalizeOrderProduct)({
|
|
@@ -2329,6 +2355,47 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
2329
2355
|
await this.finalizeProductOrderMutation(tempOrder);
|
|
2330
2356
|
return tempOrder.products;
|
|
2331
2357
|
}
|
|
2358
|
+
/**
|
|
2359
|
+
* 批量添加商品行,所有行追加完成后只触发一次促销、折扣、summary 重算与持久化。
|
|
2360
|
+
*
|
|
2361
|
+
* @example
|
|
2362
|
+
* await order.addProductsToOrder([
|
|
2363
|
+
* { product: { product_id: 1, product_variant_id: 0, num: 1 } },
|
|
2364
|
+
* { product: { product_id: 2, product_variant_id: 0, num: 1 } },
|
|
2365
|
+
* ]);
|
|
2366
|
+
*/
|
|
2367
|
+
async addProductsToOrder(items, options) {
|
|
2368
|
+
const tempOrder = this.ensureTempOrder();
|
|
2369
|
+
if (!Array.isArray(items) || items.length === 0)
|
|
2370
|
+
return tempOrder.products;
|
|
2371
|
+
for (const item of items || []) {
|
|
2372
|
+
const { product, booking } = item;
|
|
2373
|
+
if (!product)
|
|
2374
|
+
continue;
|
|
2375
|
+
if (booking) {
|
|
2376
|
+
const productRecord = product;
|
|
2377
|
+
const splitCount = (0, import_utils3.getSafeProductNum)(
|
|
2378
|
+
productRecord.num ?? productRecord.product_quantity ?? 1
|
|
2379
|
+
);
|
|
2380
|
+
if (splitCount > 1) {
|
|
2381
|
+
for (let i = 0; i < splitCount; i += 1) {
|
|
2382
|
+
const singleLine = (0, import_lodash_es.cloneDeep)(productRecord);
|
|
2383
|
+
singleLine.num = 1;
|
|
2384
|
+
delete singleLine.product_quantity;
|
|
2385
|
+
await this.appendProductLineToTempOrder(
|
|
2386
|
+
tempOrder,
|
|
2387
|
+
singleLine,
|
|
2388
|
+
(0, import_lodash_es.cloneDeep)(booking)
|
|
2389
|
+
);
|
|
2390
|
+
}
|
|
2391
|
+
continue;
|
|
2392
|
+
}
|
|
2393
|
+
}
|
|
2394
|
+
await this.appendProductLineToTempOrder(tempOrder, product, booking);
|
|
2395
|
+
}
|
|
2396
|
+
await this.finalizeProductOrderMutation(tempOrder, options);
|
|
2397
|
+
return tempOrder.products;
|
|
2398
|
+
}
|
|
2332
2399
|
hasGoodPassDiscount(product) {
|
|
2333
2400
|
var _a, _b;
|
|
2334
2401
|
const hasMainGoodPass = (product.discount_list || []).some(
|
|
@@ -2752,6 +2819,15 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
2752
2819
|
* 应传 1,确保 /shop/order/sales/checkout 返回打印所需数据。
|
|
2753
2820
|
*/
|
|
2754
2821
|
async submitTempOrder(params) {
|
|
2822
|
+
return this.runSubmitTempOrder(params);
|
|
2823
|
+
}
|
|
2824
|
+
async submitTempOrderAsync(params) {
|
|
2825
|
+
return this.runSubmitTempOrder({
|
|
2826
|
+
...params,
|
|
2827
|
+
syncMode: true
|
|
2828
|
+
});
|
|
2829
|
+
}
|
|
2830
|
+
async runSubmitTempOrder(params) {
|
|
2755
2831
|
var _a, _b, _c, _d, _e;
|
|
2756
2832
|
const tempOrder = this.ensureTempOrder();
|
|
2757
2833
|
this.persistTempOrder();
|
|
@@ -2782,8 +2858,12 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
2782
2858
|
channel: params == null ? void 0 : params.channel,
|
|
2783
2859
|
type: params == null ? void 0 : params.type,
|
|
2784
2860
|
summary: latestSummary,
|
|
2861
|
+
request_unique_idempotency_token: params == null ? void 0 : params.request_unique_idempotency_token,
|
|
2785
2862
|
enhance: enhancePayload
|
|
2786
2863
|
});
|
|
2864
|
+
if (params == null ? void 0 : params.syncMode) {
|
|
2865
|
+
payload.sync_mode = true;
|
|
2866
|
+
}
|
|
2787
2867
|
if (!payload.created_at) {
|
|
2788
2868
|
payload.created_at = (0, import_dayjs.default)().format("YYYY-MM-DD HH:mm:ss");
|
|
2789
2869
|
}
|
|
@@ -2796,7 +2876,8 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
2796
2876
|
requestUniqueIdempotencyToken: payload.request_unique_idempotency_token,
|
|
2797
2877
|
paymentStatus: payload.payment_status,
|
|
2798
2878
|
paymentsCount: ((_d = payload.payments) == null ? void 0 : _d.length) || 0,
|
|
2799
|
-
smallTicketDataFlag: payload.small_ticket_data_flag
|
|
2879
|
+
smallTicketDataFlag: payload.small_ticket_data_flag,
|
|
2880
|
+
syncMode: payload.sync_mode
|
|
2800
2881
|
});
|
|
2801
2882
|
result = await this.submitSalesOrder({
|
|
2802
2883
|
query: payload
|
|
@@ -2895,6 +2976,14 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
2895
2976
|
}
|
|
2896
2977
|
});
|
|
2897
2978
|
}
|
|
2979
|
+
generateIdempotencyToken() {
|
|
2980
|
+
const tempOrder = this.ensureTempOrder();
|
|
2981
|
+
const token = this.buildPaymentSyncIdempotencyToken(
|
|
2982
|
+
tempOrder,
|
|
2983
|
+
tempOrder.payments
|
|
2984
|
+
);
|
|
2985
|
+
return `${token}_${Date.now()}`;
|
|
2986
|
+
}
|
|
2898
2987
|
async syncPaymentsToOrder(params) {
|
|
2899
2988
|
const tempOrder = this.ensureTempOrder();
|
|
2900
2989
|
const mappedPayments = (0, import_utils.mapPaymentItemsToOrderPayments)(
|
|
@@ -3229,7 +3318,6 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
3229
3318
|
with: ["products", "bookings", "payments", "customer", "summary", "contacts_info"],
|
|
3230
3319
|
...params.forceRemote ? { forceRemote: true } : {}
|
|
3231
3320
|
}, { osServer: true });
|
|
3232
|
-
debugger;
|
|
3233
3321
|
if (res.code === 200) {
|
|
3234
3322
|
this.store.lastOrderInfo = res.data;
|
|
3235
3323
|
}
|
|
@@ -678,6 +678,17 @@ export interface OrderModuleAPI {
|
|
|
678
678
|
smallTicketDataFlag?: number;
|
|
679
679
|
enhancePayload?: SubmitPayloadEnhancer;
|
|
680
680
|
}) => Promise<T>;
|
|
681
|
+
submitTempOrderAsync: <T = any>(params?: {
|
|
682
|
+
cacheId?: string;
|
|
683
|
+
platform?: string;
|
|
684
|
+
businessCode?: string;
|
|
685
|
+
channel?: string;
|
|
686
|
+
type?: string;
|
|
687
|
+
payments?: OrderPaymentSource[];
|
|
688
|
+
paymentStatus?: SubmitSalesOrderParams['query']['payment_status'];
|
|
689
|
+
smallTicketDataFlag?: number;
|
|
690
|
+
enhancePayload?: SubmitPayloadEnhancer;
|
|
691
|
+
}) => Promise<T>;
|
|
681
692
|
getOrderPayments: () => OrderPaymentData[];
|
|
682
693
|
setOrderPayments: (payments: OrderPaymentSource[]) => OrderPaymentData[];
|
|
683
694
|
addOrderPayment: (payment: OrderPaymentSource) => OrderPaymentData[];
|
|
@@ -188,6 +188,7 @@ export declare function buildSubmitPayload(params: {
|
|
|
188
188
|
channel?: string;
|
|
189
189
|
type?: string;
|
|
190
190
|
summary?: OrderSummary | null;
|
|
191
|
+
request_unique_idempotency_token?: string;
|
|
191
192
|
enhance?: SubmitPayloadEnhancer;
|
|
192
193
|
}): OrderSubmitPayload;
|
|
193
194
|
export declare function mapPaymentItemToOrderPayment(paymentItem: OrderPaymentSource): OrderPaymentData;
|
|
@@ -754,7 +754,7 @@ function buildSubmitPayload(params) {
|
|
|
754
754
|
shop_order_number: tempOrder.shop_order_number ?? null,
|
|
755
755
|
shop_full_order_number: tempOrder.shop_full_order_number ?? null,
|
|
756
756
|
platform: normalizeSubmitPlatform(platform),
|
|
757
|
-
request_unique_idempotency_token: tempOrder.request_unique_idempotency_token || `${tempOrder.external_sale_number}_${now.getTime()}`,
|
|
757
|
+
request_unique_idempotency_token: (params == null ? void 0 : params.request_unique_idempotency_token) || tempOrder.request_unique_idempotency_token || `${tempOrder.external_sale_number}_${now.getTime()}`,
|
|
758
758
|
type: submitType,
|
|
759
759
|
business_code: businessCode ?? tempOrder.business_code,
|
|
760
760
|
sales_channel: tempOrder.sales_channel || "my_pisel",
|
package/lib/server/index.d.ts
CHANGED
|
@@ -95,6 +95,9 @@ declare class Server {
|
|
|
95
95
|
}[]>;
|
|
96
96
|
private registerDeviceTaskActions;
|
|
97
97
|
private handleSyncSalesTask;
|
|
98
|
+
private runCheckoutSync;
|
|
99
|
+
private omitCheckoutSyncMode;
|
|
100
|
+
private persistSyncedCheckoutOrder;
|
|
98
101
|
/**
|
|
99
102
|
* 将普通层 QuotationModule 的报价单计算能力桥接到 Server Products 模块。
|
|
100
103
|
*/
|
|
@@ -401,6 +404,7 @@ declare class Server {
|
|
|
401
404
|
private getLocalPrintOrderLookup;
|
|
402
405
|
private handleLocalPrintOrder;
|
|
403
406
|
private handleOrderCheckoutSubmit;
|
|
407
|
+
private handleSyncCheckoutSubmit;
|
|
404
408
|
private handlePendingSyncCheckoutOrder;
|
|
405
409
|
private buildPendingSyncCheckoutOrder;
|
|
406
410
|
private shouldBuildSmallTicketData;
|
|
@@ -455,6 +459,7 @@ declare class Server {
|
|
|
455
459
|
private buildSyncedOrderForPrint;
|
|
456
460
|
private isMergeableCheckoutOrder;
|
|
457
461
|
private normalizeCheckoutResponse;
|
|
462
|
+
private withSyncedOrderIdInCheckoutResponse;
|
|
458
463
|
private isCheckoutResponseRejected;
|
|
459
464
|
private getUnknownErrorMessage;
|
|
460
465
|
private normalizeUnknownError;
|
package/lib/server/index.js
CHANGED
|
@@ -1170,75 +1170,28 @@ var Server = class {
|
|
|
1170
1170
|
return this.taskTimeout("app.request 不可用");
|
|
1171
1171
|
}
|
|
1172
1172
|
try {
|
|
1173
|
-
const
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1173
|
+
const syncResult = await this.runCheckoutSync({
|
|
1174
|
+
backendPath,
|
|
1175
|
+
data,
|
|
1176
|
+
title,
|
|
1177
|
+
externalSaleNumber: payload.external_sale_number,
|
|
1178
|
+
deviceId: (_c = ctx.task) == null ? void 0 : _c.device_id,
|
|
1179
|
+
persistCheckoutDataWithResponse: false
|
|
1177
1180
|
});
|
|
1178
|
-
if (
|
|
1179
|
-
const message = (response == null ? void 0 : response.message) || "后端明确拒绝 checkout";
|
|
1181
|
+
if (syncResult.rejected) {
|
|
1180
1182
|
this.logError(`${title}: sync_sales 后端明确失败`, {
|
|
1181
1183
|
backendPath,
|
|
1182
|
-
response
|
|
1183
|
-
});
|
|
1184
|
-
return this.taskFail("BACKEND_REJECTED", message, response);
|
|
1185
|
-
}
|
|
1186
|
-
const fresh = this.extractOrderDataFromCheckoutResponse(response);
|
|
1187
|
-
const externalSaleNumber = this.getCheckoutExternalSaleNumber(data, payload);
|
|
1188
|
-
const shouldMergeRemoteOrder = fresh ? this.isMergeableCheckoutOrder(fresh, externalSaleNumber) : false;
|
|
1189
|
-
let syncedOrder;
|
|
1190
|
-
if (this.order && fresh && shouldMergeRemoteOrder) {
|
|
1191
|
-
syncedOrder = {
|
|
1192
|
-
...fresh,
|
|
1193
|
-
external_sale_number: fresh.external_sale_number ?? externalSaleNumber,
|
|
1194
|
-
need_sync: 0
|
|
1195
|
-
};
|
|
1196
|
-
await this.order.upsertOrdersFromRemote([syncedOrder]);
|
|
1197
|
-
this.logInfo(`${title}: sync_sales 完整订单已同步到本地`, {
|
|
1198
|
-
order_id: fresh.order_id,
|
|
1199
|
-
external_sale_number: syncedOrder.external_sale_number,
|
|
1200
|
-
order_number: fresh.order_number
|
|
1201
|
-
});
|
|
1202
|
-
} else if (this.order && externalSaleNumber && typeof this.order.markOrderSyncedByExternalSaleNumber === "function") {
|
|
1203
|
-
const patch = this.buildCheckoutSyncSuccessPatch(fresh);
|
|
1204
|
-
const result = await this.order.markOrderSyncedByExternalSaleNumber({
|
|
1205
|
-
externalSaleNumber,
|
|
1206
|
-
patch
|
|
1207
|
-
});
|
|
1208
|
-
syncedOrder = (result == null ? void 0 : result.order) || {
|
|
1209
|
-
...data,
|
|
1210
|
-
...patch,
|
|
1211
|
-
external_sale_number: externalSaleNumber,
|
|
1212
|
-
need_sync: 0
|
|
1213
|
-
};
|
|
1214
|
-
this.logInfo(`${title}: sync_sales 已按 external_sale_number 标记本地订单`, {
|
|
1215
|
-
order_id: (syncedOrder == null ? void 0 : syncedOrder.order_id) ?? null,
|
|
1216
|
-
external_sale_number: externalSaleNumber,
|
|
1217
|
-
hasRemoteOrder: !!fresh,
|
|
1218
|
-
mergedRemoteOrder: false
|
|
1219
|
-
});
|
|
1220
|
-
} else {
|
|
1221
|
-
this.logWarning(`${title}: sync_sales Order 模块未注册`, {
|
|
1222
|
-
backendPath,
|
|
1223
|
-
external_sale_number: externalSaleNumber,
|
|
1224
|
-
order_id: fresh == null ? void 0 : fresh.order_id
|
|
1225
|
-
});
|
|
1226
|
-
}
|
|
1227
|
-
const printableSyncedOrder = syncedOrder ? this.buildSyncedOrderForPrint({
|
|
1228
|
-
syncedOrder,
|
|
1229
|
-
checkoutResponseOrder: fresh
|
|
1230
|
-
}) : void 0;
|
|
1231
|
-
if (printableSyncedOrder && this.shouldPrintSyncedOrder({ checkoutData: data, syncedOrder: printableSyncedOrder })) {
|
|
1232
|
-
await this.dispatchPrintOtherReceiptTask({
|
|
1233
|
-
checkoutData: data,
|
|
1234
|
-
syncedOrder: printableSyncedOrder,
|
|
1235
|
-
response,
|
|
1236
|
-
deviceId: (_c = ctx.task) == null ? void 0 : _c.device_id
|
|
1184
|
+
response: syncResult.errorResponse
|
|
1237
1185
|
});
|
|
1186
|
+
return this.taskFail(
|
|
1187
|
+
"BACKEND_REJECTED",
|
|
1188
|
+
syncResult.message || "后端明确拒绝 checkout",
|
|
1189
|
+
syncResult.errorResponse
|
|
1190
|
+
);
|
|
1238
1191
|
}
|
|
1239
1192
|
return this.taskOk({
|
|
1240
|
-
order: syncedOrder ?? null,
|
|
1241
|
-
response:
|
|
1193
|
+
order: syncResult.syncedOrder ?? null,
|
|
1194
|
+
response: syncResult.normalizedResponse
|
|
1242
1195
|
});
|
|
1243
1196
|
} catch (error) {
|
|
1244
1197
|
const backendError = this.extractBackendErrorResponse(error);
|
|
@@ -1259,6 +1212,135 @@ var Server = class {
|
|
|
1259
1212
|
return this.taskTimeout(errorMessage);
|
|
1260
1213
|
}
|
|
1261
1214
|
}
|
|
1215
|
+
async runCheckoutSync(params) {
|
|
1216
|
+
var _a, _b;
|
|
1217
|
+
const { backendPath, title } = params;
|
|
1218
|
+
const normalizedData = await this.normalizeCheckoutSubmitData(params.data, title);
|
|
1219
|
+
const checkoutData = await this.ensureCheckoutOrderNumbers(normalizedData, title);
|
|
1220
|
+
const remoteCheckoutData = this.omitCheckoutSyncMode(checkoutData);
|
|
1221
|
+
if (!((_b = (_a = this.app) == null ? void 0 : _a.request) == null ? void 0 : _b.post)) {
|
|
1222
|
+
throw new Error("app.request 不可用");
|
|
1223
|
+
}
|
|
1224
|
+
const response = await this.app.request.post(backendPath, remoteCheckoutData, {
|
|
1225
|
+
isShopApi: true,
|
|
1226
|
+
customToast: () => {
|
|
1227
|
+
}
|
|
1228
|
+
});
|
|
1229
|
+
if (this.isCheckoutResponseRejected(response)) {
|
|
1230
|
+
return {
|
|
1231
|
+
rejected: true,
|
|
1232
|
+
message: (response == null ? void 0 : response.message) || "后端明确拒绝 checkout",
|
|
1233
|
+
errorResponse: response,
|
|
1234
|
+
response,
|
|
1235
|
+
normalizedResponse: this.normalizeCheckoutResponse(response),
|
|
1236
|
+
checkoutData: remoteCheckoutData
|
|
1237
|
+
};
|
|
1238
|
+
}
|
|
1239
|
+
const fresh = this.extractOrderDataFromCheckoutResponse(response);
|
|
1240
|
+
const externalSaleNumber = this.getCheckoutExternalSaleNumber(
|
|
1241
|
+
remoteCheckoutData,
|
|
1242
|
+
{
|
|
1243
|
+
external_sale_number: params.externalSaleNumber,
|
|
1244
|
+
data: remoteCheckoutData
|
|
1245
|
+
}
|
|
1246
|
+
);
|
|
1247
|
+
const syncedOrder = await this.persistSyncedCheckoutOrder({
|
|
1248
|
+
backendPath,
|
|
1249
|
+
checkoutData: remoteCheckoutData,
|
|
1250
|
+
externalSaleNumber,
|
|
1251
|
+
fresh,
|
|
1252
|
+
title,
|
|
1253
|
+
persistCheckoutDataWithResponse: params.persistCheckoutDataWithResponse === true
|
|
1254
|
+
});
|
|
1255
|
+
const printableSyncedOrder = syncedOrder ? this.buildSyncedOrderForPrint({
|
|
1256
|
+
syncedOrder,
|
|
1257
|
+
checkoutResponseOrder: fresh
|
|
1258
|
+
}) : void 0;
|
|
1259
|
+
if (printableSyncedOrder && this.shouldPrintSyncedOrder({
|
|
1260
|
+
checkoutData: remoteCheckoutData,
|
|
1261
|
+
syncedOrder: printableSyncedOrder
|
|
1262
|
+
})) {
|
|
1263
|
+
await this.dispatchPrintOtherReceiptTask({
|
|
1264
|
+
checkoutData: remoteCheckoutData,
|
|
1265
|
+
syncedOrder: printableSyncedOrder,
|
|
1266
|
+
response,
|
|
1267
|
+
deviceId: params.deviceId
|
|
1268
|
+
});
|
|
1269
|
+
}
|
|
1270
|
+
return {
|
|
1271
|
+
rejected: false,
|
|
1272
|
+
response,
|
|
1273
|
+
normalizedResponse: this.normalizeCheckoutResponse(response),
|
|
1274
|
+
checkoutData: remoteCheckoutData,
|
|
1275
|
+
syncedOrder,
|
|
1276
|
+
fresh
|
|
1277
|
+
};
|
|
1278
|
+
}
|
|
1279
|
+
omitCheckoutSyncMode(data) {
|
|
1280
|
+
if (!data || typeof data !== "object")
|
|
1281
|
+
return data;
|
|
1282
|
+
const next = { ...data };
|
|
1283
|
+
delete next.sync_mode;
|
|
1284
|
+
delete next.syncMode;
|
|
1285
|
+
return next;
|
|
1286
|
+
}
|
|
1287
|
+
async persistSyncedCheckoutOrder(params) {
|
|
1288
|
+
const {
|
|
1289
|
+
backendPath,
|
|
1290
|
+
checkoutData,
|
|
1291
|
+
externalSaleNumber,
|
|
1292
|
+
fresh,
|
|
1293
|
+
title,
|
|
1294
|
+
persistCheckoutDataWithResponse
|
|
1295
|
+
} = params;
|
|
1296
|
+
const shouldMergeRemoteOrder = fresh ? this.isMergeableCheckoutOrder(fresh, externalSaleNumber) : false;
|
|
1297
|
+
let syncedOrder;
|
|
1298
|
+
if (this.order && fresh && (shouldMergeRemoteOrder || persistCheckoutDataWithResponse)) {
|
|
1299
|
+
syncedOrder = persistCheckoutDataWithResponse ? {
|
|
1300
|
+
...checkoutData,
|
|
1301
|
+
...fresh,
|
|
1302
|
+
external_sale_number: fresh.external_sale_number ?? externalSaleNumber,
|
|
1303
|
+
need_sync: 0
|
|
1304
|
+
} : {
|
|
1305
|
+
...fresh,
|
|
1306
|
+
external_sale_number: fresh.external_sale_number ?? externalSaleNumber,
|
|
1307
|
+
need_sync: 0
|
|
1308
|
+
};
|
|
1309
|
+
await this.order.upsertOrdersFromRemote([syncedOrder]);
|
|
1310
|
+
this.logInfo(`${title}: sync_sales 完整订单已同步到本地`, {
|
|
1311
|
+
order_id: fresh.order_id,
|
|
1312
|
+
external_sale_number: syncedOrder.external_sale_number,
|
|
1313
|
+
order_number: fresh.order_number,
|
|
1314
|
+
mergedRemoteOrder: shouldMergeRemoteOrder,
|
|
1315
|
+
persistedCheckoutDataWithResponse: persistCheckoutDataWithResponse
|
|
1316
|
+
});
|
|
1317
|
+
} else if (this.order && externalSaleNumber && typeof this.order.markOrderSyncedByExternalSaleNumber === "function") {
|
|
1318
|
+
const patch = this.buildCheckoutSyncSuccessPatch(fresh);
|
|
1319
|
+
const result = await this.order.markOrderSyncedByExternalSaleNumber({
|
|
1320
|
+
externalSaleNumber,
|
|
1321
|
+
patch
|
|
1322
|
+
});
|
|
1323
|
+
syncedOrder = (result == null ? void 0 : result.order) || {
|
|
1324
|
+
...checkoutData,
|
|
1325
|
+
...patch,
|
|
1326
|
+
external_sale_number: externalSaleNumber,
|
|
1327
|
+
need_sync: 0
|
|
1328
|
+
};
|
|
1329
|
+
this.logInfo(`${title}: sync_sales 已按 external_sale_number 标记本地订单`, {
|
|
1330
|
+
order_id: (syncedOrder == null ? void 0 : syncedOrder.order_id) ?? null,
|
|
1331
|
+
external_sale_number: externalSaleNumber,
|
|
1332
|
+
hasRemoteOrder: !!fresh,
|
|
1333
|
+
mergedRemoteOrder: false
|
|
1334
|
+
});
|
|
1335
|
+
} else {
|
|
1336
|
+
this.logWarning(`${title}: sync_sales Order 模块未注册`, {
|
|
1337
|
+
backendPath,
|
|
1338
|
+
external_sale_number: externalSaleNumber,
|
|
1339
|
+
order_id: fresh == null ? void 0 : fresh.order_id
|
|
1340
|
+
});
|
|
1341
|
+
}
|
|
1342
|
+
return syncedOrder;
|
|
1343
|
+
}
|
|
1262
1344
|
/**
|
|
1263
1345
|
* 将普通层 QuotationModule 的报价单计算能力桥接到 Server Products 模块。
|
|
1264
1346
|
*/
|
|
@@ -2605,6 +2687,13 @@ var Server = class {
|
|
|
2605
2687
|
external_sale_number: data == null ? void 0 : data.external_sale_number,
|
|
2606
2688
|
order_number: data == null ? void 0 : data.order_number
|
|
2607
2689
|
});
|
|
2690
|
+
if ((data == null ? void 0 : data.sync_mode) || (data == null ? void 0 : data.syncMode)) {
|
|
2691
|
+
return this.handleSyncCheckoutSubmit({
|
|
2692
|
+
backendPath,
|
|
2693
|
+
data,
|
|
2694
|
+
title
|
|
2695
|
+
});
|
|
2696
|
+
}
|
|
2608
2697
|
const normalizedData = await this.normalizeCheckoutSubmitData(data, title);
|
|
2609
2698
|
const checkoutData = await this.ensureCheckoutOrderNumbers(normalizedData, title);
|
|
2610
2699
|
const pendingResult = await this.handlePendingSyncCheckoutOrder({
|
|
@@ -2642,6 +2731,63 @@ var Server = class {
|
|
|
2642
2731
|
}
|
|
2643
2732
|
return pendingResult;
|
|
2644
2733
|
}
|
|
2734
|
+
async handleSyncCheckoutSubmit(params) {
|
|
2735
|
+
var _a, _b;
|
|
2736
|
+
const { backendPath, data, title } = params;
|
|
2737
|
+
if (!((_b = (_a = this.app) == null ? void 0 : _a.request) == null ? void 0 : _b.post)) {
|
|
2738
|
+
this.logError(`${title}: sync checkout app.request 不可用`);
|
|
2739
|
+
return {
|
|
2740
|
+
code: 500,
|
|
2741
|
+
status: false,
|
|
2742
|
+
message: "app.request 不可用",
|
|
2743
|
+
data: null
|
|
2744
|
+
};
|
|
2745
|
+
}
|
|
2746
|
+
try {
|
|
2747
|
+
const syncResult = await this.runCheckoutSync({
|
|
2748
|
+
backendPath,
|
|
2749
|
+
data,
|
|
2750
|
+
title,
|
|
2751
|
+
persistCheckoutDataWithResponse: true
|
|
2752
|
+
});
|
|
2753
|
+
if (syncResult.rejected) {
|
|
2754
|
+
const normalized = this.normalizeCheckoutResponse(syncResult.errorResponse);
|
|
2755
|
+
return {
|
|
2756
|
+
...normalized,
|
|
2757
|
+
status: false,
|
|
2758
|
+
message: syncResult.message || (normalized == null ? void 0 : normalized.message) || "后端明确拒绝 checkout",
|
|
2759
|
+
data: (normalized == null ? void 0 : normalized.data) ?? null
|
|
2760
|
+
};
|
|
2761
|
+
}
|
|
2762
|
+
return this.withSyncedOrderIdInCheckoutResponse(
|
|
2763
|
+
syncResult.normalizedResponse,
|
|
2764
|
+
syncResult.syncedOrder
|
|
2765
|
+
);
|
|
2766
|
+
} catch (error) {
|
|
2767
|
+
const backendError = this.extractBackendErrorResponse(error);
|
|
2768
|
+
if (backendError) {
|
|
2769
|
+
const normalized = this.normalizeCheckoutResponse(backendError);
|
|
2770
|
+
return {
|
|
2771
|
+
...normalized,
|
|
2772
|
+
status: false,
|
|
2773
|
+
message: (backendError == null ? void 0 : backendError.message) || (normalized == null ? void 0 : normalized.message) || "后端明确拒绝 checkout",
|
|
2774
|
+
data: (normalized == null ? void 0 : normalized.data) ?? null
|
|
2775
|
+
};
|
|
2776
|
+
}
|
|
2777
|
+
const message = this.getUnknownErrorMessage(error);
|
|
2778
|
+
this.logError(`${title}: sync checkout 请求未明确成功`, {
|
|
2779
|
+
backendPath,
|
|
2780
|
+
error: message,
|
|
2781
|
+
error_detail: this.normalizeUnknownError(error)
|
|
2782
|
+
});
|
|
2783
|
+
return {
|
|
2784
|
+
code: 500,
|
|
2785
|
+
status: false,
|
|
2786
|
+
message,
|
|
2787
|
+
data: null
|
|
2788
|
+
};
|
|
2789
|
+
}
|
|
2790
|
+
}
|
|
2645
2791
|
async handlePendingSyncCheckoutOrder(params) {
|
|
2646
2792
|
var _a, _b, _c, _d;
|
|
2647
2793
|
const { backendPath, data, title, reason } = params;
|
|
@@ -3219,6 +3365,21 @@ var Server = class {
|
|
|
3219
3365
|
data: response
|
|
3220
3366
|
};
|
|
3221
3367
|
}
|
|
3368
|
+
withSyncedOrderIdInCheckoutResponse(response, syncedOrder) {
|
|
3369
|
+
const normalized = this.normalizeCheckoutResponse(response);
|
|
3370
|
+
const orderId = syncedOrder == null ? void 0 : syncedOrder.order_id;
|
|
3371
|
+
if (orderId === void 0 || orderId === null)
|
|
3372
|
+
return normalized;
|
|
3373
|
+
if (!(normalized == null ? void 0 : normalized.data) || typeof normalized.data !== "object")
|
|
3374
|
+
return normalized;
|
|
3375
|
+
return {
|
|
3376
|
+
...normalized,
|
|
3377
|
+
data: {
|
|
3378
|
+
...normalized.data,
|
|
3379
|
+
order_id: normalized.data.order_id ?? orderId
|
|
3380
|
+
}
|
|
3381
|
+
};
|
|
3382
|
+
}
|
|
3222
3383
|
isCheckoutResponseRejected(response) {
|
|
3223
3384
|
const normalized = this.normalizeCheckoutResponse(response);
|
|
3224
3385
|
const isErrorCode = (normalized == null ? void 0 : normalized.code) !== void 0 && normalized.code !== 200 && normalized.code !== "200";
|
|
@@ -192,6 +192,8 @@ export declare class OrderModule extends BaseModule implements Module {
|
|
|
192
192
|
private findOrderIndexByIdentity;
|
|
193
193
|
private getOrderCompletenessScore;
|
|
194
194
|
private pickPreferredOrder;
|
|
195
|
+
private getProductMergeKey;
|
|
196
|
+
private mergeOrderProductLists;
|
|
195
197
|
private mergeOrderRecords;
|
|
196
198
|
private summarizeDuplicateOrders;
|
|
197
199
|
private logDuplicateOrders;
|
|
@@ -1130,6 +1130,45 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1130
1130
|
return right;
|
|
1131
1131
|
return left;
|
|
1132
1132
|
}
|
|
1133
|
+
getProductMergeKey(product) {
|
|
1134
|
+
var _a;
|
|
1135
|
+
const record = product;
|
|
1136
|
+
if (!record)
|
|
1137
|
+
return "";
|
|
1138
|
+
const metadataUid = (_a = record.metadata) == null ? void 0 : _a.unique_identification_number;
|
|
1139
|
+
if (!this.isBlankIdentityValue(metadataUid))
|
|
1140
|
+
return `uid:${String(metadataUid)}`;
|
|
1141
|
+
const topLevelUid = record.unique_identification_number;
|
|
1142
|
+
if (!this.isBlankIdentityValue(topLevelUid))
|
|
1143
|
+
return `uid:${String(topLevelUid)}`;
|
|
1144
|
+
const bookingUid = record.booking_uid;
|
|
1145
|
+
if (!this.isBlankIdentityValue(bookingUid))
|
|
1146
|
+
return `booking:${String(bookingUid)}`;
|
|
1147
|
+
return "";
|
|
1148
|
+
}
|
|
1149
|
+
mergeOrderProductLists(preferred, secondary) {
|
|
1150
|
+
const preferredList = Array.isArray(preferred) ? preferred : [];
|
|
1151
|
+
const secondaryList = Array.isArray(secondary) ? secondary : [];
|
|
1152
|
+
if (secondaryList.length === 0)
|
|
1153
|
+
return preferredList;
|
|
1154
|
+
if (preferredList.length === 0)
|
|
1155
|
+
return secondaryList;
|
|
1156
|
+
const seenKeys = /* @__PURE__ */ new Set();
|
|
1157
|
+
for (const item of preferredList) {
|
|
1158
|
+
const key = this.getProductMergeKey(item);
|
|
1159
|
+
if (key)
|
|
1160
|
+
seenKeys.add(key);
|
|
1161
|
+
}
|
|
1162
|
+
const result = [...preferredList];
|
|
1163
|
+
for (const item of secondaryList) {
|
|
1164
|
+
const key = this.getProductMergeKey(item);
|
|
1165
|
+
if (!key || seenKeys.has(key))
|
|
1166
|
+
continue;
|
|
1167
|
+
seenKeys.add(key);
|
|
1168
|
+
result.push((0, import_lodash_es.cloneDeep)(item));
|
|
1169
|
+
}
|
|
1170
|
+
return result;
|
|
1171
|
+
}
|
|
1133
1172
|
mergeOrderRecords(existing, incoming) {
|
|
1134
1173
|
const preferred = this.pickPreferredOrder(existing, incoming);
|
|
1135
1174
|
const secondary = preferred === existing ? incoming : existing;
|
|
@@ -1150,7 +1189,9 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1150
1189
|
"shipping_status",
|
|
1151
1190
|
"updated_at",
|
|
1152
1191
|
"summary",
|
|
1153
|
-
"payments"
|
|
1192
|
+
"payments",
|
|
1193
|
+
"products",
|
|
1194
|
+
"bookings"
|
|
1154
1195
|
];
|
|
1155
1196
|
const mergedRecord = merged;
|
|
1156
1197
|
const preferredRecord = preferred;
|
|
@@ -1174,6 +1215,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
1174
1215
|
continue;
|
|
1175
1216
|
mergedRecord[field] = (0, import_lodash_es.cloneDeep)(incomingRecord[field]);
|
|
1176
1217
|
}
|
|
1218
|
+
mergedRecord.products = this.mergeOrderProductLists(preferredRecord.products, secondaryRecord.products);
|
|
1177
1219
|
if (!this.isPendingSyncOrder(preferred) || !this.isPendingSyncOrder(secondary)) {
|
|
1178
1220
|
merged.need_sync = 0;
|
|
1179
1221
|
}
|
|
@@ -203,6 +203,12 @@ export declare class BaseSalesImpl extends BaseModule implements Module {
|
|
|
203
203
|
smallTicketDataFlag?: number;
|
|
204
204
|
enhancePayload?: SubmitPayloadEnhancer;
|
|
205
205
|
}): Promise<T>;
|
|
206
|
+
submitTempOrderAsync<T = any>(params?: {
|
|
207
|
+
payments?: OrderPaymentSource[];
|
|
208
|
+
paymentStatus?: BaseSalesPaymentStatus;
|
|
209
|
+
smallTicketDataFlag?: number;
|
|
210
|
+
enhancePayload?: SubmitPayloadEnhancer;
|
|
211
|
+
}): Promise<T>;
|
|
206
212
|
printLocalOrderReceipt<T = any>(lookup?: BaseSalesPrintLocalOrderReceiptParams): Promise<T>;
|
|
207
213
|
private getSubmitPaymentStatus;
|
|
208
214
|
syncPaymentsToOrder<T = any>(params: SyncPaymentsToOrderParams): Promise<SyncPaymentsToOrderResult<T>>;
|