@pisell/pisellos 2.3.94 → 2.3.95
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/model/strategy/adapter/itemRule/adapter.d.ts +4 -1
- package/dist/model/strategy/adapter/itemRule/adapter.js +135 -35
- package/dist/model/strategy/adapter/itemRule/evaluator.d.ts +8 -1
- package/dist/model/strategy/adapter/itemRule/evaluator.js +25 -1
- package/dist/model/strategy/adapter/itemRule/type.d.ts +44 -0
- package/dist/model/strategy/adapter/itemRule/type.js +19 -1
- package/dist/model/strategy/adapter/promotion/index.js +9 -0
- package/dist/modules/Order/index.d.ts +18 -3
- package/dist/modules/Order/index.js +885 -485
- package/dist/modules/Order/salesNotes.d.ts +31 -0
- package/dist/modules/Order/salesNotes.js +492 -0
- package/dist/modules/Order/types.d.ts +91 -5
- package/dist/modules/Order/types.js +5 -0
- package/dist/modules/Order/utils.d.ts +12 -0
- package/dist/modules/Order/utils.js +75 -26
- package/dist/modules/ProductList/index.d.ts +2 -1
- package/dist/modules/ProductList/index.js +100 -20
- package/dist/modules/ProductList/types.d.ts +10 -0
- package/dist/server/index.d.ts +6 -0
- package/dist/server/index.js +43 -3
- package/dist/solution/BaseSales/index.d.ts +9 -1
- package/dist/solution/BaseSales/index.js +894 -706
- package/dist/solution/BookingByStep/index.d.ts +2 -2
- package/dist/solution/BookingTicket/utils/orderCustomer.js +3 -2
- package/dist/solution/RegisterAndLogin/config.d.ts +9 -3
- package/dist/solution/RegisterAndLogin/config.js +95 -40
- package/dist/solution/RegisterAndLogin/index.js +4 -1
- package/dist/solution/ScanOrder/index.d.ts +1 -0
- package/dist/solution/ScanOrder/index.js +31 -27
- package/dist/solution/ScanOrder/utils.d.ts +1 -0
- package/dist/solution/ScanOrder/utils.js +2 -0
- package/dist/solution/UnifiedBookingSales/index.d.ts +15 -2
- package/dist/solution/UnifiedBookingSales/index.js +751 -483
- package/dist/solution/UnifiedBookingSales/types.d.ts +14 -1
- package/dist/solution/VenueBooking/index.d.ts +1 -0
- package/dist/solution/VenueBooking/index.js +8 -4
- package/lib/model/strategy/adapter/itemRule/adapter.d.ts +4 -1
- package/lib/model/strategy/adapter/itemRule/adapter.js +73 -4
- package/lib/model/strategy/adapter/itemRule/evaluator.d.ts +8 -1
- package/lib/model/strategy/adapter/itemRule/evaluator.js +23 -1
- package/lib/model/strategy/adapter/itemRule/type.d.ts +44 -0
- package/lib/model/strategy/adapter/itemRule/type.js +19 -1
- package/lib/modules/Order/index.d.ts +18 -3
- package/lib/modules/Order/index.js +325 -28
- package/lib/modules/Order/salesNotes.d.ts +31 -0
- package/lib/modules/Order/salesNotes.js +382 -0
- package/lib/modules/Order/types.d.ts +91 -5
- package/lib/modules/Order/types.js +4 -0
- package/lib/modules/Order/utils.d.ts +12 -0
- package/lib/modules/Order/utils.js +68 -16
- package/lib/modules/ProductList/index.d.ts +2 -1
- package/lib/modules/ProductList/index.js +47 -2
- package/lib/modules/ProductList/types.d.ts +10 -0
- package/lib/server/index.d.ts +6 -0
- package/lib/server/index.js +37 -3
- package/lib/solution/BaseSales/index.d.ts +9 -1
- package/lib/solution/BaseSales/index.js +105 -1
- package/lib/solution/BookingByStep/index.d.ts +2 -2
- package/lib/solution/BookingTicket/utils/orderCustomer.js +2 -1
- package/lib/solution/RegisterAndLogin/config.d.ts +9 -3
- package/lib/solution/RegisterAndLogin/config.js +49 -8
- package/lib/solution/RegisterAndLogin/index.js +4 -1
- package/lib/solution/ScanOrder/index.d.ts +1 -0
- package/lib/solution/ScanOrder/index.js +5 -1
- package/lib/solution/ScanOrder/utils.d.ts +1 -0
- package/lib/solution/ScanOrder/utils.js +1 -0
- package/lib/solution/UnifiedBookingSales/index.d.ts +15 -2
- package/lib/solution/UnifiedBookingSales/index.js +125 -1
- package/lib/solution/UnifiedBookingSales/types.d.ts +14 -1
- package/lib/solution/VenueBooking/index.d.ts +1 -0
- package/lib/solution/VenueBooking/index.js +5 -1
- package/package.json +1 -1
|
@@ -101,6 +101,7 @@ Object.defineProperty(exports, "resolveSafeProductNum", {
|
|
|
101
101
|
}
|
|
102
102
|
});
|
|
103
103
|
exports.resolveSubmitCollectPax = resolveSubmitCollectPax;
|
|
104
|
+
exports.resolveSubmitOrderType = resolveSubmitOrderType;
|
|
104
105
|
Object.defineProperty(exports, "shouldBuildManualProductDiscount", {
|
|
105
106
|
enumerable: true,
|
|
106
107
|
get: function () {
|
|
@@ -125,6 +126,7 @@ var _decimal = _interopRequireDefault(require("decimal.js"));
|
|
|
125
126
|
var _utils = require("../Holder/utils");
|
|
126
127
|
var _utils2 = require("../../solution/ScanOrder/utils");
|
|
127
128
|
var _orderCollectionIdentity = require("./utils/orderCollectionIdentity");
|
|
129
|
+
var _salesNotes = require("./salesNotes");
|
|
128
130
|
var _manualProductDiscount = require("./utils/manualProductDiscount");
|
|
129
131
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
130
132
|
/**
|
|
@@ -1127,6 +1129,7 @@ function createDefaultTempOrder(params) {
|
|
|
1127
1129
|
request_unique_idempotency_token: '',
|
|
1128
1130
|
vouchers: [],
|
|
1129
1131
|
products: [],
|
|
1132
|
+
notes: [],
|
|
1130
1133
|
bookings: [],
|
|
1131
1134
|
payments: [],
|
|
1132
1135
|
surcharges: [],
|
|
@@ -1136,10 +1139,58 @@ function createDefaultTempOrder(params) {
|
|
|
1136
1139
|
holder: null,
|
|
1137
1140
|
metadata: {},
|
|
1138
1141
|
_extend: {
|
|
1139
|
-
productsByUid: {}
|
|
1142
|
+
productsByUid: {},
|
|
1143
|
+
salesNotesState: {
|
|
1144
|
+
loaded: true,
|
|
1145
|
+
dirty: false
|
|
1146
|
+
}
|
|
1140
1147
|
}
|
|
1141
1148
|
};
|
|
1142
1149
|
}
|
|
1150
|
+
function hasBoundBookingResource(bookings) {
|
|
1151
|
+
if (!Array.isArray(bookings)) return false;
|
|
1152
|
+
return bookings.some(booking => {
|
|
1153
|
+
if (!booking || typeof booking !== 'object') return false;
|
|
1154
|
+
if (Number(booking.parent_id) === 0) return false;
|
|
1155
|
+
const resources = booking.resources;
|
|
1156
|
+
if (!Array.isArray(resources)) return false;
|
|
1157
|
+
return resources.some(resource => {
|
|
1158
|
+
if (!resource || typeof resource !== 'object') return false;
|
|
1159
|
+
const relationId = String(resource.relation_id ?? '').trim();
|
|
1160
|
+
return relationId !== '' && relationId !== '0';
|
|
1161
|
+
});
|
|
1162
|
+
});
|
|
1163
|
+
}
|
|
1164
|
+
function isPersistedSubmitOrderId(orderId) {
|
|
1165
|
+
if (orderId === undefined || orderId === null || orderId === '') return false;
|
|
1166
|
+
const normalizedOrderId = Number(orderId);
|
|
1167
|
+
return Number.isFinite(normalizedOrderId) && normalizedOrderId > 0;
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
/**
|
|
1171
|
+
* 解析 checkout 的订单类型。
|
|
1172
|
+
* dine_in 普通落库单在新增桌台资源后,即使原类型仍是 virtual,也必须按 table-order 提交。
|
|
1173
|
+
*/
|
|
1174
|
+
function resolveSubmitOrderType(params) {
|
|
1175
|
+
const {
|
|
1176
|
+
requestedType,
|
|
1177
|
+
tempOrderType,
|
|
1178
|
+
orderId,
|
|
1179
|
+
businessCode,
|
|
1180
|
+
tempOrderBusinessCode,
|
|
1181
|
+
bookings
|
|
1182
|
+
} = params;
|
|
1183
|
+
const currentType = requestedType ?? tempOrderType;
|
|
1184
|
+
const resolvedBusinessCode = businessCode ?? tempOrderBusinessCode;
|
|
1185
|
+
if (isPersistedSubmitOrderId(orderId) && resolvedBusinessCode === 'dine_in' && currentType === 'virtual' && hasBoundBookingResource(bookings)) {
|
|
1186
|
+
return 'table-order';
|
|
1187
|
+
}
|
|
1188
|
+
if (currentType) return currentType;
|
|
1189
|
+
if (Array.isArray(bookings) && bookings.length > 0) {
|
|
1190
|
+
return businessCode === 'dine_in' ? 'table-order' : 'appointment_booking';
|
|
1191
|
+
}
|
|
1192
|
+
return 'virtual';
|
|
1193
|
+
}
|
|
1143
1194
|
function buildSubmitPayload(params) {
|
|
1144
1195
|
const {
|
|
1145
1196
|
tempOrder,
|
|
@@ -1173,22 +1224,18 @@ function buildSubmitPayload(params) {
|
|
|
1173
1224
|
total_refund_amount: _totalRefundAmount,
|
|
1174
1225
|
create_date: _createDate,
|
|
1175
1226
|
holder_id: _holderId,
|
|
1227
|
+
notes: _notes,
|
|
1176
1228
|
...tempOrderRest
|
|
1177
1229
|
} = tempOrder;
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
}
|
|
1188
|
-
} else {
|
|
1189
|
-
submitType = 'virtual';
|
|
1190
|
-
}
|
|
1191
|
-
}
|
|
1230
|
+
const resolvedBusinessCode = businessCode ?? tempOrder.business_code;
|
|
1231
|
+
const submitType = resolveSubmitOrderType({
|
|
1232
|
+
requestedType: type,
|
|
1233
|
+
tempOrderType: tempOrder.type,
|
|
1234
|
+
orderId: tempOrder.order_id,
|
|
1235
|
+
businessCode,
|
|
1236
|
+
tempOrderBusinessCode: tempOrder.business_code,
|
|
1237
|
+
bookings: tempOrder.bookings
|
|
1238
|
+
});
|
|
1192
1239
|
const payload = {
|
|
1193
1240
|
...tempOrderRest,
|
|
1194
1241
|
customer_id: tempOrder.customer_id ?? 1,
|
|
@@ -1202,7 +1249,7 @@ function buildSubmitPayload(params) {
|
|
|
1202
1249
|
platform: normalizeSubmitPlatform(platform),
|
|
1203
1250
|
request_unique_idempotency_token: params?.request_unique_idempotency_token || tempOrder.request_unique_idempotency_token || `${tempOrder.external_sale_number}_${now.getTime()}`,
|
|
1204
1251
|
type: submitType,
|
|
1205
|
-
business_code:
|
|
1252
|
+
business_code: resolvedBusinessCode,
|
|
1206
1253
|
sales_channel: tempOrder.sales_channel || 'my_pisel',
|
|
1207
1254
|
order_sales_channel: channel ?? tempOrder.order_sales_channel ?? 'online_store',
|
|
1208
1255
|
status: tempOrder.status || 'normal',
|
|
@@ -1235,6 +1282,11 @@ function buildSubmitPayload(params) {
|
|
|
1235
1282
|
...rest
|
|
1236
1283
|
};
|
|
1237
1284
|
})(),
|
|
1285
|
+
...(tempOrder._extend?.salesNotesState?.dirty ? {
|
|
1286
|
+
notes: (0, _salesNotes.encodeSalesNotes)(tempOrder.notes || [], {
|
|
1287
|
+
allowUnresolvedOrderTarget: true
|
|
1288
|
+
})
|
|
1289
|
+
} : {}),
|
|
1238
1290
|
products: (tempOrder.products || []).map(product => normalizeSubmitProduct(product))
|
|
1239
1291
|
};
|
|
1240
1292
|
if (!enhance) return payload;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Module, PisellCore } from '../../types';
|
|
2
2
|
import { BaseModule } from '../BaseModule';
|
|
3
|
-
import { ProductListLoadProductsParams } from './types';
|
|
3
|
+
import { ProductListLoadProductsParams, ProductListStoreQueryParams } from './types';
|
|
4
4
|
import { ProductData } from '../Product/types';
|
|
5
5
|
export * from './types';
|
|
6
6
|
export declare class ProductList extends BaseModule implements Module {
|
|
@@ -52,6 +52,7 @@ export declare class ProductList extends BaseModule implements Module {
|
|
|
52
52
|
getRawProductPriceSources(ids: number[]): Map<number, ProductData>;
|
|
53
53
|
getProducts(): Promise<ProductData[]>;
|
|
54
54
|
getProduct(id: number): Promise<ProductData | undefined>;
|
|
55
|
+
queryProducts(params?: ProductListStoreQueryParams): Promise<ProductData[]>;
|
|
55
56
|
getProductByIds(ids: number[]): Promise<ProductData[] | undefined>;
|
|
56
57
|
addProduct(products: ProductData[]): Promise<void>;
|
|
57
58
|
selectProducts(products: ProductData[]): Promise<void>;
|
|
@@ -25,6 +25,15 @@ Object.keys(_types).forEach(function (key) {
|
|
|
25
25
|
});
|
|
26
26
|
});
|
|
27
27
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
28
|
+
function normalizeQuerySet(values) {
|
|
29
|
+
if (!Array.isArray(values) || values.length === 0) return null;
|
|
30
|
+
const normalized = values.map(value => String(value ?? '').trim()).filter(Boolean);
|
|
31
|
+
return normalized.length ? new Set(normalized) : null;
|
|
32
|
+
}
|
|
33
|
+
function matchesAny(values, querySet) {
|
|
34
|
+
if (!querySet) return true;
|
|
35
|
+
return values.some(value => querySet.has(String(value ?? '').trim()));
|
|
36
|
+
}
|
|
28
37
|
class ProductList extends _BaseModule.BaseModule {
|
|
29
38
|
defaultName = 'productList';
|
|
30
39
|
defaultVersion = '1.0.0';
|
|
@@ -281,10 +290,46 @@ class ProductList extends _BaseModule.BaseModule {
|
|
|
281
290
|
const product = this.store.list.find(product => product.id === id);
|
|
282
291
|
return product ? (0, _lodashEs.cloneDeep)(product) : undefined;
|
|
283
292
|
}
|
|
293
|
+
async queryProducts(params = {}) {
|
|
294
|
+
const includeIds = normalizeQuerySet(params.includeIds);
|
|
295
|
+
const excludeIds = normalizeQuerySet(params.excludeIds);
|
|
296
|
+
const categoryIds = normalizeQuerySet(params.categoryIds);
|
|
297
|
+
const collectionIds = normalizeQuerySet(params.collectionIds);
|
|
298
|
+
const extensionTypes = normalizeQuerySet(params.extensionTypes);
|
|
299
|
+
const statuses = normalizeQuerySet(params.statuses);
|
|
300
|
+
const channelApplications = normalizeQuerySet(params.channelApplications);
|
|
301
|
+
const codeOrBarcode = typeof params.codeOrBarcode === 'string' ? params.codeOrBarcode.trim() : '';
|
|
302
|
+
const products = (this.store.list || []).filter(product => {
|
|
303
|
+
const productId = String(product.id ?? '').trim();
|
|
304
|
+
if (includeIds && !includeIds.has(productId)) return false;
|
|
305
|
+
if (excludeIds && excludeIds.has(productId)) return false;
|
|
306
|
+
if (categoryIds) {
|
|
307
|
+
const productCategoryIds = (product.categories || []).flatMap(category => [category?.id, category?.pivot?.product_category_id]);
|
|
308
|
+
if (!matchesAny(productCategoryIds, categoryIds)) return false;
|
|
309
|
+
}
|
|
310
|
+
if (collectionIds) {
|
|
311
|
+
const productCollectionIds = (product.collection || []).map(collection => collection?.id);
|
|
312
|
+
if (!matchesAny(productCollectionIds, collectionIds)) return false;
|
|
313
|
+
}
|
|
314
|
+
if (extensionTypes && !extensionTypes.has(String(product.extension_type ?? '').trim())) return false;
|
|
315
|
+
if (statuses && !statuses.has(String(product.status ?? '').trim())) return false;
|
|
316
|
+
if (channelApplications) {
|
|
317
|
+
if (!matchesAny(product.channel_application || [], channelApplications)) return false;
|
|
318
|
+
}
|
|
319
|
+
if (codeOrBarcode) {
|
|
320
|
+
const code = typeof product.code === 'string' ? product.code.trim() : '';
|
|
321
|
+
const barcode = typeof product.barcode === 'string' ? product.barcode.trim() : '';
|
|
322
|
+
if (code !== codeOrBarcode && barcode !== codeOrBarcode) return false;
|
|
323
|
+
}
|
|
324
|
+
return true;
|
|
325
|
+
});
|
|
326
|
+
return (0, _lodashEs.cloneDeep)(products);
|
|
327
|
+
}
|
|
284
328
|
async getProductByIds(ids) {
|
|
285
329
|
await this.core.effects.emit(`${this.name}:onGetProductByIds`, this.store.list);
|
|
286
|
-
|
|
287
|
-
|
|
330
|
+
return this.queryProducts({
|
|
331
|
+
includeIds: ids
|
|
332
|
+
});
|
|
288
333
|
}
|
|
289
334
|
async addProduct(products) {
|
|
290
335
|
// list 需要根据 id 去重
|
|
@@ -15,6 +15,16 @@ export interface ProductListLoadProductsParams {
|
|
|
15
15
|
/** 智能定价条件上下文,仅影响策略命中,不参与商品集合筛选 */
|
|
16
16
|
strategy_context?: Record<string, any>;
|
|
17
17
|
}
|
|
18
|
+
export interface ProductListStoreQueryParams {
|
|
19
|
+
includeIds?: Array<number | string>;
|
|
20
|
+
excludeIds?: Array<number | string>;
|
|
21
|
+
categoryIds?: Array<number | string>;
|
|
22
|
+
collectionIds?: Array<number | string>;
|
|
23
|
+
extensionTypes?: string[];
|
|
24
|
+
statuses?: ProductData['status'][];
|
|
25
|
+
channelApplications?: string[];
|
|
26
|
+
codeOrBarcode?: string;
|
|
27
|
+
}
|
|
18
28
|
export interface ProductListData {
|
|
19
29
|
list: ProductData[];
|
|
20
30
|
selectProducts: ProductData[];
|
package/lib/server/index.d.ts
CHANGED
|
@@ -520,6 +520,12 @@ declare class Server {
|
|
|
520
520
|
private stringifyCheckoutResourceIdentifier;
|
|
521
521
|
private normalizeCheckoutSubmitData;
|
|
522
522
|
private ensureCheckoutOrderNumbers;
|
|
523
|
+
/**
|
|
524
|
+
* Notes 允许在本地草稿阶段暂存空订单目标;checkout 的统一出口负责用最终
|
|
525
|
+
* shop_order_number 完成绑定并校验,保证后端请求、pending、设备任务和打印
|
|
526
|
+
* 都使用同一份完整快照。
|
|
527
|
+
*/
|
|
528
|
+
private finalizeCheckoutSalesNotes;
|
|
523
529
|
private dispatchCheckoutSyncTask;
|
|
524
530
|
private dispatchPrintOtherReceiptTask;
|
|
525
531
|
private buildPrintOtherReceiptIdempotencyKey;
|
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 _salesNotes = require("../modules/Order/salesNotes");
|
|
30
31
|
var _modules = require("./modules");
|
|
31
32
|
Object.keys(_modules).forEach(function (key) {
|
|
32
33
|
if (key === "default" || key === "__esModule") return;
|
|
@@ -3585,14 +3586,16 @@ class Server {
|
|
|
3585
3586
|
};
|
|
3586
3587
|
const needsShopOrderNumber = next.shop_order_number === undefined || next.shop_order_number === null || next.shop_order_number === '';
|
|
3587
3588
|
const needsShopFullOrderNumber = next.shop_full_order_number === undefined || next.shop_full_order_number === null || next.shop_full_order_number === '';
|
|
3588
|
-
if (!needsShopOrderNumber && !needsShopFullOrderNumber)
|
|
3589
|
+
if (!needsShopOrderNumber && !needsShopFullOrderNumber) {
|
|
3590
|
+
return this.finalizeCheckoutSalesNotes(next, title);
|
|
3591
|
+
}
|
|
3589
3592
|
const idGenerator = this.getIdGeneratorPlugin();
|
|
3590
3593
|
if (!idGenerator) {
|
|
3591
3594
|
this.logWarning(`${title}: idGenerator 插件不可用,无法生成订单号`, {
|
|
3592
3595
|
needsShopOrderNumber,
|
|
3593
3596
|
needsShopFullOrderNumber
|
|
3594
3597
|
});
|
|
3595
|
-
return next;
|
|
3598
|
+
return this.finalizeCheckoutSalesNotes(next, title);
|
|
3596
3599
|
}
|
|
3597
3600
|
try {
|
|
3598
3601
|
if (needsShopOrderNumber && idGenerator.generateShopOrderNumber) {
|
|
@@ -3614,7 +3617,38 @@ class Server {
|
|
|
3614
3617
|
error: error instanceof Error ? error.message : String(error)
|
|
3615
3618
|
});
|
|
3616
3619
|
}
|
|
3617
|
-
return next;
|
|
3620
|
+
return this.finalizeCheckoutSalesNotes(next, title);
|
|
3621
|
+
}
|
|
3622
|
+
|
|
3623
|
+
/**
|
|
3624
|
+
* Notes 允许在本地草稿阶段暂存空订单目标;checkout 的统一出口负责用最终
|
|
3625
|
+
* shop_order_number 完成绑定并校验,保证后端请求、pending、设备任务和打印
|
|
3626
|
+
* 都使用同一份完整快照。
|
|
3627
|
+
*/
|
|
3628
|
+
finalizeCheckoutSalesNotes(data, title) {
|
|
3629
|
+
if (!data || typeof data !== 'object') return data;
|
|
3630
|
+
if (!Object.prototype.hasOwnProperty.call(data, 'notes')) return data;
|
|
3631
|
+
if (data.notes === undefined || data.notes === null) return data;
|
|
3632
|
+
if (!Array.isArray(data.notes)) {
|
|
3633
|
+
throw new Error('[Order Notes] checkout notes 必须为数组');
|
|
3634
|
+
}
|
|
3635
|
+
if (data.notes.length === 0) return data;
|
|
3636
|
+
const productTargetUuids = (Array.isArray(data.products) ? data.products : []).map(product => product?.metadata?.unique_identification_number ?? product?.unique_identification_number).filter(targetUuid => targetUuid !== undefined && targetUuid !== null && String(targetUuid).trim().length > 0).map(targetUuid => String(targetUuid));
|
|
3637
|
+
const shopOrderNumber = String(data.shop_order_number ?? '').trim();
|
|
3638
|
+
const notes = (0, _salesNotes.finalizeSalesNotesForCheckout)({
|
|
3639
|
+
notes: data.notes,
|
|
3640
|
+
shopOrderNumber,
|
|
3641
|
+
productTargetUuids
|
|
3642
|
+
});
|
|
3643
|
+
this.logInfo(`${title}: checkout Notes 已绑定订单号`, {
|
|
3644
|
+
shop_order_number: shopOrderNumber,
|
|
3645
|
+
note_count: notes.length
|
|
3646
|
+
});
|
|
3647
|
+
return {
|
|
3648
|
+
...data,
|
|
3649
|
+
shop_order_number: shopOrderNumber,
|
|
3650
|
+
notes
|
|
3651
|
+
};
|
|
3618
3652
|
}
|
|
3619
3653
|
async dispatchCheckoutSyncTask(params) {
|
|
3620
3654
|
this.registerDeviceTaskActions();
|
|
@@ -2,7 +2,7 @@ import { Module, ModuleOptions, PisellCore } from '../../types';
|
|
|
2
2
|
import { BaseModule } from '../../modules/BaseModule';
|
|
3
3
|
import { BaseSalesOrderProduct, BaseSalesOrderProductIdentity, BaseSalesPaymentStatus, BaseSalesUpdateOrderProductQuantityParams, BaseSalesCalculateProductBookingPriceParams, BaseSalesPriceRecalculationContextChange, BaseSalesProductBookingPriceResult, BaseSalesQuotationCustomerScopeInfo, BaseSalesScanCodeResult, BaseSalesCashPaymentConfig, BaseSalesPayCashParams, BaseSalesPayCashResult, BaseSalesCommitPaymentMethodParams, BaseSalesCommitPaymentMethodResult, BaseSalesConfirmWalletPaymentResult } from './types';
|
|
4
4
|
import { OrderModule } from '../../modules/Order';
|
|
5
|
-
import type { AddProductBookingInput, AddProductToOrderOptions, LoadSalesDetailParams, OrderPaymentData, OrderPaymentUpdateOptions, OrderPaymentUpdateResult, OrderPaymentSource, SendCustomerPayLinkParams, SyncPaymentsToOrderParams, SyncPaymentsToOrderResult, UpdateTempOrderCustomerInput, UpdateOrderBookingParams, UpdateOrderProductParams, OrderTempOrder, OrderSummary, OrderPromotionEvaluator, OrderGiftSelectResolver, OrderUnfulfilledPromotion, OrderLastGiftActions, RemoveProductsFromOrderOptions, ReplaceTempOrderOptions } from '../../modules/Order/types';
|
|
5
|
+
import type { AddProductBookingInput, AddProductToOrderOptions, LoadSalesDetailParams, OrderPaymentData, OrderPaymentUpdateOptions, OrderPaymentUpdateResult, OrderPaymentSource, SendCustomerPayLinkParams, SyncPaymentsToOrderParams, SyncPaymentsToOrderResult, UpdateTempOrderCustomerInput, UpdateOrderBookingParams, UpdateOrderProductParams, OrderTempOrder, OrderSummary, OrderPromotionEvaluator, OrderGiftSelectResolver, OrderUnfulfilledPromotion, OrderLastGiftActions, RemoveProductsFromOrderOptions, ReplaceTempOrderOptions, SalesNote, SalesNotesMutationSnapshot, SetSalesNoteInput, PickupReferenceMode, ShopServiceData, ShopServiceType } from '../../modules/Order/types';
|
|
6
6
|
import type { SubmitPayloadEnhancer } from '../../modules/Order/utils';
|
|
7
7
|
import type { Discount } from '../../modules/Discount/types';
|
|
8
8
|
import { RequestPlugin, WindowPlugin } from '../../plugins';
|
|
@@ -225,12 +225,20 @@ export declare class BaseSalesImpl extends BaseModule implements Module {
|
|
|
225
225
|
getOrderSyncState(): import("../../modules/Order/types").OrderSyncState;
|
|
226
226
|
getOrderAmountSnapshot(): import("../../modules/Order/types").OrderAmountSnapshot | null;
|
|
227
227
|
getTempOrderNote(): string;
|
|
228
|
+
getSalesNotes(): SalesNote[];
|
|
229
|
+
createSalesNotesMutationSnapshot(): SalesNotesMutationSnapshot;
|
|
230
|
+
restoreSalesNotesMutationSnapshot(snapshot: SalesNotesMutationSnapshot): void;
|
|
231
|
+
setSalesNote(input: SetSalesNoteInput): Promise<SalesNote>;
|
|
232
|
+
removeSalesNote(uuid: string): Promise<void>;
|
|
233
|
+
clearSalesNotes(): Promise<void>;
|
|
228
234
|
updateTempOrderNote(note: string): string;
|
|
229
235
|
updateTempOrderNote(note: string, sync: true): Promise<string>;
|
|
230
236
|
updateTempOrderNote(note: string, sync: boolean): string | Promise<string>;
|
|
231
237
|
updateRemoteOrderNote(orderId: number | string, note: string): void;
|
|
232
238
|
updateTempOrderShopDiscount(amount: string | number): string;
|
|
233
239
|
updateTempOrderDepositAmount(amount: string | number): OrderSummary;
|
|
240
|
+
setPickupReferenceMode(mode: PickupReferenceMode): ShopServiceData;
|
|
241
|
+
setServiceType(serviceType: ShopServiceType): ShopServiceData;
|
|
234
242
|
updateTempOrderContactsInfo(contactsInfo: Record<string, any> | null): Record<string, any> | null;
|
|
235
243
|
/** @deprecated OrderModule 不再负责 tempOrder localStorage 持久化。 */
|
|
236
244
|
setEnableTempOrderPersist(enabled: boolean): void;
|
|
@@ -283,7 +283,56 @@ function mergeBaseSalesUniqueArray(currentValue, loadedValue, metadataKey) {
|
|
|
283
283
|
loadedValue.forEach(appendOrReplaceByUid);
|
|
284
284
|
return result;
|
|
285
285
|
}
|
|
286
|
+
|
|
287
|
+
// checkout / realtime snapshots may reorder protocol arrays or append persistence fields.
|
|
288
|
+
// Compare only the Sales Note protocol fields so a matching remote echo can acknowledge dirty state.
|
|
289
|
+
function normalizeBaseSalesNotesForComparison(value, options) {
|
|
290
|
+
if (!Array.isArray(value)) return null;
|
|
291
|
+
const unresolvedOrderTargetUuid = String(options?.unresolvedOrderTargetUuid ?? '').trim();
|
|
292
|
+
return value.map(note => {
|
|
293
|
+
if (!note || typeof note !== 'object' || Array.isArray(note)) {
|
|
294
|
+
return (0, _lodashEs.cloneDeep)(note);
|
|
295
|
+
}
|
|
296
|
+
const noteRecord = note;
|
|
297
|
+
const relations = Array.isArray(noteRecord.note_relations) ? noteRecord.note_relations.map(relation => {
|
|
298
|
+
if (!relation || typeof relation !== 'object' || Array.isArray(relation)) {
|
|
299
|
+
return (0, _lodashEs.cloneDeep)(relation);
|
|
300
|
+
}
|
|
301
|
+
const shouldResolveOrderTarget = relation.is_primary === 0 && relation.relation_type === 'related_to' && relation.target_type === 'order' && String(relation.target_uuid ?? '').trim() === '' && unresolvedOrderTargetUuid.length > 0;
|
|
302
|
+
return {
|
|
303
|
+
uuid: relation.uuid,
|
|
304
|
+
relation_type: relation.relation_type,
|
|
305
|
+
target_type: relation.target_type,
|
|
306
|
+
target_uuid: shouldResolveOrderTarget ? unresolvedOrderTargetUuid : relation.target_uuid,
|
|
307
|
+
is_primary: relation.is_primary
|
|
308
|
+
};
|
|
309
|
+
}).sort((left, right) => String(left?.uuid ?? '').localeCompare(String(right?.uuid ?? ''))) : (0, _lodashEs.cloneDeep)(noteRecord.note_relations);
|
|
310
|
+
return {
|
|
311
|
+
uuid: noteRecord.uuid,
|
|
312
|
+
note_type: noteRecord.note_type,
|
|
313
|
+
content: {
|
|
314
|
+
text: (0, _lodashEs.cloneDeep)(noteRecord.content?.text)
|
|
315
|
+
},
|
|
316
|
+
importance: noteRecord.importance,
|
|
317
|
+
note_relations: relations
|
|
318
|
+
};
|
|
319
|
+
}).sort((left, right) => String(left?.uuid ?? '').localeCompare(String(right?.uuid ?? '')));
|
|
320
|
+
}
|
|
321
|
+
function areBaseSalesNotesEquivalent(currentValue, loadedValue, options) {
|
|
322
|
+
const currentNotes = normalizeBaseSalesNotesForComparison(currentValue, {
|
|
323
|
+
unresolvedOrderTargetUuid: options?.currentOrderTargetUuid
|
|
324
|
+
});
|
|
325
|
+
const loadedNotes = normalizeBaseSalesNotesForComparison(loadedValue);
|
|
326
|
+
return currentNotes !== null && loadedNotes !== null && (0, _lodashEs.isEqual)(currentNotes, loadedNotes);
|
|
327
|
+
}
|
|
286
328
|
function mergeSalesDetailRecordWithTempOrder(currentTempOrder, loadedRecord, strategy) {
|
|
329
|
+
const loadedHasSalesNotes = Object.prototype.hasOwnProperty.call(loadedRecord || {}, 'notes');
|
|
330
|
+
const hasDirtyLocalSalesNotes = currentTempOrder?._extend?.salesNotesState?.dirty === true;
|
|
331
|
+
const incomingSalesNotesMatchLocal = loadedHasSalesNotes && areBaseSalesNotesEquivalent(currentTempOrder?.notes, loadedRecord.notes, {
|
|
332
|
+
currentOrderTargetUuid: loadedRecord?.shop_order_number || currentTempOrder?.shop_order_number
|
|
333
|
+
});
|
|
334
|
+
const shouldAwaitAuthoritativeSalesNotes = strategy === 'authoritative-incoming' && hasDirtyLocalSalesNotes && (Number(loadedRecord?.need_sync) === 1 || !incomingSalesNotesMatchLocal);
|
|
335
|
+
const preserveDirtyLocalSalesNotes = hasDirtyLocalSalesNotes && (strategy === 'preserve-local' || shouldAwaitAuthoritativeSalesNotes);
|
|
287
336
|
const normalizedLoadedRecord = normalizeBaseSalesRecordCollections(loadedRecord || {}, {
|
|
288
337
|
ensureUid: false
|
|
289
338
|
});
|
|
@@ -295,6 +344,12 @@ function mergeSalesDetailRecordWithTempOrder(currentTempOrder, loadedRecord, str
|
|
|
295
344
|
});
|
|
296
345
|
const uidRemaps = [];
|
|
297
346
|
const mergedRecord = (0, _lodashEs.mergeWith)(normalizedCurrentTempOrder, normalizedLoadedRecord, (currentValue, loadedValue, key) => {
|
|
347
|
+
if (key === 'notes') {
|
|
348
|
+
if (preserveDirtyLocalSalesNotes && Array.isArray(currentValue)) {
|
|
349
|
+
return (0, _lodashEs.cloneDeep)(currentValue);
|
|
350
|
+
}
|
|
351
|
+
if (Array.isArray(loadedValue)) return (0, _lodashEs.cloneDeep)(loadedValue);
|
|
352
|
+
}
|
|
298
353
|
const collectionKind = getBaseSalesOrderCollectionKind(key);
|
|
299
354
|
if (collectionKind && Array.isArray(loadedValue)) {
|
|
300
355
|
return mergeBaseSalesOrderCollection(collectionKind, Array.isArray(currentValue) ? currentValue : [], loadedValue, strategy, uidRemaps);
|
|
@@ -318,7 +373,24 @@ function mergeSalesDetailRecordWithTempOrder(currentTempOrder, loadedRecord, str
|
|
|
318
373
|
return undefined;
|
|
319
374
|
});
|
|
320
375
|
delete mergedRecord.request_unique_idempotency_token;
|
|
321
|
-
|
|
376
|
+
const normalizedMergedRecord = normalizeBaseSalesRecordCollections((0, _orderCollectionIdentity.applyOrderCollectionUidRemaps)(mergedRecord, uidRemaps));
|
|
377
|
+
normalizedMergedRecord._extend = {
|
|
378
|
+
...(normalizedMergedRecord._extend || {}),
|
|
379
|
+
salesNotesState: preserveDirtyLocalSalesNotes ? {
|
|
380
|
+
loaded: true,
|
|
381
|
+
dirty: true
|
|
382
|
+
} : loadedHasSalesNotes ? {
|
|
383
|
+
loaded: true,
|
|
384
|
+
dirty: normalizedLoadedRecord._extend?.salesNotesState?.dirty === true
|
|
385
|
+
} : {
|
|
386
|
+
loaded: false,
|
|
387
|
+
dirty: false
|
|
388
|
+
}
|
|
389
|
+
};
|
|
390
|
+
if (!loadedHasSalesNotes && !preserveDirtyLocalSalesNotes) {
|
|
391
|
+
delete normalizedMergedRecord.notes;
|
|
392
|
+
}
|
|
393
|
+
return normalizedMergedRecord;
|
|
322
394
|
}
|
|
323
395
|
function filterPendingPaymentsFromLoadedSalesDetail(sourceRecord) {
|
|
324
396
|
if (!sourceRecord || typeof sourceRecord !== 'object') return sourceRecord;
|
|
@@ -1426,6 +1498,30 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
1426
1498
|
if (!this.store.order) return '';
|
|
1427
1499
|
return this.store.order.getTempOrderNote();
|
|
1428
1500
|
}
|
|
1501
|
+
getSalesNotes() {
|
|
1502
|
+
if (!this.store.order) return [];
|
|
1503
|
+
return this.store.order.getSalesNotes();
|
|
1504
|
+
}
|
|
1505
|
+
createSalesNotesMutationSnapshot() {
|
|
1506
|
+
if (!this.store.order) throw new Error('order 模块未初始化');
|
|
1507
|
+
return this.store.order.createSalesNotesMutationSnapshot();
|
|
1508
|
+
}
|
|
1509
|
+
restoreSalesNotesMutationSnapshot(snapshot) {
|
|
1510
|
+
if (!this.store.order) throw new Error('order 模块未初始化');
|
|
1511
|
+
this.store.order.restoreSalesNotesMutationSnapshot(snapshot);
|
|
1512
|
+
}
|
|
1513
|
+
async setSalesNote(input) {
|
|
1514
|
+
if (!this.store.order) throw new Error('order 模块未初始化');
|
|
1515
|
+
return this.store.order.setSalesNote(input);
|
|
1516
|
+
}
|
|
1517
|
+
async removeSalesNote(uuid) {
|
|
1518
|
+
if (!this.store.order) throw new Error('order 模块未初始化');
|
|
1519
|
+
await this.store.order.removeSalesNote(uuid);
|
|
1520
|
+
}
|
|
1521
|
+
async clearSalesNotes() {
|
|
1522
|
+
if (!this.store.order) throw new Error('order 模块未初始化');
|
|
1523
|
+
await this.store.order.clearSalesNotes();
|
|
1524
|
+
}
|
|
1429
1525
|
updateTempOrderNote(note, sync = false) {
|
|
1430
1526
|
try {
|
|
1431
1527
|
if (!this.store.order) throw new Error('order 模块未初始化');
|
|
@@ -1447,6 +1543,14 @@ class BaseSalesImpl extends _BaseModule.BaseModule {
|
|
|
1447
1543
|
if (!this.store.order) throw new Error('order 模块未初始化');
|
|
1448
1544
|
return this.store.order.updateTempOrderDepositAmount(amount);
|
|
1449
1545
|
}
|
|
1546
|
+
setPickupReferenceMode(mode) {
|
|
1547
|
+
if (!this.store.order) throw new Error('order 模块未初始化');
|
|
1548
|
+
return this.store.order.updateTempOrderPickupReferenceMode(mode);
|
|
1549
|
+
}
|
|
1550
|
+
setServiceType(serviceType) {
|
|
1551
|
+
if (!this.store.order) throw new Error('order 模块未初始化');
|
|
1552
|
+
return this.store.order.updateTempOrderServiceType(serviceType);
|
|
1553
|
+
}
|
|
1450
1554
|
updateTempOrderContactsInfo(contactsInfo) {
|
|
1451
1555
|
if (!this.store.order) throw new Error('order 模块未初始化');
|
|
1452
1556
|
return this.store.order.updateTempOrderContactsInfo(contactsInfo);
|
|
@@ -326,7 +326,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
|
|
|
326
326
|
date: string;
|
|
327
327
|
status: string;
|
|
328
328
|
week: string;
|
|
329
|
-
weekNum: 0 |
|
|
329
|
+
weekNum: 0 | 2 | 1 | 3 | 4 | 5 | 6;
|
|
330
330
|
}[]>;
|
|
331
331
|
submitTimeSlot(timeSlots: TimeSliceItem): void;
|
|
332
332
|
private getScheduleDataByIds;
|
|
@@ -345,7 +345,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
|
|
|
345
345
|
count: number;
|
|
346
346
|
left: number;
|
|
347
347
|
summaryCount: number;
|
|
348
|
-
status: "
|
|
348
|
+
status: "lots_of_space" | "filling_up_fast" | "sold_out";
|
|
349
349
|
}[];
|
|
350
350
|
/**
|
|
351
351
|
* 找到多个资源的公共可用时间段
|
|
@@ -23,7 +23,8 @@ function resolveCustomerDisplayName(customer) {
|
|
|
23
23
|
|
|
24
24
|
/** 将 ICustomer 格式化为写入 tempOrder 的协议字段。 */
|
|
25
25
|
function formatOrderCustomerPatch(customer) {
|
|
26
|
-
const
|
|
26
|
+
const c = customer;
|
|
27
|
+
const rawId = c.customer_id ?? c.customerId ?? customer.id;
|
|
27
28
|
const numericId = typeof rawId === 'number' ? rawId : rawId !== undefined && rawId !== null && rawId !== '' ? Number(rawId) : null;
|
|
28
29
|
return {
|
|
29
30
|
customer_id: Number.isFinite(numericId) ? numericId : null,
|
|
@@ -10,7 +10,11 @@ export interface ApiConfig {
|
|
|
10
10
|
method: 'GET' | 'POST' | 'PUT' | 'DELETE';
|
|
11
11
|
transformParams?: (params: any) => any;
|
|
12
12
|
transformResponse?: (response: any) => any;
|
|
13
|
-
options?: Record<string, any
|
|
13
|
+
options?: Record<string, any> | ((params: any) => Record<string, any>);
|
|
14
|
+
}
|
|
15
|
+
export interface ApiCallerOptions {
|
|
16
|
+
baseUrl?: string;
|
|
17
|
+
shopDomain?: string;
|
|
14
18
|
}
|
|
15
19
|
/**
|
|
16
20
|
* 渠道配置接口
|
|
@@ -65,12 +69,14 @@ export declare function getChannelConfig(channel: string): ChannelConfig;
|
|
|
65
69
|
export declare class ApiCaller {
|
|
66
70
|
private request;
|
|
67
71
|
private config;
|
|
72
|
+
private options;
|
|
68
73
|
constructor(request: {
|
|
69
74
|
get: <T = any>(url: string, data?: any, options?: any) => Promise<T>;
|
|
70
75
|
post: <T = any>(url: string, data?: any, options?: any) => Promise<T>;
|
|
71
76
|
put: <T = any>(url: string, data?: any, options?: any) => Promise<T>;
|
|
72
77
|
delete: <T = any>(url: string, options?: any) => Promise<T>;
|
|
73
|
-
}, config: ChannelConfig);
|
|
78
|
+
}, config: ChannelConfig, options?: ApiCallerOptions);
|
|
79
|
+
private resolveUrl;
|
|
74
80
|
/**
|
|
75
81
|
* 执行 API 调用
|
|
76
82
|
*/
|
|
@@ -84,4 +90,4 @@ export declare function createApiCaller(request: {
|
|
|
84
90
|
post: <T = any>(url: string, data?: any, options?: any) => Promise<T>;
|
|
85
91
|
put: <T = any>(url: string, data?: any, options?: any) => Promise<T>;
|
|
86
92
|
delete: <T = any>(url: string, options?: any) => Promise<T>;
|
|
87
|
-
}, channel: string): ApiCaller;
|
|
93
|
+
}, channel: string, options?: ApiCallerOptions): ApiCaller;
|