@pisell/pisellos 0.10.16 → 0.10.17
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/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 +852 -484
- 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 +399 -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,18 @@ 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
|
+
invoice: this.normalizePrintInvoiceLayoutConfig(params.invoiceLayoutConfig),
|
|
3689
|
+
template_settings: this.normalizePrintInvoiceTemplateSettings(params.invoiceTemplateSettings),
|
|
3513
3690
|
skip_wristband: true,
|
|
3514
3691
|
skip_voucher: true
|
|
3515
3692
|
} : {
|
|
3516
3693
|
order_id: printIdentity,
|
|
3517
3694
|
machine_code_print_info: params.syncedOrder?.payment_info?.machine_code_print_info,
|
|
3518
3695
|
machine_code_print_info_v2: params.syncedOrder?.machine_code_print_info_v2,
|
|
3696
|
+
...(params.invoiceLayoutConfig ? {
|
|
3697
|
+
invoice: this.normalizePrintInvoiceLayoutConfig(params.invoiceLayoutConfig)
|
|
3698
|
+
} : {}),
|
|
3699
|
+
template_settings: this.normalizePrintInvoiceTemplateSettings(params.invoiceTemplateSettings),
|
|
3519
3700
|
skip_receipt: true
|
|
3520
3701
|
}
|
|
3521
3702
|
},
|
|
@@ -3567,7 +3748,9 @@ class Server {
|
|
|
3567
3748
|
syncedOrder: printableOrder,
|
|
3568
3749
|
response: params.response,
|
|
3569
3750
|
receiptOnly: true,
|
|
3570
|
-
isManualPrint: params.isManualPrint
|
|
3751
|
+
isManualPrint: params.isManualPrint,
|
|
3752
|
+
invoiceLayoutConfig: params.invoiceLayoutConfig,
|
|
3753
|
+
invoiceTemplateSettings: params.invoiceTemplateSettings
|
|
3571
3754
|
});
|
|
3572
3755
|
return {
|
|
3573
3756
|
printed: true,
|
|
@@ -3587,11 +3770,35 @@ class Server {
|
|
|
3587
3770
|
}
|
|
3588
3771
|
return undefined;
|
|
3589
3772
|
}
|
|
3773
|
+
mergeLocalPrintOrderInput(localOrder, inputOrder) {
|
|
3774
|
+
const definedInput = Object.fromEntries(Object.entries(inputOrder || {}).filter(([, value]) => value !== undefined));
|
|
3775
|
+
return {
|
|
3776
|
+
...localOrder,
|
|
3777
|
+
...definedInput,
|
|
3778
|
+
order_id: localOrder.order_id ?? definedInput.order_id ?? definedInput.orderId,
|
|
3779
|
+
external_sale_number: localOrder.external_sale_number ?? definedInput.external_sale_number ?? definedInput.externalSaleNumber
|
|
3780
|
+
};
|
|
3781
|
+
}
|
|
3590
3782
|
handleLocalPrintOrder = async ({
|
|
3591
3783
|
data
|
|
3592
3784
|
}) => {
|
|
3593
3785
|
try {
|
|
3594
|
-
const
|
|
3786
|
+
const extractedRequest = this.extractInvoiceLayoutConfig(data, {
|
|
3787
|
+
includePublicInvoice: true
|
|
3788
|
+
});
|
|
3789
|
+
const extractedRequestTemplateSettings = this.extractInvoiceTemplateSettings(extractedRequest.data, {
|
|
3790
|
+
includePublicTemplateSettings: true
|
|
3791
|
+
});
|
|
3792
|
+
const requestOrder = extractedRequestTemplateSettings.data?.order;
|
|
3793
|
+
const nestedOrder = requestOrder && typeof requestOrder === 'object' ? this.extractInvoiceLayoutConfig(requestOrder, {
|
|
3794
|
+
includePublicInvoice: true
|
|
3795
|
+
}) : null;
|
|
3796
|
+
const nestedOrderTemplateSettings = nestedOrder ? this.extractInvoiceTemplateSettings(nestedOrder.data, {
|
|
3797
|
+
includePublicTemplateSettings: true
|
|
3798
|
+
}) : null;
|
|
3799
|
+
const inputOrder = nestedOrderTemplateSettings?.data ?? extractedRequestTemplateSettings.data;
|
|
3800
|
+
const invoiceLayoutConfig = extractedRequest.invoiceLayoutConfig ?? nestedOrder?.invoiceLayoutConfig;
|
|
3801
|
+
const invoiceTemplateSettings = this.normalizePrintInvoiceTemplateSettings(extractedRequestTemplateSettings.invoiceTemplateSettings ?? nestedOrderTemplateSettings?.invoiceTemplateSettings);
|
|
3595
3802
|
if (!inputOrder || typeof inputOrder !== 'object') {
|
|
3596
3803
|
return {
|
|
3597
3804
|
code: 400,
|
|
@@ -3603,13 +3810,13 @@ class Server {
|
|
|
3603
3810
|
}
|
|
3604
3811
|
};
|
|
3605
3812
|
}
|
|
3606
|
-
const shouldLookup = this.shouldLookupLocalPrintOrder(inputOrder) || this.shouldLookupLocalPrintOrder(data);
|
|
3813
|
+
const shouldLookup = this.shouldLookupLocalPrintOrder(inputOrder) || this.shouldLookupLocalPrintOrder(extractedRequest.data);
|
|
3607
3814
|
this.logInfo('handleLocalPrintOrder: 是否需要查找本地订单', {
|
|
3608
3815
|
shouldLookup,
|
|
3609
3816
|
inputOrder,
|
|
3610
3817
|
data
|
|
3611
3818
|
});
|
|
3612
|
-
const lookup = shouldLookup ? this.getLocalPrintOrderLookup(inputOrder) ?? this.getLocalPrintOrderLookup(data) : undefined;
|
|
3819
|
+
const lookup = shouldLookup ? this.getLocalPrintOrderLookup(inputOrder) ?? this.getLocalPrintOrderLookup(extractedRequest.data) : undefined;
|
|
3613
3820
|
let sourceOrder = inputOrder;
|
|
3614
3821
|
if (shouldLookup) {
|
|
3615
3822
|
if (lookup === undefined) {
|
|
@@ -3634,24 +3841,25 @@ class Server {
|
|
|
3634
3841
|
}
|
|
3635
3842
|
};
|
|
3636
3843
|
}
|
|
3637
|
-
|
|
3844
|
+
let localOrder = await this.order.getLocalOrderByLookup(lookup);
|
|
3638
3845
|
if (!localOrder) {
|
|
3639
|
-
|
|
3640
|
-
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3846
|
+
const remoteResult = await this.fetchAndPersistSalesOrderByLookup(lookup, {
|
|
3847
|
+
with: ['all']
|
|
3848
|
+
}, 'handleLocalPrintOrder');
|
|
3849
|
+
if (!remoteResult.order) {
|
|
3850
|
+
return {
|
|
3851
|
+
code: remoteResult.code,
|
|
3852
|
+
status: false,
|
|
3853
|
+
message: remoteResult.message,
|
|
3854
|
+
data: {
|
|
3855
|
+
printed: false,
|
|
3856
|
+
order: null
|
|
3857
|
+
}
|
|
3858
|
+
};
|
|
3859
|
+
}
|
|
3860
|
+
localOrder = remoteResult.order;
|
|
3648
3861
|
}
|
|
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
|
-
};
|
|
3862
|
+
sourceOrder = this.mergeLocalPrintOrderInput(localOrder, inputOrder);
|
|
3655
3863
|
}
|
|
3656
3864
|
const checkoutData = await this.ensureCheckoutOrderNumbers({
|
|
3657
3865
|
...sourceOrder,
|
|
@@ -3670,7 +3878,9 @@ class Server {
|
|
|
3670
3878
|
order: printableOrder,
|
|
3671
3879
|
response: null,
|
|
3672
3880
|
requireFullyPaid: false,
|
|
3673
|
-
isManualPrint: true
|
|
3881
|
+
isManualPrint: true,
|
|
3882
|
+
invoiceLayoutConfig,
|
|
3883
|
+
invoiceTemplateSettings
|
|
3674
3884
|
});
|
|
3675
3885
|
return {
|
|
3676
3886
|
code: 200,
|
|
@@ -3881,9 +4091,17 @@ class Server {
|
|
|
3881
4091
|
async handleOrderCheckoutSubmit(params) {
|
|
3882
4092
|
const {
|
|
3883
4093
|
backendPath,
|
|
3884
|
-
data,
|
|
3885
4094
|
title
|
|
3886
4095
|
} = params;
|
|
4096
|
+
const extractedInvoice = this.extractInvoiceLayoutConfig(params.data, {
|
|
4097
|
+
includePublicInvoice: true
|
|
4098
|
+
});
|
|
4099
|
+
const extractedTemplateSettings = this.extractInvoiceTemplateSettings(extractedInvoice.data, {
|
|
4100
|
+
includePublicTemplateSettings: true
|
|
4101
|
+
});
|
|
4102
|
+
const data = extractedTemplateSettings.data;
|
|
4103
|
+
const invoiceLayoutConfig = extractedInvoice.invoiceLayoutConfig;
|
|
4104
|
+
const invoiceTemplateSettings = this.normalizePrintInvoiceTemplateSettings(extractedTemplateSettings.invoiceTemplateSettings);
|
|
3887
4105
|
this.logInfo(`${title}: 开始处理`, {
|
|
3888
4106
|
backendPath,
|
|
3889
4107
|
order_id: data?.order_id,
|
|
@@ -3894,11 +4112,14 @@ class Server {
|
|
|
3894
4112
|
return this.handleSyncCheckoutSubmit({
|
|
3895
4113
|
backendPath,
|
|
3896
4114
|
data,
|
|
3897
|
-
title
|
|
4115
|
+
title,
|
|
4116
|
+
invoiceLayoutConfig,
|
|
4117
|
+
invoiceTemplateSettings
|
|
3898
4118
|
});
|
|
3899
4119
|
}
|
|
3900
4120
|
const normalizedData = await this.normalizeCheckoutSubmitData(data, title);
|
|
3901
|
-
const
|
|
4121
|
+
const numberedData = await this.ensureCheckoutOrderNumbers(normalizedData, title);
|
|
4122
|
+
const checkoutData = this.applyCheckoutFulfillmentBuzzer(numberedData, title);
|
|
3902
4123
|
const pendingResult = await this.handlePendingSyncCheckoutOrder({
|
|
3903
4124
|
backendPath,
|
|
3904
4125
|
data: checkoutData,
|
|
@@ -3912,13 +4133,17 @@ class Server {
|
|
|
3912
4133
|
checkoutData,
|
|
3913
4134
|
order: pendingOrder,
|
|
3914
4135
|
response: pendingResult,
|
|
3915
|
-
requireFullyPaid: true
|
|
4136
|
+
requireFullyPaid: true,
|
|
4137
|
+
invoiceLayoutConfig,
|
|
4138
|
+
invoiceTemplateSettings
|
|
3916
4139
|
});
|
|
3917
4140
|
}
|
|
3918
4141
|
await this.dispatchCheckoutSyncTask({
|
|
3919
4142
|
backendPath,
|
|
3920
4143
|
data: checkoutData,
|
|
3921
|
-
title
|
|
4144
|
+
title,
|
|
4145
|
+
invoiceLayoutConfig,
|
|
4146
|
+
invoiceTemplateSettings
|
|
3922
4147
|
});
|
|
3923
4148
|
}
|
|
3924
4149
|
if (!pendingResult.data.order_id) {
|
|
@@ -3936,7 +4161,9 @@ class Server {
|
|
|
3936
4161
|
const {
|
|
3937
4162
|
backendPath,
|
|
3938
4163
|
data,
|
|
3939
|
-
title
|
|
4164
|
+
title,
|
|
4165
|
+
invoiceLayoutConfig,
|
|
4166
|
+
invoiceTemplateSettings
|
|
3940
4167
|
} = params;
|
|
3941
4168
|
if (!this.app?.request?.post) {
|
|
3942
4169
|
this.logError(`${title}: sync checkout app.request 不可用`);
|
|
@@ -3952,7 +4179,9 @@ class Server {
|
|
|
3952
4179
|
backendPath,
|
|
3953
4180
|
data,
|
|
3954
4181
|
title,
|
|
3955
|
-
persistCheckoutDataWithResponse: true
|
|
4182
|
+
persistCheckoutDataWithResponse: true,
|
|
4183
|
+
invoiceLayoutConfig,
|
|
4184
|
+
invoiceTemplateSettings
|
|
3956
4185
|
});
|
|
3957
4186
|
if (syncResult.rejected) {
|
|
3958
4187
|
const normalized = this.normalizeCheckoutResponse(syncResult.errorResponse);
|
|
@@ -3970,7 +4199,9 @@ class Server {
|
|
|
3970
4199
|
checkoutData: syncResult.checkoutData,
|
|
3971
4200
|
order: syncedOrder,
|
|
3972
4201
|
response: syncResult.normalizedResponse,
|
|
3973
|
-
requireFullyPaid: true
|
|
4202
|
+
requireFullyPaid: true,
|
|
4203
|
+
invoiceLayoutConfig,
|
|
4204
|
+
invoiceTemplateSettings
|
|
3974
4205
|
// print_all 的 type=0 是收据打印;不要沿用同步成功后的券/手环打印 type=99。
|
|
3975
4206
|
});
|
|
3976
4207
|
}
|
|
@@ -4002,9 +4233,16 @@ class Server {
|
|
|
4002
4233
|
}
|
|
4003
4234
|
async handleOrderDraftSubmit(params) {
|
|
4004
4235
|
const {
|
|
4005
|
-
data,
|
|
4006
4236
|
title
|
|
4007
4237
|
} = params;
|
|
4238
|
+
const extractedInvoice = this.extractInvoiceLayoutConfig(params.data, {
|
|
4239
|
+
includePublicInvoice: true
|
|
4240
|
+
});
|
|
4241
|
+
const {
|
|
4242
|
+
data
|
|
4243
|
+
} = this.extractInvoiceTemplateSettings(extractedInvoice.data, {
|
|
4244
|
+
includePublicTemplateSettings: true
|
|
4245
|
+
});
|
|
4008
4246
|
this.logInfo(`${title}: 开始处理`, {
|
|
4009
4247
|
order_id: data?.order_id,
|
|
4010
4248
|
external_sale_number: data?.external_sale_number,
|
|
@@ -4488,6 +4726,122 @@ class Server {
|
|
|
4488
4726
|
return order;
|
|
4489
4727
|
}
|
|
4490
4728
|
}
|
|
4729
|
+
normalizeRemoteSalesOrderErrorCode(value) {
|
|
4730
|
+
if (value === undefined || value === null || value === '') return 500;
|
|
4731
|
+
const code = typeof value === 'number' ? value : Number(value);
|
|
4732
|
+
return Number.isFinite(code) ? code : 500;
|
|
4733
|
+
}
|
|
4734
|
+
async fetchAndPersistSalesOrderByLookup(lookup, data, title) {
|
|
4735
|
+
if (!this.order?.getLocalOrderByLookup || !this.order?.upsertOrdersFromRemote) {
|
|
4736
|
+
this.logError(`${title}: Order 模块未注册`);
|
|
4737
|
+
return {
|
|
4738
|
+
code: 500,
|
|
4739
|
+
message: 'Order 模块未注册',
|
|
4740
|
+
order: null
|
|
4741
|
+
};
|
|
4742
|
+
}
|
|
4743
|
+
if (!this.app?.request?.get) {
|
|
4744
|
+
this.logError(`${title}: app.request 不可用`);
|
|
4745
|
+
return {
|
|
4746
|
+
code: 500,
|
|
4747
|
+
message: 'app.request 不可用',
|
|
4748
|
+
order: null
|
|
4749
|
+
};
|
|
4750
|
+
}
|
|
4751
|
+
const backendPath = this.buildOrderSalesDetailBackendPath(String(lookup), data);
|
|
4752
|
+
try {
|
|
4753
|
+
const response = await this.app.request.get(backendPath, {
|
|
4754
|
+
lookup_mode: 'multi'
|
|
4755
|
+
}, {
|
|
4756
|
+
isShopApi: true,
|
|
4757
|
+
customToast: () => {}
|
|
4758
|
+
});
|
|
4759
|
+
if (this.isCheckoutResponseRejected(response)) {
|
|
4760
|
+
const responseStatusCode = typeof response?.status === 'number' ? response.status : undefined;
|
|
4761
|
+
const code = this.normalizeRemoteSalesOrderErrorCode(response?.code ?? responseStatusCode);
|
|
4762
|
+
const message = response?.message || '后端拒绝订单查询';
|
|
4763
|
+
this.logInfo(`${title}: 后端拒绝订单查询`, {
|
|
4764
|
+
lookup,
|
|
4765
|
+
backendPath,
|
|
4766
|
+
code,
|
|
4767
|
+
message
|
|
4768
|
+
});
|
|
4769
|
+
return {
|
|
4770
|
+
code,
|
|
4771
|
+
message,
|
|
4772
|
+
order: null
|
|
4773
|
+
};
|
|
4774
|
+
}
|
|
4775
|
+
const fresh = this.extractOrderDataFromCheckoutResponse(response);
|
|
4776
|
+
if (!fresh || fresh.order_id === undefined || fresh.order_id === null || String(fresh.order_id).trim() === '') {
|
|
4777
|
+
this.logInfo(`${title}: 后端返回订单为空`, {
|
|
4778
|
+
lookup,
|
|
4779
|
+
backendPath
|
|
4780
|
+
});
|
|
4781
|
+
return {
|
|
4782
|
+
code: 500,
|
|
4783
|
+
message: '后端返回订单为空',
|
|
4784
|
+
order: null
|
|
4785
|
+
};
|
|
4786
|
+
}
|
|
4787
|
+
await this.order.upsertOrdersFromRemote([fresh]);
|
|
4788
|
+
let savedOrder = await this.order.getLocalOrderByLookup(lookup);
|
|
4789
|
+
if (!savedOrder && fresh.order_id !== undefined && fresh.order_id !== null && String(fresh.order_id) !== String(lookup)) {
|
|
4790
|
+
savedOrder = await this.order.getLocalOrderByLookup(fresh.order_id);
|
|
4791
|
+
}
|
|
4792
|
+
if (!savedOrder) {
|
|
4793
|
+
this.logError(`${title}: 订单写入后回读失败`, {
|
|
4794
|
+
lookup,
|
|
4795
|
+
remote_order_id: fresh.order_id
|
|
4796
|
+
});
|
|
4797
|
+
return {
|
|
4798
|
+
code: 500,
|
|
4799
|
+
message: '订单写入后回读失败',
|
|
4800
|
+
order: null
|
|
4801
|
+
};
|
|
4802
|
+
}
|
|
4803
|
+
this.logInfo(`${title}: 远端订单已同步到本地`, {
|
|
4804
|
+
lookup,
|
|
4805
|
+
remote_order_id: fresh.order_id
|
|
4806
|
+
});
|
|
4807
|
+
return {
|
|
4808
|
+
code: 200,
|
|
4809
|
+
message: '',
|
|
4810
|
+
order: savedOrder
|
|
4811
|
+
};
|
|
4812
|
+
} catch (error) {
|
|
4813
|
+
const backendError = this.extractBackendErrorResponse(error);
|
|
4814
|
+
const errorRecord = error;
|
|
4815
|
+
const responseStatusCode = typeof errorRecord?.response?.status === 'number' ? errorRecord.response.status : undefined;
|
|
4816
|
+
if (backendError || responseStatusCode !== undefined) {
|
|
4817
|
+
const backendStatusCode = typeof backendError?.status === 'number' ? backendError.status : undefined;
|
|
4818
|
+
const code = this.normalizeRemoteSalesOrderErrorCode(backendError?.code ?? backendStatusCode ?? responseStatusCode);
|
|
4819
|
+
const message = backendError?.message || this.getUnknownErrorMessage(error);
|
|
4820
|
+
this.logInfo(`${title}: 后端订单查询失败`, {
|
|
4821
|
+
lookup,
|
|
4822
|
+
backendPath,
|
|
4823
|
+
code,
|
|
4824
|
+
message
|
|
4825
|
+
});
|
|
4826
|
+
return {
|
|
4827
|
+
code,
|
|
4828
|
+
message,
|
|
4829
|
+
order: null
|
|
4830
|
+
};
|
|
4831
|
+
}
|
|
4832
|
+
const message = this.getUnknownErrorMessage(error);
|
|
4833
|
+
this.logInfo(`${title}: 请求失败`, {
|
|
4834
|
+
lookup,
|
|
4835
|
+
backendPath,
|
|
4836
|
+
error: message
|
|
4837
|
+
});
|
|
4838
|
+
return {
|
|
4839
|
+
code: 500,
|
|
4840
|
+
message,
|
|
4841
|
+
order: null
|
|
4842
|
+
};
|
|
4843
|
+
}
|
|
4844
|
+
}
|
|
4491
4845
|
handleOrderSalesDetail = async ({
|
|
4492
4846
|
url,
|
|
4493
4847
|
data,
|
|
@@ -4536,73 +4890,22 @@ class Server {
|
|
|
4536
4890
|
};
|
|
4537
4891
|
}
|
|
4538
4892
|
}
|
|
4539
|
-
|
|
4540
|
-
|
|
4893
|
+
const remoteResult = await this.fetchAndPersistSalesOrderByLookup(lookup, data, 'handleOrderSalesDetail');
|
|
4894
|
+
if (!remoteResult.order) {
|
|
4541
4895
|
return {
|
|
4542
|
-
code:
|
|
4896
|
+
code: remoteResult.code,
|
|
4543
4897
|
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,
|
|
4898
|
+
message: remoteResult.message,
|
|
4603
4899
|
data: null
|
|
4604
4900
|
};
|
|
4605
4901
|
}
|
|
4902
|
+
const enrichedOrder = await this.withSalesDetailProductSnapshots(remoteResult.order);
|
|
4903
|
+
return {
|
|
4904
|
+
code: 200,
|
|
4905
|
+
status: true,
|
|
4906
|
+
message: '',
|
|
4907
|
+
data: enrichedOrder
|
|
4908
|
+
};
|
|
4606
4909
|
};
|
|
4607
4910
|
|
|
4608
4911
|
/**
|