@pisell/pisellos 0.10.16 → 0.10.18
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/model/strategy/adapter/promotion/index.js +9 -0
- package/dist/modules/OpenData/index.d.ts +5 -2
- package/dist/modules/OpenData/index.js +27 -12
- package/dist/modules/OpenData/types.d.ts +42 -0
- package/dist/modules/OpenData/types.js +7 -1
- package/dist/modules/OpenData/utils.d.ts +15 -1
- package/dist/modules/OpenData/utils.js +85 -0
- package/dist/modules/Order/index.d.ts +3 -1
- package/dist/modules/Order/index.js +68 -44
- package/dist/modules/Order/types.d.ts +3 -0
- package/dist/modules/Order/types.js +1 -0
- package/dist/modules/ProductList/index.js +96 -74
- package/dist/modules/Rules/index.js +11 -8
- package/dist/modules/SalesSummary/index.js +6 -4
- package/dist/server/index.d.ts +11 -0
- package/dist/server/index.js +845 -481
- package/dist/server/modules/order/index.d.ts +8 -0
- package/dist/server/modules/order/index.js +251 -215
- package/dist/server/utils/small-ticket.d.ts +9 -1
- package/dist/server/utils/small-ticket.js +117 -43
- package/dist/solution/BaseSales/index.d.ts +7 -0
- package/dist/solution/BaseSales/index.js +251 -144
- package/dist/solution/BookingByStep/index.d.ts +2 -2
- package/dist/solution/BookingTicket/index.d.ts +14 -19
- package/dist/solution/BookingTicket/index.js +545 -429
- package/dist/solution/Sales/index.d.ts +20 -4
- package/dist/solution/Sales/index.js +348 -75
- package/dist/solution/Sales/types.d.ts +10 -0
- package/dist/solution/UnifiedBookingSales/index.d.ts +5 -4
- package/dist/solution/UnifiedBookingSales/index.js +495 -422
- package/dist/solution/UnifiedBookingSales/types.d.ts +7 -1
- package/lib/model/strategy/adapter/promotion/index.js +1 -46
- package/lib/modules/OpenData/index.d.ts +5 -2
- package/lib/modules/OpenData/index.js +50 -3
- package/lib/modules/OpenData/types.d.ts +42 -0
- package/lib/modules/OpenData/types.js +9 -1
- package/lib/modules/OpenData/utils.d.ts +15 -1
- package/lib/modules/OpenData/utils.js +85 -0
- package/lib/modules/Order/index.d.ts +3 -1
- package/lib/modules/Order/index.js +41 -21
- package/lib/modules/Order/types.d.ts +3 -0
- package/lib/modules/Order/types.js +1 -0
- package/lib/modules/ProductList/index.js +9 -6
- package/lib/modules/Rules/index.js +8 -6
- package/lib/modules/SalesSummary/index.js +3 -1
- package/lib/server/index.d.ts +11 -0
- package/lib/server/index.js +395 -96
- package/lib/server/modules/order/index.d.ts +8 -0
- package/lib/server/modules/order/index.js +23 -0
- package/lib/server/utils/small-ticket.d.ts +9 -1
- package/lib/server/utils/small-ticket.js +107 -35
- package/lib/solution/BaseSales/index.d.ts +7 -0
- package/lib/solution/BaseSales/index.js +125 -28
- package/lib/solution/BookingByStep/index.d.ts +2 -2
- package/lib/solution/BookingTicket/index.d.ts +14 -19
- package/lib/solution/BookingTicket/index.js +70 -17
- package/lib/solution/Sales/index.d.ts +20 -4
- package/lib/solution/Sales/index.js +183 -15
- package/lib/solution/Sales/types.d.ts +10 -0
- package/lib/solution/UnifiedBookingSales/index.d.ts +5 -4
- package/lib/solution/UnifiedBookingSales/index.js +41 -15
- package/lib/solution/UnifiedBookingSales/types.d.ts +7 -1
- package/package.json +1 -1
package/lib/server/index.js
CHANGED
|
@@ -27,6 +27,7 @@ var _filterBookings = require("./modules/order/utils/filterBookings");
|
|
|
27
27
|
var _smallTicket = require("./utils/small-ticket");
|
|
28
28
|
var _BaseSales = require("../solution/BaseSales");
|
|
29
29
|
var _paymentUtils = require("../modules/Order/payment-utils");
|
|
30
|
+
var _OpenData = require("../modules/OpenData");
|
|
30
31
|
var _modules = require("./modules");
|
|
31
32
|
Object.keys(_modules).forEach(function (key) {
|
|
32
33
|
if (key === "default" || key === "__esModule") return;
|
|
@@ -40,6 +41,10 @@ Object.keys(_modules).forEach(function (key) {
|
|
|
40
41
|
});
|
|
41
42
|
});
|
|
42
43
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
44
|
+
const OS_FULFILLMENT_REF_MODE_FIELD = '_os_fulfillment_ref_mode';
|
|
45
|
+
const OS_INVOICE_LAYOUT_CONFIG_FIELD = '_os_invoice_layout_config';
|
|
46
|
+
const OS_INVOICE_TEMPLATE_SETTINGS_FIELD = '_os_invoice_template_settings';
|
|
47
|
+
|
|
43
48
|
// 重新导出类型供外部使用
|
|
44
49
|
|
|
45
50
|
/** 商品查询订阅者 */
|
|
@@ -560,7 +565,16 @@ class Server {
|
|
|
560
565
|
async handleSyncSalesTask(ctx) {
|
|
561
566
|
const payload = ctx.task?.payload || {};
|
|
562
567
|
const backendPath = payload.backendPath;
|
|
563
|
-
const
|
|
568
|
+
const extractedInvoice = this.extractInvoiceLayoutConfig(payload.data, {
|
|
569
|
+
includePublicInvoice: true
|
|
570
|
+
});
|
|
571
|
+
const extractedTemplateSettings = this.extractInvoiceTemplateSettings(extractedInvoice.data, {
|
|
572
|
+
includePublicTemplateSettings: true
|
|
573
|
+
});
|
|
574
|
+
const data = extractedTemplateSettings.data;
|
|
575
|
+
const rawInvoiceLayoutConfig = payload.invoice ?? extractedInvoice.invoiceLayoutConfig;
|
|
576
|
+
const invoiceLayoutConfig = rawInvoiceLayoutConfig === undefined || rawInvoiceLayoutConfig === null ? undefined : this.normalizePrintInvoiceLayoutConfig(rawInvoiceLayoutConfig);
|
|
577
|
+
const invoiceTemplateSettings = this.normalizePrintInvoiceTemplateSettings(payload.template_settings ?? extractedTemplateSettings.invoiceTemplateSettings);
|
|
564
578
|
const title = payload.title || 'sync_sales';
|
|
565
579
|
if (!backendPath || !data) {
|
|
566
580
|
return this.taskFail('INVALID_PAYLOAD', '缺少 backendPath 或 data');
|
|
@@ -576,7 +590,9 @@ class Server {
|
|
|
576
590
|
title,
|
|
577
591
|
externalSaleNumber: payload.external_sale_number,
|
|
578
592
|
deviceId: ctx.task?.device_id,
|
|
579
|
-
persistCheckoutDataWithResponse: false
|
|
593
|
+
persistCheckoutDataWithResponse: false,
|
|
594
|
+
invoiceLayoutConfig,
|
|
595
|
+
invoiceTemplateSettings
|
|
580
596
|
});
|
|
581
597
|
if (syncResult.rejected) {
|
|
582
598
|
this.logError(`${title}: sync_sales 后端明确失败`, {
|
|
@@ -614,7 +630,8 @@ class Server {
|
|
|
614
630
|
title
|
|
615
631
|
} = params;
|
|
616
632
|
const normalizedData = await this.normalizeCheckoutSubmitData(params.data, title);
|
|
617
|
-
const
|
|
633
|
+
const numberedData = await this.ensureCheckoutOrderNumbers(normalizedData, title);
|
|
634
|
+
const checkoutData = this.applyCheckoutFulfillmentBuzzer(numberedData, title);
|
|
618
635
|
const remoteCheckoutData = this.buildRemoteCheckoutData(checkoutData, title);
|
|
619
636
|
if (!this.app?.request?.post) {
|
|
620
637
|
throw new Error('app.request 不可用');
|
|
@@ -658,7 +675,9 @@ class Server {
|
|
|
658
675
|
checkoutData,
|
|
659
676
|
syncedOrder: printableSyncedOrder,
|
|
660
677
|
response,
|
|
661
|
-
deviceId: params.deviceId
|
|
678
|
+
deviceId: params.deviceId,
|
|
679
|
+
invoiceLayoutConfig: params.invoiceLayoutConfig,
|
|
680
|
+
invoiceTemplateSettings: params.invoiceTemplateSettings
|
|
662
681
|
});
|
|
663
682
|
}
|
|
664
683
|
return {
|
|
@@ -683,6 +702,8 @@ class Server {
|
|
|
683
702
|
const next = (0, _lodashEs.cloneDeep)(this.omitCheckoutSyncMode(data));
|
|
684
703
|
if (!next || typeof next !== 'object') return next;
|
|
685
704
|
const record = next;
|
|
705
|
+
delete record[OS_FULFILLMENT_REF_MODE_FIELD];
|
|
706
|
+
delete record[OS_INVOICE_LAYOUT_CONFIG_FIELD];
|
|
686
707
|
if (!Array.isArray(record.payments)) return next;
|
|
687
708
|
const originalPayments = record.payments;
|
|
688
709
|
const filteredPayments = originalPayments.filter(payment => !(0, _paymentUtils.isPendingOrderPayment)(payment));
|
|
@@ -3342,6 +3363,158 @@ class Server {
|
|
|
3342
3363
|
isLocalCheckoutOrderId(orderId) {
|
|
3343
3364
|
return typeof orderId === 'string' && orderId.startsWith('LOCAL_');
|
|
3344
3365
|
}
|
|
3366
|
+
normalizePrintInvoiceLayoutConfig(value) {
|
|
3367
|
+
if (value === undefined || value === null) {
|
|
3368
|
+
return (0, _OpenData.getDefaultInvoiceLayoutConfig)();
|
|
3369
|
+
}
|
|
3370
|
+
let parsed = value;
|
|
3371
|
+
if (typeof parsed === 'string') {
|
|
3372
|
+
try {
|
|
3373
|
+
parsed = JSON.parse(parsed);
|
|
3374
|
+
} catch {
|
|
3375
|
+
return (0, _OpenData.getDefaultInvoiceLayoutConfig)();
|
|
3376
|
+
}
|
|
3377
|
+
}
|
|
3378
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
3379
|
+
return (0, _OpenData.getDefaultInvoiceLayoutConfig)();
|
|
3380
|
+
}
|
|
3381
|
+
const record = parsed;
|
|
3382
|
+
if (!Array.isArray(record.module)) {
|
|
3383
|
+
return (0, _OpenData.getDefaultInvoiceLayoutConfig)();
|
|
3384
|
+
}
|
|
3385
|
+
return {
|
|
3386
|
+
...(typeof record.locale === 'string' ? {
|
|
3387
|
+
locale: record.locale
|
|
3388
|
+
} : {}),
|
|
3389
|
+
module: record.module.map(moduleConfig => moduleConfig && typeof moduleConfig === 'object' && !Array.isArray(moduleConfig) ? {
|
|
3390
|
+
...moduleConfig
|
|
3391
|
+
} : moduleConfig)
|
|
3392
|
+
};
|
|
3393
|
+
}
|
|
3394
|
+
extractInvoiceLayoutConfig(data, options) {
|
|
3395
|
+
if (!data || typeof data !== 'object' || Array.isArray(data)) {
|
|
3396
|
+
return {
|
|
3397
|
+
data
|
|
3398
|
+
};
|
|
3399
|
+
}
|
|
3400
|
+
const record = data;
|
|
3401
|
+
const rawInvoiceLayoutConfig = options?.includePublicInvoice ? record.invoice ?? record[OS_INVOICE_LAYOUT_CONFIG_FIELD] : record[OS_INVOICE_LAYOUT_CONFIG_FIELD];
|
|
3402
|
+
const next = {
|
|
3403
|
+
...record
|
|
3404
|
+
};
|
|
3405
|
+
delete next[OS_INVOICE_LAYOUT_CONFIG_FIELD];
|
|
3406
|
+
if (options?.includePublicInvoice) delete next.invoice;
|
|
3407
|
+
return {
|
|
3408
|
+
data: next,
|
|
3409
|
+
...(rawInvoiceLayoutConfig !== undefined && rawInvoiceLayoutConfig !== null ? {
|
|
3410
|
+
invoiceLayoutConfig: this.normalizePrintInvoiceLayoutConfig(rawInvoiceLayoutConfig)
|
|
3411
|
+
} : {})
|
|
3412
|
+
};
|
|
3413
|
+
}
|
|
3414
|
+
normalizePrintInvoiceTemplateSettings(value) {
|
|
3415
|
+
if (value === undefined || value === null) {
|
|
3416
|
+
return (0, _OpenData.getDefaultInvoiceTemplateSettings)();
|
|
3417
|
+
}
|
|
3418
|
+
return (0, _OpenData.normalizeRawInvoiceTemplateSettings)(value);
|
|
3419
|
+
}
|
|
3420
|
+
extractInvoiceTemplateSettings(data, options) {
|
|
3421
|
+
if (!data || typeof data !== 'object' || Array.isArray(data)) {
|
|
3422
|
+
return {
|
|
3423
|
+
data
|
|
3424
|
+
};
|
|
3425
|
+
}
|
|
3426
|
+
const record = data;
|
|
3427
|
+
const rawInvoiceTemplateSettings = options?.includePublicTemplateSettings ? record.template_settings ?? record[OS_INVOICE_TEMPLATE_SETTINGS_FIELD] : record[OS_INVOICE_TEMPLATE_SETTINGS_FIELD];
|
|
3428
|
+
const next = {
|
|
3429
|
+
...record
|
|
3430
|
+
};
|
|
3431
|
+
delete next[OS_INVOICE_TEMPLATE_SETTINGS_FIELD];
|
|
3432
|
+
if (options?.includePublicTemplateSettings) delete next.template_settings;
|
|
3433
|
+
return {
|
|
3434
|
+
data: next,
|
|
3435
|
+
...(rawInvoiceTemplateSettings !== undefined && rawInvoiceTemplateSettings !== null ? {
|
|
3436
|
+
invoiceTemplateSettings: this.normalizePrintInvoiceTemplateSettings(rawInvoiceTemplateSettings)
|
|
3437
|
+
} : {})
|
|
3438
|
+
};
|
|
3439
|
+
}
|
|
3440
|
+
applyCheckoutFulfillmentBuzzer(data, title) {
|
|
3441
|
+
if (!data || typeof data !== 'object') return data;
|
|
3442
|
+
const next = {
|
|
3443
|
+
...data
|
|
3444
|
+
};
|
|
3445
|
+
const refMode = String(next[OS_FULFILLMENT_REF_MODE_FIELD] || '').trim();
|
|
3446
|
+
delete next[OS_FULFILLMENT_REF_MODE_FIELD];
|
|
3447
|
+
if (!refMode) return next;
|
|
3448
|
+
if (refMode === 'manual_input') {
|
|
3449
|
+
this.logInfo(`${title}: fulfillment ref mode 保留手动 buzzer`, {
|
|
3450
|
+
fulfillment_ref_mode: refMode,
|
|
3451
|
+
has_buzzer: !this.isBlankCheckoutValue(next.buzzer)
|
|
3452
|
+
});
|
|
3453
|
+
return next;
|
|
3454
|
+
}
|
|
3455
|
+
if (refMode === 'resource_identifier') {
|
|
3456
|
+
next.buzzer = this.buildCheckoutResourceIdentifierBuzzer(next.bookings);
|
|
3457
|
+
} else if (refMode === 'sale_number') {
|
|
3458
|
+
next.buzzer = this.isBlankCheckoutValue(next.shop_order_number) ? '' : String(next.shop_order_number);
|
|
3459
|
+
} else if (refMode === 'short_number') {
|
|
3460
|
+
next.buzzer = this.isBlankCheckoutValue(next.shop_full_order_number) ? '' : String(next.shop_full_order_number);
|
|
3461
|
+
} else {
|
|
3462
|
+
this.logWarning(`${title}: 未识别的 fulfillment ref mode,跳过 buzzer 自动填充`, {
|
|
3463
|
+
fulfillment_ref_mode: refMode
|
|
3464
|
+
});
|
|
3465
|
+
return next;
|
|
3466
|
+
}
|
|
3467
|
+
this.logInfo(`${title}: fulfillment ref mode 已填充 buzzer`, {
|
|
3468
|
+
fulfillment_ref_mode: refMode,
|
|
3469
|
+
buzzer: next.buzzer
|
|
3470
|
+
});
|
|
3471
|
+
return next;
|
|
3472
|
+
}
|
|
3473
|
+
buildCheckoutResourceIdentifierBuzzer(bookings) {
|
|
3474
|
+
if (!Array.isArray(bookings)) return '';
|
|
3475
|
+
const values = [];
|
|
3476
|
+
const seen = new Set();
|
|
3477
|
+
const visitResource = (resource, fallbackName) => {
|
|
3478
|
+
const identifier = this.getCheckoutResourceIdentifier(resource, fallbackName);
|
|
3479
|
+
if (identifier && !seen.has(identifier)) {
|
|
3480
|
+
seen.add(identifier);
|
|
3481
|
+
values.push(identifier);
|
|
3482
|
+
}
|
|
3483
|
+
if (Array.isArray(resource?.children)) {
|
|
3484
|
+
resource.children.forEach(child => visitResource(child));
|
|
3485
|
+
}
|
|
3486
|
+
};
|
|
3487
|
+
bookings.forEach(booking => {
|
|
3488
|
+
if (Array.isArray(booking?.resources)) {
|
|
3489
|
+
booking.resources.forEach((resource, index) => {
|
|
3490
|
+
visitResource(resource, index === 0 ? booking?.relation_form_name : undefined);
|
|
3491
|
+
});
|
|
3492
|
+
}
|
|
3493
|
+
});
|
|
3494
|
+
return values.join(',');
|
|
3495
|
+
}
|
|
3496
|
+
getCheckoutResourceIdentifier(resource, fallbackName) {
|
|
3497
|
+
if (!resource || typeof resource !== 'object') return '';
|
|
3498
|
+
const candidates = [resource.main_field, resource.name, resource.title, resource.metadata?.resource_name, resource.metadata?.name, fallbackName, resource.relation_id, resource.id];
|
|
3499
|
+
for (const candidate of candidates) {
|
|
3500
|
+
const value = this.stringifyCheckoutResourceIdentifier(candidate);
|
|
3501
|
+
if (value) return value;
|
|
3502
|
+
}
|
|
3503
|
+
return '';
|
|
3504
|
+
}
|
|
3505
|
+
stringifyCheckoutResourceIdentifier(value) {
|
|
3506
|
+
if (value === undefined || value === null) return '';
|
|
3507
|
+
if (typeof value === 'string' || typeof value === 'number') {
|
|
3508
|
+
return String(value).trim();
|
|
3509
|
+
}
|
|
3510
|
+
if (typeof value !== 'object' || Array.isArray(value)) return '';
|
|
3511
|
+
const localeCandidates = [value.original, value.auto, value.en, value['zh-CN'], value.zh_CN, value['zh-HK'], value.zh_HK];
|
|
3512
|
+
for (const candidate of localeCandidates) {
|
|
3513
|
+
const normalized = this.stringifyCheckoutResourceIdentifier(candidate);
|
|
3514
|
+
if (normalized) return normalized;
|
|
3515
|
+
}
|
|
3516
|
+
return '';
|
|
3517
|
+
}
|
|
3345
3518
|
async normalizeCheckoutSubmitData(data, title) {
|
|
3346
3519
|
if (!data || typeof data !== 'object') return data;
|
|
3347
3520
|
const next = {
|
|
@@ -3472,6 +3645,8 @@ class Server {
|
|
|
3472
3645
|
payload: {
|
|
3473
3646
|
backendPath: params.backendPath,
|
|
3474
3647
|
data: params.data,
|
|
3648
|
+
invoice: this.normalizePrintInvoiceLayoutConfig(params.invoiceLayoutConfig),
|
|
3649
|
+
template_settings: this.normalizePrintInvoiceTemplateSettings(params.invoiceTemplateSettings),
|
|
3475
3650
|
external_sale_number: params.data?.external_sale_number,
|
|
3476
3651
|
title: params.title
|
|
3477
3652
|
},
|
|
@@ -3510,12 +3685,14 @@ class Server {
|
|
|
3510
3685
|
data: params.receiptOnly ? {
|
|
3511
3686
|
order_id: printIdentity,
|
|
3512
3687
|
small_ticket_data: params.syncedOrder?.payment_info?.small_ticket_data,
|
|
3688
|
+
template_settings: this.normalizePrintInvoiceTemplateSettings(params.invoiceTemplateSettings),
|
|
3513
3689
|
skip_wristband: true,
|
|
3514
3690
|
skip_voucher: true
|
|
3515
3691
|
} : {
|
|
3516
3692
|
order_id: printIdentity,
|
|
3517
3693
|
machine_code_print_info: params.syncedOrder?.payment_info?.machine_code_print_info,
|
|
3518
3694
|
machine_code_print_info_v2: params.syncedOrder?.machine_code_print_info_v2,
|
|
3695
|
+
template_settings: this.normalizePrintInvoiceTemplateSettings(params.invoiceTemplateSettings),
|
|
3519
3696
|
skip_receipt: true
|
|
3520
3697
|
}
|
|
3521
3698
|
},
|
|
@@ -3567,7 +3744,9 @@ class Server {
|
|
|
3567
3744
|
syncedOrder: printableOrder,
|
|
3568
3745
|
response: params.response,
|
|
3569
3746
|
receiptOnly: true,
|
|
3570
|
-
isManualPrint: params.isManualPrint
|
|
3747
|
+
isManualPrint: params.isManualPrint,
|
|
3748
|
+
invoiceLayoutConfig: params.invoiceLayoutConfig,
|
|
3749
|
+
invoiceTemplateSettings: params.invoiceTemplateSettings
|
|
3571
3750
|
});
|
|
3572
3751
|
return {
|
|
3573
3752
|
printed: true,
|
|
@@ -3587,11 +3766,35 @@ class Server {
|
|
|
3587
3766
|
}
|
|
3588
3767
|
return undefined;
|
|
3589
3768
|
}
|
|
3769
|
+
mergeLocalPrintOrderInput(localOrder, inputOrder) {
|
|
3770
|
+
const definedInput = Object.fromEntries(Object.entries(inputOrder || {}).filter(([, value]) => value !== undefined));
|
|
3771
|
+
return {
|
|
3772
|
+
...localOrder,
|
|
3773
|
+
...definedInput,
|
|
3774
|
+
order_id: localOrder.order_id ?? definedInput.order_id ?? definedInput.orderId,
|
|
3775
|
+
external_sale_number: localOrder.external_sale_number ?? definedInput.external_sale_number ?? definedInput.externalSaleNumber
|
|
3776
|
+
};
|
|
3777
|
+
}
|
|
3590
3778
|
handleLocalPrintOrder = async ({
|
|
3591
3779
|
data
|
|
3592
3780
|
}) => {
|
|
3593
3781
|
try {
|
|
3594
|
-
const
|
|
3782
|
+
const extractedRequest = this.extractInvoiceLayoutConfig(data, {
|
|
3783
|
+
includePublicInvoice: true
|
|
3784
|
+
});
|
|
3785
|
+
const extractedRequestTemplateSettings = this.extractInvoiceTemplateSettings(extractedRequest.data, {
|
|
3786
|
+
includePublicTemplateSettings: true
|
|
3787
|
+
});
|
|
3788
|
+
const requestOrder = extractedRequestTemplateSettings.data?.order;
|
|
3789
|
+
const nestedOrder = requestOrder && typeof requestOrder === 'object' ? this.extractInvoiceLayoutConfig(requestOrder, {
|
|
3790
|
+
includePublicInvoice: true
|
|
3791
|
+
}) : null;
|
|
3792
|
+
const nestedOrderTemplateSettings = nestedOrder ? this.extractInvoiceTemplateSettings(nestedOrder.data, {
|
|
3793
|
+
includePublicTemplateSettings: true
|
|
3794
|
+
}) : null;
|
|
3795
|
+
const inputOrder = nestedOrderTemplateSettings?.data ?? extractedRequestTemplateSettings.data;
|
|
3796
|
+
const invoiceLayoutConfig = extractedRequest.invoiceLayoutConfig ?? nestedOrder?.invoiceLayoutConfig;
|
|
3797
|
+
const invoiceTemplateSettings = this.normalizePrintInvoiceTemplateSettings(extractedRequestTemplateSettings.invoiceTemplateSettings ?? nestedOrderTemplateSettings?.invoiceTemplateSettings);
|
|
3595
3798
|
if (!inputOrder || typeof inputOrder !== 'object') {
|
|
3596
3799
|
return {
|
|
3597
3800
|
code: 400,
|
|
@@ -3603,13 +3806,13 @@ class Server {
|
|
|
3603
3806
|
}
|
|
3604
3807
|
};
|
|
3605
3808
|
}
|
|
3606
|
-
const shouldLookup = this.shouldLookupLocalPrintOrder(inputOrder) || this.shouldLookupLocalPrintOrder(data);
|
|
3809
|
+
const shouldLookup = this.shouldLookupLocalPrintOrder(inputOrder) || this.shouldLookupLocalPrintOrder(extractedRequest.data);
|
|
3607
3810
|
this.logInfo('handleLocalPrintOrder: 是否需要查找本地订单', {
|
|
3608
3811
|
shouldLookup,
|
|
3609
3812
|
inputOrder,
|
|
3610
3813
|
data
|
|
3611
3814
|
});
|
|
3612
|
-
const lookup = shouldLookup ? this.getLocalPrintOrderLookup(inputOrder) ?? this.getLocalPrintOrderLookup(data) : undefined;
|
|
3815
|
+
const lookup = shouldLookup ? this.getLocalPrintOrderLookup(inputOrder) ?? this.getLocalPrintOrderLookup(extractedRequest.data) : undefined;
|
|
3613
3816
|
let sourceOrder = inputOrder;
|
|
3614
3817
|
if (shouldLookup) {
|
|
3615
3818
|
if (lookup === undefined) {
|
|
@@ -3634,24 +3837,25 @@ class Server {
|
|
|
3634
3837
|
}
|
|
3635
3838
|
};
|
|
3636
3839
|
}
|
|
3637
|
-
|
|
3840
|
+
let localOrder = await this.order.getLocalOrderByLookup(lookup);
|
|
3638
3841
|
if (!localOrder) {
|
|
3639
|
-
|
|
3640
|
-
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3842
|
+
const remoteResult = await this.fetchAndPersistSalesOrderByLookup(lookup, {
|
|
3843
|
+
with: ['all']
|
|
3844
|
+
}, 'handleLocalPrintOrder');
|
|
3845
|
+
if (!remoteResult.order) {
|
|
3846
|
+
return {
|
|
3847
|
+
code: remoteResult.code,
|
|
3848
|
+
status: false,
|
|
3849
|
+
message: remoteResult.message,
|
|
3850
|
+
data: {
|
|
3851
|
+
printed: false,
|
|
3852
|
+
order: null
|
|
3853
|
+
}
|
|
3854
|
+
};
|
|
3855
|
+
}
|
|
3856
|
+
localOrder = remoteResult.order;
|
|
3648
3857
|
}
|
|
3649
|
-
sourceOrder =
|
|
3650
|
-
...localOrder,
|
|
3651
|
-
...inputOrder,
|
|
3652
|
-
order_id: localOrder.order_id ?? inputOrder.order_id ?? inputOrder.orderId,
|
|
3653
|
-
external_sale_number: localOrder.external_sale_number ?? inputOrder.external_sale_number ?? inputOrder.externalSaleNumber
|
|
3654
|
-
};
|
|
3858
|
+
sourceOrder = this.mergeLocalPrintOrderInput(localOrder, inputOrder);
|
|
3655
3859
|
}
|
|
3656
3860
|
const checkoutData = await this.ensureCheckoutOrderNumbers({
|
|
3657
3861
|
...sourceOrder,
|
|
@@ -3670,7 +3874,9 @@ class Server {
|
|
|
3670
3874
|
order: printableOrder,
|
|
3671
3875
|
response: null,
|
|
3672
3876
|
requireFullyPaid: false,
|
|
3673
|
-
isManualPrint: true
|
|
3877
|
+
isManualPrint: true,
|
|
3878
|
+
invoiceLayoutConfig,
|
|
3879
|
+
invoiceTemplateSettings
|
|
3674
3880
|
});
|
|
3675
3881
|
return {
|
|
3676
3882
|
code: 200,
|
|
@@ -3881,9 +4087,17 @@ class Server {
|
|
|
3881
4087
|
async handleOrderCheckoutSubmit(params) {
|
|
3882
4088
|
const {
|
|
3883
4089
|
backendPath,
|
|
3884
|
-
data,
|
|
3885
4090
|
title
|
|
3886
4091
|
} = params;
|
|
4092
|
+
const extractedInvoice = this.extractInvoiceLayoutConfig(params.data, {
|
|
4093
|
+
includePublicInvoice: true
|
|
4094
|
+
});
|
|
4095
|
+
const extractedTemplateSettings = this.extractInvoiceTemplateSettings(extractedInvoice.data, {
|
|
4096
|
+
includePublicTemplateSettings: true
|
|
4097
|
+
});
|
|
4098
|
+
const data = extractedTemplateSettings.data;
|
|
4099
|
+
const invoiceLayoutConfig = extractedInvoice.invoiceLayoutConfig;
|
|
4100
|
+
const invoiceTemplateSettings = this.normalizePrintInvoiceTemplateSettings(extractedTemplateSettings.invoiceTemplateSettings);
|
|
3887
4101
|
this.logInfo(`${title}: 开始处理`, {
|
|
3888
4102
|
backendPath,
|
|
3889
4103
|
order_id: data?.order_id,
|
|
@@ -3894,11 +4108,14 @@ class Server {
|
|
|
3894
4108
|
return this.handleSyncCheckoutSubmit({
|
|
3895
4109
|
backendPath,
|
|
3896
4110
|
data,
|
|
3897
|
-
title
|
|
4111
|
+
title,
|
|
4112
|
+
invoiceLayoutConfig,
|
|
4113
|
+
invoiceTemplateSettings
|
|
3898
4114
|
});
|
|
3899
4115
|
}
|
|
3900
4116
|
const normalizedData = await this.normalizeCheckoutSubmitData(data, title);
|
|
3901
|
-
const
|
|
4117
|
+
const numberedData = await this.ensureCheckoutOrderNumbers(normalizedData, title);
|
|
4118
|
+
const checkoutData = this.applyCheckoutFulfillmentBuzzer(numberedData, title);
|
|
3902
4119
|
const pendingResult = await this.handlePendingSyncCheckoutOrder({
|
|
3903
4120
|
backendPath,
|
|
3904
4121
|
data: checkoutData,
|
|
@@ -3912,13 +4129,17 @@ class Server {
|
|
|
3912
4129
|
checkoutData,
|
|
3913
4130
|
order: pendingOrder,
|
|
3914
4131
|
response: pendingResult,
|
|
3915
|
-
requireFullyPaid: true
|
|
4132
|
+
requireFullyPaid: true,
|
|
4133
|
+
invoiceLayoutConfig,
|
|
4134
|
+
invoiceTemplateSettings
|
|
3916
4135
|
});
|
|
3917
4136
|
}
|
|
3918
4137
|
await this.dispatchCheckoutSyncTask({
|
|
3919
4138
|
backendPath,
|
|
3920
4139
|
data: checkoutData,
|
|
3921
|
-
title
|
|
4140
|
+
title,
|
|
4141
|
+
invoiceLayoutConfig,
|
|
4142
|
+
invoiceTemplateSettings
|
|
3922
4143
|
});
|
|
3923
4144
|
}
|
|
3924
4145
|
if (!pendingResult.data.order_id) {
|
|
@@ -3936,7 +4157,9 @@ class Server {
|
|
|
3936
4157
|
const {
|
|
3937
4158
|
backendPath,
|
|
3938
4159
|
data,
|
|
3939
|
-
title
|
|
4160
|
+
title,
|
|
4161
|
+
invoiceLayoutConfig,
|
|
4162
|
+
invoiceTemplateSettings
|
|
3940
4163
|
} = params;
|
|
3941
4164
|
if (!this.app?.request?.post) {
|
|
3942
4165
|
this.logError(`${title}: sync checkout app.request 不可用`);
|
|
@@ -3952,7 +4175,9 @@ class Server {
|
|
|
3952
4175
|
backendPath,
|
|
3953
4176
|
data,
|
|
3954
4177
|
title,
|
|
3955
|
-
persistCheckoutDataWithResponse: true
|
|
4178
|
+
persistCheckoutDataWithResponse: true,
|
|
4179
|
+
invoiceLayoutConfig,
|
|
4180
|
+
invoiceTemplateSettings
|
|
3956
4181
|
});
|
|
3957
4182
|
if (syncResult.rejected) {
|
|
3958
4183
|
const normalized = this.normalizeCheckoutResponse(syncResult.errorResponse);
|
|
@@ -3970,7 +4195,9 @@ class Server {
|
|
|
3970
4195
|
checkoutData: syncResult.checkoutData,
|
|
3971
4196
|
order: syncedOrder,
|
|
3972
4197
|
response: syncResult.normalizedResponse,
|
|
3973
|
-
requireFullyPaid: true
|
|
4198
|
+
requireFullyPaid: true,
|
|
4199
|
+
invoiceLayoutConfig,
|
|
4200
|
+
invoiceTemplateSettings
|
|
3974
4201
|
// print_all 的 type=0 是收据打印;不要沿用同步成功后的券/手环打印 type=99。
|
|
3975
4202
|
});
|
|
3976
4203
|
}
|
|
@@ -4002,9 +4229,16 @@ class Server {
|
|
|
4002
4229
|
}
|
|
4003
4230
|
async handleOrderDraftSubmit(params) {
|
|
4004
4231
|
const {
|
|
4005
|
-
data,
|
|
4006
4232
|
title
|
|
4007
4233
|
} = params;
|
|
4234
|
+
const extractedInvoice = this.extractInvoiceLayoutConfig(params.data, {
|
|
4235
|
+
includePublicInvoice: true
|
|
4236
|
+
});
|
|
4237
|
+
const {
|
|
4238
|
+
data
|
|
4239
|
+
} = this.extractInvoiceTemplateSettings(extractedInvoice.data, {
|
|
4240
|
+
includePublicTemplateSettings: true
|
|
4241
|
+
});
|
|
4008
4242
|
this.logInfo(`${title}: 开始处理`, {
|
|
4009
4243
|
order_id: data?.order_id,
|
|
4010
4244
|
external_sale_number: data?.external_sale_number,
|
|
@@ -4488,6 +4722,122 @@ class Server {
|
|
|
4488
4722
|
return order;
|
|
4489
4723
|
}
|
|
4490
4724
|
}
|
|
4725
|
+
normalizeRemoteSalesOrderErrorCode(value) {
|
|
4726
|
+
if (value === undefined || value === null || value === '') return 500;
|
|
4727
|
+
const code = typeof value === 'number' ? value : Number(value);
|
|
4728
|
+
return Number.isFinite(code) ? code : 500;
|
|
4729
|
+
}
|
|
4730
|
+
async fetchAndPersistSalesOrderByLookup(lookup, data, title) {
|
|
4731
|
+
if (!this.order?.getLocalOrderByLookup || !this.order?.upsertOrdersFromRemote) {
|
|
4732
|
+
this.logError(`${title}: Order 模块未注册`);
|
|
4733
|
+
return {
|
|
4734
|
+
code: 500,
|
|
4735
|
+
message: 'Order 模块未注册',
|
|
4736
|
+
order: null
|
|
4737
|
+
};
|
|
4738
|
+
}
|
|
4739
|
+
if (!this.app?.request?.get) {
|
|
4740
|
+
this.logError(`${title}: app.request 不可用`);
|
|
4741
|
+
return {
|
|
4742
|
+
code: 500,
|
|
4743
|
+
message: 'app.request 不可用',
|
|
4744
|
+
order: null
|
|
4745
|
+
};
|
|
4746
|
+
}
|
|
4747
|
+
const backendPath = this.buildOrderSalesDetailBackendPath(String(lookup), data);
|
|
4748
|
+
try {
|
|
4749
|
+
const response = await this.app.request.get(backendPath, {
|
|
4750
|
+
lookup_mode: 'multi'
|
|
4751
|
+
}, {
|
|
4752
|
+
isShopApi: true,
|
|
4753
|
+
customToast: () => {}
|
|
4754
|
+
});
|
|
4755
|
+
if (this.isCheckoutResponseRejected(response)) {
|
|
4756
|
+
const responseStatusCode = typeof response?.status === 'number' ? response.status : undefined;
|
|
4757
|
+
const code = this.normalizeRemoteSalesOrderErrorCode(response?.code ?? responseStatusCode);
|
|
4758
|
+
const message = response?.message || '后端拒绝订单查询';
|
|
4759
|
+
this.logInfo(`${title}: 后端拒绝订单查询`, {
|
|
4760
|
+
lookup,
|
|
4761
|
+
backendPath,
|
|
4762
|
+
code,
|
|
4763
|
+
message
|
|
4764
|
+
});
|
|
4765
|
+
return {
|
|
4766
|
+
code,
|
|
4767
|
+
message,
|
|
4768
|
+
order: null
|
|
4769
|
+
};
|
|
4770
|
+
}
|
|
4771
|
+
const fresh = this.extractOrderDataFromCheckoutResponse(response);
|
|
4772
|
+
if (!fresh || fresh.order_id === undefined || fresh.order_id === null || String(fresh.order_id).trim() === '') {
|
|
4773
|
+
this.logInfo(`${title}: 后端返回订单为空`, {
|
|
4774
|
+
lookup,
|
|
4775
|
+
backendPath
|
|
4776
|
+
});
|
|
4777
|
+
return {
|
|
4778
|
+
code: 500,
|
|
4779
|
+
message: '后端返回订单为空',
|
|
4780
|
+
order: null
|
|
4781
|
+
};
|
|
4782
|
+
}
|
|
4783
|
+
await this.order.upsertOrdersFromRemote([fresh]);
|
|
4784
|
+
let savedOrder = await this.order.getLocalOrderByLookup(lookup);
|
|
4785
|
+
if (!savedOrder && fresh.order_id !== undefined && fresh.order_id !== null && String(fresh.order_id) !== String(lookup)) {
|
|
4786
|
+
savedOrder = await this.order.getLocalOrderByLookup(fresh.order_id);
|
|
4787
|
+
}
|
|
4788
|
+
if (!savedOrder) {
|
|
4789
|
+
this.logError(`${title}: 订单写入后回读失败`, {
|
|
4790
|
+
lookup,
|
|
4791
|
+
remote_order_id: fresh.order_id
|
|
4792
|
+
});
|
|
4793
|
+
return {
|
|
4794
|
+
code: 500,
|
|
4795
|
+
message: '订单写入后回读失败',
|
|
4796
|
+
order: null
|
|
4797
|
+
};
|
|
4798
|
+
}
|
|
4799
|
+
this.logInfo(`${title}: 远端订单已同步到本地`, {
|
|
4800
|
+
lookup,
|
|
4801
|
+
remote_order_id: fresh.order_id
|
|
4802
|
+
});
|
|
4803
|
+
return {
|
|
4804
|
+
code: 200,
|
|
4805
|
+
message: '',
|
|
4806
|
+
order: savedOrder
|
|
4807
|
+
};
|
|
4808
|
+
} catch (error) {
|
|
4809
|
+
const backendError = this.extractBackendErrorResponse(error);
|
|
4810
|
+
const errorRecord = error;
|
|
4811
|
+
const responseStatusCode = typeof errorRecord?.response?.status === 'number' ? errorRecord.response.status : undefined;
|
|
4812
|
+
if (backendError || responseStatusCode !== undefined) {
|
|
4813
|
+
const backendStatusCode = typeof backendError?.status === 'number' ? backendError.status : undefined;
|
|
4814
|
+
const code = this.normalizeRemoteSalesOrderErrorCode(backendError?.code ?? backendStatusCode ?? responseStatusCode);
|
|
4815
|
+
const message = backendError?.message || this.getUnknownErrorMessage(error);
|
|
4816
|
+
this.logInfo(`${title}: 后端订单查询失败`, {
|
|
4817
|
+
lookup,
|
|
4818
|
+
backendPath,
|
|
4819
|
+
code,
|
|
4820
|
+
message
|
|
4821
|
+
});
|
|
4822
|
+
return {
|
|
4823
|
+
code,
|
|
4824
|
+
message,
|
|
4825
|
+
order: null
|
|
4826
|
+
};
|
|
4827
|
+
}
|
|
4828
|
+
const message = this.getUnknownErrorMessage(error);
|
|
4829
|
+
this.logInfo(`${title}: 请求失败`, {
|
|
4830
|
+
lookup,
|
|
4831
|
+
backendPath,
|
|
4832
|
+
error: message
|
|
4833
|
+
});
|
|
4834
|
+
return {
|
|
4835
|
+
code: 500,
|
|
4836
|
+
message,
|
|
4837
|
+
order: null
|
|
4838
|
+
};
|
|
4839
|
+
}
|
|
4840
|
+
}
|
|
4491
4841
|
handleOrderSalesDetail = async ({
|
|
4492
4842
|
url,
|
|
4493
4843
|
data,
|
|
@@ -4536,73 +4886,22 @@ class Server {
|
|
|
4536
4886
|
};
|
|
4537
4887
|
}
|
|
4538
4888
|
}
|
|
4539
|
-
|
|
4540
|
-
|
|
4889
|
+
const remoteResult = await this.fetchAndPersistSalesOrderByLookup(lookup, data, 'handleOrderSalesDetail');
|
|
4890
|
+
if (!remoteResult.order) {
|
|
4541
4891
|
return {
|
|
4542
|
-
code:
|
|
4892
|
+
code: remoteResult.code,
|
|
4543
4893
|
status: false,
|
|
4544
|
-
message:
|
|
4545
|
-
data: null
|
|
4546
|
-
};
|
|
4547
|
-
}
|
|
4548
|
-
const backendPath = this.buildOrderSalesDetailBackendPath(lookup, data);
|
|
4549
|
-
try {
|
|
4550
|
-
const response = await this.app.request.get(backendPath, {
|
|
4551
|
-
lookup_mode: 'multi'
|
|
4552
|
-
}, {
|
|
4553
|
-
isShopApi: true,
|
|
4554
|
-
customToast: () => {}
|
|
4555
|
-
});
|
|
4556
|
-
const fresh = response?.data ?? response;
|
|
4557
|
-
if (!fresh || typeof fresh !== 'object' || fresh.order_id == null) {
|
|
4558
|
-
this.logInfo('handleOrderSalesDetail: 后端返回订单为空', {
|
|
4559
|
-
lookup,
|
|
4560
|
-
backendPath
|
|
4561
|
-
});
|
|
4562
|
-
return {
|
|
4563
|
-
code: 500,
|
|
4564
|
-
status: false,
|
|
4565
|
-
message: '后端返回订单为空',
|
|
4566
|
-
data: null
|
|
4567
|
-
};
|
|
4568
|
-
}
|
|
4569
|
-
await this.order.upsertOrdersFromRemote([fresh]);
|
|
4570
|
-
const savedOrder = await this.order.getLocalOrderByLookup(lookup);
|
|
4571
|
-
if (!savedOrder) {
|
|
4572
|
-
this.logError('handleOrderSalesDetail: 订单写入后回读失败', {
|
|
4573
|
-
lookup
|
|
4574
|
-
});
|
|
4575
|
-
return {
|
|
4576
|
-
code: 500,
|
|
4577
|
-
status: false,
|
|
4578
|
-
message: '订单写入后回读失败',
|
|
4579
|
-
data: null
|
|
4580
|
-
};
|
|
4581
|
-
}
|
|
4582
|
-
this.logInfo('handleOrderSalesDetail: 远端订单已同步到本地', {
|
|
4583
|
-
lookup
|
|
4584
|
-
});
|
|
4585
|
-
const enrichedOrder = await this.withSalesDetailProductSnapshots(savedOrder);
|
|
4586
|
-
return {
|
|
4587
|
-
code: 200,
|
|
4588
|
-
status: true,
|
|
4589
|
-
message: '',
|
|
4590
|
-
data: enrichedOrder
|
|
4591
|
-
};
|
|
4592
|
-
} catch (error) {
|
|
4593
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
4594
|
-
this.logInfo('handleOrderSalesDetail: 请求失败', {
|
|
4595
|
-
lookup,
|
|
4596
|
-
backendPath,
|
|
4597
|
-
error: errorMessage
|
|
4598
|
-
});
|
|
4599
|
-
return {
|
|
4600
|
-
code: 500,
|
|
4601
|
-
status: false,
|
|
4602
|
-
message: errorMessage,
|
|
4894
|
+
message: remoteResult.message,
|
|
4603
4895
|
data: null
|
|
4604
4896
|
};
|
|
4605
4897
|
}
|
|
4898
|
+
const enrichedOrder = await this.withSalesDetailProductSnapshots(remoteResult.order);
|
|
4899
|
+
return {
|
|
4900
|
+
code: 200,
|
|
4901
|
+
status: true,
|
|
4902
|
+
message: '',
|
|
4903
|
+
data: enrichedOrder
|
|
4904
|
+
};
|
|
4606
4905
|
};
|
|
4607
4906
|
|
|
4608
4907
|
/**
|