@pisell/pisellos 0.10.58 → 0.10.59

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 (34) hide show
  1. package/dist/index.d.ts +1 -0
  2. package/dist/index.js +1 -0
  3. package/dist/inventory/index.d.ts +92 -0
  4. package/dist/inventory/index.js +500 -0
  5. package/dist/model/strategy/adapter/promotion/index.js +0 -9
  6. package/dist/modules/Order/index.d.ts +19 -2
  7. package/dist/modules/Order/index.js +1369 -1021
  8. package/dist/modules/Order/types.d.ts +5 -0
  9. package/dist/modules/ProductList/index.d.ts +1 -3
  10. package/dist/modules/ProductList/index.js +120 -192
  11. package/dist/modules/ProductList/types.d.ts +0 -8
  12. package/dist/modules/ProductList/types.js +0 -2
  13. package/dist/solution/BaseSales/index.d.ts +8 -0
  14. package/dist/solution/BaseSales/index.js +1382 -1207
  15. package/dist/solution/BookingByStep/index.d.ts +1 -1
  16. package/dist/solution/UnifiedBookingSales/index.d.ts +1 -7
  17. package/dist/solution/UnifiedBookingSales/index.js +446 -586
  18. package/lib/index.d.ts +1 -0
  19. package/lib/index.js +12 -0
  20. package/lib/inventory/index.d.ts +92 -0
  21. package/lib/inventory/index.js +280 -0
  22. package/lib/modules/Order/index.d.ts +19 -2
  23. package/lib/modules/Order/index.js +111 -19
  24. package/lib/modules/Order/types.d.ts +5 -0
  25. package/lib/modules/ProductList/index.d.ts +1 -3
  26. package/lib/modules/ProductList/index.js +22 -31
  27. package/lib/modules/ProductList/types.d.ts +0 -8
  28. package/lib/modules/ProductList/types.js +0 -1
  29. package/lib/solution/BaseSales/index.d.ts +8 -0
  30. package/lib/solution/BaseSales/index.js +82 -7
  31. package/lib/solution/BookingByStep/index.d.ts +1 -1
  32. package/lib/solution/UnifiedBookingSales/index.d.ts +1 -7
  33. package/lib/solution/UnifiedBookingSales/index.js +12 -80
  34. package/package.json +1 -1
package/lib/index.d.ts CHANGED
@@ -7,6 +7,7 @@ export * from './modules';
7
7
  export * from './plugins';
8
8
  export * from './solution';
9
9
  export * from './model';
10
+ export * from './inventory';
10
11
  export { PisellOSCore } from './core';
11
12
  import PisellOSCore from './core';
12
13
  export default PisellOSCore;
package/lib/index.js CHANGED
@@ -80,6 +80,18 @@ Object.keys(_model).forEach(function (key) {
80
80
  }
81
81
  });
82
82
  });
83
+ var _inventory = require("./inventory");
84
+ Object.keys(_inventory).forEach(function (key) {
85
+ if (key === "default" || key === "__esModule") return;
86
+ if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
87
+ if (key in exports && exports[key] === _inventory[key]) return;
88
+ Object.defineProperty(exports, key, {
89
+ enumerable: true,
90
+ get: function () {
91
+ return _inventory[key];
92
+ }
93
+ });
94
+ });
83
95
  var _core = _interopRequireWildcard(require("./core"));
84
96
  var _smallTicket = require("./shared/receipt/small-ticket");
