@pisell/pisellos 2.3.163 → 2.3.165

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.
Files changed (81) hide show
  1. package/dist/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.d.ts +3 -1
  2. package/dist/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +28 -4
  3. package/dist/modules/Holder/utils.d.ts +2 -0
  4. package/dist/modules/Holder/utils.js +32 -2
  5. package/dist/modules/OpenData/contactInfo.d.ts +20 -0
  6. package/dist/modules/OpenData/contactInfo.js +70 -0
  7. package/dist/modules/OpenData/index.d.ts +1 -0
  8. package/dist/modules/OpenData/index.js +1 -0
  9. package/dist/modules/OpenData/types.d.ts +9 -0
  10. package/dist/modules/Order/holderRelations.d.ts +14 -0
  11. package/dist/modules/Order/holderRelations.js +154 -0
  12. package/dist/modules/Order/index.d.ts +2 -2
  13. package/dist/modules/Order/index.js +89 -44
  14. package/dist/modules/Order/types.d.ts +19 -1
  15. package/dist/modules/Order/types.js +2 -0
  16. package/dist/modules/Order/utils/discountProductLineIdentity.d.ts +1 -1
  17. package/dist/modules/Order/utils/discountProductLineIdentity.js +142 -7
  18. package/dist/modules/Order/utils/orderCollectionIdentity.js +24 -10
  19. package/dist/modules/Order/utils.d.ts +1 -1
  20. package/dist/modules/Order/utils.js +35 -9
  21. package/dist/modules/Rules/index.js +62 -61
  22. package/dist/server/index.js +18 -12
  23. package/dist/server/modules/order/index.d.ts +4 -0
  24. package/dist/server/modules/order/index.js +255 -190
  25. package/dist/server/modules/order/types.d.ts +3 -0
  26. package/dist/server/modules/products/index.js +3 -2
  27. package/dist/shared/receipt/small-ticket.js +24 -12
  28. package/dist/shared/receipt/templateVisibility.d.ts +3 -0
  29. package/dist/shared/receipt/templateVisibility.js +6 -2
  30. package/dist/shared/sales/loadSalesOrderSnapshot.js +1 -1
  31. package/dist/solution/BaseSales/index.d.ts +4 -0
  32. package/dist/solution/BaseSales/index.js +1116 -935
  33. package/dist/solution/BaseSales/types.d.ts +2 -1
  34. package/dist/solution/BaseSales/utils/parseSalesResponse.d.ts +3 -1
  35. package/dist/solution/BaseSales/utils/parseSalesResponse.js +7 -3
  36. package/dist/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +14 -4
  37. package/dist/solution/BookingByStep/index.d.ts +1 -1
  38. package/dist/solution/BookingTicket/index.d.ts +15 -1
  39. package/dist/solution/BookingTicket/index.js +784 -501
  40. package/dist/solution/UnifiedBookingSales/index.js +1 -1
  41. package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.d.ts +3 -1
  42. package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +17 -1
  43. package/lib/modules/Holder/utils.d.ts +2 -0
  44. package/lib/modules/Holder/utils.js +27 -1
  45. package/lib/modules/OpenData/contactInfo.d.ts +20 -0
  46. package/lib/modules/OpenData/contactInfo.js +56 -0
  47. package/lib/modules/OpenData/index.d.ts +1 -0
  48. package/lib/modules/OpenData/index.js +12 -0
  49. package/lib/modules/OpenData/types.d.ts +9 -0
  50. package/lib/modules/Order/holderRelations.d.ts +14 -0
  51. package/lib/modules/Order/holderRelations.js +98 -0
  52. package/lib/modules/Order/index.d.ts +2 -2
  53. package/lib/modules/Order/index.js +44 -12
  54. package/lib/modules/Order/types.d.ts +19 -1
  55. package/lib/modules/Order/types.js +1 -0
  56. package/lib/modules/Order/utils/discountProductLineIdentity.d.ts +1 -1
  57. package/lib/modules/Order/utils/discountProductLineIdentity.js +51 -2
  58. package/lib/modules/Order/utils/orderCollectionIdentity.js +5 -0
  59. package/lib/modules/Order/utils.d.ts +1 -1
  60. package/lib/modules/Order/utils.js +27 -6
  61. package/lib/modules/Rules/index.js +2 -1
  62. package/lib/server/index.js +6 -0
  63. package/lib/server/modules/order/index.d.ts +4 -0
  64. package/lib/server/modules/order/index.js +46 -4
  65. package/lib/server/modules/order/types.d.ts +3 -0
  66. package/lib/server/modules/products/index.js +2 -1
  67. package/lib/shared/receipt/small-ticket.js +22 -13
  68. package/lib/shared/receipt/templateVisibility.d.ts +3 -0
  69. package/lib/shared/receipt/templateVisibility.js +6 -2
  70. package/lib/shared/sales/loadSalesOrderSnapshot.js +1 -1
  71. package/lib/solution/BaseSales/index.d.ts +4 -0
  72. package/lib/solution/BaseSales/index.js +68 -2
  73. package/lib/solution/BaseSales/types.d.ts +2 -1
  74. package/lib/solution/BaseSales/utils/parseSalesResponse.d.ts +3 -1
  75. package/lib/solution/BaseSales/utils/parseSalesResponse.js +4 -0
  76. package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +16 -8
  77. package/lib/solution/BookingByStep/index.d.ts +1 -1
  78. package/lib/solution/BookingTicket/index.d.ts +15 -1
  79. package/lib/solution/BookingTicket/index.js +132 -3
  80. package/lib/solution/UnifiedBookingSales/index.js +1 -1
  81. package/package.json +1 -1