85
97
  Object.keys(_smallTicket).forEach(function (key) {
@@ -0,0 +1,92 @@
1
+ /** Optional, instance-scoped sales inventory. Never stored in ProductData or order payloads. */
2
+ export type InventoryRecord = Record<string, any>;
3
+ export type InventoryRefreshReason = 'catalog-entry' | 'detail-open' | 'checkout' | 'manual';
4
+ export interface InventoryAvailability {
5
+ status: 'ready' | 'loading' | 'stale' | 'error' | 'unmapped';
6
+ quantity?: number;
7
+ message?: string;
8
+ }
9
+ export interface InventorySelectionAvailability {
10
+ availability: InventoryAvailability;
11
+ /** Stock remaining after other cart lines using the same inventory key. */
12
+ availableQuantity: number;
13
+ /** The existing line can still be reduced when stock is unavailable. */
14
+ retainedQuantity: number;
15
+ maxQuantity: number;
16
+ }
17
+ export interface InventorySource {
18
+ readonly scopeKey: string;
19
+ assertCurrent(): void;
20
+ keyOf(product: InventoryRecord, variant?: InventoryRecord): string | undefined;
21
+ read(context: {
22
+ reason: InventoryRefreshReason;
23
+ signal: AbortSignal;
24
+ }): Promise<ReadonlyMap<string, {
25
+ quantity: number | null;
26
+ message?: string;
27
+ }>>;
28
+ message(reason: 'unavailable' | 'unmapped' | 'insufficient', values?: {
29
+ key: string;
30
+ quantity: number;
31
+ }): string;
32
+ }
33
+ export interface CheckoutInventoryLine {
34
+ readonly lineId: string;
35
+ readonly productId: string | number;
36
+ readonly variantId: string | number;
37
+ readonly quantity: number;
38
+ readonly inventoryKey: string;
39
+ }
40
+ export interface CheckoutRuntimeSnapshot {
41
+ readonly scopeKey: string;
42
+ readonly revision: number;
43
+ readonly lines: readonly CheckoutInventoryLine[];
44
+ }
45
+ export interface SalesCheckoutHooks {
46
+ beforeCheckout?(context: {
47
+ items: readonly InventoryRecord[];
48
+ signal?: AbortSignal;
49
+ }): Promise<void>;
50
+ }
51
+ export declare const salesGuardError: (message: string) => Error & {
52
+ code: string;
53
+ };
54
+ export declare class InventoryController {
55
+ private readonly source;
56
+ readonly identity: symbol;
57
+ readonly scopeKey: string;
58
+ private entries;
59
+ private lastQuantities;
60
+ private products;
61
+ private keys;
62
+ private catalogProducts;
63
+ private listeners;
64
+ private revision;
65
+ private state;
66
+ private pending?;
67
+ private disposed;
68
+ constructor(source: InventorySource);
69
+ getRevision: () => number;
70
+ subscribe: (listener: () => void) => () => void;
71
+ private publish;
72
+ private assertCurrent;
73
+ activate(): void;
74
+ dispose(): void;
75
+ invalidate(): void;
76
+ /** Catalog replaces identities; partial detail only merges its variants, never its prices. */
77
+ registerProducts(products: readonly InventoryRecord[], complete?: boolean): void;
78
+ /** Consumers share I/O; cancelling one detail does not cancel another consumer. */
79
+ refresh(context: {
80
+ reason: InventoryRefreshReason;
81
+ signal?: AbortSignal;
82
+ force?: boolean;
83
+ }): Promise<void>;
84
+ availabilityForKey(key?: string): InventoryAvailability;
85
+ availability(product: InventoryRecord, variantId?: string | number): InventoryAvailability;
86
+ private keyForLine;
87
+ /** Advisory UI limit only. The serialized cart guard remains authoritative. */
88
+ selectionAvailability(product: InventoryRecord, variantId: string | number, items: readonly InventoryRecord[], editingItem?: InventoryRecord): InventorySelectionAvailability;
89
+ private totals;
90
+ validate(proposed: readonly InventoryRecord[], current?: readonly InventoryRecord[], allowReductions?: boolean): void;
91
+ freezeCheckout(items: readonly InventoryRecord[]): CheckoutRuntimeSnapshot;
92
+ }
@@ -0,0 +1,280 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.salesGuardError = exports.InventoryController = void 0;
7
+ /** Optional, instance-scoped sales inventory. Never stored in ProductData or order payloads. */
8
+
9
+ const salesGuardError = message => Object.assign(new Error(message), {
10
+ code: 'SALES_GUARD_REJECTED'
11
+ });
12
+ exports.salesGuardError = salesGuardError;
13
+ const cancelled = () => Object.assign(new Error('Inventory request cancelled'), {
14
+ name: 'AbortError'
15
+ });
16
+ const variantIdentity = (productId, variantId) => JSON.stringify([String(productId), String(variantId ?? 0)]);
17
+ class InventoryController {
18
+ identity = Symbol('sales-inventory-instance');
19
+ scopeKey;
20
+ entries = new Map();
21
+ lastQuantities = new Map();
22
+ products = new Map();
23
+ keys = new Map();
24
+ catalogProducts = new Map();
25
+ listeners = new Set();
26
+ revision = 0;
27
+ state = 'stale';
28
+ pending;
29
+ disposed = false;
30
+ constructor(source) {
31
+ this.source = source;
32
+ this.scopeKey = source.scopeKey;
33
+ }
34
+ getRevision = () => this.revision;
35
+ subscribe = listener => {
36
+ this.listeners.add(listener);
37
+ return () => {
38
+ this.listeners.delete(listener);
39
+ };
40
+ };
41
+ publish() {
42
+ this.revision += 1;
43
+ this.listeners.forEach(listener => {
44
+ try {
45
+ listener();
46
+ } catch {/* A view cannot interrupt a stock update. */}
47
+ });
48
+ }
49
+ assertCurrent(signal) {
50
+ if (this.disposed || signal?.aborted) throw cancelled();
51
+ this.source.assertCurrent();
52
+ }
53
+ activate() {
54
+ this.disposed = false;
55
+ }
56
+ dispose() {
57
+ this.disposed = true;
58
+ this.invalidate();
59
+ }
60
+ invalidate() {
61
+ this.pending?.controller.abort();
62
+ this.pending = undefined;
63
+ this.state = 'stale';
64
+ this.publish();
65
+ }
66
+
67
+ /** Catalog replaces identities; partial detail only merges its variants, never its prices. */
68
+ registerProducts(products, complete = false) {
69
+ this.assertCurrent();
70
+ let changed = false;
71
+ for (const product of products) {
72
+ const id = String(product.id ?? product.product_id);
73
+ if (complete && this.catalogProducts.get(id) === product) continue;
74
+ if (complete) this.catalogProducts.set(id, product);
75
+ const previous = this.products.get(id);
76
+ if (complete) for (const variantId of previous?.keys() || []) this.keys.delete(variantIdentity(id, variantId));
77
+ const variants = complete ? new Map() : new Map(previous);
78
+ const list = product.variant?.length ? product.variant : [{
79
+ id: 0,
80
+ code: product.code
81
+ }];
82
+ for (const variant of list) {
83
+ const variantId = String(variant.id ?? variant.product_variant_id ?? 0);
84
+ const key = this.source.keyOf(product, variant) ?? previous?.get(variantId);
85
+ variants.set(variantId, key);
86
+ this.keys.set(variantIdentity(id, variantId), key);
87
+ }
88
+ if (!previous || previous.size !== variants.size || [...variants].some(([id, key]) => previous.get(id) !== key)) changed = true;
89
+ this.products.set(id, variants);
90
+ }
91
+ if (changed) this.publish();
92
+ }
93
+
94
+ /** Consumers share I/O; cancelling one detail does not cancel another consumer. */
95
+ async refresh(context) {
96
+ this.assertCurrent(context.signal);
97
+ if (context.force) this.invalidate();
98
+ let read = this.pending;
99
+ if (!read) {
100
+ read = {
101
+ controller: new AbortController(),
102
+ consumers: 0,
103
+ promise: Promise.resolve()
104
+ };
105
+ const current = read;
106
+ this.pending = current;
107
+ this.state = 'loading';
108
+ this.publish();
109
+ current.promise = (async () => {
110
+ try {
111
+ const entries = await this.source.read({
112
+ reason: context.reason,
113
+ signal: current.controller.signal
114
+ });
115
+ this.assertCurrent(current.controller.signal);
116
+ if (this.pending !== current) throw cancelled();
117
+ this.entries = entries;
118
+ for (const [key, stock] of entries) if (stock.quantity !== null && Number.isSafeInteger(stock.quantity) && stock.quantity >= 0) this.lastQuantities.set(key, stock.quantity);
119
+ this.state = 'ready';
120
+ } catch (error) {
121
+ if (this.pending !== current || current.controller.signal.aborted) throw cancelled();
122
+ this.state = 'error';
123
+ throw error;
124
+ } finally {
125
+ if (this.pending === current) {
126
+ this.pending = undefined;
127
+ this.publish();
128
+ }
129
+ }
130
+ })();
131
+ }
132
+ read.consumers += 1;
133
+ try {
134
+ if (!context.signal) await read.promise;else await new Promise((resolve, reject) => {
135
+ const signal = context.signal;
136
+ const abort = () => reject(cancelled());
137
+ signal.addEventListener('abort', abort, {
138
+ once: true
139
+ });
140
+ read.promise.then(resolve, reject).finally(() => signal.removeEventListener('abort', abort));
141
+ if (signal.aborted) abort();
142
+ });
143
+ this.assertCurrent(context.signal);
144
+ } finally {
145
+ read.consumers -= 1;
146
+ if (this.pending === read && read.consumers === 0) this.invalidate();
147
+ }
148
+ }
149
+ availabilityForKey(key) {
150
+ const stock = key ? this.entries.get(key) : undefined;
151
+ const quantity = key ? this.lastQuantities.get(key) : undefined;
152
+ if (this.state !== 'ready') return {
153
+ status: this.state,
154
+ quantity,
155
+ message: this.source.message('unavailable')
156
+ };
157
+ if (!stock) return {
158
+ status: 'unmapped',
159
+ quantity,
160
+ message: this.source.message('unmapped')
161
+ };
162
+ if (stock.quantity === null || !Number.isSafeInteger(stock.quantity) || stock.quantity < 0) return {
163
+ status: 'error',
164
+ quantity,
165
+ message: stock.message || this.source.message('unavailable')
166
+ };
167
+ return {
168
+ status: 'ready',
169
+ quantity: stock.quantity
170
+ };
171
+ }
172
+ availability(product, variantId) {
173
+ const id = product.id ?? product.product_id;
174
+ if (variantId !== undefined && variantId !== null) return this.availabilityForKey(this.keys.get(variantIdentity(id, variantId)));
175
+ const keys = [...new Set(this.products.get(String(id))?.values() || [])];
176
+ const states = keys.map(key => this.availabilityForKey(key));
177
+ if (!states.length) return this.availabilityForKey();
178
+ const quantity = states.every(entry => entry.quantity !== undefined) ? states.reduce((sum, entry) => sum + entry.quantity, 0) : undefined;
179
+ const failed = states.find(entry => entry.status !== 'ready');
180
+ if (quantity !== undefined && !Number.isSafeInteger(quantity)) return {
181
+ status: 'error',
182
+ message: this.source.message('unavailable')
183
+ };
184
+ return {
185
+ status: failed?.status || 'ready',
186
+ quantity,
187
+ message: failed?.message
188
+ };
189
+ }
190
+ keyForLine(item) {
191
+ return this.keys.get(variantIdentity(item.product_id, item.product_variant_id ?? item.product_sku?.product_variant_id));
192
+ }
193
+ /** Advisory UI limit only. The serialized cart guard remains authoritative. */
194
+ selectionAvailability(product, variantId, items, editingItem) {
195
+ const identity = variantIdentity(product.id ?? product.product_id, variantId);
196
+ const key = this.keys.get(identity);
197
+ let availability = this.availabilityForKey(key);
198
+ let reserved = 0;
199
+ let retainedQuantity = 0;
200
+ for (const item of items) {
201
+ const matches = key ? this.keyForLine(item) === key : variantIdentity(item.product_id, item.product_variant_id ?? item.product_sku?.product_variant_id) === identity;
202
+ if (!matches) continue;
203
+ const count = Number(item.num ?? item.quantity);
204
+ if (!Number.isSafeInteger(count) || count < 0) {
205
+ availability = {
206
+ ...availability,
207
+ status: 'error',
208
+ message: this.source.message('unavailable')
209
+ };
210
+ continue;
211
+ }
212
+ if (item === editingItem) retainedQuantity = count;else reserved += count;
213
+ }
214
+ if (!Number.isSafeInteger(reserved)) {
215
+ availability = {
216
+ ...availability,
217
+ status: 'error',
218
+ message: this.source.message('unavailable')
219
+ };
220
+ }
221
+ const availableQuantity = availability.status === 'ready' ? Math.max(0, availability.quantity - reserved) : 0;
222
+ return {
223
+ availability,
224
+ availableQuantity,
225
+ retainedQuantity,
226
+ maxQuantity: Math.max(availableQuantity, retainedQuantity)
227
+ };
228
+ }
229
+ totals(items) {
230
+ const totals = new Map();
231
+ for (const item of items) {
232
+ const key = this.keyForLine(item);
233
+ const identity = key ? JSON.stringify(['inventory', key]) : variantIdentity(item.product_id, item.product_variant_id);
234
+ const quantity = Number(item.num ?? item.quantity);
235
+ if (!Number.isSafeInteger(quantity) || quantity < 0) throw salesGuardError(this.source.message('unavailable'));
236
+ if (!quantity) continue;
237
+ const total = (totals.get(identity)?.quantity || 0) + quantity;
238
+ if (!Number.isSafeInteger(total)) throw salesGuardError(this.source.message('unavailable'));
239
+ totals.set(identity, {
240
+ key,
241
+ quantity: total
242
+ });
243
+ }
244
+ return totals;
245
+ }
246
+ validate(proposed, current = [], allowReductions = true) {
247
+ this.assertCurrent();
248
+ const previous = this.totals(current);
249
+ for (const [identity, {
250
+ key,
251
+ quantity
252
+ }] of this.totals(proposed)) {
253
+ if (allowReductions && quantity <= (previous.get(identity)?.quantity || 0)) continue;
254
+ const stock = this.availabilityForKey(key);
255
+ if (stock.status !== 'ready') throw salesGuardError(stock.message || this.source.message('unavailable'));
256
+ if (quantity > stock.quantity) throw salesGuardError(this.source.message('insufficient', {
257
+ key: key,
258
+ quantity: stock.quantity
259
+ }));
260
+ }
261
+ }
262
+ freezeCheckout(items) {
263
+ if (!items.length || items.some(item => Number(item.num ?? item.quantity) <= 0)) {
264
+ throw salesGuardError(this.source.message('unavailable'));
265
+ }
266
+ this.validate(items, [], false);
267
+ return Object.freeze({
268
+ scopeKey: this.scopeKey,
269
+ revision: this.revision,
270
+ lines: Object.freeze(items.map((item, index) => Object.freeze({
271
+ lineId: String(item.metadata?.unique_identification_number ?? item.unique_identification_number ?? item.order_detail_id ?? index),
272
+ productId: item.product_id,
273
+ variantId: item.product_variant_id ?? item.product_sku?.product_variant_id ?? 0,
274
+ quantity: Number(item.num ?? item.quantity),
275
+ inventoryKey: this.keyForLine(item)
276
+ })))
277
+ });
278
+ }
279
+ }
280
+ exports.InventoryController = InventoryController;
@@ -4,7 +4,7 @@ import { OrderModuleAPI, CommitOrderParams, UpdateOrderBookingParams, UpdateOrde
4
4
  import { CartItem } from '../Cart/types';
5
5
  import { type SubmitPayloadEnhancer } from './utils';
6
6
  import { type PickupTimingBooking, type PickupTimingBookingInput } from './pickupTiming';
7
- import type { OrderAmountSnapshot, AddProductBookingInput, AddProductToOrderOptions, OrderIdentitySnapshot, OrderPaymentSource, OrderSnapshot, OrderSyncState, SyncPaymentsToOrderParams, SyncPaymentsToOrderResult, SubmitSalesOrderParams, OrderProduct, OrderProductIdentity, OrderSummary, OrderTempOrder, OrderPaymentData, OrderPaymentUpdateOptions, OrderPaymentUpdateResult, SendCustomerPayLinkParams, UpdateTempOrderCustomerInput, OrderCustomerPatch, OrderCustomerView, OrderCartIntentCommitContext, ReplaceTempOrderOptions, OrderPromotionEvaluator, OrderGiftSelectResolver, OrderUnfulfilledPromotion, OrderLastGiftActions, RemoveProductsFromOrderOptions, SalesNote, SalesNotesMutationSnapshot, SetSalesNoteInput, PickupReferenceMode, PointCardSnapshotMergeContext, PointCardSnapshotItem, ShopServiceData, ShopServiceType } from './types';
7
+ import type { OrderAmountSnapshot, AddProductBookingInput, AddProductToOrderOptions, OrderIdentitySnapshot, OrderPaymentSource, OrderSnapshot, OrderSyncState, SyncPaymentsToOrderParams, SyncPaymentsToOrderResult, SubmitSalesOrderParams, OrderProduct, OrderProductIdentity, OrderSummary, OrderTempOrder, OrderPaymentData, OrderPaymentUpdateOptions, OrderPaymentUpdateResult, SendCustomerPayLinkParams, UpdateTempOrderCustomerInput, OrderCustomerPatch, OrderCustomerView, OrderHooksConfig, OrderCartIntentCommitContext, ReplaceTempOrderOptions, OrderPromotionEvaluator, OrderGiftSelectResolver, OrderUnfulfilledPromotion, OrderLastGiftActions, RemoveProductsFromOrderOptions, SalesNote, SalesNotesMutationSnapshot, SetSalesNoteInput, PickupReferenceMode, PointCardSnapshotMergeContext, PointCardSnapshotItem, ShopServiceData, ShopServiceType } from './types';
8
8
  import type { ICustomer } from '../AccountList/types';
9
9
  import type { Discount } from '../Discount/types';
10
10
  import { UnavailableReason } from '../Rules/types';
@@ -29,6 +29,12 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
29
29
  private rulesHooksOverride?;
30
30
  private moduleHooksOverride?;
31
31
  private orderHooks?;
32
+ private cartCommandQueue;
33
+ private queueCartCommand;
34
+ /** Use the exact Order normalizers/merge rules on a private draft, not a second projection. */
35
+ private beginCartMutation;
36
+ /** Serializes checkout preparation with local cart commands; hydration remains outside this guard. */
37
+ prepareCheckout<T>(prepare: (items: OrderProduct[]) => Promise<T>): Promise<T>;
32
38
  private otherParams?;
33
39
  /** 评估器引用;由 SalesSdkProvider 注入,未注入时 applyPromotion 静默跳过 */
34
40
  private promotionEvaluator;
@@ -66,7 +72,11 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
66
72
  * @example
67
73
  * orderModule.updateOtherParams({ cacheId: 'cache-2', channel: 'pos' });
68
74
  */
69
- updateOtherParams(params: Record<string, any>): void;
75
+ updateOtherParams(params: Record<string, any>, options?: {
76
+ hooks?: OrderHooksConfig;
77
+ changedParams?: Record<string, any>;
78
+ cover?: boolean;
79
+ }): void;
70
80
  /** Internal intent boundary shared with asynchronous scanner/detail flows. */
71
81
  createCartIntentCommitGuard(action: OrderCartIntentCommitContext['action'], tempOrder?: OrderTempOrder | null): () => void;
72
82
  /** PC/H5 属于在线店铺;其它或缺失平台统一沿用 POS 行为。 */
@@ -481,6 +491,7 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
481
491
  * // → tempOrder.products 新增 3 行,每行 num=1,bookings 3 条
482
492
  */
483
493
  addProductToOrder(product: Partial<OrderProduct> & OrderProductIdentity, booking?: AddProductBookingInput, options?: AddProductToOrderOptions): Promise<OrderProduct[]>;
494
+ private addProductToOrderDraft;
484
495
  /**
485
496
  * 批量添加商品行,所有行追加完成后只触发一次促销、折扣、summary 重算与持久化。
486
497
  *
@@ -496,6 +507,7 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
496
507
  }>, options?: {
497
508
  skipEditDiscountConfigRefresh?: boolean;
498
509
  }): Promise<OrderProduct[]>;
510
+ private addProductsToOrderDraft;
499
511
  private getFullCoveragePassDiscounts;
500
512
  private hasEntitlementPassDiscount;
501
513
  private hasGoodPassDiscount;
@@ -507,8 +519,11 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
507
519
  private isRestrictedCartProductUpdate;
508
520
  private applyOrderProductUpdateToTempOrder;
509
521
  updateOrderProduct(params: UpdateOrderProductParams): Promise<OrderProduct[]>;
522
+ private updateOrderProductDraft;
510
523
  updateOrderProducts(paramsList: UpdateOrderProductParams[]): Promise<OrderProduct[]>;
524
+ private updateOrderProductsDraft;
511
525
  updateOrderProductQuantity(params: UpdateOrderProductQuantityParams): Promise<OrderProduct[]>;
526
+ private updateOrderProductQuantityDraft;
512
527
  updateOrderBooking(params: UpdateOrderBookingParams): any[];
513
528
  /**
514
529
  * 商品行写路径收尾:促销 → 折扣 → 清洗 → summary → 持久化。
@@ -525,12 +540,14 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
525
540
  * await order.removeProductsFromOrder([identityA, identityB]);
526
541
  */
527
542
  removeProductsFromOrder(identities: OrderProductIdentity[], options?: RemoveProductsFromOrderOptions): Promise<OrderProduct[]>;
543
+ private removeProductsFromOrderDraft;
528
544
  removeProductFromOrder(identity: OrderProductIdentity, options?: RemoveProductsFromOrderOptions): Promise<OrderProduct[]>;
529
545
  /**
530
546
  * 仅清空购物车行(products / bookings),不重置整单。
531
547
  * 普通整单 note 保持不变;以商品行为主体的 Sales Notes 同步删除。
532
548
  */
533
549
  clearOrderCartLines(): Promise<OrderTempOrder>;
550
+ private clearOrderCartLinesDraft;
534
551
  /**
535
552
  * 切换购物车结算单位时清理所有会影响新币种的订单状态,但保留当前客户。
536
553
  */