@@ -2421,7 +2421,7 @@ export var UnifiedBookingSalesImpl = /*#__PURE__*/function (_BookingTicket) {
2421
2421
  (_this$store$customer = this.store.customer) === null || _this$store$customer === void 0 || (_this$store$customer$ = _this$store$customer.setSelectedCustomer) === null || _this$store$customer$ === void 0 || _this$store$customer$.call(_this$store$customer, authenticatedCustomer);
2422
2422
  this.setOrderCustomer(authenticatedCustomer);
2423
2423
  _context10.next = 15;
2424
- return Promise.all([this.refreshDiscountConfigAfterOrderCustomerChange(authenticatedCustomerId), this.waitForOrderCustomerPromotionRefresh()]);
2424
+ return Promise.all([this.refreshDiscountConfigAfterOrderCustomerChange(authenticatedCustomerId), this.waitForOrderCustomerPromotionRefresh(), this.waitForOrderCustomerContactInfo()]);
2425
2425
  case 15:
2426
2426
  return _context10.abrupt("return", true);
2427
2427
  case 16:
@@ -1,8 +1,10 @@
1
- import type { OrderProduct } from '../../Order/types';
1
+ import type { OrderHolderRelation, OrderProduct } from '../../Order/types';
2
2
  export interface BuildNormalProductCacheItemFromOrderLineInput {
3
3
  /** tempOrder.products 中的一行(普通商品,无关联 booking) */
4
4
  product: OrderProduct;
5
5
  /** 商品 catalog / 详情,用于 variant / option / bundle 模板字段 */
6
6
  sourceProduct?: Record<string, any> | null;
7
+ /** 整单关系集合,按商品行 UID 回填。 */
8
+ holder_relations?: OrderHolderRelation[];
7
9
  }
8
10
  export declare function buildNormalProductCacheItemFromOrderLine(input: BuildNormalProductCacheItemFromOrderLineInput): Record<string, any>;
@@ -4,13 +4,16 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.buildNormalProductCacheItemFromOrderLine = buildNormalProductCacheItemFromOrderLine;
7
+ var _lodashEs = require("lodash-es");
8
+ var _holderRelations = require("../../Order/holderRelations");
7
9
  var _utils = require("../../Order/utils");
8
10
  var _entitlementPass = require("../../Discount/entitlementPass");
11
+ var _utils2 = require("../../Holder/utils");
9
12
  var _orderLineDisplay = require("./orderLineDisplay");
10
13
  /**
11
14
  * 从已加车的普通商品 order line 反查 SkuDetailModal edit 所需的 cacheItem。
12
15
  *
13
- * 与 `buildCacheItemFromOrderLine`(预约行 + booking)并列;不含 resource / duration / holder 等预约字段。
16
+ * 与 `buildCacheItemFromOrderLine`(预约行 + booking)并列;Holder 从订单关系回填,不生成预约字段。
14
17
  */
15
18
  /**
16
19
  * 解析 v2 主商品 source 价(不含 option、不含 bundle),供 SkuDetailModal / transform 使用。
@@ -84,6 +87,15 @@ function buildNormalProductCacheItemFromOrderLine(input) {
84
87
  const original = Number(product.original_price ?? selling);
85
88
  const uid = product.metadata?.unique_identification_number;
86
89
  const originExtend = product.metadata?.origin?._extend;
90
+ const holderRelations = (0, _lodashEs.cloneDeep)((0, _holderRelations.getProductHolderRelations)(input, product));
91
+ const formRelations = holderRelations.filter(relation => relation.holder_type === 'form');
92
+ const holderIds = formRelations.map(relation => relation.holder_id);
93
+ const holderNames = formRelations.map(relation => relation.metadata?.name).filter(name => typeof name === 'string' && name.length > 0);
94
+ const holder = formRelations.length > 0 ? {
95
+ ...(formRelations[0].metadata || {}),
96
+ form_record: holderIds,
97
+ name: holderNames.join(',')
98
+ } : null;
87
99
  const shouldPreserveEntitlementPriceOverride = hasEntitlementPassDiscount(product) && (originExtend?.priceOverride !== undefined || product.metadata?.price_override != null);
88
100
  const hasPriceOverride = originExtend?.priceOverride !== undefined || shouldPreserveEntitlementPriceOverride;
89
101
  const option = (0, _utils.getProductSkuOptions)(product);
@@ -115,6 +127,9 @@ function buildNormalProductCacheItemFromOrderLine(input) {
115
127
  skuValue: JSON.parse(JSON.stringify(skuValue)),
116
128
  _skuValue: JSON.parse(JSON.stringify(skuValue)),
117
129
  isNormalProduct: true,
130
+ holder_relations: holderRelations,
131
+ holder,
132
+ holder_id: holderIds,
118
133
  metadata: {
119
134
  product_add_schedule_time: product.metadata?.product_add_schedule_time
120
135
  },
@@ -134,6 +149,7 @@ function buildNormalProductCacheItemFromOrderLine(input) {
134
149
  }
135
150
  return {
136
151
  ...(sourceProduct || {}),
152
+ holder_config: (0, _utils2.resolveProductHolderConfig)(sourceProduct) ?? (0, _utils2.resolveProductHolderConfig)(product) ?? undefined,
137
153
  id: resolvedId,
138
154
  product_id: resolvedId,
139
155
  _id: uid,
@@ -1,5 +1,7 @@
1
1
  import { ProductData } from '../Product/types';
2
2
  import { IFormItemData, IHolderConfig } from './types';
3
+ /** 保留显式禁用配置;仅在新配置缺失时兼容商品旧 holder 定义。 */
4
+ export declare function resolveProductHolderConfig(product?: ProductData | Record<string, any> | null): Record<string, any> | null;
3
5
  export declare function getProductHolderConfig(product?: ProductData | Record<string, any> | null): IHolderConfig | null;
4
6
  export declare function getFormIdFromHolderConfig(config: IHolderConfig): number;
5
7
  export declare function normalizeFormId(formId: number | string): number;
@@ -8,9 +8,35 @@ exports.getFormIdFromHolderConfig = getFormIdFromHolderConfig;
8
8
  exports.getProductHolderConfig = getProductHolderConfig;
9
9
  exports.normalizeFormId = normalizeFormId;
10
10
  exports.resolveFormMetaFromHolderItem = resolveFormMetaFromHolderItem;
11
+ exports.resolveProductHolderConfig = resolveProductHolderConfig;
12
+ /** 保留显式禁用配置;仅在新配置缺失时兼容商品旧 holder 定义。 */
13
+ function resolveProductHolderConfig(product) {
14
+ if (!product || typeof product !== 'object') return null;
15
+ const source = product;
16
+ const configSources = [source.holder_config, source.metadata?.holder_config, source.origin?.holder_config, source.metadata?.origin?.holder_config, source._origin?.holder_config, source._extend?.holder_config, source._extend?.product?.holder_config, source._extend?.product?.origin?.holder_config, source._extend?.product?.metadata?.holder_config, source._extend?.product?.metadata?.origin?.holder_config, source._extend?.product?._origin?.holder_config, source._extend?.product?._extend?.holder_config];
17
+ const config = configSources.find(value => value !== null && typeof value === 'object');
18
+ if (config) return config;
19
+
20
+ // metadata.holder / _extend.holder 是选择结果,不能作为商品配置读取。
21
+ const legacySources = [source.holder, source.origin?.holder, source.metadata?.origin?.holder, source._origin?.holder, source._extend?.product?.holder, source._extend?.product?.origin?.holder, source._extend?.product?.metadata?.origin?.holder, source._extend?.product?._origin?.holder];
22
+ const legacy = legacySources.find(value => value && typeof value === 'object' && !Array.isArray(value) && typeof value.type === 'string');
23
+ if (!legacy) return null;
24
+ const formId = legacy.custom?.custom_id;
25
+ if (legacy.type === 'custom' && legacy.custom?.type === 'form' && (typeof formId === 'number' || typeof formId === 'string') && Number.isInteger(Number(formId)) && Number(formId) > 0) {
26
+ return {
27
+ status: 'enable',
28
+ required: 0,
29
+ resource_id: formId
30
+ };
31
+ }
32
+ return {
33
+ status: 'disable',
34
+ required: 0
35
+ };
36
+ }
11
37
  function getProductHolderConfig(product) {
12
38
  if (!product) return null;
13
- const config = product?.holder_config ?? product?.origin?.holder_config;
39
+ const config = resolveProductHolderConfig(product);
14
40
  if (config?.status && config?.status !== 'enable') return null;
15
41
  if (!config?.resource_id) return null;
16
42
  return config;
@@ -0,0 +1,20 @@
1
+ import type { OpenDataConfig } from './types';
2
+ export declare const CONTACT_INFO_FIELDS: readonly ["first_name", "last_name", "phone", "email"];
3
+ export type ContactInfoField = typeof CONTACT_INFO_FIELDS[number];
4
+ export interface ContactInfoConfig {
5
+ enabled: boolean;
6
+ fields: Record<ContactInfoField, {
7
+ visible: boolean;
8
+ required: boolean;
9
+ }>;
10
+ }
11
+ export declare function resolveContactInfoConfig(data?: OpenDataConfig | null): ContactInfoConfig;
12
+ export declare function getMissingContactInfoFields(config: ContactInfoConfig, value: unknown): ContactInfoField[];
13
+ export declare function isContactRecord(value: unknown): value is Record<string, any>;
14
+ /** Customer relations wrap the contact in value; sales orders store the object itself. */
15
+ export declare function extractCustomerContactInfo(customer: unknown): Record<string, any> | null;
16
+ export declare class ContactInfoRequiredError extends Error {
17
+ readonly fields: ContactInfoField[];
18
+ readonly code = "CONTACT_INFO_REQUIRED";
19
+ constructor(fields: ContactInfoField[]);
20
+ }
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.ContactInfoRequiredError = exports.CONTACT_INFO_FIELDS = void 0;
7
+ exports.extractCustomerContactInfo = extractCustomerContactInfo;
8
+ exports.getMissingContactInfoFields = getMissingContactInfoFields;
9
+ exports.isContactRecord = isContactRecord;
10
+ exports.resolveContactInfoConfig = resolveContactInfoConfig;
11
+ const CONTACT_INFO_FIELDS = exports.CONTACT_INFO_FIELDS = ['first_name', 'last_name', 'phone', 'email'];
12
+ function resolveContactInfoConfig(data) {
13
+ const enabled = data?.['sale.enable_contact_info'] === true;
14
+ const fields = CONTACT_INFO_FIELDS.reduce((result, field) => {
15
+ const visible = data?.[`sale.${field}.visible`] !== false;
16
+ result[field] = {
17
+ visible,
18
+ required: enabled && visible && data?.[`sale.${field}.required`] === true
19
+ };
20
+ return result;
21
+ }, {});
22
+ return {
23
+ enabled: enabled && CONTACT_INFO_FIELDS.some(field => fields[field].visible),
24
+ fields
25
+ };
26
+ }
27
+ function getMissingContactInfoFields(config, value) {
28
+ if (!config.enabled) return [];
29
+ const contact = isContactRecord(value) ? value : {};
30
+ return CONTACT_INFO_FIELDS.filter(field => {
31
+ if (!config.fields[field].visible || !config.fields[field].required) return false;
32
+ const fieldValue = field === 'phone' ? isContactRecord(contact.phone) ? contact.phone.phone : undefined : contact[field];
33
+ return typeof fieldValue !== 'string' || !fieldValue.trim();
34
+ });
35
+ }
36
+ function isContactRecord(value) {
37
+ return !!value && typeof value === 'object' && !Array.isArray(value);
38
+ }
39
+
40
+ /** Customer relations wrap the contact in value; sales orders store the object itself. */
41
+ function extractCustomerContactInfo(customer) {
42
+ if (!isContactRecord(customer)) return null;
43
+ const contact = customer.contacts_info;
44
+ if (!isContactRecord(contact)) return null;
45
+ const value = Object.prototype.hasOwnProperty.call(contact, 'value') ? contact.value : contact;
46
+ return isContactRecord(value) ? value : null;
47
+ }
48
+ class ContactInfoRequiredError extends Error {
49
+ code = 'CONTACT_INFO_REQUIRED';
50
+ constructor(fields) {
51
+ super(`Contact information is required: ${fields.join(', ')}`);
52
+ this.fields = fields;
53
+ this.name = 'ContactInfoRequiredError';
54
+ }
55
+ }
56
+ exports.ContactInfoRequiredError = ContactInfoRequiredError;
@@ -3,6 +3,7 @@ import { BaseModule } from '../BaseModule';
3
3
  import type { ScheduleModule } from '../Schedule';
4
4
  import type { OpenDataConfig, OpenDataFetchParams, OpenDataAvailabilityResult, InvoiceLayoutConfig, InvoiceTemplateSettings } from './types';
5
5
  export * from './types';
6
+ export * from './contactInfo';
6
7
  export { computeAvailability, getDefaultInvoiceLayoutConfig, getDefaultInvoiceTemplateSettings, normalizeInvoiceLayoutConfig, normalizeInvoiceLayoutFromTemplateSettings, normalizeInvoiceTemplateSettings, normalizeRawInvoiceTemplateSettings, resolveInvoiceReceiptLocales, } from './utils';
7
8
  export declare class OpenDataModule extends BaseModule implements Module {
8
9
  protected defaultName: string;
@@ -77,6 +77,18 @@ Object.keys(_types).forEach(function (key) {
77
77
  }
78
78
  });
79
79
  });
80
+ var _contactInfo = require("./contactInfo");
81
+ Object.keys(_contactInfo).forEach(function (key) {
82
+ if (key === "default" || key === "__esModule") return;
83
+ if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
84
+ if (key in exports && exports[key] === _contactInfo[key]) return;
85
+ Object.defineProperty(exports, key, {
86
+ enumerable: true,
87
+ get: function () {
88
+ return _contactInfo[key];
89
+ }
90
+ });
91
+ });
80
92
  function isRecord(value) {
81
93
  return !!value && typeof value === 'object' && !Array.isArray(value);
82
94
  }
@@ -69,6 +69,15 @@ export interface OpenDataConfig {
69
69
  'reservation.time_slice'?: number | string;
70
70
  'sale.allow_item_notes'?: boolean;
71
71
  'sale.allow_order_notes'?: boolean;
72
+ 'sale.enable_contact_info'?: boolean;
73
+ 'sale.first_name.visible'?: boolean;
74
+ 'sale.first_name.required'?: boolean;
75
+ 'sale.last_name.visible'?: boolean;
76
+ 'sale.last_name.required'?: boolean;
77
+ 'sale.phone.visible'?: boolean;
78
+ 'sale.phone.required'?: boolean;
79
+ 'sale.email.visible'?: boolean;
80
+ 'sale.email.required'?: boolean;
72
81
  /** False submits an order without starting or confirming payment. */
73
82
  'sale.require_payment_on_submit'?: boolean | null;
74
83
  'sale.enable_item_rules'?: boolean;
@@ -0,0 +1,14 @@
1
+ import type { OrderHolderRelation, OrderTempOrder } from './types';
2
+ /** 在原订单上补齐关系身份,让缓存、提交和重试共用同一个 UUID。 */
3
+ export declare function ensureHolderRelationUuids(order: {
4
+ holder_relations?: OrderHolderRelation[];
5
+ }): void;
6
+ export declare function hasProductBooking(product: Record<string, any>): boolean;
7
+ export declare function getProductHolderRelations(order: {
8
+ holder_relations?: OrderHolderRelation[];
9
+ }, product: Record<string, any>): OrderHolderRelation[];
10
+ export declare function replaceProductHolderRelations(order: OrderTempOrder, product: Record<string, any>, patch: OrderHolderRelation[] | undefined): void;
11
+ /** 只删除明确被用户删除的行,不从稀疏远端快照推断删除。 */
12
+ export declare function removeProductHolderRelations(order: OrderTempOrder, products: Array<Record<string, any>>): void;
13
+ /** 仅兼容尚无新字段的旧测试草稿;显式 [] 永远不恢复旧 product 数据。 */
14
+ export declare function restoreLegacyHolderRelations(order: Record<string, any>): OrderHolderRelation[] | undefined;
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.ensureHolderRelationUuids = ensureHolderRelationUuids;
7
+ exports.getProductHolderRelations = getProductHolderRelations;
8
+ exports.hasProductBooking = hasProductBooking;
9
+ exports.removeProductHolderRelations = removeProductHolderRelations;
10
+ exports.replaceProductHolderRelations = replaceProductHolderRelations;
11
+ exports.restoreLegacyHolderRelations = restoreLegacyHolderRelations;
12
+ var _orderCollectionIdentity = require("./utils/orderCollectionIdentity");
13
+ function getHolderRelationUuid(relation) {
14
+ return typeof relation?.uuid === 'string' && relation.uuid.trim() ? relation.uuid : undefined;
15
+ }
16
+
17
+ /** 在原订单上补齐关系身份,让缓存、提交和重试共用同一个 UUID。 */
18
+ function ensureHolderRelationUuids(order) {
19
+ if (!Array.isArray(order.holder_relations)) return;
20
+ for (const relation of order.holder_relations) {
21
+ if (relation && typeof relation === 'object' && !getHolderRelationUuid(relation)) {
22
+ relation.uuid = (0, _orderCollectionIdentity.createUuidV4)();
23
+ }
24
+ }
25
+ }
26
+ function hasProductBooking(product) {
27
+ const bookingIds = [product.booking_id, product.metadata?.booking_id, product.schedule_event_id];
28
+ return Boolean(product.booking_uid || product.metadata?.booking_uid) || bookingIds.some(id => id !== undefined && id !== null && String(id) !== '' && String(id) !== '0');
29
+ }
30
+ function getProductHolderRelations(order, product) {
31
+ const uid = product.metadata?.unique_identification_number ?? product.unique_identification_number;
32
+ if (uid === undefined || uid === null || uid === '') return [];
33
+ return (order.holder_relations || []).filter(relation => relation.relation_model === 'order_detail' && String(relation.relation_uuid) === String(uid));
34
+ }
35
+ function replaceProductHolderRelations(order, product, patch) {
36
+ if (patch === undefined || hasProductBooking(product)) return;
37
+ const uid = product.metadata?.unique_identification_number ?? product.unique_identification_number;
38
+ if (uid === undefined || uid === null || uid === '') return;
39
+ const existing = getProductHolderRelations(order, product);
40
+ const next = new Map();
41
+ for (const relation of patch) {
42
+ const key = `${relation.holder_type}:${relation.holder_id}`;
43
+ const previous = existing.find(item => item.holder_type === relation.holder_type && String(item.holder_id) === String(relation.holder_id));
44
+ next.set(key, {
45
+ ...previous,
46
+ ...relation,
47
+ uuid: getHolderRelationUuid(previous) || getHolderRelationUuid(relation) || (0, _orderCollectionIdentity.createUuidV4)(),
48
+ relation_model: 'order_detail',
49
+ relation_uuid: String(uid),
50
+ ...(previous?.metadata || relation.metadata ? {
51
+ metadata: {
52
+ ...previous?.metadata,
53
+ ...relation.metadata
54
+ }
55
+ } : {})
56
+ });
57
+ }
58
+ order.holder_relations = [...(order.holder_relations || []).filter(relation => relation.relation_model !== 'order_detail' || String(relation.relation_uuid) !== String(uid)), ...next.values()];
59
+ }
60
+
61
+ /** 只删除明确被用户删除的行,不从稀疏远端快照推断删除。 */
62
+ function removeProductHolderRelations(order, products) {
63
+ if (!Array.isArray(order.holder_relations)) return;
64
+ const removedUids = new Set(products.map(product => String(product.metadata?.unique_identification_number ?? product.unique_identification_number ?? '')));
65
+ order.holder_relations = order.holder_relations.filter(relation => relation.relation_model !== 'order_detail' || !removedUids.has(String(relation.relation_uuid)));
66
+ }
67
+
68
+ /** 仅兼容尚无新字段的旧测试草稿;显式 [] 永远不恢复旧 product 数据。 */
69
+ function restoreLegacyHolderRelations(order) {
70
+ if (Object.prototype.hasOwnProperty.call(order, 'holder_relations')) {
71
+ return Array.isArray(order.holder_relations) ? order.holder_relations : undefined;
72
+ }
73
+ const relations = [];
74
+ const bookingProductUids = new Set((order.bookings || []).map(booking => String(booking.product_uid ?? booking.metadata?.product_uid ?? '')));
75
+ for (const product of order.products || []) {
76
+ if (hasProductBooking(product)) continue;
77
+ const uid = product.metadata?.unique_identification_number ?? product.unique_identification_number;
78
+ if (uid === undefined || uid === null || uid === '' || bookingProductUids.has(String(uid))) continue;
79
+ const holder = product.metadata?.holder || {};
80
+ const rawIds = product.metadata?.holder_id ?? holder.form_record;
81
+ const ids = (Array.isArray(rawIds) ? rawIds : [rawIds]).filter(id => id !== undefined && id !== null && id !== '' && Number.isInteger(Number(id)) && Number(id) >= 0);
82
+ for (const id of ids) {
83
+ const metadata = {
84
+ ...holder,
85
+ form_record: [Number(id)]
86
+ };
87
+ if (ids.length !== 1) delete metadata.name;
88
+ relations.push({
89
+ relation_model: 'order_detail',
90
+ relation_uuid: String(uid),
91
+ holder_type: 'form',
92
+ holder_id: Number(id),
93
+ metadata
94
+ });
95
+ }
96
+ }
97
+ return relations.length ? relations : undefined;
98
+ }
@@ -595,7 +595,7 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
595
595
  generateIdempotencyToken(): string;
596
596
  syncPaymentsToOrder<T = any>(params: SyncPaymentsToOrderParams): Promise<SyncPaymentsToOrderResult<T>>;
597
597
  createOrder(params: CommitOrderParams['query']): {
598
- type: "virtual" | "appointment_booking";
598
+ type: "appointment_booking" | "virtual";
599
599
  platform: string;
600
600
  sales_channel: string;
601
601
  order_sales_channel: string;
@@ -673,6 +673,6 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
673
673
  getOrderInfo(order_id: number): Promise<any>;
674
674
  getVouchers(): any[];
675
675
  }
676
- export type { AddProductToOrderOptions, OrderMetaList, PointCardSnapshotItem, VirtualCurrencySnapshotItem, RemoveProductsFromOrderOptions, SalesNote, SalesNoteDraftInput, SalesNoteLocalizedSelection, SalesNoteLocalizedText, SalesNoteRelation, SalesNoteTextInput, SetSalesNoteInput, UpdateOrderBookingParams, UpdateOrderProductParams, UpdateOrderProductQuantityParams, } from './types';
676
+ export type { OrderHolderRelation, AddProductToOrderOptions, OrderMetaList, PointCardSnapshotItem, VirtualCurrencySnapshotItem, RemoveProductsFromOrderOptions, SalesNote, SalesNoteDraftInput, SalesNoteLocalizedSelection, SalesNoteLocalizedText, SalesNoteRelation, SalesNoteTextInput, SetSalesNoteInput, UpdateOrderBookingParams, UpdateOrderProductParams, UpdateOrderProductQuantityParams, } from './types';
677
677
  export { isFulfillmentTimingBooking } from './pickupTiming';
678
678
  export type { PickupTimingBooking, PickupTimingBookingInput, PickupTimingBookingMetadata, PickupTimingSelectionMode, PickupTimingSource, } from './pickupTiming';
@@ -16,6 +16,7 @@ var _BaseModule = require("../BaseModule");
16
16
  var _types = require("./types");
17
17
  var _utils = require("./utils");
18
18
  var _utils2 = require("../Product/utils");
19
+ var _holderRelations = require("./holderRelations");
19
20
  var _weighedProduct = require("./utils/weighedProduct");
20
21
  var _pickupTiming = require("./pickupTiming");
21
22
  var _dayjs = _interopRequireDefault(require("dayjs"));
@@ -543,7 +544,7 @@ class OrderModule extends _BaseModule.BaseModule {
543
544
  this.store.rules = rules;
544
545
  }
545
546
  createDefaultRulesHooks() {
546
- return (0, _utils.createDefaultOrderRulesHooks)(() => this.store.tempOrder?.bookings || []);
547
+ return (0, _utils.createDefaultOrderRulesHooks)(() => this.store.tempOrder?.bookings || [], () => this.store.tempOrder?.holder_relations);
547
548
  }
548
549
 
549
550
  /**
@@ -857,7 +858,7 @@ class OrderModule extends _BaseModule.BaseModule {
857
858
  discount_list: (0, _utils.normalizeOrderProductDiscountList)((0, _manualProductDiscount.syncManualProductDiscountProductNum)(mergedProduct.discount_list, mergedProduct.num))
858
859
  };
859
860
  }));
860
- (0, _discountProductLineIdentity.ensureUniqueProductLineUids)(tempOrder);
861
+ (0, _discountProductLineIdentity.ensureUniqueProductLineUids)(tempOrder, discountList);
861
862
  (0, _discountProductLineIdentity.consolidateDiscountFreeProductLines)(tempOrder);
862
863
  }
863
864
  if (result?.discountList) {
@@ -1118,7 +1119,9 @@ class OrderModule extends _BaseModule.BaseModule {
1118
1119
  * sessionStorage 的 cacheId 分桶。写入失败由 BaseModule 静默降级。
1119
1120
  */
1120
1121
  persistTempOrder() {
1121
- if (!this.sessionStoragePersistEnabled || !this.store.tempOrder) return;
1122
+ if (!this.store.tempOrder) return;
1123
+ (0, _holderRelations.ensureHolderRelationUuids)(this.store.tempOrder);
1124
+ if (!this.sessionStoragePersistEnabled) return;
1122
1125
  this.checkSaveCache({
1123
1126
  cacheId: this.cacheId,
1124
1127
  fatherModule: this.fatherModule,
@@ -1827,7 +1830,10 @@ class OrderModule extends _BaseModule.BaseModule {
1827
1830
  source_product_price: this.normalizeFingerprintMoney(metadata.source_product_price),
1828
1831
  main_product_selling_price: this.normalizeFingerprintMoney(metadata.main_product_selling_price),
1829
1832
  main_product_original_price: this.normalizeFingerprintMoney(metadata.main_product_original_price),
1830
- product_discount_difference: this.normalizeFingerprintMoney(metadata.product_discount_difference)
1833
+ product_discount_difference: this.normalizeFingerprintMoney(metadata.product_discount_difference),
1834
+ ...(!(0, _holderRelations.hasProductBooking)(product) ? {
1835
+ holder_relations: this.normalizeFingerprintValue((0, _holderRelations.getProductHolderRelations)(this.store.tempOrder || {}, product))
1836
+ } : {})
1831
1837
  },
1832
1838
  product_sku: this.normalizeFingerprintValue({
1833
1839
  code: sku.code ?? '',
@@ -1863,7 +1869,7 @@ class OrderModule extends _BaseModule.BaseModule {
1863
1869
  items.sort((left, right) => JSON.stringify(left).localeCompare(JSON.stringify(right)));
1864
1870
  return JSON.stringify(items);
1865
1871
  }
1866
- buildProductStructuralFingerprintItem(product) {
1872
+ buildProductStructuralFingerprintItem(product, order = this.store.tempOrder || {}) {
1867
1873
  const sku = product?.product_sku || {};
1868
1874
  const metadata = product?.metadata || {};
1869
1875
  const discountTypes = (product?.discount_list || []).map(discount => discount?.type ?? discount?.tag);
@@ -1878,7 +1884,10 @@ class OrderModule extends _BaseModule.BaseModule {
1878
1884
  unique_identification_number: metadata.unique_identification_number ?? product?.unique_identification_number ?? '',
1879
1885
  price_override: metadata.price_override ?? '',
1880
1886
  is_manual_discount: metadata.is_manual_discount ?? '',
1881
- product_discount_reason: metadata.product_discount_reason ?? ''
1887
+ product_discount_reason: metadata.product_discount_reason ?? '',
1888
+ ...(!(0, _holderRelations.hasProductBooking)(product) ? {
1889
+ holder_relations: this.normalizeFingerprintValue((0, _holderRelations.getProductHolderRelations)(order, product))
1890
+ } : {})
1882
1891
  },
1883
1892
  product_sku: this.normalizeFingerprintValue({
1884
1893
  code: sku.code ?? '',
@@ -1916,8 +1925,8 @@ class OrderModule extends _BaseModule.BaseModule {
1916
1925
  })))
1917
1926
  };
1918
1927
  }
1919
- buildOrderProductsStructuralFingerprint(products) {
1920
- const items = (products || []).map(product => this.buildProductStructuralFingerprintItem(product));
1928
+ buildOrderProductsStructuralFingerprint(products, order = this.store.tempOrder || {}) {
1929
+ const items = (products || []).map(product => this.buildProductStructuralFingerprintItem(product, order));
1921
1930
  items.sort((left, right) => JSON.stringify(left).localeCompare(JSON.stringify(right)));
1922
1931
  return JSON.stringify(items);
1923
1932
  }
@@ -1984,7 +1993,7 @@ class OrderModule extends _BaseModule.BaseModule {
1984
1993
  const manualDepositOverride = this.getManualDepositOverride(tempOrder);
1985
1994
  if (currentFingerprint !== snapshot.productFingerprint) {
1986
1995
  const currentStructuralFingerprint = this.buildOrderProductsStructuralFingerprint(tempOrder.products);
1987
- const snapshotStructuralFingerprint = this.buildOrderProductsStructuralFingerprint(Array.isArray(snapshot.products) ? snapshot.products : []);
1996
+ const snapshotStructuralFingerprint = this.buildOrderProductsStructuralFingerprint(Array.isArray(snapshot.products) ? snapshot.products : [], snapshot);
1988
1997
  if (currentStructuralFingerprint !== snapshotStructuralFingerprint) return null;
1989
1998
  }
1990
1999
  let summary = {
@@ -2205,9 +2214,16 @@ class OrderModule extends _BaseModule.BaseModule {
2205
2214
  product.metadata = metadata;
2206
2215
  return String(uid);
2207
2216
  }
2208
- sanitizeOrderProductForTempOrder(product) {
2217
+ sanitizeOrderProductForTempOrder(product, deferHolderCleanup = false) {
2209
2218
  if (product.metadata && typeof product.metadata === 'object') {
2210
2219
  delete product.metadata.origin;
2220
+ if (!deferHolderCleanup && !(0, _holderRelations.hasProductBooking)(product)) {
2221
+ delete product.metadata.holder;
2222
+ delete product.metadata.holder_id;
2223
+ }
2224
+ }
2225
+ if (product._extend?.holder_relations !== undefined) {
2226
+ delete product._extend.holder_relations;
2211
2227
  }
2212
2228
  return product;
2213
2229
  }
@@ -3006,6 +3022,7 @@ class OrderModule extends _BaseModule.BaseModule {
3006
3022
  const nextCustomerId = tempOrder.customer_id ?? null;
3007
3023
  if (String(previousCustomerId ?? '') !== String(nextCustomerId ?? '')) {
3008
3024
  this.clearCustomerWalletState(tempOrder);
3025
+ (0, _holderRelations.removeProductHolderRelations)(tempOrder, tempOrder.products.filter(product => !(0, _holderRelations.hasProductBooking)(product)));
3009
3026
  }
3010
3027
  this.persistTempOrder();
3011
3028
  return {
@@ -3569,10 +3586,13 @@ class OrderModule extends _BaseModule.BaseModule {
3569
3586
  const hasIncomingProductNote = this.hasOrderProductLineNote(normalizedIncoming);
3570
3587
  const hasIncomingManualProductDiscount = isManualProductDiscountProduct(normalizedIncoming);
3571
3588
  const hasIncomingBookingUid = this.hasLinkedBookingUid(productToAdd) || this.hasLinkedBookingUid(normalizedIncoming);
3589
+ const holderRelationsPatch = !hasIncomingBookingUid ? productToAdd._extend?.holder_relations : undefined;
3590
+ const hasIncomingHolder = Array.isArray(holderRelationsPatch) && holderRelationsPatch.length > 0;
3572
3591
  const isIncomingCustomItem = productToAdd.metadata?.origin?.isCustomItem === true || productToAdd._origin?.isCustomItem === true;
3573
- const shouldForceNewLine = disableMerge || !!booking || hasIncomingGoodPass || isIncomingPersistedEntitlementPass || hasIncomingBookingUid || isIncomingCustomItem || isWeighingProduct;
3592
+ const shouldForceNewLine = disableMerge || !!booking || hasIncomingGoodPass || isIncomingPersistedEntitlementPass || hasIncomingBookingUid || hasIncomingHolder || isIncomingCustomItem || isWeighingProduct;
3574
3593
  const matchedIndex = shouldForceNewLine ? -1 : tempOrder.products.findIndex(item => {
3575
3594
  if (this.hasGoodPassDiscount(item)) return false;
3595
+ if ((0, _holderRelations.getProductHolderRelations)(tempOrder, item).length > 0 || (0, _utils.hasAssignedHolderId)(item.metadata?.holder_id)) return false;
3576
3596
  const isRuntimeEntitlementPass = this.isRuntimeEntitlementAppend(item, tempOrder);
3577
3597
  if (isIncomingEntitlementAppend !== isRuntimeEntitlementPass) {
3578
3598
  return false;
@@ -3663,6 +3683,7 @@ class OrderModule extends _BaseModule.BaseModule {
3663
3683
  if (linked) {
3664
3684
  tempOrder.bookings = [...(tempOrder.bookings || []), linked.booking];
3665
3685
  }
3686
+ (0, _holderRelations.replaceProductHolderRelations)(tempOrder, committedProduct, holderRelationsPatch);
3666
3687
  return committedProduct;
3667
3688
  };
3668
3689
  if (!matchedProduct) {
@@ -3772,6 +3793,7 @@ class OrderModule extends _BaseModule.BaseModule {
3772
3793
  }));
3773
3794
  const mutationSnapshot = salesNoteDrafts.length > 0 ? {
3774
3795
  products: (0, _lodashEs.cloneDeep)(tempOrder.products || []),
3796
+ holder_relations: (0, _lodashEs.cloneDeep)(tempOrder.holder_relations),
3775
3797
  bookings: (0, _lodashEs.cloneDeep)(tempOrder.bookings || []),
3776
3798
  notes: (0, _lodashEs.cloneDeep)(tempOrder.notes || []),
3777
3799
  extend: (0, _lodashEs.cloneDeep)(tempOrder._extend || {})
@@ -3796,6 +3818,7 @@ class OrderModule extends _BaseModule.BaseModule {
3796
3818
  const rollbackProductAndNotesMutation = () => {
3797
3819
  if (!mutationSnapshot) return;
3798
3820
  tempOrder.products = mutationSnapshot.products;
3821
+ if (mutationSnapshot.holder_relations === undefined) delete tempOrder.holder_relations;else tempOrder.holder_relations = mutationSnapshot.holder_relations;
3799
3822
  tempOrder.bookings = mutationSnapshot.bookings;
3800
3823
  tempOrder.notes = mutationSnapshot.notes;
3801
3824
  tempOrder._extend = mutationSnapshot.extend;
@@ -4280,6 +4303,7 @@ class OrderModule extends _BaseModule.BaseModule {
4280
4303
  if (uid) reapplyWeighedDiscountProductUids?.push(String(uid));
4281
4304
  }
4282
4305
  tempOrder.products[productIndex] = normalizedProduct;
4306
+ (0, _holderRelations.replaceProductHolderRelations)(tempOrder, normalizedProduct, updates._extend?.holder_relations);
4283
4307
  this.syncTempOrderHolderFromBookings(tempOrder);
4284
4308
  this.captureProductRuntime(tempOrder, updates, tempOrder.products[productIndex], tempOrder.products[productIndex].metadata?.unique_identification_number);
4285
4309
  return tempOrder.products[productIndex].metadata?.unique_identification_number;
@@ -4557,6 +4581,7 @@ class OrderModule extends _BaseModule.BaseModule {
4557
4581
  tempOrder.products = nextProductIndex >= 0 ? [...productsWithoutRemaining.slice(0, nextProductIndex), remainingProduct, ...productsWithoutRemaining.slice(nextProductIndex)] : [...productsWithoutRemaining, remainingProduct];
4558
4582
  }
4559
4583
  }
4584
+ (0, _holderRelations.removeProductHolderRelations)(tempOrder, productsBeforeRemove.filter(product => !tempOrder.products.includes(product)));
4560
4585
  this.removeSalesNotesForMissingProductLines(tempOrder);
4561
4586
  if (isCurrentOrder) {
4562
4587
  await this.finalizeProductOrderMutation(tempOrder, {
@@ -4582,6 +4607,7 @@ class OrderModule extends _BaseModule.BaseModule {
4582
4607
  async clearOrderCartLines() {
4583
4608
  const tempOrder = this.ensureTempOrder();
4584
4609
  this.ensureSalesNotesLoadedForMutation(tempOrder);
4610
+ (0, _holderRelations.removeProductHolderRelations)(tempOrder, tempOrder.products);
4585
4611
  tempOrder.products = [];
4586
4612
  tempOrder.bookings = [];
4587
4613
  (0, _virtualSettlement.releaseTempOrderSettlementState)(tempOrder);
@@ -4611,6 +4637,7 @@ class OrderModule extends _BaseModule.BaseModule {
4611
4637
  async clearOrderForSettlementSwitch() {
4612
4638
  const tempOrder = this.ensureTempOrder();
4613
4639
  this.ensureSalesNotesLoadedForMutation(tempOrder);
4640
+ (0, _holderRelations.removeProductHolderRelations)(tempOrder, tempOrder.products);
4614
4641
  tempOrder.products = [];
4615
4642
  tempOrder.bookings = [];
4616
4643
  this.removeSalesNotesForMissingProductLines(tempOrder);
@@ -5354,6 +5381,7 @@ class OrderModule extends _BaseModule.BaseModule {
5354
5381
  originalSalesSnapshot: {
5355
5382
  summary: (0, _lodashEs.cloneDeep)(this.store.summary),
5356
5383
  products: (0, _lodashEs.cloneDeep)(nextTempOrder.products || []),
5384
+ holder_relations: (0, _lodashEs.cloneDeep)(nextTempOrder.holder_relations),
5357
5385
  bookings: (0, _lodashEs.cloneDeep)(nextTempOrder.bookings || []),
5358
5386
  payments: (0, _lodashEs.cloneDeep)(nextTempOrder.payments || []),
5359
5387
  surcharges: (0, _lodashEs.cloneDeep)(nextTempOrder.surcharges || []),
@@ -5506,6 +5534,9 @@ class OrderModule extends _BaseModule.BaseModule {
5506
5534
  nextTempOrder.metadata = raw.metadata && typeof raw.metadata === 'object' ? {
5507
5535
  ...raw.metadata
5508
5536
  } : {};
5537
+ const holderRelations = (0, _holderRelations.restoreLegacyHolderRelations)(raw);
5538
+ if (holderRelations === undefined) delete nextTempOrder.holder_relations;else nextTempOrder.holder_relations = (0, _lodashEs.cloneDeep)(holderRelations);
5539
+ (0, _holderRelations.ensureHolderRelationUuids)(nextTempOrder);
5509
5540
  nextTempOrder.holder = raw.holder && typeof raw.holder === 'object' ? {
5510
5541
  ...raw.holder
5511
5542
  } : null;
@@ -5583,6 +5614,7 @@ class OrderModule extends _BaseModule.BaseModule {
5583
5614
  }
5584
5615
  tempOrderExtend.productsByUid = productsByUid;
5585
5616
  this.hydrateLinkedBookingIdentity(nextTempOrder);
5617
+ nextTempOrder.products.forEach(product => this.sanitizeOrderProductForTempOrder(product));
5586
5618
  if (options?.ensureIdentity !== false) {
5587
5619
  this.ensureExternalSaleNumber(nextTempOrder);
5588
5620
  }
@@ -5743,7 +5775,7 @@ class OrderModule extends _BaseModule.BaseModule {
5743
5775
  };
5744
5776
  if (result.metadata) delete result.metadata.price_schema_version;
5745
5777
  const restored = (0, _bundleDiscountHydration.restoreHydratedBundleDiscounts)(result, _utils.normalizeOrderProductDiscountList);
5746
- return this.sanitizeOrderProductForTempOrder(this.normalizeVirtualSettlementProductIfEnabled(restored));
5778
+ return this.sanitizeOrderProductForTempOrder(this.normalizeVirtualSettlementProductIfEnabled(restored), true);
5747
5779
  }
5748
5780
  getLastOrderInfo() {
5749
5781
  return this.store?.lastOrderInfo;
@@ -243,6 +243,11 @@ export interface OrderProduct extends OrderProductIdentity {
243
243
  product_cover?: string;
244
244
  metadata: Record<string, any>;
245
245
  note?: string;
246
+ /** 仅作按行更新输入;正式数据保存于订单顶层。 */
247
+ _extend?: {
248
+ holder_relations?: OrderHolderRelation[];
249
+ [key: string]: any;
250
+ };
246
251
  }
247
252
  export interface OrderSummary {
248
253
  product_quantity: number;
@@ -340,6 +345,17 @@ export interface SalesNotesMutationSnapshot {
340
345
  }
341
346
  export type SalesNoteProtocolRelation = SalesNoteRelation;
342
347
  export type SalesNoteProtocol = SalesNote;
348
+ /** 后端关系及 metadata 均为开放对象,未知字段必须往返保留。 */
349
+ export interface OrderHolderRelation {
350
+ /** 关系自身的 UUID;新选择/旧草稿可缺省,入单与提交时由 OS 补齐。 */
351
+ uuid?: string;
352
+ relation_model: string;
353
+ relation_uuid: string;
354
+ holder_type: 'form' | 'customer';
355
+ holder_id: number;
356
+ metadata?: Record<string, any>;
357
+ [key: string]: any;
358
+ }
343
359
  export interface OrderTempOrder {
344
360
  order_id: number | null;
345
361
  external_sale_number: string;
@@ -379,6 +395,7 @@ export interface OrderTempOrder {
379
395
  created_at: string | undefined;
380
396
  request_unique_idempotency_token?: string;
381
397
  products: OrderProduct[];
398
+ holder_relations?: OrderHolderRelation[];
382
399
  notes: SalesNote[];
383
400
  bookings: any[];
384
401
  payments: any[];
@@ -398,7 +415,7 @@ export interface OrderTempOrder {
398
415
  [key: string]: any;
399
416
  };
400
417
  }
401
- export interface OrderSubmitProduct extends Omit<OrderProduct, 'unique_identification_number' | 'num'> {
418
+ export interface OrderSubmitProduct extends Omit<OrderProduct, 'unique_identification_number' | 'num' | '_extend'> {
402
419
  product_quantity: number;
403
420
  payment_price: string;
404
421
  product_sku: OrderProductSku;
@@ -607,6 +624,7 @@ export interface SubmitSalesOrderParams {
607
624
  schedule_date: string;
608
625
  created_at?: string | undefined;
609
626
  products: OrderSubmitProduct[];
627
+ holder_relations?: OrderHolderRelation[];
610
628
  bookings: OrderSubmitBooking[];
611
629
  payments: any[];
612
630
  vouchers: any[];