@pisell/pisellos 2.2.283 → 2.2.285
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/core/index.js +6 -10
- package/dist/model/strategy/adapter/walletPass/example.js +3 -26
- package/dist/model/strategy/strategy-example.js +5 -19
- package/dist/modules/Cart/index.js +0 -3
- package/dist/modules/Cart/utils/cartProduct.js +0 -1
- package/dist/modules/Date/index.js +1 -5
- package/dist/modules/Discount/index.js +2 -4
- package/dist/modules/OpenData/index.js +0 -2
- package/dist/modules/Order/index.d.ts +1 -1
- package/dist/modules/Order/index.js +64 -86
- package/dist/modules/Order/types.d.ts +3 -1
- package/dist/modules/Order/types.js +1 -0
- package/dist/modules/Payment/index.js +97 -162
- package/dist/modules/ProductList/index.js +91 -65
- package/dist/modules/Rules/index.js +1 -4
- package/dist/modules/Schedule/index.js +0 -1
- package/dist/modules/Schedule/utils.js +0 -1
- package/dist/modules/Step/index.js +0 -1
- package/dist/plugins/request.js +1 -4
- package/dist/plugins/window.js +2 -6
- package/dist/server/index.js +97 -129
- package/dist/server/modules/menu/index.js +32 -41
- package/dist/server/modules/order/index.js +2 -4
- package/dist/server/modules/products/index.js +24 -42
- package/dist/server/modules/quotation/index.js +29 -38
- package/dist/server/modules/resource/index.js +3 -4
- package/dist/server/modules/schedule/index.js +27 -35
- package/dist/server/utils/product.js +0 -1
- package/dist/solution/BaseSales/index.js +115 -76
- package/dist/solution/BookingByStep/index.d.ts +1 -1
- package/dist/solution/BookingByStep/index.js +7 -59
- package/dist/solution/BookingByStep/utils/capacity.js +1 -11
- package/dist/solution/BookingByStep/utils/resources.js +1 -3
- package/dist/solution/BookingByStep/utils/timeslots.js +2 -43
- package/dist/solution/BookingTicket/index.d.ts +6 -16
- package/dist/solution/BookingTicket/index.js +13 -6
- package/dist/solution/BookingTicket/utils/scan/cloudSearch.js +6 -7
- package/dist/solution/BookingTicket/utils/scan/handleScan.js +25 -31
- package/dist/solution/BookingTicket/utils/scan/index.js +6 -10
- package/dist/solution/BuyTickets/index.js +9 -12
- package/dist/solution/Checkout/index.js +177 -252
- package/dist/solution/Checkout/utils/index.js +4 -16
- package/dist/solution/RegisterAndLogin/index.js +30 -76
- package/dist/solution/ScanOrder/index.js +50 -60
- package/dist/solution/ShopDiscount/index.js +2 -7
- package/dist/solution/VenueBooking/index.js +45 -55
- package/dist/utils/task.js +15 -18
- package/dist/utils/watch.js +0 -1
- package/lib/apis/picoding.js +2 -0
- package/lib/core/index.js +131 -132
- package/lib/effects/index.js +46 -57
- package/lib/index.js +82 -49
- package/lib/model/index.js +14 -21
- package/lib/model/strategy/adapter/dataVariant/adapter.js +38 -50
- package/lib/model/strategy/adapter/dataVariant/evaluator.js +162 -236
- package/lib/model/strategy/adapter/dataVariant/examples.js +229 -237
- package/lib/model/strategy/adapter/dataVariant/index.js +39 -34
- package/lib/model/strategy/adapter/dataVariant/type.js +57 -28
- package/lib/model/strategy/adapter/index.js +100 -64
- package/lib/model/strategy/adapter/itemRule/adapter.js +156 -144
- package/lib/model/strategy/adapter/itemRule/evaluator.js +36 -48
- package/lib/model/strategy/adapter/itemRule/examples.js +295 -225
- package/lib/model/strategy/adapter/itemRule/index.js +83 -57
- package/lib/model/strategy/adapter/itemRule/type.js +97 -36
- package/lib/model/strategy/adapter/promotion/adapter.js +91 -69
- package/lib/model/strategy/adapter/promotion/evaluator.js +444 -310
- package/lib/model/strategy/adapter/promotion/examples.js +222 -234
- package/lib/model/strategy/adapter/promotion/index.js +46 -0
- package/lib/model/strategy/adapter/promotion/type.js +243 -36
- package/lib/model/strategy/adapter/type.js +4 -16
- package/lib/model/strategy/adapter/walletPass/evaluator.js +180 -150
- package/lib/model/strategy/adapter/walletPass/example.js +217 -190
- package/lib/model/strategy/adapter/walletPass/index.js +75 -51
- package/lib/model/strategy/adapter/walletPass/locales.js +36 -58
- package/lib/model/strategy/adapter/walletPass/type.js +4 -16
- package/lib/model/strategy/adapter/walletPass/utils.js +588 -378
- package/lib/model/strategy/engine.js +270 -168
- package/lib/model/strategy/index.js +49 -34
- package/lib/model/strategy/strategy-example.js +243 -239
- package/lib/model/strategy/type.js +100 -40
- package/lib/modules/Account/index.js +39 -53
- package/lib/modules/Account/types.js +20 -33
- package/lib/modules/AccountList/index.js +116 -154
- package/lib/modules/AccountList/types.js +30 -31
- package/lib/modules/AccountList/utils.js +18 -30
- package/lib/modules/BaseModule.js +23 -42
- package/lib/modules/BookingContext/index.js +158 -136
- package/lib/modules/BookingContext/types.js +46 -32
- package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +138 -146
- package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +78 -83
- package/lib/modules/BookingContext/utils/cacheItemToBookingInput.js +170 -150
- package/lib/modules/BookingContext/utils/flexible.js +38 -55
- package/lib/modules/BookingContext/utils/formatResourceList.js +19 -34
- package/lib/modules/BookingContext/utils/index.js +124 -41
- package/lib/modules/BookingContext/utils/noResource.js +58 -70
- package/lib/modules/BookingContext/utils/orderLineDisplay.js +14 -41
- package/lib/modules/BookingContext/utils/productExtend.js +202 -155
- package/lib/modules/BookingContext/utils/resourceErrors.js +53 -53
- package/lib/modules/BookingContext/utils/resourceSelection.js +19 -41
- package/lib/modules/BookingContext/utils/resources.js +209 -167
- package/lib/modules/BookingContext/utils/serviceTimes.js +115 -116
- package/lib/modules/BookingContext/utils/timeSlices.js +76 -86
- package/lib/modules/Cart/index.js +170 -124
- package/lib/modules/Cart/types.js +46 -51
- package/lib/modules/Cart/utils/cartAccount.js +40 -39
- package/lib/modules/Cart/utils/cartDate.js +56 -61
- package/lib/modules/Cart/utils/cartDiscount.js +28 -33
- package/lib/modules/Cart/utils/cartNote.js +27 -32
- package/lib/modules/Cart/utils/cartProduct.js +321 -251
- package/lib/modules/Cart/utils/cartRelationForms.js +29 -35
- package/lib/modules/Cart/utils/cartResource.js +70 -78
- package/lib/modules/Cart/utils/changePrice.js +22 -50
- package/lib/modules/Cart/utils/index.js +106 -48
- package/lib/modules/Customer/constants.js +13 -34
- package/lib/modules/Customer/index.js +235 -172
- package/lib/modules/Customer/types.js +38 -35
- package/lib/modules/Date/index.js +116 -115
- package/lib/modules/Date/types.js +16 -28
- package/lib/modules/Date/utils.js +174 -123
- package/lib/modules/Discount/index.js +122 -127
- package/lib/modules/Discount/types.js +9 -31
- package/lib/modules/Guests/index.js +30 -56
- package/lib/modules/Guests/types.js +23 -33
- package/lib/modules/Holder/index.js +209 -189
- package/lib/modules/Holder/types.js +4 -16
- package/lib/modules/Holder/utils.js +20 -49
- package/lib/modules/OpenData/index.js +70 -76
- package/lib/modules/OpenData/types.js +4 -16
- package/lib/modules/OpenData/utils.js +44 -78
- package/lib/modules/Order/index.d.ts +1 -1
- package/lib/modules/Order/index.js +1728 -2123
- package/lib/modules/Order/payment-utils.js +77 -120
- package/lib/modules/Order/types.d.ts +3 -1
- package/lib/modules/Order/types.js +88 -35
- package/lib/modules/Order/utils/bundleDiscountHydration.js +41 -74
- package/lib/modules/Order/utils/discountProductLineIdentity.js +142 -100
- package/lib/modules/Order/utils/manualProductDiscount.js +124 -123
- package/lib/modules/Order/utils/orderCollectionIdentity.js +184 -244
- package/lib/modules/Order/utils.js +814 -647
- package/lib/modules/Payment/cash.js +20 -33
- package/lib/modules/Payment/cashRecommendationAlgorithm.js +145 -76
- package/lib/modules/Payment/eftpos.js +16 -30
- package/lib/modules/Payment/index.js +532 -399
- package/lib/modules/Payment/mx51.js +1 -0
- package/lib/modules/Payment/types.js +230 -108
- package/lib/modules/Payment/utils.js +52 -51
- package/lib/modules/Payment/walletpass.js +485 -660
- package/lib/modules/Product/index.js +51 -46
- package/lib/modules/Product/types.js +4 -16
- package/lib/modules/Product/utils.js +32 -33
- package/lib/modules/ProductList/index.js +119 -123
- package/lib/modules/ProductList/types.js +9 -31
- package/lib/modules/Quotation/index.js +66 -100
- package/lib/modules/Quotation/types.js +4 -16
- package/lib/modules/Resource/index.js +27 -59
- package/lib/modules/Resource/types.js +22 -32
- package/lib/modules/Resource/utils.js +30 -38
- package/lib/modules/ResourcePlanner/index.js +60 -61
- package/lib/modules/ResourcePlanner/planner.js +346 -384
- package/lib/modules/ResourcePlanner/types.js +4 -16
- package/lib/modules/Rules/index.js +1218 -959
- package/lib/modules/Rules/types.js +17 -40
- package/lib/modules/SalesSummary/index.js +85 -90
- package/lib/modules/SalesSummary/types.js +4 -16
- package/lib/modules/SalesSummary/utils.js +355 -430
- package/lib/modules/ScanOrderLogger/index.js +59 -79
- package/lib/modules/ScanOrderLogger/providers/feishu.js +54 -78
- package/lib/modules/ScanOrderLogger/providers/grafana.js +13 -36
- package/lib/modules/ScanOrderLogger/types.js +4 -16
- package/lib/modules/Schedule/getDateIsInSchedule.js +334 -163
- package/lib/modules/Schedule/index.js +100 -114
- package/lib/modules/Schedule/type.js +4 -16
- package/lib/modules/Schedule/types.js +4 -16
- package/lib/modules/Schedule/utils.js +433 -291
- package/lib/modules/Step/index.js +40 -52
- package/lib/modules/Step/tyeps.js +4 -16
- package/lib/modules/Summary/index.js +66 -71
- package/lib/modules/Summary/types.js +4 -16
- package/lib/modules/Summary/utils.js +773 -418
- package/lib/modules/SurchargeList/index.js +46 -60
- package/lib/modules/SurchargeList/types.js +4 -16
- package/lib/modules/index.js +245 -63
- package/lib/plugins/app.js +4 -16
- package/lib/plugins/index.js +36 -25
- package/lib/plugins/request.js +137 -126
- package/lib/plugins/shopStore.js +4 -16
- package/lib/plugins/user.js +4 -16
- package/lib/plugins/window.js +171 -179
- package/lib/server/index.js +3027 -2655
- package/lib/server/modules/floor-plan/index.js +102 -123
- package/lib/server/modules/floor-plan/types.js +15 -30
- package/lib/server/modules/index.js +106 -68
- package/lib/server/modules/menu/index.js +146 -122
- package/lib/server/modules/menu/types.js +18 -31
- package/lib/server/modules/order/index.js +758 -956
- package/lib/server/modules/order/types.js +122 -33
- package/lib/server/modules/order/utils/filterBookings.js +219 -194
- package/lib/server/modules/order/utils/filterOrders.js +118 -92
- package/lib/server/modules/payment/index.js +59 -83
- package/lib/server/modules/payment/types.js +4 -16
- package/lib/server/modules/products/index.js +575 -459
- package/lib/server/modules/products/types.js +44 -34
- package/lib/server/modules/quotation/index.js +137 -172
- package/lib/server/modules/quotation/types.js +21 -31
- package/lib/server/modules/resource/index.js +213 -184
- package/lib/server/modules/resource/types.js +42 -33
- package/lib/server/modules/schedule/index.js +135 -123
- package/lib/server/modules/schedule/types.js +14 -21
- package/lib/server/modules/schedule/utils.js +334 -163
- package/lib/server/types.js +4 -16
- package/lib/server/utils/index.js +25 -23
- package/lib/server/utils/product.js +196 -139
- package/lib/server/utils/schedule.js +34 -41
- package/lib/server/utils/small-ticket.js +479 -456
- package/lib/server/utils/time.js +40 -49
- package/lib/solution/BaseSales/index.js +1220 -1412
- package/lib/solution/BaseSales/types.js +42 -38
- package/lib/solution/BaseSales/utils/cartPromotion.js +650 -502
- package/lib/solution/BaseSales/utils/parseSalesResponse.js +85 -105
- package/lib/solution/BaseSales/utils/quotationPrice.js +56 -114
- package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +108 -145
- package/lib/solution/BaseSales/utils.js +158 -143
- package/lib/solution/BookingByStep/index.d.ts +1 -1
- package/lib/solution/BookingByStep/index.js +1527 -1340
- package/lib/solution/BookingByStep/types.js +40 -99
- package/lib/solution/BookingByStep/utils/capacity.js +192 -160
- package/lib/solution/BookingByStep/utils/products.js +42 -52
- package/lib/solution/BookingByStep/utils/resources.js +527 -330
- package/lib/solution/BookingByStep/utils/stock.js +65 -44
- package/lib/solution/BookingByStep/utils/timeslots.js +129 -131
- package/lib/solution/BookingTicket/index.d.ts +6 -16
- package/lib/solution/BookingTicket/index.js +608 -517
- package/lib/solution/BookingTicket/types.js +99 -77
- package/lib/solution/BookingTicket/utils/addProductDecision.js +225 -187
- package/lib/solution/BookingTicket/utils/addTimeAvailability.js +58 -89
- package/lib/solution/BookingTicket/utils/bookingStatus.js +107 -78
- package/lib/solution/BookingTicket/utils/cartView.js +114 -99
- package/lib/solution/BookingTicket/utils/exampleData.js +185 -0
- package/lib/solution/BookingTicket/utils/orderCustomer.js +18 -41
- package/lib/solution/BookingTicket/utils/resolveBestAddTimePlan.js +219 -86
- package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.js +168 -116
- package/lib/solution/BookingTicket/utils/scan/cloudSearch.js +79 -91
- package/lib/solution/BookingTicket/utils/scan/formatGlobalScan.js +54 -41
- package/lib/solution/BookingTicket/utils/scan/handleScan.js +84 -81
- package/lib/solution/BookingTicket/utils/scan/index.js +98 -104
- package/lib/solution/BookingTicket/utils/scan/scanCache.js +90 -43
- package/lib/solution/BookingTicket/utils/scan/scanProductValues.js +52 -64
- package/lib/solution/BookingTicket/utils/sessionCatalogStale.js +56 -58
- package/lib/solution/BookingTicket/utils/weighingProductSku.js +34 -48
- package/lib/solution/BuyTickets/index.js +67 -70
- package/lib/solution/BuyTickets/types.js +22 -38
- package/lib/solution/Checkout/index.js +1451 -1158
- package/lib/solution/Checkout/types.js +91 -61
- package/lib/solution/Checkout/utils/index.js +228 -156
- package/lib/solution/PlaceOrder/index.js +55 -0
- package/lib/solution/RegisterAndLogin/config.js +493 -460
- package/lib/solution/RegisterAndLogin/index.js +633 -630
- package/lib/solution/RegisterAndLogin/types.js +189 -76
- package/lib/solution/RegisterAndLogin/utils.js +183 -125
- package/lib/solution/Sales/index.js +328 -324
- package/lib/solution/Sales/types.js +27 -33
- package/lib/solution/ScanOrder/index.js +832 -864
- package/lib/solution/ScanOrder/types.js +33 -34
- package/lib/solution/ScanOrder/utils.js +409 -374
- package/lib/solution/ShopDiscount/index.js +226 -232
- package/lib/solution/ShopDiscount/types.js +15 -37
- package/lib/solution/ShopDiscount/utils.js +300 -172
- package/lib/solution/UnifiedBookingSales/index.js +437 -487
- package/lib/solution/UnifiedBookingSales/types.js +12 -31
- package/lib/solution/VenueBooking/index.js +811 -879
- package/lib/solution/VenueBooking/types.js +19 -39
- package/lib/solution/VenueBooking/utils/dateSummary.js +27 -56
- package/lib/solution/VenueBooking/utils/resource.js +31 -54
- package/lib/solution/VenueBooking/utils/slotMerge.js +94 -107
- package/lib/solution/VenueBooking/utils/timeSlot.js +132 -132
- package/lib/solution/VenueBooking/utils.js +130 -67
- package/lib/solution/index.js +124 -41
- package/lib/store/createStore.js +32 -29
- package/lib/types/index.js +4 -16
- package/lib/utils/payment-number.js +26 -46
- package/lib/utils/task.js +36 -36
- package/lib/utils/watch.js +81 -47
- package/package.json +2 -1
|
@@ -1,200 +1,213 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
var
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
-
};
|
|
11
|
-
var __copyProps = (to, from, except, desc) => {
|
|
12
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
-
for (let key of __getOwnPropNames(from))
|
|
14
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
-
}
|
|
17
|
-
return to;
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
var _exportNames = {
|
|
7
|
+
BookingTicketImpl: true,
|
|
8
|
+
BookingTicket: true
|
|
18
9
|
};
|
|
19
|
-
|
|
20
|
-
var
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
__export(BookingTicket_exports, {
|
|
33
|
-
BookingTicket: () => BookingTicketImpl,
|
|
34
|
-
BookingTicketImpl: () => BookingTicketImpl
|
|
10
|
+
exports.BookingTicketImpl = exports.BookingTicket = void 0;
|
|
11
|
+
var _dayjs = _interopRequireDefault(require("dayjs"));
|
|
12
|
+
var _types = require("./types");
|
|
13
|
+
Object.keys(_types).forEach(function (key) {
|
|
14
|
+
if (key === "default" || key === "__esModule") return;
|
|
15
|
+
if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
|
|
16
|
+
if (key in exports && exports[key] === _types[key]) return;
|
|
17
|
+
Object.defineProperty(exports, key, {
|
|
18
|
+
enumerable: true,
|
|
19
|
+
get: function () {
|
|
20
|
+
return _types[key];
|
|
21
|
+
}
|
|
22
|
+
});
|
|
35
23
|
});
|
|
36
|
-
|
|
37
|
-
var
|
|
38
|
-
var
|
|
39
|
-
var
|
|
40
|
-
var
|
|
41
|
-
var
|
|
42
|
-
var
|
|
43
|
-
var
|
|
44
|
-
var
|
|
45
|
-
var
|
|
46
|
-
var
|
|
47
|
-
var
|
|
48
|
-
var
|
|
49
|
-
var
|
|
50
|
-
var
|
|
51
|
-
var
|
|
52
|
-
var
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
24
|
+
var _BookingContext = require("../../modules/BookingContext");
|
|
25
|
+
var _BaseSales = require("../BaseSales");
|
|
26
|
+
var _scan = _interopRequireDefault(require("./utils/scan"));
|
|
27
|
+
var _orderCustomer = require("./utils/orderCustomer");
|
|
28
|
+
var _handleScan = require("./utils/scan/handleScan");
|
|
29
|
+
var _scanCache = _interopRequireDefault(require("./utils/scan/scanCache"));
|
|
30
|
+
var _formatGlobalScan = require("./utils/scan/formatGlobalScan");
|
|
31
|
+
var _applyGlobalScan = require("./utils/scan/applyGlobalScan");
|
|
32
|
+
var _cartView = require("./utils/cartView");
|
|
33
|
+
var _addProductDecision = require("./utils/addProductDecision");
|
|
34
|
+
var _buildCacheItemFromOrderLine = require("../../modules/BookingContext/utils/buildCacheItemFromOrderLine");
|
|
35
|
+
var _sessionCatalogStale = require("./utils/sessionCatalogStale");
|
|
36
|
+
var _buildNormalProductCacheItemFromOrderLine = require("../../modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine");
|
|
37
|
+
var _orderLineDisplay = require("../../modules/BookingContext/utils/orderLineDisplay");
|
|
38
|
+
var _bookingStatus = require("./utils/bookingStatus");
|
|
39
|
+
var _resolveBestAddTimePlan = require("./utils/resolveBestAddTimePlan");
|
|
40
|
+
var _utils = require("../../modules/Order/utils");
|
|
41
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
42
|
+
const OPEN_DATA_SECTION_CODES = ['sale', 'reservation', 'fulfillment', 'menu', 'workflow'];
|
|
43
|
+
const OPEN_DATA_CACHE_TTL = 5 * 60 * 1000;
|
|
44
|
+
const USER_PLATFORM = ['pc', 'h5'];
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* 读取已有 booking 的协议唯一值,用于加时商品行绑定原预约。
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* const bookingUid = resolveBookingUidForAddTime(booking);
|
|
51
|
+
*/
|
|
60
52
|
function resolveBookingUidForAddTime(booking) {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
return uid === void 0 || uid === null ? "" : String(uid);
|
|
53
|
+
const uid = booking?.metadata?.unique_identification_number;
|
|
54
|
+
return uid === undefined || uid === null ? '' : String(uid);
|
|
64
55
|
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* 规范化加车数量,避免非法值进入 OrderModule。
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* const quantity = normalizeAddTimeQuantity(product.num);
|
|
62
|
+
*/
|
|
65
63
|
function normalizeAddTimeQuantity(value) {
|
|
66
64
|
const parsed = Math.floor(Number(value));
|
|
67
65
|
return Number.isFinite(parsed) && parsed > 0 ? parsed : 1;
|
|
68
66
|
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* 解析加时时长,优先使用显式入参,其次回退商品字段。
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* const minutes = resolveAddTimeScheduleMinutes(input.product_add_schedule_time, product);
|
|
73
|
+
*/
|
|
69
74
|
function resolveAddTimeScheduleMinutes(explicitValue, product) {
|
|
70
|
-
const raw = explicitValue ??
|
|
71
|
-
if (raw ===
|
|
72
|
-
return void 0;
|
|
75
|
+
const raw = explicitValue ?? product?.product_add_schedule_time;
|
|
76
|
+
if (raw === undefined || raw === null || raw === '') return undefined;
|
|
73
77
|
const parsed = Number(raw);
|
|
74
|
-
return Number.isFinite(parsed) ? parsed :
|
|
78
|
+
return Number.isFinite(parsed) ? parsed : undefined;
|
|
75
79
|
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* 计算加时商品行价格字段,保持 `price` 与 `selling_price` 输入口径一致。
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* const price = resolveAddTimeProductPrice(input.price, product);
|
|
86
|
+
*/
|
|
76
87
|
function resolveAddTimeProductPrice(explicitValue, product) {
|
|
77
|
-
return explicitValue ??
|
|
88
|
+
return explicitValue ?? product?.price ?? product?.selling_price ?? product?.base_price;
|
|
78
89
|
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* 规范化加时覆盖分钟数。
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* const minutes = normalizeCoveredMinutes(input.coveredMinutes);
|
|
96
|
+
*/
|
|
79
97
|
function normalizeCoveredMinutes(value) {
|
|
80
98
|
const parsed = Math.ceil(Number(value));
|
|
81
99
|
return Number.isFinite(parsed) && parsed > 0 ? parsed : 0;
|
|
82
100
|
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* 计算 booking 加时后的结束时间与时长。
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* const updates = buildAddTimeBookingTimePatch(booking, 30);
|
|
107
|
+
*/
|
|
83
108
|
function buildAddTimeBookingTimePatch(booking, coveredMinutes) {
|
|
84
|
-
if (coveredMinutes <= 0)
|
|
85
|
-
|
|
86
|
-
const
|
|
87
|
-
const endTime = booking == null ? void 0 : booking.end_time;
|
|
109
|
+
if (coveredMinutes <= 0) return null;
|
|
110
|
+
const endDate = booking?.end_date;
|
|
111
|
+
const endTime = booking?.end_time;
|
|
88
112
|
if (!endDate || !endTime) {
|
|
89
|
-
throw new Error(
|
|
113
|
+
throw new Error('[BookingTicket] addAddTimeProductsToBooking: booking.end_date/end_time 缺失');
|
|
90
114
|
}
|
|
91
|
-
const currentEnd = (0,
|
|
115
|
+
const currentEnd = (0, _dayjs.default)(`${endDate} ${endTime}`);
|
|
92
116
|
if (!currentEnd.isValid()) {
|
|
93
|
-
throw new Error(
|
|
117
|
+
throw new Error('[BookingTicket] addAddTimeProductsToBooking: booking.end_date/end_time 无效');
|
|
94
118
|
}
|
|
95
|
-
const nextEnd = currentEnd.add(coveredMinutes,
|
|
96
|
-
const currentDuration = Number(booking
|
|
119
|
+
const nextEnd = currentEnd.add(coveredMinutes, 'minute');
|
|
120
|
+
const currentDuration = Number(booking?.duration);
|
|
97
121
|
let duration = Number.isFinite(currentDuration) ? currentDuration + coveredMinutes : coveredMinutes;
|
|
98
|
-
if (
|
|
99
|
-
const start = (0,
|
|
122
|
+
if (booking?.start_date && booking?.start_time) {
|
|
123
|
+
const start = (0, _dayjs.default)(`${booking.start_date} ${booking.start_time}`);
|
|
100
124
|
if (start.isValid()) {
|
|
101
|
-
const diffMinutes = nextEnd.diff(start,
|
|
125
|
+
const diffMinutes = nextEnd.diff(start, 'minute');
|
|
102
126
|
duration = diffMinutes > 0 ? diffMinutes : duration;
|
|
103
127
|
}
|
|
104
128
|
}
|
|
105
129
|
return {
|
|
106
|
-
end_date: nextEnd.format(
|
|
107
|
-
end_time: nextEnd.format(
|
|
130
|
+
end_date: nextEnd.format('YYYY-MM-DD'),
|
|
131
|
+
end_time: nextEnd.format('HH:mm'),
|
|
108
132
|
duration
|
|
109
133
|
};
|
|
110
134
|
}
|
|
111
135
|
function withProductOptionString(cacheItem) {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
if (!productOptionString)
|
|
115
|
-
return cacheItem;
|
|
136
|
+
const productOptionString = (0, _orderLineDisplay.buildProductOptionStringFromOrderLine)(cacheItem);
|
|
137
|
+
if (!productOptionString) return cacheItem;
|
|
116
138
|
return {
|
|
117
139
|
...cacheItem,
|
|
118
|
-
product_option_string:
|
|
140
|
+
product_option_string: cacheItem?.product_option_string || productOptionString,
|
|
119
141
|
_extend: {
|
|
120
|
-
...(cacheItem
|
|
121
|
-
product_option_string:
|
|
142
|
+
...(cacheItem?._extend || {}),
|
|
143
|
+
product_option_string: cacheItem?._extend?.product_option_string || productOptionString
|
|
122
144
|
}
|
|
123
145
|
};
|
|
124
146
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
147
|
+
class BookingTicketImpl extends _BaseSales.BaseSalesImpl {
|
|
148
|
+
defaultName = 'bookingTicket';
|
|
149
|
+
defaultVersion = '1.0.0';
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* 子类覆盖 store 类型为 BookingTicket 子模块清单(在父类基础上追加 customer)。
|
|
153
|
+
* 父类按 `getRegisteredModuleNames` 注入成员到该 store。
|
|
154
|
+
*/
|
|
155
|
+
store = {};
|
|
156
|
+
platform;
|
|
157
|
+
scan;
|
|
158
|
+
productCatalog = [];
|
|
159
|
+
addTimeProductsCatalog = [];
|
|
160
|
+
orderCustomerDiscountRefreshInFlight = null;
|
|
161
|
+
orderCustomerDiscountRefreshCustomerId = null;
|
|
162
|
+
orderCustomerPromotionRefreshInFlight = null;
|
|
163
|
+
loadOpenDataConfigInFlight = null;
|
|
164
|
+
|
|
142
165
|
/**
|
|
143
166
|
* 在 BaseSales 默认模块清单(products/order/salesSummary/schedule)基础上追加 customer + bookingContext。
|
|
144
167
|
* bookingContext 是 SalesSdk 加车下沉所需的「预约 UI 上下文」(bookingConfig / resourcesOrigin / date)。
|
|
145
168
|
*/
|
|
146
169
|
getRegisteredModuleNames() {
|
|
147
|
-
return [...super.getRegisteredModuleNames(),
|
|
170
|
+
return [...super.getRegisteredModuleNames(), 'customer', 'bookingContext', 'openData'];
|
|
148
171
|
}
|
|
149
172
|
getSubmitOrderSalesChannel() {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
return !channel || channel === "system" ? "pos" : channel;
|
|
173
|
+
const channel = this.core?.context?.getChannel?.();
|
|
174
|
+
return !channel || channel === 'system' ? 'pos' : channel;
|
|
153
175
|
}
|
|
176
|
+
|
|
154
177
|
/**
|
|
155
178
|
* 业务侧子模块工厂:BookingTicket 自带的 createBookingTicketModule 优先匹配;
|
|
156
179
|
* 未识别的模块名(如 BookingByStep 公共类型)回退到父类工厂。
|
|
157
180
|
*/
|
|
158
181
|
createSubModule(moduleName) {
|
|
159
|
-
const localModule = (0,
|
|
160
|
-
|
|
161
|
-
this.name
|
|
162
|
-
);
|
|
163
|
-
if (localModule)
|
|
164
|
-
return localModule;
|
|
182
|
+
const localModule = (0, _types.createBookingTicketModule)(moduleName, this.name);
|
|
183
|
+
if (localModule) return localModule;
|
|
165
184
|
return super.createSubModule(moduleName);
|
|
166
185
|
}
|
|
167
186
|
async initialize(core, options = {}) {
|
|
168
|
-
|
|
169
|
-
this.scan = new import_scan.default(this, `BOOKING_TICKET_SCAN:${this.name}`);
|
|
187
|
+
this.scan = new _scan.default(this, `BOOKING_TICKET_SCAN:${this.name}`);
|
|
170
188
|
await super.initialize(core, options);
|
|
171
189
|
if (!this.request) {
|
|
172
|
-
throw new Error(
|
|
190
|
+
throw new Error('bookingTicket解决方案需要 request 插件支持');
|
|
173
191
|
}
|
|
174
|
-
this.platform =
|
|
192
|
+
this.platform = this.otherParams?.platform;
|
|
175
193
|
await this.configureIdGeneratorFromOpenData();
|
|
176
|
-
console.log("[BookingTicket] 初始化完成");
|
|
177
194
|
}
|
|
178
195
|
getBookingTicketBusinessCode() {
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
if (businessCode === void 0 || businessCode === null)
|
|
182
|
-
return null;
|
|
196
|
+
const businessCode = this.otherParams?.businessCode ?? this.otherParams?.business_code;
|
|
197
|
+
if (businessCode === undefined || businessCode === null) return null;
|
|
183
198
|
const normalized = String(businessCode).trim();
|
|
184
199
|
return normalized || null;
|
|
185
200
|
}
|
|
186
201
|
getIdGeneratorPlugin() {
|
|
187
|
-
|
|
188
|
-
const
|
|
189
|
-
|
|
190
|
-
return ((_b = app == null ? void 0 : app.getPlugin) == null ? void 0 : _b.call(app, "idGenerator")) || null;
|
|
202
|
+
const appPlugin = this.core.getPlugin('app');
|
|
203
|
+
const app = appPlugin?.getApp?.();
|
|
204
|
+
return app?.getPlugin?.('idGenerator') || null;
|
|
191
205
|
}
|
|
192
206
|
async loadOpenDataConfig() {
|
|
193
|
-
if (!this.store.openData)
|
|
194
|
-
throw new Error("openData 模块未初始化");
|
|
207
|
+
if (!this.store.openData) throw new Error('openData 模块未初始化');
|
|
195
208
|
const businessCode = this.getBookingTicketBusinessCode();
|
|
196
209
|
if (!businessCode) {
|
|
197
|
-
console.warn(
|
|
210
|
+
console.warn('[BookingTicket] businessCode 缺失,跳过 OpenData 配置加载,当前 module name: ', this.name);
|
|
198
211
|
return null;
|
|
199
212
|
}
|
|
200
213
|
const lastFetchedAt = this.store.openData.getLastFetchedAt();
|
|
@@ -203,11 +216,10 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
203
216
|
this.otherParams.openData = cachedData;
|
|
204
217
|
return cachedData;
|
|
205
218
|
}
|
|
206
|
-
if (this.loadOpenDataConfigInFlight)
|
|
207
|
-
return await this.loadOpenDataConfigInFlight;
|
|
219
|
+
if (this.loadOpenDataConfigInFlight) return await this.loadOpenDataConfigInFlight;
|
|
208
220
|
const channel = this.getSubmitOrderSalesChannel();
|
|
209
221
|
this.loadOpenDataConfigInFlight = this.store.openData.fetchOpenData({
|
|
210
|
-
scope:
|
|
222
|
+
scope: 'board',
|
|
211
223
|
target: `${businessCode}+${channel}`,
|
|
212
224
|
// target: `dine_in+pos`,
|
|
213
225
|
section_code: [...OPEN_DATA_SECTION_CODES]
|
|
@@ -223,60 +235,52 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
223
235
|
async getOpenData() {
|
|
224
236
|
return this.loadOpenDataConfig();
|
|
225
237
|
}
|
|
238
|
+
|
|
226
239
|
/** 清除店铺级 OpenData;下一次 getOpenData 时会重新拉取。 */
|
|
227
240
|
clearOpenDataCache() {
|
|
228
|
-
var _a;
|
|
229
241
|
this.loadOpenDataConfigInFlight = null;
|
|
230
242
|
this.otherParams.openData = null;
|
|
231
|
-
|
|
243
|
+
this.store.openData?.clearCache();
|
|
232
244
|
}
|
|
233
245
|
async getShortNumberOrDeviceId() {
|
|
234
|
-
const getAsyncIotDeviceInfo = this.getAppData(
|
|
246
|
+
const getAsyncIotDeviceInfo = this.getAppData('async_iot_device_info');
|
|
235
247
|
if (getAsyncIotDeviceInfo) {
|
|
236
|
-
const res = await
|
|
237
|
-
if (res
|
|
238
|
-
return res
|
|
248
|
+
const res = await getAsyncIotDeviceInfo?.();
|
|
249
|
+
if (res?.short_number) {
|
|
250
|
+
return res?.short_number;
|
|
239
251
|
}
|
|
240
252
|
}
|
|
241
|
-
return String(this.getAppData(
|
|
253
|
+
return String(this.getAppData('device_id') || 0).slice(-2);
|
|
242
254
|
}
|
|
243
255
|
async configureIdGeneratorFromOpenData() {
|
|
256
|
+
// 业务码切换或配置失败时不能复用上一次初始化的短号。
|
|
244
257
|
this.setPaymentNumberDevicePrefix(null);
|
|
245
258
|
const idGenerator = this.getIdGeneratorPlugin();
|
|
246
|
-
if (!
|
|
247
|
-
console.warn(
|
|
259
|
+
if (!idGenerator?.configure) {
|
|
260
|
+
console.warn('[BookingTicket] idGenerator 插件不可用,跳过配置');
|
|
248
261
|
return;
|
|
249
262
|
}
|
|
250
263
|
let openDataConfig = null;
|
|
251
264
|
try {
|
|
252
265
|
openDataConfig = await this.loadOpenDataConfig();
|
|
253
266
|
} catch (error) {
|
|
254
|
-
console.warn(
|
|
267
|
+
console.warn('[BookingTicket] OpenData 配置加载失败,跳过 idGenerator 配置', error);
|
|
255
268
|
return;
|
|
256
269
|
}
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
);
|
|
261
|
-
const receiptSequenceStart = this.normalizePositiveInteger(
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
const
|
|
266
|
-
openDataConfig == null ? void 0 : openDataConfig["sale.short_number_prefix"],
|
|
267
|
-
""
|
|
268
|
-
);
|
|
269
|
-
const shopOrderPrefix = this.normalizeIdPrefix(
|
|
270
|
-
openDataConfig == null ? void 0 : openDataConfig["sale.sale_number_prefix"],
|
|
271
|
-
""
|
|
272
|
-
);
|
|
273
|
-
const resetReceiptSequenceDaily = typeof (openDataConfig == null ? void 0 : openDataConfig["sale.short_number_daily_reset"]) === "boolean" ? openDataConfig == null ? void 0 : openDataConfig["sale.short_number_daily_reset"] : false;
|
|
274
|
-
const operatingDayBoundary = this.getAppData("operating_day_boundary");
|
|
270
|
+
|
|
271
|
+
// if (!openDataConfig) return;
|
|
272
|
+
|
|
273
|
+
const receiptSequenceLength = this.normalizePositiveInteger(openDataConfig?.['sale.short_number_digits'], 5);
|
|
274
|
+
const receiptSequenceStart = this.normalizePositiveInteger(openDataConfig?.['sale.short_number_start_number'], 1);
|
|
275
|
+
const prefix = this.normalizeIdPrefix(openDataConfig?.['sale.short_number_prefix'], '');
|
|
276
|
+
const shopOrderPrefix = this.normalizeIdPrefix(openDataConfig?.['sale.sale_number_prefix'], '');
|
|
277
|
+
const resetReceiptSequenceDaily = typeof openDataConfig?.['sale.short_number_daily_reset'] === 'boolean' ? openDataConfig?.['sale.short_number_daily_reset'] : false;
|
|
278
|
+
const operatingDayBoundary = this.getAppData('operating_day_boundary');
|
|
275
279
|
const deviceId = await this.getShortNumberOrDeviceId();
|
|
276
280
|
this.setPaymentNumberDevicePrefix(deviceId);
|
|
277
281
|
const businessCode = this.getBookingTicketBusinessCode();
|
|
278
282
|
if (!businessCode) {
|
|
279
|
-
console.warn(
|
|
283
|
+
console.warn('[BookingTicket] businessCode 缺失,跳过 idGenerator 配置');
|
|
280
284
|
return;
|
|
281
285
|
}
|
|
282
286
|
try {
|
|
@@ -295,21 +299,20 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
295
299
|
}
|
|
296
300
|
});
|
|
297
301
|
} catch (error) {
|
|
298
|
-
console.warn(
|
|
302
|
+
console.warn('[BookingTicket] idGenerator 配置失败', error);
|
|
299
303
|
}
|
|
300
304
|
}
|
|
301
305
|
normalizePositiveInteger(value, fallback) {
|
|
302
306
|
const numeric = Number(value);
|
|
303
|
-
if (!Number.isInteger(numeric) || numeric <= 0)
|
|
304
|
-
return fallback;
|
|
307
|
+
if (!Number.isInteger(numeric) || numeric <= 0) return fallback;
|
|
305
308
|
return numeric;
|
|
306
309
|
}
|
|
307
310
|
normalizeIdPrefix(value, fallback) {
|
|
308
|
-
if (value ===
|
|
309
|
-
return fallback;
|
|
311
|
+
if (value === undefined || value === null) return fallback;
|
|
310
312
|
const normalized = String(value).trim().toUpperCase();
|
|
311
313
|
return normalized || fallback;
|
|
312
314
|
}
|
|
315
|
+
|
|
313
316
|
/**
|
|
314
317
|
* 加载销售详情,并在父类基础上把 customer 信息装配到 CustomerModule。
|
|
315
318
|
*
|
|
@@ -320,49 +323,61 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
320
323
|
async loadSalesDetail(orderIdOrParams) {
|
|
321
324
|
const sales = await super.loadSalesDetail(orderIdOrParams);
|
|
322
325
|
const customerModule = this.store.customer;
|
|
323
|
-
const detailCustomer = sales
|
|
326
|
+
const detailCustomer = sales?.customer;
|
|
324
327
|
const orderCustomerSnapshot = this.store.order.getOrderCustomerSnapshot();
|
|
325
|
-
const protocolCustomerId = sales
|
|
326
|
-
const protocolCustomer = protocolCustomerId !==
|
|
328
|
+
const protocolCustomerId = sales?.customer_id;
|
|
329
|
+
const protocolCustomer = protocolCustomerId !== undefined && protocolCustomerId !== null ? {
|
|
327
330
|
id: protocolCustomerId,
|
|
328
|
-
name: String(
|
|
329
|
-
phone: sales
|
|
330
|
-
email: sales
|
|
331
|
-
country_calling_code: sales
|
|
331
|
+
name: String(sales?.customer_name || ''),
|
|
332
|
+
phone: sales?.phone,
|
|
333
|
+
email: sales?.email,
|
|
334
|
+
country_calling_code: sales?.country_calling_code
|
|
332
335
|
} : null;
|
|
333
336
|
const selectedCustomer = detailCustomer ?? orderCustomerSnapshot ?? protocolCustomer;
|
|
334
337
|
if (customerModule && selectedCustomer) {
|
|
335
|
-
const {
|
|
336
|
-
|
|
338
|
+
const {
|
|
339
|
+
id: detailCustomerId,
|
|
340
|
+
...detailCustomerRest
|
|
341
|
+
} = selectedCustomer ?? {};
|
|
342
|
+
const rawId = detailCustomerId ?? '';
|
|
337
343
|
const customer = {
|
|
338
344
|
...detailCustomerRest,
|
|
339
|
-
id: rawId == null ?
|
|
340
|
-
name:
|
|
341
|
-
phone: selectedCustomer
|
|
342
|
-
email: selectedCustomer
|
|
343
|
-
country_calling_code: selectedCustomer
|
|
345
|
+
id: rawId == null ? '' : rawId,
|
|
346
|
+
name: selectedCustomer?.name ?? '',
|
|
347
|
+
phone: selectedCustomer?.phone,
|
|
348
|
+
email: selectedCustomer?.email,
|
|
349
|
+
country_calling_code: selectedCustomer?.country_calling_code
|
|
344
350
|
};
|
|
345
351
|
customerModule.setSelectedCustomer(customer);
|
|
346
|
-
|
|
352
|
+
// 详情 hydrate 后仍需广播一次,让 CustomerContext 等 UI 订阅方拿到刚补齐的
|
|
353
|
+
// customerSnapshot;但它不是用户主动切换客户。通过 source 明确标记初始化事件,
|
|
354
|
+
// 商品报价/折扣订阅方即可跳过 prepare/config,其他旧订阅方仍可照常刷新 UI。
|
|
355
|
+
this.setOrderCustomer(customer, {
|
|
356
|
+
source: 'detailHydrate'
|
|
357
|
+
});
|
|
358
|
+
// await this.store.order.saveDraft();
|
|
347
359
|
}
|
|
348
360
|
return sales;
|
|
349
361
|
}
|
|
350
362
|
async scanPromotionCode(code, customerId) {
|
|
351
|
-
if (!this.store.order)
|
|
352
|
-
throw new Error("order 模块未初始化");
|
|
363
|
+
if (!this.store.order) throw new Error('order 模块未初始化');
|
|
353
364
|
const raw = await this.store.order.scanCode(code, customerId);
|
|
354
365
|
const scannedList = raw.scannedDiscountList || [];
|
|
355
366
|
const extractedCustomerId = this.getDiscountCustomerId(scannedList);
|
|
356
367
|
const hasOrderCustomer = Boolean(this.store.order.getOrderCustomer());
|
|
357
368
|
const isUserPlatform = USER_PLATFORM.includes(this.otherParams.platform);
|
|
369
|
+
|
|
370
|
+
// 缺 Holder 等场景 isAvailable=false,但仍需把 Pass 归属客户带入订单,供 Holder 弹窗使用。
|
|
358
371
|
if (!hasOrderCustomer && extractedCustomerId && !isUserPlatform) {
|
|
359
372
|
await this.hydrateOrderCustomerFromScanDiscounts(scannedList);
|
|
360
373
|
}
|
|
361
374
|
if (raw.isAvailable) {
|
|
362
|
-
await this.store.order.recalculateSummary({
|
|
375
|
+
await this.store.order.recalculateSummary({
|
|
376
|
+
createIfMissing: true
|
|
377
|
+
});
|
|
363
378
|
this.store.order.persistTempOrder();
|
|
364
379
|
const tempOrder = this.store.order.ensureTempOrder();
|
|
365
|
-
await this.effectsEmit(
|
|
380
|
+
await this.effectsEmit('onDiscountApplied', {
|
|
366
381
|
productList: tempOrder.products || [],
|
|
367
382
|
discountList: this.store.order.getDiscountList(),
|
|
368
383
|
selectedDiscountList: tempOrder.discount_list || [],
|
|
@@ -371,7 +386,9 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
371
386
|
}
|
|
372
387
|
return {
|
|
373
388
|
isAvailable: raw.isAvailable,
|
|
374
|
-
...raw.isAccepted !==
|
|
389
|
+
...(raw.isAccepted !== undefined ? {
|
|
390
|
+
isAccepted: raw.isAccepted
|
|
391
|
+
} : {}),
|
|
375
392
|
type: raw.type,
|
|
376
393
|
unavailableReason: raw.unavailableReason,
|
|
377
394
|
scannedDiscountList: raw.scannedDiscountList
|
|
@@ -379,21 +396,20 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
379
396
|
}
|
|
380
397
|
async hydrateOrderCustomerFromScanDiscounts(discounts) {
|
|
381
398
|
const currentOrderCustomer = this.store.order.getOrderCustomer();
|
|
382
|
-
if (currentOrderCustomer)
|
|
383
|
-
return;
|
|
399
|
+
if (currentOrderCustomer) return;
|
|
384
400
|
const customerId = this.getDiscountCustomerId(discounts);
|
|
385
|
-
if (!customerId)
|
|
386
|
-
return;
|
|
401
|
+
if (!customerId) return;
|
|
387
402
|
const customer = await this.resolveCustomerByDiscountCustomerId(customerId);
|
|
388
|
-
if (!customer)
|
|
389
|
-
return;
|
|
403
|
+
if (!customer) return;
|
|
390
404
|
this.store.customer.setSelectedCustomer(customer);
|
|
391
405
|
this.setOrderCustomer(customer);
|
|
392
406
|
}
|
|
393
407
|
getDiscountCustomerId(discounts) {
|
|
394
408
|
for (const item of discounts) {
|
|
395
409
|
const rawCustomerId = item.customer_id;
|
|
396
|
-
if (!rawCustomerId || (0,
|
|
410
|
+
if (!rawCustomerId || (0, _cartView.isWalkInCustomer)({
|
|
411
|
+
id: rawCustomerId
|
|
412
|
+
})) {
|
|
397
413
|
continue;
|
|
398
414
|
}
|
|
399
415
|
const topLevelId = Number(rawCustomerId);
|
|
@@ -404,7 +420,6 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
404
420
|
return null;
|
|
405
421
|
}
|
|
406
422
|
async resolveCustomerById(customerId) {
|
|
407
|
-
var _a;
|
|
408
423
|
const localCustomers = this.store.customer.getCustomers();
|
|
409
424
|
const localCustomer = this.findCustomerById(localCustomers, customerId);
|
|
410
425
|
const normalizedLocalCustomer = localCustomer ? this.normalizeCustomer(localCustomer) : null;
|
|
@@ -416,7 +431,7 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
416
431
|
skip: 1,
|
|
417
432
|
num: 1
|
|
418
433
|
});
|
|
419
|
-
const remoteCustomer = this.findCustomerById(
|
|
434
|
+
const remoteCustomer = this.findCustomerById(result?.list || [], customerId) || result?.list?.[0] || null;
|
|
420
435
|
if (remoteCustomer) {
|
|
421
436
|
return this.normalizeCustomer(remoteCustomer);
|
|
422
437
|
}
|
|
@@ -424,19 +439,20 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
424
439
|
const detailCustomer = await this.store.customer.queryCustomerDetail(customerId);
|
|
425
440
|
return detailCustomer ? this.normalizeCustomer(detailCustomer) : null;
|
|
426
441
|
} catch (error) {
|
|
427
|
-
console.warn(
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
);
|
|
442
|
+
console.warn('[BookingTicket] resolveCustomerById detail request failed', {
|
|
443
|
+
customerId,
|
|
444
|
+
error
|
|
445
|
+
});
|
|
431
446
|
return null;
|
|
432
447
|
}
|
|
433
448
|
}
|
|
449
|
+
|
|
434
450
|
/** 兼容既有优惠码扫码逻辑。 */
|
|
435
451
|
resolveCustomerByDiscountCustomerId(customerId) {
|
|
436
452
|
return this.resolveCustomerById(customerId);
|
|
437
453
|
}
|
|
438
454
|
findCustomerById(customers = [], customerId) {
|
|
439
|
-
return customers.find(
|
|
455
|
+
return customers.find(customer => {
|
|
440
456
|
const rawId = this.getRawCustomerId(customer);
|
|
441
457
|
return rawId !== null && String(rawId) === String(customerId);
|
|
442
458
|
}) || null;
|
|
@@ -444,14 +460,14 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
444
460
|
normalizeCustomer(customer) {
|
|
445
461
|
const raw = customer;
|
|
446
462
|
const rawId = this.getRawCustomerId(customer);
|
|
447
|
-
const name = customer.name || raw.display_name || raw.nickname || raw.customer_name || [raw.first_name, raw.last_name].filter(Boolean).join(
|
|
463
|
+
const name = customer.name || raw.display_name || raw.nickname || raw.customer_name || [raw.first_name, raw.last_name].filter(Boolean).join(' ') || '';
|
|
448
464
|
return {
|
|
449
465
|
...customer,
|
|
450
466
|
id: rawId ?? customer.id,
|
|
451
467
|
name,
|
|
452
|
-
phone: customer.phone ?? raw.phone ?? raw.mobile ??
|
|
453
|
-
email: customer.email ?? raw.email ??
|
|
454
|
-
country_calling_code: customer.country_calling_code ?? raw.country_calling_code ??
|
|
468
|
+
phone: customer.phone ?? raw.phone ?? raw.mobile ?? '',
|
|
469
|
+
email: customer.email ?? raw.email ?? '',
|
|
470
|
+
country_calling_code: customer.country_calling_code ?? raw.country_calling_code ?? ''
|
|
455
471
|
};
|
|
456
472
|
}
|
|
457
473
|
getRawCustomerId(customer) {
|
|
@@ -461,6 +477,7 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
461
477
|
hasUsableCustomerDetails(customer) {
|
|
462
478
|
return !!(customer.name || customer.phone || customer.email || customer.display_name || customer.customer_name);
|
|
463
479
|
}
|
|
480
|
+
|
|
464
481
|
/**
|
|
465
482
|
* 更新当前预约的 appointment_status。
|
|
466
483
|
*
|
|
@@ -476,39 +493,36 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
476
493
|
* @returns 接口返回的 data
|
|
477
494
|
*/
|
|
478
495
|
async setBookingStatus(status) {
|
|
479
|
-
|
|
480
|
-
const tempOrder = (_b = (_a = this.store.order) == null ? void 0 : _a.getTempOrder) == null ? void 0 : _b.call(_a);
|
|
496
|
+
const tempOrder = this.store.order?.getTempOrder?.();
|
|
481
497
|
if (!tempOrder) {
|
|
482
|
-
throw new Error(
|
|
498
|
+
throw new Error('setBookingStatus: tempOrder 未加载');
|
|
483
499
|
}
|
|
484
500
|
const orderId = tempOrder.order_id;
|
|
485
|
-
if (orderId ===
|
|
486
|
-
throw new Error(
|
|
501
|
+
if (orderId === undefined || orderId === null) {
|
|
502
|
+
throw new Error('setBookingStatus: tempOrder.order_id 缺失');
|
|
487
503
|
}
|
|
488
|
-
const scheduleId = (0,
|
|
504
|
+
const scheduleId = (0, _bookingStatus.resolveScheduleId)(tempOrder);
|
|
489
505
|
if (scheduleId === null) {
|
|
490
|
-
throw new Error(
|
|
491
|
-
"setBookingStatus: 无法解析 schedule id(metadata 与 root booking 均缺失)"
|
|
492
|
-
);
|
|
506
|
+
throw new Error('setBookingStatus: 无法解析 schedule id(metadata 与 root booking 均缺失)');
|
|
493
507
|
}
|
|
494
508
|
const bookings = Array.isArray(tempOrder.bookings) ? tempOrder.bookings : [];
|
|
495
|
-
const previous = (0,
|
|
509
|
+
const previous = (0, _bookingStatus.applyBookingsStatus)(bookings, status);
|
|
496
510
|
try {
|
|
497
|
-
const res = await this.request.put(
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
);
|
|
511
|
+
const res = await this.request.put(`/schedule/booking/appointment-status/${scheduleId}`, {
|
|
512
|
+
appointment_status: status
|
|
513
|
+
});
|
|
501
514
|
await this.refreshSalesDetail();
|
|
502
515
|
this.core.effects.emit(`${this.name}:onBookingStatusChange`, {
|
|
503
516
|
orderId,
|
|
504
517
|
status
|
|
505
518
|
});
|
|
506
|
-
return
|
|
519
|
+
return res?.data ?? res;
|
|
507
520
|
} catch (error) {
|
|
508
|
-
(0,
|
|
521
|
+
(0, _bookingStatus.restoreBookingsStatus)(bookings, previous);
|
|
509
522
|
throw error;
|
|
510
523
|
}
|
|
511
524
|
}
|
|
525
|
+
|
|
512
526
|
/**
|
|
513
527
|
* 子预约状态机转移(POST /schedule/booking-transition/{schedule_event_id})。
|
|
514
528
|
*
|
|
@@ -530,30 +544,31 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
530
544
|
* });
|
|
531
545
|
*/
|
|
532
546
|
async transitionChildBooking(params) {
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
547
|
+
const {
|
|
548
|
+
schedule_event_id,
|
|
549
|
+
action
|
|
550
|
+
} = params;
|
|
551
|
+
if (schedule_event_id === undefined || schedule_event_id === null || schedule_event_id === '') {
|
|
552
|
+
throw new Error('transitionChildBooking: schedule_event_id 不能为空');
|
|
537
553
|
}
|
|
538
554
|
if (!action) {
|
|
539
|
-
throw new Error(
|
|
555
|
+
throw new Error('transitionChildBooking: action 不能为空');
|
|
540
556
|
}
|
|
541
|
-
const tempOrder =
|
|
557
|
+
const tempOrder = this.store.order?.getTempOrder?.();
|
|
542
558
|
if (!tempOrder) {
|
|
543
|
-
throw new Error(
|
|
559
|
+
throw new Error('transitionChildBooking: tempOrder 未加载');
|
|
544
560
|
}
|
|
545
561
|
const orderId = tempOrder.order_id;
|
|
546
|
-
if (orderId ===
|
|
547
|
-
throw new Error(
|
|
562
|
+
if (orderId === undefined || orderId === null) {
|
|
563
|
+
throw new Error('transitionChildBooking: tempOrder.order_id 缺失');
|
|
548
564
|
}
|
|
549
565
|
const bookings = Array.isArray(tempOrder.bookings) ? tempOrder.bookings : [];
|
|
550
|
-
const targetStatus = (0,
|
|
551
|
-
const previous = targetStatus !== null ? (0,
|
|
566
|
+
const targetStatus = (0, _bookingStatus.resolveStatusAfterTransition)(action);
|
|
567
|
+
const previous = targetStatus !== null ? (0, _bookingStatus.applyChildBookingStatus)(bookings, schedule_event_id, targetStatus) : undefined;
|
|
552
568
|
try {
|
|
553
|
-
const res = await this.request.post(
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
);
|
|
569
|
+
const res = await this.request.post(`/schedule/booking-transition/${schedule_event_id}`, {
|
|
570
|
+
action
|
|
571
|
+
});
|
|
557
572
|
await this.refreshSalesDetail();
|
|
558
573
|
this.core.effects.emit(`${this.name}:onChildBookingStatusChange`, {
|
|
559
574
|
orderId,
|
|
@@ -561,14 +576,15 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
561
576
|
action,
|
|
562
577
|
status: targetStatus
|
|
563
578
|
});
|
|
564
|
-
return
|
|
579
|
+
return res?.data ?? res;
|
|
565
580
|
} catch (error) {
|
|
566
|
-
if (previous !==
|
|
567
|
-
(0,
|
|
581
|
+
if (previous !== undefined) {
|
|
582
|
+
(0, _bookingStatus.restoreChildBookingStatus)(bookings, schedule_event_id, previous);
|
|
568
583
|
}
|
|
569
584
|
throw error;
|
|
570
585
|
}
|
|
571
586
|
}
|
|
587
|
+
|
|
572
588
|
/**
|
|
573
589
|
* 基于当前 tempOrder.order_id 强制从远端重新拉取销售详情。
|
|
574
590
|
*
|
|
@@ -580,36 +596,44 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
580
596
|
* @returns loadSalesDetail 的返回值
|
|
581
597
|
*/
|
|
582
598
|
async refreshSalesDetail(params = {}) {
|
|
583
|
-
|
|
584
|
-
const tempOrder = (_b = (_a = this.store.order) == null ? void 0 : _a.getTempOrder) == null ? void 0 : _b.call(_a);
|
|
599
|
+
const tempOrder = this.store.order?.getTempOrder?.();
|
|
585
600
|
if (!tempOrder) {
|
|
586
|
-
throw new Error(
|
|
601
|
+
throw new Error('refreshSalesDetail: tempOrder 未加载');
|
|
587
602
|
}
|
|
588
603
|
debugger;
|
|
589
604
|
const orderId = tempOrder.order_id || tempOrder.external_sale_number;
|
|
590
|
-
if (orderId ===
|
|
605
|
+
if (orderId === undefined || orderId === null) {
|
|
591
606
|
return {};
|
|
592
607
|
}
|
|
593
608
|
return this.loadSalesDetail({
|
|
594
|
-
orderId,
|
|
609
|
+
orderId: orderId,
|
|
595
610
|
// merge: true
|
|
596
611
|
forceRemote: params.forceRemote
|
|
597
612
|
});
|
|
598
613
|
}
|
|
614
|
+
|
|
599
615
|
/**
|
|
600
616
|
* 获取商品列表
|
|
601
617
|
* @param params 包含 schedule_date 的参数
|
|
602
618
|
* @returns 商品列表
|
|
603
619
|
*/
|
|
604
620
|
async loadProducts(params = {}, options) {
|
|
605
|
-
const {
|
|
606
|
-
|
|
621
|
+
const {
|
|
622
|
+
schedule_date,
|
|
623
|
+
customer_id,
|
|
624
|
+
menu_list_ids,
|
|
625
|
+
schedule_datetime
|
|
626
|
+
} = params;
|
|
627
|
+
|
|
628
|
+
// 优先写入 schedule_datetime(含时分),供加购 presetStartTime 与 TimeBar 对齐;
|
|
629
|
+
// requiresDetail 弹窗仍通过 formatBookingDateForUI 只取日历日 YYYY-MM-DD。
|
|
630
|
+
const bookingDate = schedule_datetime || schedule_date || '';
|
|
607
631
|
if (bookingDate) {
|
|
608
632
|
this.setBookingDate(bookingDate);
|
|
609
633
|
}
|
|
610
634
|
try {
|
|
611
635
|
const result = await this.store.products.loadProducts({
|
|
612
|
-
with_count: [
|
|
636
|
+
with_count: ['bundleGroup', 'optionGroup'],
|
|
613
637
|
with_schedule: 1,
|
|
614
638
|
...params,
|
|
615
639
|
cacheId: this.cacheId
|
|
@@ -618,10 +642,11 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
618
642
|
this.core.effects.emit(`${this.name}:onProductsLoaded`, result);
|
|
619
643
|
return result;
|
|
620
644
|
} catch (error) {
|
|
621
|
-
console.error(
|
|
645
|
+
console.error('Failed to load products:', error);
|
|
622
646
|
throw error;
|
|
623
647
|
}
|
|
624
648
|
}
|
|
649
|
+
|
|
625
650
|
/**
|
|
626
651
|
* 获取加时商品列表。
|
|
627
652
|
*
|
|
@@ -636,6 +661,7 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
636
661
|
this.addTimeProductsCatalog = Array.isArray(result) ? [...result] : [];
|
|
637
662
|
return result;
|
|
638
663
|
}
|
|
664
|
+
|
|
639
665
|
/**
|
|
640
666
|
* 只读查询单商品详情:走 ProductList 报价查询,但不写 productCatalog、
|
|
641
667
|
* 不 emit onProductsLoaded、不修改 BookingDate。
|
|
@@ -651,52 +677,57 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
651
677
|
* });
|
|
652
678
|
*/
|
|
653
679
|
async queryProductDetail(params, options) {
|
|
654
|
-
const {
|
|
680
|
+
const {
|
|
681
|
+
product_id,
|
|
682
|
+
...queryParams
|
|
683
|
+
} = params;
|
|
655
684
|
try {
|
|
656
685
|
const result = await this.store.products.loadProducts({
|
|
657
|
-
with_count: [
|
|
686
|
+
with_count: ['bundleGroup', 'optionGroup'],
|
|
658
687
|
with_schedule: 1,
|
|
659
688
|
...queryParams,
|
|
660
689
|
product_ids: [product_id],
|
|
661
690
|
cacheId: this.cacheId
|
|
662
691
|
}, options);
|
|
663
692
|
const list = Array.isArray(result) ? result : [];
|
|
664
|
-
return list.find(
|
|
665
|
-
(product) => Number(product.id) === Number(product_id)
|
|
666
|
-
);
|
|
693
|
+
return list.find(product => Number(product.id) === Number(product_id));
|
|
667
694
|
} catch (error) {
|
|
668
|
-
console.error(
|
|
695
|
+
console.error('Failed to query product detail:', error);
|
|
669
696
|
throw error;
|
|
670
697
|
}
|
|
671
698
|
}
|
|
699
|
+
|
|
672
700
|
/**
|
|
673
701
|
* 按预约时间加载单个商品详情。
|
|
674
702
|
* 价格仍由 server products 的报价单桥接统一计算,避免 solution 实例重复请求报价单。
|
|
675
703
|
*/
|
|
676
704
|
async loadProductDetail(params, options) {
|
|
677
|
-
const {
|
|
705
|
+
const {
|
|
706
|
+
product_id,
|
|
707
|
+
...queryParams
|
|
708
|
+
} = params;
|
|
678
709
|
const products = await this.loadProducts({
|
|
679
710
|
...queryParams,
|
|
680
711
|
product_ids: [product_id]
|
|
681
712
|
}, options);
|
|
682
|
-
return products.find(
|
|
683
|
-
(product) => Number(product.id) === Number(product_id)
|
|
684
|
-
);
|
|
713
|
+
return products.find(product => Number(product.id) === Number(product_id));
|
|
685
714
|
}
|
|
715
|
+
|
|
686
716
|
/**
|
|
687
717
|
* 取消商品查询订阅
|
|
688
718
|
* @param subscriberId 订阅时传入的 subscriberId
|
|
689
719
|
*/
|
|
690
720
|
unsubscribeProductQuery(subscriberId) {
|
|
691
|
-
|
|
692
|
-
(_a = this.core.server) == null ? void 0 : _a.removeProductQuerySubscriber(subscriberId);
|
|
721
|
+
this.core.server?.removeProductQuerySubscriber(subscriberId);
|
|
693
722
|
}
|
|
723
|
+
|
|
694
724
|
/**
|
|
695
725
|
* 初始化外设扫码结果监听
|
|
696
726
|
*/
|
|
697
727
|
initPeripheralsListener() {
|
|
698
728
|
this.scan.initPeripheralsListener();
|
|
699
729
|
}
|
|
730
|
+
|
|
700
731
|
/**
|
|
701
732
|
* 获取商品列表(不加载到模块中)
|
|
702
733
|
* @returns 商品列表
|
|
@@ -704,6 +735,7 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
704
735
|
async getProducts() {
|
|
705
736
|
return this.store.products.getProducts();
|
|
706
737
|
}
|
|
738
|
+
|
|
707
739
|
/**
|
|
708
740
|
* 获取当前已加载的商品池 UI 视图。
|
|
709
741
|
*
|
|
@@ -715,98 +747,93 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
715
747
|
products: [...this.productCatalog]
|
|
716
748
|
};
|
|
717
749
|
}
|
|
750
|
+
|
|
718
751
|
/**
|
|
719
752
|
* 获取购物车 UI 视图。
|
|
720
753
|
*
|
|
721
754
|
* tempOrder 仍是 checkout 协议对象;商品行直接透传 products,bookings 附带关联商品。
|
|
722
755
|
*/
|
|
723
756
|
getCart() {
|
|
724
|
-
|
|
725
|
-
const tempOrder = ((_a = this.store.order) == null ? void 0 : _a.getTempOrder()) ?? null;
|
|
757
|
+
const tempOrder = this.store.order?.getTempOrder() ?? null;
|
|
726
758
|
const salesDetail = this.getSalesOrder();
|
|
727
|
-
const bookings =
|
|
759
|
+
const bookings = salesDetail?.bookings ?? (tempOrder?.bookings || []);
|
|
728
760
|
let operatingDayBoundary;
|
|
729
761
|
try {
|
|
730
|
-
operatingDayBoundary = this.getAppData(
|
|
762
|
+
operatingDayBoundary = this.getAppData('operating_day_boundary');
|
|
731
763
|
} catch {
|
|
732
|
-
operatingDayBoundary =
|
|
764
|
+
operatingDayBoundary = undefined;
|
|
733
765
|
}
|
|
734
|
-
const shopOpeningHours =
|
|
735
|
-
return (0,
|
|
766
|
+
const shopOpeningHours = operatingDayBoundary?.type === 'start_time' ? '23:59' : operatingDayBoundary?.time;
|
|
767
|
+
return (0, _cartView.buildCartView)(tempOrder?.products || [], bookings, {
|
|
736
768
|
addTimeProducts: this.addTimeProductsCatalog,
|
|
737
769
|
bookingConfig: this.getBookingConfig(),
|
|
738
|
-
productsByUid:
|
|
770
|
+
productsByUid: tempOrder?._extend?.productsByUid,
|
|
739
771
|
shopOpeningHours
|
|
740
772
|
});
|
|
741
773
|
}
|
|
774
|
+
|
|
742
775
|
/**
|
|
743
776
|
* 获取当前下单客户(与 OrderModule.tempOrder snapshot 一致)。
|
|
744
777
|
*/
|
|
745
778
|
getCustomer() {
|
|
746
779
|
return this.getOrderCustomerSnapshot();
|
|
747
780
|
}
|
|
781
|
+
|
|
748
782
|
/**
|
|
749
783
|
* 通过 ids 获取商品列表;默认只读取内存,显式开启 loadMissing 时按当前订单上下文补查缺失商品。
|
|
750
784
|
* 补查直接写入 ProductList,不更新 BookingTicket.productCatalog,避免当前商品列表被查询子集覆盖。
|
|
751
785
|
*/
|
|
752
786
|
async getProductByIds(ids, options) {
|
|
753
|
-
|
|
754
|
-
const
|
|
755
|
-
|
|
756
|
-
(ids || []).map((id) => Number(id)).filter((id) => Number.isFinite(id))
|
|
757
|
-
)
|
|
758
|
-
);
|
|
759
|
-
const localProducts = await this.store.products.getProductByIds(normalizedIds) || [];
|
|
760
|
-
if (!(options == null ? void 0 : options.loadMissing)) {
|
|
787
|
+
const normalizedIds = Array.from(new Set((ids || []).map(id => Number(id)).filter(id => Number.isFinite(id))));
|
|
788
|
+
const localProducts = (await this.store.products.getProductByIds(normalizedIds)) || [];
|
|
789
|
+
if (!options?.loadMissing) {
|
|
761
790
|
return localProducts;
|
|
762
791
|
}
|
|
763
|
-
const localProductIds = new Set(
|
|
764
|
-
|
|
765
|
-
);
|
|
766
|
-
const missingIds = normalizedIds.filter(
|
|
767
|
-
(id) => !localProductIds.has(id)
|
|
768
|
-
);
|
|
792
|
+
const localProductIds = new Set(localProducts.map(product => Number(product.id)));
|
|
793
|
+
const missingIds = normalizedIds.filter(id => !localProductIds.has(id));
|
|
769
794
|
if (!missingIds.length) {
|
|
770
795
|
return localProducts;
|
|
771
796
|
}
|
|
772
797
|
const rawBookingDate = this.getBookingDate();
|
|
773
|
-
const bookingDate = rawBookingDate && (0,
|
|
774
|
-
const customerId = Number(
|
|
775
|
-
((_a = this.getOrderCustomerSnapshot()) == null ? void 0 : _a.id) ?? ((_b = this.getOrderCustomer()) == null ? void 0 : _b.customer_id)
|
|
776
|
-
);
|
|
798
|
+
const bookingDate = rawBookingDate && (0, _dayjs.default)(rawBookingDate).isValid() ? (0, _dayjs.default)(rawBookingDate) : null;
|
|
799
|
+
const customerId = Number(this.getOrderCustomerSnapshot()?.id ?? this.getOrderCustomer()?.customer_id);
|
|
777
800
|
const loadedProducts = await this.store.products.loadProducts({
|
|
778
801
|
product_ids: missingIds,
|
|
779
|
-
with_count: [
|
|
802
|
+
with_count: ['bundleGroup', 'optionGroup'],
|
|
780
803
|
with_schedule: 1,
|
|
781
804
|
cacheId: this.cacheId,
|
|
782
|
-
...bookingDate ? {
|
|
783
|
-
schedule_date: bookingDate.format(
|
|
784
|
-
schedule_datetime: bookingDate.format(
|
|
785
|
-
} : {},
|
|
786
|
-
...Number.isFinite(customerId) && customerId > 0 ? {
|
|
805
|
+
...(bookingDate ? {
|
|
806
|
+
schedule_date: bookingDate.format('YYYY-MM-DD'),
|
|
807
|
+
schedule_datetime: bookingDate.format('YYYY-MM-DD HH:mm:ss')
|
|
808
|
+
} : {}),
|
|
809
|
+
...(Number.isFinite(customerId) && customerId > 0 ? {
|
|
810
|
+
customer_id: customerId
|
|
811
|
+
} : {})
|
|
787
812
|
});
|
|
788
|
-
const productById =
|
|
789
|
-
[...localProducts, ...loadedProducts || []].forEach(
|
|
813
|
+
const productById = new Map();
|
|
814
|
+
[...localProducts, ...(loadedProducts || [])].forEach(product => {
|
|
790
815
|
const productId = Number(product.id);
|
|
791
816
|
if (Number.isFinite(productId)) {
|
|
792
817
|
productById.set(productId, product);
|
|
793
818
|
}
|
|
794
819
|
});
|
|
795
|
-
return normalizedIds.map(
|
|
820
|
+
return normalizedIds.map(id => productById.get(id)).filter(product => Boolean(product));
|
|
796
821
|
}
|
|
822
|
+
|
|
797
823
|
/**
|
|
798
824
|
* 获取日程时间段点
|
|
799
825
|
* @param params 参数
|
|
800
826
|
* @returns 日程时间段点
|
|
801
827
|
*/
|
|
802
828
|
async getScheduleTimePoints(params) {
|
|
803
|
-
const result = await this.request.post(
|
|
829
|
+
const result = await this.request.post('/menu/schedule-time-points', {
|
|
804
830
|
menu_list_ids: params.menu_list_ids
|
|
805
831
|
}, {
|
|
806
832
|
osServer: true
|
|
807
833
|
});
|
|
808
834
|
return result.data || [];
|
|
809
835
|
}
|
|
836
|
+
|
|
810
837
|
/**
|
|
811
838
|
* 获取客户列表
|
|
812
839
|
* @param params 查询参数
|
|
@@ -817,10 +844,11 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
817
844
|
const result = await this.store.customer.getCustomerList(params);
|
|
818
845
|
return result;
|
|
819
846
|
} catch (error) {
|
|
820
|
-
console.error(
|
|
847
|
+
console.error('Failed to get customer list:', error);
|
|
821
848
|
throw error;
|
|
822
849
|
}
|
|
823
850
|
}
|
|
851
|
+
|
|
824
852
|
/**
|
|
825
853
|
* 设置活跃客户
|
|
826
854
|
* @param customer 客户信息
|
|
@@ -831,6 +859,7 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
831
859
|
customer
|
|
832
860
|
});
|
|
833
861
|
}
|
|
862
|
+
|
|
834
863
|
/**
|
|
835
864
|
* 获取当前活跃客户
|
|
836
865
|
* @returns 当前活跃客户
|
|
@@ -838,6 +867,7 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
838
867
|
getActiveCustomer() {
|
|
839
868
|
return this.store.customer.getSelectedCustomer();
|
|
840
869
|
}
|
|
870
|
+
|
|
841
871
|
/**
|
|
842
872
|
* 根据ID设置选中的客户
|
|
843
873
|
* @param customerId 客户ID
|
|
@@ -851,6 +881,7 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
851
881
|
});
|
|
852
882
|
}
|
|
853
883
|
}
|
|
884
|
+
|
|
854
885
|
/**
|
|
855
886
|
* 获取所有客户
|
|
856
887
|
* @returns 客户列表
|
|
@@ -858,6 +889,7 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
858
889
|
getCustomers() {
|
|
859
890
|
return this.store.customer.getCustomers();
|
|
860
891
|
}
|
|
892
|
+
|
|
861
893
|
/**
|
|
862
894
|
* 根据ID获取客户
|
|
863
895
|
* @param customerId 客户ID
|
|
@@ -866,12 +898,14 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
866
898
|
getCustomerById(customerId) {
|
|
867
899
|
return this.store.customer.getCustomerById(customerId);
|
|
868
900
|
}
|
|
901
|
+
|
|
869
902
|
/**
|
|
870
903
|
* 清空客户列表
|
|
871
904
|
*/
|
|
872
905
|
clearCustomers() {
|
|
873
906
|
this.store.customer.clearCustomers();
|
|
874
907
|
}
|
|
908
|
+
|
|
875
909
|
/**
|
|
876
910
|
* 添加客户到列表第一位
|
|
877
911
|
* @param customer 要添加的客户信息
|
|
@@ -879,11 +913,13 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
879
913
|
addCustomerToFirst(customer) {
|
|
880
914
|
this.store.customer.addCustomerToFirst(customer);
|
|
881
915
|
}
|
|
916
|
+
|
|
882
917
|
// ─── 下单客户(基于 OrderModule.tempOrder,单一真源)───
|
|
883
918
|
// 与老的 setActiveCustomer/getActiveCustomer 解耦:
|
|
884
919
|
// - 老路:写入 CustomerModule.selectedCustomer(保留兼容,存量调用方不动)
|
|
885
920
|
// - 新路:写入 tempOrder 的 customer 协议字段 + _extend.customerSnapshot
|
|
886
921
|
// 新业务(如 SalesSdk)应优先使用本组方法。
|
|
922
|
+
|
|
887
923
|
/**
|
|
888
924
|
* 设置当前下单客户。
|
|
889
925
|
*
|
|
@@ -895,15 +931,14 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
895
931
|
* 同时透传 OrderModule 内部 emit 的 `order:onOrderCustomerChange` 之外,
|
|
896
932
|
* 在 BookingTicket 命名空间也 emit 一次,方便上层统一从 Solution 订阅。
|
|
897
933
|
*/
|
|
898
|
-
setOrderCustomer(customer) {
|
|
899
|
-
var _a;
|
|
934
|
+
setOrderCustomer(customer, options) {
|
|
900
935
|
if (!customer) {
|
|
901
936
|
this.clearOrderCustomer();
|
|
902
937
|
return;
|
|
903
938
|
}
|
|
904
|
-
const previousCustomerId =
|
|
939
|
+
const previousCustomerId = this.store.order.getOrderCustomer()?.customer_id;
|
|
905
940
|
const snapshotBeforeSet = this.store.order.getOrderCustomerSnapshot();
|
|
906
|
-
const patch = (0,
|
|
941
|
+
const patch = (0, _orderCustomer.formatOrderCustomerPatch)(customer);
|
|
907
942
|
const customerUnchanged = Number(previousCustomerId || 0) === Number(patch.customer_id || 0);
|
|
908
943
|
if (!customerUnchanged) {
|
|
909
944
|
this.discountConfigCacheKey = null;
|
|
@@ -912,72 +947,80 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
912
947
|
this.store.order.setOrderCustomer(patch, customer);
|
|
913
948
|
const snapshotAfterOrderSet = this.store.order.getOrderCustomerSnapshot();
|
|
914
949
|
if (customerUnchanged) {
|
|
950
|
+
// hydrate 后 customer_id 已存在但 _extend.customerSnapshot 仍为空时,
|
|
951
|
+
// 须通知 SalesSdk 刷新 selected(否则会一直停在 onSalesOrderLoaded 时的 null)。
|
|
915
952
|
const snapshotReplenished = !snapshotBeforeSet && Boolean(snapshotAfterOrderSet);
|
|
916
953
|
if (snapshotReplenished) {
|
|
917
|
-
const
|
|
918
|
-
this.core.effects.emit(`${this.name}:onOrderCustomerChange`,
|
|
954
|
+
const next = this.buildOrderCustomerPayload();
|
|
955
|
+
this.core.effects.emit(`${this.name}:onOrderCustomerChange`, next && options?.source ? {
|
|
956
|
+
...next,
|
|
957
|
+
source: options.source
|
|
958
|
+
} : next);
|
|
919
959
|
}
|
|
920
960
|
return;
|
|
921
961
|
}
|
|
922
962
|
const next = this.buildOrderCustomerPayload();
|
|
923
|
-
this.core.effects.emit(`${this.name}:onOrderCustomerChange`, next
|
|
963
|
+
this.core.effects.emit(`${this.name}:onOrderCustomerChange`, next && options?.source ? {
|
|
964
|
+
...next,
|
|
965
|
+
source: options.source
|
|
966
|
+
} : next);
|
|
924
967
|
this.refreshDiscountConfigAfterOrderCustomerChange(patch.customer_id);
|
|
925
|
-
|
|
968
|
+
// 客户切换可能改变可用促销/赠品;触发一次重算(recursion-safe)。
|
|
969
|
+
const promotionRefreshTask = this.store.order.applyPromotion().then(() => undefined);
|
|
926
970
|
this.orderCustomerPromotionRefreshInFlight = promotionRefreshTask;
|
|
927
|
-
void promotionRefreshTask.then(
|
|
928
|
-
()
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
if (this.orderCustomerPromotionRefreshInFlight !== promotionRefreshTask)
|
|
936
|
-
return;
|
|
937
|
-
this.orderCustomerPromotionRefreshInFlight = null;
|
|
938
|
-
}
|
|
939
|
-
);
|
|
971
|
+
void promotionRefreshTask.then(() => {
|
|
972
|
+
if (this.orderCustomerPromotionRefreshInFlight !== promotionRefreshTask) return;
|
|
973
|
+
this.orderCustomerPromotionRefreshInFlight = null;
|
|
974
|
+
}, error => {
|
|
975
|
+
console.error('[BookingTicket] applyPromotion after customer change failed', error);
|
|
976
|
+
if (this.orderCustomerPromotionRefreshInFlight !== promotionRefreshTask) return;
|
|
977
|
+
this.orderCustomerPromotionRefreshInFlight = null;
|
|
978
|
+
});
|
|
940
979
|
}
|
|
980
|
+
|
|
941
981
|
/**
|
|
942
982
|
* 读取 tempOrder 上的下单客户协议字段;customer_id 缺失时返回 null。
|
|
943
983
|
*/
|
|
944
984
|
getOrderCustomer() {
|
|
945
985
|
return this.store.order.getOrderCustomer();
|
|
946
986
|
}
|
|
987
|
+
|
|
947
988
|
/**
|
|
948
989
|
* 读取 tempOrder._extend.customerSnapshot 中的完整客户对象。
|
|
949
990
|
*/
|
|
950
991
|
getOrderCustomerSnapshot() {
|
|
951
992
|
return this.store.order.getOrderCustomerSnapshot();
|
|
952
993
|
}
|
|
994
|
+
|
|
953
995
|
/**
|
|
954
996
|
* 清空下单客户(协议字段 + snapshot)。
|
|
955
997
|
*/
|
|
956
998
|
clearOrderCustomer() {
|
|
957
|
-
var _a, _b;
|
|
958
999
|
this.store.order.clearOrderCustomer();
|
|
959
1000
|
this.discountConfigCacheKey = null;
|
|
960
1001
|
this.hasManualDiscountSelection = false;
|
|
961
1002
|
const orderStore = this.store.order.store || {};
|
|
962
1003
|
const discountModule = orderStore.discount;
|
|
963
|
-
void
|
|
964
|
-
void
|
|
1004
|
+
void discountModule?.setOriginalDiscountList?.([]);
|
|
1005
|
+
void discountModule?.setDiscountList?.([]);
|
|
965
1006
|
this.store.order.applyDiscount();
|
|
966
|
-
void this.store.order.recalculateSummary({
|
|
967
|
-
|
|
1007
|
+
void this.store.order.recalculateSummary({
|
|
1008
|
+
createIfMissing: true
|
|
1009
|
+
}).then(() => {
|
|
968
1010
|
const tempOrder = this.store.order.ensureTempOrder();
|
|
969
1011
|
this.store.order.persistTempOrder();
|
|
970
|
-
return this.effectsEmit(
|
|
1012
|
+
return this.effectsEmit('onDiscountApplied', {
|
|
971
1013
|
productList: tempOrder.products || [],
|
|
972
|
-
discountList:
|
|
1014
|
+
discountList: discountModule?.getDiscountList?.() || [],
|
|
973
1015
|
selectedDiscountList: tempOrder.discount_list || [],
|
|
974
1016
|
tempOrder
|
|
975
1017
|
});
|
|
976
|
-
}).catch(
|
|
977
|
-
console.error(
|
|
1018
|
+
}).catch(error => {
|
|
1019
|
+
console.error('Failed to recalculate summary after clearing customer:', error);
|
|
978
1020
|
});
|
|
979
1021
|
this.core.effects.emit(`${this.name}:onOrderCustomerChange`, null);
|
|
980
1022
|
}
|
|
1023
|
+
|
|
981
1024
|
/**
|
|
982
1025
|
* 重置 tempOrder,并同步清空下单客户运行态。
|
|
983
1026
|
*
|
|
@@ -988,50 +1031,49 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
988
1031
|
* 因此在 super.restoreOrder 之后显式清客户,保证 SalesSdk / ticketBooking 订阅方与 tempOrder 一致。
|
|
989
1032
|
*/
|
|
990
1033
|
async restoreOrder() {
|
|
991
|
-
var _a;
|
|
992
1034
|
const tempOrder = await super.restoreOrder();
|
|
993
1035
|
this.clearOrderCustomer();
|
|
994
|
-
|
|
1036
|
+
this.store.customer?.setSelectedCustomer(null);
|
|
995
1037
|
return tempOrder;
|
|
996
1038
|
}
|
|
1039
|
+
|
|
997
1040
|
/** 内部:基于 OrderModule 当前状态构造一份 OrderCustomerChangePayload。 */
|
|
998
1041
|
buildOrderCustomerPayload() {
|
|
999
1042
|
const patch = this.store.order.getOrderCustomer();
|
|
1000
|
-
if (!patch)
|
|
1001
|
-
return null;
|
|
1043
|
+
if (!patch) return null;
|
|
1002
1044
|
return {
|
|
1003
1045
|
patch,
|
|
1004
1046
|
snapshot: this.store.order.getOrderCustomerSnapshot()
|
|
1005
1047
|
};
|
|
1006
1048
|
}
|
|
1007
1049
|
refreshDiscountConfigAfterOrderCustomerChange(customerId) {
|
|
1008
|
-
if (!customerId || customerId === 1)
|
|
1009
|
-
return Promise.resolve();
|
|
1050
|
+
if (!customerId || customerId === 1) return Promise.resolve();
|
|
1010
1051
|
if (this.orderCustomerDiscountRefreshInFlight && this.orderCustomerDiscountRefreshCustomerId === customerId) {
|
|
1011
1052
|
return this.orderCustomerDiscountRefreshInFlight;
|
|
1012
1053
|
}
|
|
1013
1054
|
const previousRefresh = this.orderCustomerDiscountRefreshInFlight;
|
|
1014
1055
|
const refreshTask = (async () => {
|
|
1015
|
-
var _a, _b, _c, _d;
|
|
1016
1056
|
if (previousRefresh) {
|
|
1017
|
-
await previousRefresh.catch(() =>
|
|
1057
|
+
await previousRefresh.catch(() => undefined);
|
|
1018
1058
|
}
|
|
1019
1059
|
const currentCustomer = this.store.order.getOrderCustomer();
|
|
1020
1060
|
if (!currentCustomer || Number(currentCustomer.customer_id) !== customerId) {
|
|
1021
1061
|
return;
|
|
1022
1062
|
}
|
|
1023
|
-
const tempOrder =
|
|
1024
|
-
const orderId =
|
|
1025
|
-
const action = !orderId || String(orderId).startsWith(
|
|
1026
|
-
await this.loadDiscountConfig({
|
|
1063
|
+
const tempOrder = this.store.order.getTempOrder?.();
|
|
1064
|
+
const orderId = tempOrder?.order_id || this.getOrderIdentity?.()?.orderId;
|
|
1065
|
+
const action = !orderId || String(orderId).startsWith('local_order') ? 'create' : 'edit';
|
|
1066
|
+
await this.loadDiscountConfig({
|
|
1067
|
+
customerId,
|
|
1068
|
+
action
|
|
1069
|
+
});
|
|
1027
1070
|
})();
|
|
1028
1071
|
this.orderCustomerDiscountRefreshInFlight = refreshTask;
|
|
1029
1072
|
this.orderCustomerDiscountRefreshCustomerId = customerId;
|
|
1030
|
-
refreshTask.catch(
|
|
1031
|
-
console.error(
|
|
1073
|
+
refreshTask.catch(error => {
|
|
1074
|
+
console.error('Failed to load discount config after customer change:', error);
|
|
1032
1075
|
}).finally(() => {
|
|
1033
|
-
if (this.orderCustomerDiscountRefreshInFlight !== refreshTask)
|
|
1034
|
-
return;
|
|
1076
|
+
if (this.orderCustomerDiscountRefreshInFlight !== refreshTask) return;
|
|
1035
1077
|
this.orderCustomerDiscountRefreshInFlight = null;
|
|
1036
1078
|
this.orderCustomerDiscountRefreshCustomerId = null;
|
|
1037
1079
|
});
|
|
@@ -1041,6 +1083,8 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1041
1083
|
return this.orderCustomerPromotionRefreshInFlight || Promise.resolve();
|
|
1042
1084
|
}
|
|
1043
1085
|
async prepareProductPriceQueryContext(customerId) {
|
|
1086
|
+
// onOrderCustomerChange 的订阅回调会立即开始重报价,而客户 Wallet/优惠资产
|
|
1087
|
+
// 在事件派发后才创建异步刷新任务。先让出一个微任务,确保能观察到该任务。
|
|
1044
1088
|
await Promise.resolve();
|
|
1045
1089
|
const normalizedCustomerId = Number(customerId || 0);
|
|
1046
1090
|
const refreshTask = this.orderCustomerDiscountRefreshInFlight;
|
|
@@ -1050,8 +1094,11 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1050
1094
|
}
|
|
1051
1095
|
}
|
|
1052
1096
|
preferAuthoritativeProductQueryPrice() {
|
|
1097
|
+
// BookingTicket 的 /product/query 已按预约时间、客户及 Wallet 上下文执行
|
|
1098
|
+
// 智能定价;再次应用 legacy quotation 会把最终价覆盖成另一套时段价格。
|
|
1053
1099
|
return true;
|
|
1054
1100
|
}
|
|
1101
|
+
|
|
1055
1102
|
/**
|
|
1056
1103
|
* 获取客户分页信息
|
|
1057
1104
|
* @returns 分页信息
|
|
@@ -1059,6 +1106,7 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1059
1106
|
getCustomerPaginationInfo() {
|
|
1060
1107
|
return this.store.customer.getPaginationInfo();
|
|
1061
1108
|
}
|
|
1109
|
+
|
|
1062
1110
|
/**
|
|
1063
1111
|
* 获取客户列表总数
|
|
1064
1112
|
* @returns 总数
|
|
@@ -1066,6 +1114,7 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1066
1114
|
getCustomerTotal() {
|
|
1067
1115
|
return this.store.customer.getState().total;
|
|
1068
1116
|
}
|
|
1117
|
+
|
|
1069
1118
|
/**
|
|
1070
1119
|
* 设置客户分页信息
|
|
1071
1120
|
* @param page 页码
|
|
@@ -1074,6 +1123,7 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1074
1123
|
setCustomerPaginationInfo(page, pageSize) {
|
|
1075
1124
|
this.store.customer.setPaginationInfo(page, pageSize);
|
|
1076
1125
|
}
|
|
1126
|
+
|
|
1077
1127
|
/**
|
|
1078
1128
|
* 便捷方法:切换客户分页并自动获取数据
|
|
1079
1129
|
* @param page 页码
|
|
@@ -1082,16 +1132,14 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1082
1132
|
*/
|
|
1083
1133
|
async changeCustomerPage(page, pageSize) {
|
|
1084
1134
|
try {
|
|
1085
|
-
const result = await this.store.customer.changeCustomerPage(
|
|
1086
|
-
page,
|
|
1087
|
-
pageSize
|
|
1088
|
-
);
|
|
1135
|
+
const result = await this.store.customer.changeCustomerPage(page, pageSize);
|
|
1089
1136
|
return result;
|
|
1090
1137
|
} catch (error) {
|
|
1091
|
-
console.error(
|
|
1138
|
+
console.error('Failed to change customer page:', error);
|
|
1092
1139
|
throw error;
|
|
1093
1140
|
}
|
|
1094
1141
|
}
|
|
1142
|
+
|
|
1095
1143
|
/**
|
|
1096
1144
|
* 滚动加载更多客户数据 - 数据会追加到现有列表中
|
|
1097
1145
|
* @returns 客户列表响应
|
|
@@ -1102,10 +1150,11 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1102
1150
|
this.core.effects.emit(`${this.name}:onCustomerListUpdate`, result);
|
|
1103
1151
|
return result;
|
|
1104
1152
|
} catch (error) {
|
|
1105
|
-
console.error(
|
|
1153
|
+
console.error('Failed to load more customers:', error);
|
|
1106
1154
|
throw error;
|
|
1107
1155
|
}
|
|
1108
1156
|
}
|
|
1157
|
+
|
|
1109
1158
|
/**
|
|
1110
1159
|
* 重置并重新开始滚动加载客户数据
|
|
1111
1160
|
* @param params 查询参数
|
|
@@ -1117,10 +1166,11 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1117
1166
|
this.core.effects.emit(`${this.name}:onCustomerListReset`, result);
|
|
1118
1167
|
return result;
|
|
1119
1168
|
} catch (error) {
|
|
1120
|
-
console.error(
|
|
1169
|
+
console.error('Failed to reset and load customers:', error);
|
|
1121
1170
|
throw error;
|
|
1122
1171
|
}
|
|
1123
1172
|
}
|
|
1173
|
+
|
|
1124
1174
|
/**
|
|
1125
1175
|
* 检查是否还有更多客户数据可以加载
|
|
1126
1176
|
* @returns 是否还有更多数据
|
|
@@ -1128,6 +1178,7 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1128
1178
|
hasMoreCustomers() {
|
|
1129
1179
|
return this.store.customer.hasMoreCustomers();
|
|
1130
1180
|
}
|
|
1181
|
+
|
|
1131
1182
|
/**
|
|
1132
1183
|
* 获取当前的客户搜索条件
|
|
1133
1184
|
* @returns 当前搜索条件
|
|
@@ -1135,6 +1186,7 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1135
1186
|
getCurrentCustomerSearchParams() {
|
|
1136
1187
|
return this.store.customer.getCurrentSearchParams();
|
|
1137
1188
|
}
|
|
1189
|
+
|
|
1138
1190
|
/**
|
|
1139
1191
|
* 获取客户列表状态(包含滚动加载相关状态)
|
|
1140
1192
|
* @returns 客户状态
|
|
@@ -1142,96 +1194,105 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1142
1194
|
getCustomerState() {
|
|
1143
1195
|
return this.store.customer.getState();
|
|
1144
1196
|
}
|
|
1197
|
+
|
|
1145
1198
|
/**
|
|
1146
1199
|
* 全局扫描监听
|
|
1147
1200
|
* @param callback 回调
|
|
1148
1201
|
*/
|
|
1149
1202
|
scanGlobalListener(callback) {
|
|
1150
|
-
const localSearch =
|
|
1151
|
-
const scanCallback = (0,
|
|
1152
|
-
|
|
1153
|
-
localSearch,
|
|
1154
|
-
this.getSubmitOrderSalesChannel()
|
|
1155
|
-
);
|
|
1156
|
-
const safeCallback = (d) => {
|
|
1203
|
+
const localSearch = v => this.store.products.findProductsByCodeOrBarcode(v);
|
|
1204
|
+
const scanCallback = (0, _handleScan.handleGlobalScan)(this.request, localSearch, this.getSubmitOrderSalesChannel());
|
|
1205
|
+
const safeCallback = d => {
|
|
1157
1206
|
try {
|
|
1158
1207
|
callback(d);
|
|
1159
1208
|
} catch (error) {
|
|
1160
|
-
console.error(
|
|
1209
|
+
console.error('scanGlobalListener传入的回调函数异常', error);
|
|
1161
1210
|
}
|
|
1162
1211
|
};
|
|
1163
|
-
const listener = {
|
|
1212
|
+
const listener = {
|
|
1213
|
+
key: 'global',
|
|
1214
|
+
callback: safeCallback
|
|
1215
|
+
};
|
|
1164
1216
|
const removeListener = this.scan.addListener(listener, scanCallback);
|
|
1165
1217
|
return removeListener;
|
|
1166
1218
|
}
|
|
1219
|
+
|
|
1167
1220
|
/**
|
|
1168
1221
|
* 客户扫描监听
|
|
1169
1222
|
* @param callback 回调
|
|
1170
1223
|
*/
|
|
1171
1224
|
scanCustomerListener(callback) {
|
|
1172
|
-
const scanCallback = (0,
|
|
1173
|
-
const safeCallback =
|
|
1225
|
+
const scanCallback = (0, _handleScan.handleCustomerScan)();
|
|
1226
|
+
const safeCallback = d => {
|
|
1174
1227
|
try {
|
|
1175
1228
|
callback(d);
|
|
1176
1229
|
} catch (error) {
|
|
1177
|
-
console.error(
|
|
1230
|
+
console.error('scanCustomerListener传入的回调函数异常', error);
|
|
1178
1231
|
}
|
|
1179
1232
|
};
|
|
1180
|
-
const listener = {
|
|
1233
|
+
const listener = {
|
|
1234
|
+
key: 'customer',
|
|
1235
|
+
callback: safeCallback
|
|
1236
|
+
};
|
|
1181
1237
|
const removeListener = this.scan.addListener(listener, scanCallback);
|
|
1182
1238
|
return removeListener;
|
|
1183
1239
|
}
|
|
1240
|
+
|
|
1184
1241
|
/**
|
|
1185
1242
|
* @title 通用扫描监听
|
|
1186
1243
|
* @description 直接将扫描结果返回给调用方
|
|
1187
1244
|
* @param callback 回调
|
|
1188
1245
|
*/
|
|
1189
1246
|
scanUniversalListener(callback, key) {
|
|
1190
|
-
const scanCallback = (0,
|
|
1191
|
-
const safeCallback =
|
|
1247
|
+
const scanCallback = (0, _handleScan.handleUniversalScan)();
|
|
1248
|
+
const safeCallback = d => {
|
|
1192
1249
|
try {
|
|
1193
1250
|
callback(d);
|
|
1194
1251
|
} catch (error) {
|
|
1195
|
-
console.error(
|
|
1196
|
-
`scanUniversalListener传入的回调函数异常, key: ${key}`,
|
|
1197
|
-
error
|
|
1198
|
-
);
|
|
1252
|
+
console.error(`scanUniversalListener传入的回调函数异常, key: ${key}`, error);
|
|
1199
1253
|
}
|
|
1200
1254
|
};
|
|
1201
|
-
const listener = {
|
|
1255
|
+
const listener = {
|
|
1256
|
+
key,
|
|
1257
|
+
callback: safeCallback
|
|
1258
|
+
};
|
|
1202
1259
|
const removeListener = this.scan.addListener(listener, scanCallback);
|
|
1203
1260
|
return removeListener;
|
|
1204
1261
|
}
|
|
1262
|
+
|
|
1205
1263
|
/**
|
|
1206
1264
|
* 调用摄像头
|
|
1207
1265
|
* @param data 用户自定义数据
|
|
1208
1266
|
*/
|
|
1209
1267
|
activateCamera(data) {
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
key: "active_native_scanner",
|
|
1268
|
+
this.window?.interaction?.utils?.postMessageToApp?.({
|
|
1269
|
+
module: 'global',
|
|
1270
|
+
key: 'active_native_scanner',
|
|
1214
1271
|
data
|
|
1215
1272
|
});
|
|
1216
1273
|
}
|
|
1274
|
+
|
|
1217
1275
|
/**
|
|
1218
1276
|
* 禁用所有扫描监听
|
|
1219
1277
|
*/
|
|
1220
1278
|
disableAllScanListeners() {
|
|
1221
1279
|
this.scan.disableAllListeners();
|
|
1222
1280
|
}
|
|
1281
|
+
|
|
1223
1282
|
/**
|
|
1224
1283
|
* 启用所有扫描监听
|
|
1225
1284
|
*/
|
|
1226
1285
|
enableAllScanListeners() {
|
|
1227
1286
|
this.scan.enableAllListeners();
|
|
1228
1287
|
}
|
|
1288
|
+
|
|
1229
1289
|
/**
|
|
1230
1290
|
* 清空所有扫描监听对应的任务执行队列
|
|
1231
1291
|
*/
|
|
1232
1292
|
clearAllScanListenersTaskQueue() {
|
|
1233
1293
|
this.scan.clearTaskQueue();
|
|
1234
1294
|
}
|
|
1295
|
+
|
|
1235
1296
|
/**
|
|
1236
1297
|
* 获取其他参数
|
|
1237
1298
|
* @returns 其他参数
|
|
@@ -1239,110 +1300,128 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1239
1300
|
async getOtherParams() {
|
|
1240
1301
|
return this.otherParams;
|
|
1241
1302
|
}
|
|
1303
|
+
|
|
1242
1304
|
// ─── BookingContext API(透传给 BookingContextModule) ──────────────────────
|
|
1243
1305
|
// SalesSdkProvider 挂载时默认调 initBookingContext;也可由 UI 显式 set* 灌入已有数据。
|
|
1306
|
+
|
|
1244
1307
|
/** 拉取 board config 并写入 BookingContext。 */
|
|
1245
1308
|
loadBookingConfig(params) {
|
|
1246
1309
|
return this.store.bookingContext.loadBookingConfig(params);
|
|
1247
1310
|
}
|
|
1311
|
+
|
|
1248
1312
|
/** 拉取资源全集并写入 BookingContext。 */
|
|
1249
1313
|
loadBookingResources(params) {
|
|
1250
1314
|
return this.store.bookingContext.loadResources(params);
|
|
1251
1315
|
}
|
|
1316
|
+
|
|
1252
1317
|
/** 初始化 BookingContext(date + config + resources)。 */
|
|
1253
1318
|
initBookingContext(params) {
|
|
1254
1319
|
return this.store.bookingContext.initBookingContext(params);
|
|
1255
1320
|
}
|
|
1321
|
+
|
|
1256
1322
|
/** 当前 store 是否已具备与入参等价的 config / resources(无需再请求接口)。 */
|
|
1257
1323
|
isBookingContextReady(params) {
|
|
1258
1324
|
return this.store.bookingContext.isBookingContextReady(params);
|
|
1259
1325
|
}
|
|
1326
|
+
|
|
1260
1327
|
/** 写入 booking config(来源:`/core/board/management/config`)。 */
|
|
1261
1328
|
setBookingConfig(config) {
|
|
1262
1329
|
this.store.bookingContext.setBookingConfig(config);
|
|
1263
1330
|
}
|
|
1331
|
+
|
|
1264
1332
|
/** 读取当前 booking config。 */
|
|
1265
1333
|
getBookingConfig() {
|
|
1266
|
-
|
|
1267
|
-
return (_a = this.store.bookingContext) == null ? void 0 : _a.getBookingConfig();
|
|
1334
|
+
return this.store.bookingContext?.getBookingConfig();
|
|
1268
1335
|
}
|
|
1336
|
+
|
|
1269
1337
|
/** 写入资源全集(来源:`/form/schedule`),同步派生 resourcesOriginMap。 */
|
|
1270
1338
|
setResources(resources) {
|
|
1271
1339
|
this.store.bookingContext.setResources(resources);
|
|
1272
1340
|
}
|
|
1341
|
+
|
|
1273
1342
|
/** 读取资源全集(浅克隆)。 */
|
|
1274
1343
|
getResourcesOrigin() {
|
|
1275
1344
|
return this.store.bookingContext.getResourcesOrigin();
|
|
1276
1345
|
}
|
|
1346
|
+
|
|
1277
1347
|
/** 读取资源全集 map(id → resource)。 */
|
|
1278
1348
|
getResourcesOriginMap() {
|
|
1279
1349
|
return this.store.bookingContext.getResourcesOriginMap();
|
|
1280
1350
|
}
|
|
1351
|
+
|
|
1281
1352
|
/** 写入当前选择的日期;支持 dayjs / Date / string。 */
|
|
1282
1353
|
setBookingDate(date) {
|
|
1283
1354
|
this.store.bookingContext.setDate(date);
|
|
1284
1355
|
}
|
|
1356
|
+
|
|
1285
1357
|
/** 读取当前选择的日期(统一 string)。 */
|
|
1286
1358
|
getBookingDate() {
|
|
1287
1359
|
return this.store.bookingContext.getDate();
|
|
1288
1360
|
}
|
|
1361
|
+
|
|
1289
1362
|
/** 读取 BookingContext 完整 store(调试 / 测试 / 透传给 SDK 使用)。 */
|
|
1290
1363
|
getBookingContextState() {
|
|
1291
1364
|
return this.store.bookingContext.getState();
|
|
1292
1365
|
}
|
|
1366
|
+
|
|
1293
1367
|
/** 清空 BookingContext(切租户 / destroy 场景)。 */
|
|
1294
1368
|
clearBookingContext() {
|
|
1295
1369
|
this.store.bookingContext.clear();
|
|
1296
1370
|
}
|
|
1371
|
+
|
|
1297
1372
|
/**
|
|
1298
1373
|
* 构造 BookingContext 计算上下文(供 getProductExtend / getResourceByIds 等读 API 复用)。
|
|
1299
1374
|
*/
|
|
1300
1375
|
buildBookingCalcContext(extra) {
|
|
1301
1376
|
const state = this.store.bookingContext.getState();
|
|
1302
|
-
const date =
|
|
1377
|
+
const date = extra?.date ?? state.date;
|
|
1303
1378
|
return {
|
|
1304
1379
|
bookingConfig: state.bookingConfig,
|
|
1305
1380
|
resourcesOrigin: state.resourcesOrigin,
|
|
1306
1381
|
resourcesOriginMap: state.resourcesOriginMap,
|
|
1307
1382
|
date,
|
|
1308
|
-
presetStartTime:
|
|
1309
|
-
...extra || {}
|
|
1383
|
+
presetStartTime: extra?.presetStartTime ?? (0, _BookingContext.derivePresetStartTimeFromDate)(date),
|
|
1384
|
+
...(extra || {})
|
|
1310
1385
|
};
|
|
1311
1386
|
}
|
|
1387
|
+
|
|
1312
1388
|
/**
|
|
1313
1389
|
* 取商品当前可选资源列表(透传 OS BookingContext utils#getResourceByIds)。
|
|
1314
1390
|
* `extraResources` 用于把拖入未绑定的资源也展示出来。
|
|
1315
1391
|
*/
|
|
1316
1392
|
getResourcesForProduct(product, options) {
|
|
1317
|
-
var _a, _b;
|
|
1318
1393
|
const ctx = this.buildBookingCalcContext();
|
|
1319
|
-
return (0,
|
|
1320
|
-
resourceTab:
|
|
1394
|
+
return (0, _BookingContext.getResourceByIds)(ctx.resourcesOriginMap || {}, product, {
|
|
1395
|
+
resourceTab: ctx.bookingConfig?.config?.resource_tab,
|
|
1321
1396
|
resourcesOrigin: ctx.resourcesOrigin,
|
|
1322
|
-
extraResources:
|
|
1397
|
+
extraResources: options?.extraResources || []
|
|
1323
1398
|
});
|
|
1324
1399
|
}
|
|
1400
|
+
|
|
1325
1401
|
/**
|
|
1326
1402
|
* 拼装 cacheItem 的 _extend / _data(资源 / 容量 / timeObj),与 info2 `getProductExtend` 等价。
|
|
1327
1403
|
*/
|
|
1328
1404
|
getProductExtend(cacheItem, extra) {
|
|
1329
1405
|
const preparedCacheItem = withProductOptionString(cacheItem);
|
|
1330
|
-
const result = (0,
|
|
1406
|
+
const result = (0, _BookingContext.getProductExtend)({
|
|
1331
1407
|
cacheItem: preparedCacheItem,
|
|
1332
1408
|
ctx: this.buildBookingCalcContext(extra)
|
|
1333
1409
|
});
|
|
1334
1410
|
return result;
|
|
1335
1411
|
}
|
|
1412
|
+
|
|
1336
1413
|
/**
|
|
1337
1414
|
* 取资源不可用原因列表(结构化 enum + params,i18n 文案由 UI 渲染)。
|
|
1338
1415
|
*/
|
|
1339
1416
|
getResourceErrors(resource, cacheItem) {
|
|
1340
|
-
return (0,
|
|
1417
|
+
return (0, _BookingContext.getResourceErrors)(resource, cacheItem);
|
|
1341
1418
|
}
|
|
1419
|
+
|
|
1342
1420
|
// ─── addProduct 决策 / 转换 API(SDK 加车下沉所需) ─────────────────────────
|
|
1343
1421
|
// 这一组方法是 SalesSdkCartContext.addProduct / confirmDetail 的 OS 后端。
|
|
1344
1422
|
// 调用方传入 ProductData,OS 自取 bookingContext / customer / date 等上下文,
|
|
1345
1423
|
// 输出 (a) autoClose 决策结果或 (b) `{ product, booking }` 协议入参。
|
|
1424
|
+
|
|
1346
1425
|
/**
|
|
1347
1426
|
* session 商品 catalog 日期与 TimeBar 不一致时写业务日志。
|
|
1348
1427
|
*
|
|
@@ -1350,51 +1429,53 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1350
1429
|
* this.logSessionCatalogDateMismatch(product, ctx.date);
|
|
1351
1430
|
*/
|
|
1352
1431
|
logSessionCatalogDateMismatch(item, bookingDate) {
|
|
1353
|
-
var _a, _b;
|
|
1354
1432
|
const logger = this.logger;
|
|
1355
|
-
if (!
|
|
1356
|
-
|
|
1357
|
-
const
|
|
1358
|
-
const staleInfo = (0, import_sessionCatalogStale.buildSessionCatalogStaleInfo)(item, bookingDate);
|
|
1433
|
+
if (!logger?.addLog) return;
|
|
1434
|
+
const tempOrder = this.getTempOrder?.();
|
|
1435
|
+
const staleInfo = (0, _sessionCatalogStale.buildSessionCatalogStaleInfo)(item, bookingDate);
|
|
1359
1436
|
logger.addLog({
|
|
1360
|
-
type:
|
|
1437
|
+
type: 'warning',
|
|
1361
1438
|
title: `[BookingTicket] session catalog date mismatch, reload products`,
|
|
1362
1439
|
metadata: {
|
|
1363
|
-
order_id:
|
|
1364
|
-
external_sale_number:
|
|
1440
|
+
order_id: tempOrder?.order_id ?? null,
|
|
1441
|
+
external_sale_number: tempOrder?.external_sale_number ?? null,
|
|
1365
1442
|
...staleInfo,
|
|
1366
|
-
cartDetailValueSession:
|
|
1443
|
+
cartDetailValueSession: item?.cartDetailValue?.session ?? null
|
|
1367
1444
|
}
|
|
1368
1445
|
});
|
|
1369
1446
|
}
|
|
1447
|
+
|
|
1370
1448
|
/**
|
|
1371
1449
|
* 加车前:session 商品 catalog 日历日与 bookingDate 不一致时中断加购,交由 SDK reload products。
|
|
1372
1450
|
*/
|
|
1373
1451
|
resolveSessionCatalogBeforeAdd(item, ctx) {
|
|
1374
|
-
if (!(0,
|
|
1452
|
+
if (!(0, _sessionCatalogStale.isSessionCatalogDateStale)(item, ctx.date)) {
|
|
1375
1453
|
return null;
|
|
1376
1454
|
}
|
|
1377
1455
|
this.logSessionCatalogDateMismatch(item, ctx.date);
|
|
1378
|
-
return {
|
|
1456
|
+
return {
|
|
1457
|
+
action: 'reloadCatalog'
|
|
1458
|
+
};
|
|
1379
1459
|
}
|
|
1460
|
+
|
|
1380
1461
|
/**
|
|
1381
1462
|
* 拼装 addProductDecision 通用上下文(从 store 自取)。
|
|
1382
1463
|
*/
|
|
1383
1464
|
buildAddProductCtx(extra) {
|
|
1384
|
-
var _a, _b;
|
|
1385
1465
|
const bookingContextState = this.store.bookingContext.getState();
|
|
1386
|
-
const date =
|
|
1387
|
-
const orderCustomerId =
|
|
1466
|
+
const date = extra?.date ?? bookingContextState.date;
|
|
1467
|
+
const orderCustomerId = this.getOrderCustomerSnapshot()?.id ?? this.store.order.getTempOrder()?.customer_id ?? undefined;
|
|
1388
1468
|
return {
|
|
1389
1469
|
bookingConfig: bookingContextState.bookingConfig,
|
|
1390
1470
|
resourcesOrigin: bookingContextState.resourcesOrigin,
|
|
1391
1471
|
resourcesOriginMap: bookingContextState.resourcesOriginMap,
|
|
1392
1472
|
date,
|
|
1393
|
-
presetStartTime:
|
|
1473
|
+
presetStartTime: extra?.presetStartTime ?? (0, _BookingContext.derivePresetStartTimeFromDate)(date),
|
|
1394
1474
|
customerId: orderCustomerId,
|
|
1395
|
-
...extra || {}
|
|
1475
|
+
...(extra || {})
|
|
1396
1476
|
};
|
|
1397
1477
|
}
|
|
1478
|
+
|
|
1398
1479
|
/**
|
|
1399
1480
|
* 加车两阶段主决策(规格弹窗 / 资源编辑 / 直接加车)。
|
|
1400
1481
|
* 与 ticketBooking `handleSelectProduct` + `handleBooking4Service` 等价。
|
|
@@ -1405,60 +1486,75 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1405
1486
|
if (staleDecision) {
|
|
1406
1487
|
return staleDecision;
|
|
1407
1488
|
}
|
|
1408
|
-
return (0,
|
|
1489
|
+
return (0, _addProductDecision.decideAddProduct)(item, ctx);
|
|
1409
1490
|
}
|
|
1491
|
+
|
|
1410
1492
|
/** 规格弹窗 callback 后的第二段决策。 */
|
|
1411
1493
|
decideAfterDetail(cacheItem, options) {
|
|
1412
|
-
return (0,
|
|
1494
|
+
return (0, _addProductDecision.decideAfterDetail)(cacheItem, this.buildAddProductCtx(options));
|
|
1413
1495
|
}
|
|
1496
|
+
|
|
1414
1497
|
/**
|
|
1415
1498
|
* @deprecated 请用 `decideAddProduct`;`autoClose=true` 仅当 action=add。
|
|
1416
1499
|
*/
|
|
1417
1500
|
decideAutoClose(item, options) {
|
|
1418
|
-
return (0,
|
|
1501
|
+
return (0, _addProductDecision.decideAutoClose)(item, this.buildAddProductCtx(options));
|
|
1419
1502
|
}
|
|
1503
|
+
|
|
1420
1504
|
/** 替代 info2 `getIsEject`:商品是否需要弹窗(0/1)。 */
|
|
1421
|
-
getIsEject(item, type =
|
|
1422
|
-
return (0,
|
|
1505
|
+
getIsEject(item, type = 'select') {
|
|
1506
|
+
return (0, _addProductDecision.getIsEject)(item, type);
|
|
1423
1507
|
}
|
|
1508
|
+
|
|
1424
1509
|
/** 仅 session 商品(无 variant/option/package)→ true。 */
|
|
1425
1510
|
getIsOnlySession(item) {
|
|
1426
|
-
return (0,
|
|
1511
|
+
return (0, _addProductDecision.getIsOnlySession)(item);
|
|
1427
1512
|
}
|
|
1513
|
+
|
|
1428
1514
|
/**
|
|
1429
1515
|
* 拼装 requiresDetail payload(给 SDK 直接 return 给 UI 用)。
|
|
1430
1516
|
*/
|
|
1431
1517
|
buildRequiresDetailPayload(item, options) {
|
|
1432
1518
|
const ctx = this.buildAddProductCtx(options);
|
|
1433
|
-
return (0,
|
|
1519
|
+
return (0, _addProductDecision.buildRequiresDetailPayload)(item, ctx);
|
|
1434
1520
|
}
|
|
1521
|
+
|
|
1435
1522
|
/**
|
|
1436
1523
|
* 把 detail 弹窗回调结果(e, extension_type, detail)转换为 `(product, booking)` 入参。
|
|
1437
1524
|
* 内部会先拼 cacheItem,再走 cacheItemToBookingInput 严格协议对齐。
|
|
1438
1525
|
*/
|
|
1439
1526
|
transformDetailToProductAndBooking(input) {
|
|
1440
|
-
const {
|
|
1527
|
+
const {
|
|
1528
|
+
item,
|
|
1529
|
+
cacheItem: preparedCacheItem,
|
|
1530
|
+
detailResult,
|
|
1531
|
+
options
|
|
1532
|
+
} = input;
|
|
1441
1533
|
const ctx = this.buildAddProductCtx(options);
|
|
1442
|
-
const cacheItem = preparedCacheItem || (detailResult ? (0,
|
|
1443
|
-
return (0,
|
|
1534
|
+
const cacheItem = preparedCacheItem || (detailResult ? (0, _addProductDecision.buildCacheItemFromDetail)(item, detailResult, ctx) : (0, _addProductDecision.buildCacheItemFromCartDetail)(item, ctx));
|
|
1535
|
+
return (0, _addProductDecision.transformDetailToProductAndBooking)(cacheItem, ctx);
|
|
1444
1536
|
}
|
|
1537
|
+
|
|
1445
1538
|
/**
|
|
1446
1539
|
* 从已加车的 order line + booking 反查资源编辑抽屉所需的 cacheItem。
|
|
1447
1540
|
* 供 SalesSdk「编辑资源」等场景使用;字段语义与 buildCacheItemFromDetail 产出对齐。
|
|
1448
1541
|
*/
|
|
1449
1542
|
buildCacheItemFromOrderLine(input) {
|
|
1450
|
-
return (0,
|
|
1543
|
+
return (0, _buildCacheItemFromOrderLine.buildCacheItemFromOrderLine)(input);
|
|
1451
1544
|
}
|
|
1545
|
+
|
|
1452
1546
|
/**
|
|
1453
1547
|
* 从已加车的普通商品 order line 反查 SkuDetailModal edit 所需的 cacheItem。
|
|
1454
1548
|
*/
|
|
1455
1549
|
buildNormalProductCacheItemFromOrderLine(input) {
|
|
1456
|
-
return (0,
|
|
1550
|
+
return (0, _buildNormalProductCacheItemFromOrderLine.buildNormalProductCacheItemFromOrderLine)(input);
|
|
1457
1551
|
}
|
|
1552
|
+
|
|
1458
1553
|
/** 文档别名:与 OrderModule.updateOrderProduct 一致。 */
|
|
1459
1554
|
async updateProductInOrder(params) {
|
|
1460
1555
|
return this.updateOrderProduct(params);
|
|
1461
1556
|
}
|
|
1557
|
+
|
|
1462
1558
|
/**
|
|
1463
1559
|
* 全局扫码 pubsub 入口:解析码值 → 搜索 → 业务分发(客户 / 加车 / 开单)。
|
|
1464
1560
|
* UI 层在 pubsub 订阅回调里注入 `bridge`(uiHosts / action / cart.confirm*)。
|
|
@@ -1473,55 +1569,56 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1473
1569
|
* ```
|
|
1474
1570
|
*/
|
|
1475
1571
|
async handleGlobalScanCode(code, bridge) {
|
|
1476
|
-
|
|
1477
|
-
const trimmed = typeof code === "string" ? code.trim() : "";
|
|
1572
|
+
const trimmed = typeof code === 'string' ? code.trim() : '';
|
|
1478
1573
|
if (!trimmed) {
|
|
1479
|
-
|
|
1480
|
-
return {
|
|
1574
|
+
bridge?.onNotify?.('fail', 'pisell2.text.scan-global-failed');
|
|
1575
|
+
return {
|
|
1576
|
+
status: 'failed',
|
|
1577
|
+
reason: 'empty_code'
|
|
1578
|
+
};
|
|
1481
1579
|
}
|
|
1482
1580
|
try {
|
|
1483
|
-
const localSearch =
|
|
1484
|
-
const scanCallback = (0,
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
);
|
|
1489
|
-
const
|
|
1490
|
-
const formatted = (0, import_formatGlobalScan.formatGlobalScanResult)(raw, trimmed);
|
|
1581
|
+
const localSearch = v => this.store.products.findProductsByCodeOrBarcode(v);
|
|
1582
|
+
const scanCallback = (0, _handleScan.handleGlobalScan)(this.request, localSearch, this.getSubmitOrderSalesChannel());
|
|
1583
|
+
const raw = await scanCallback({
|
|
1584
|
+
type: 'nativeScanner',
|
|
1585
|
+
value: trimmed
|
|
1586
|
+
});
|
|
1587
|
+
const formatted = (0, _formatGlobalScan.formatGlobalScanResult)(raw, trimmed);
|
|
1491
1588
|
if (!formatted) {
|
|
1492
|
-
|
|
1493
|
-
return {
|
|
1589
|
+
bridge?.onNotify?.('fail', 'pisell2.text.scan-global-failed');
|
|
1590
|
+
return {
|
|
1591
|
+
status: 'failed',
|
|
1592
|
+
reason: 'not_found'
|
|
1593
|
+
};
|
|
1494
1594
|
}
|
|
1495
|
-
const result = await (0,
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
refreshWalletAssets: (params) => this.refreshWalletAssets(params),
|
|
1509
|
-
scanWalletAsset: (scanCode) => this.scanWalletAsset(scanCode)
|
|
1510
|
-
},
|
|
1511
|
-
formatted,
|
|
1512
|
-
bridge
|
|
1513
|
-
);
|
|
1514
|
-
(_c = bridge == null ? void 0 : bridge.refresh) == null ? void 0 : _c.call(bridge);
|
|
1595
|
+
const result = await (0, _applyGlobalScan.applyGlobalScan)({
|
|
1596
|
+
setOrderCustomer: customer => this.setOrderCustomer(customer),
|
|
1597
|
+
getOrderCustomerSnapshot: () => this.getOrderCustomerSnapshot(),
|
|
1598
|
+
getBusinessCode: () => this.otherParams?.businessCode,
|
|
1599
|
+
buildAddProductCtx: extra => this.buildAddProductCtx(extra),
|
|
1600
|
+
decideAddProduct: (item, options) => this.decideAddProduct(item, options),
|
|
1601
|
+
decideAfterDetail: (cacheItem, options) => this.decideAfterDetail(cacheItem, options),
|
|
1602
|
+
transformDetailToProductAndBooking: input => this.transformDetailToProductAndBooking(input),
|
|
1603
|
+
addProductToOrder: (product, booking) => this.addProductToOrder(product, booking),
|
|
1604
|
+
refreshWalletAssets: params => this.refreshWalletAssets(params),
|
|
1605
|
+
scanWalletAsset: scanCode => this.scanWalletAsset(scanCode)
|
|
1606
|
+
}, formatted, bridge);
|
|
1607
|
+
bridge?.refresh?.();
|
|
1515
1608
|
return result;
|
|
1516
1609
|
} catch (error) {
|
|
1517
|
-
console.error(
|
|
1518
|
-
|
|
1519
|
-
return {
|
|
1610
|
+
console.error('[BookingTicket] handleGlobalScanCode failed', error);
|
|
1611
|
+
bridge?.onNotify?.('fail', 'pisell2.text.scan-global-failed');
|
|
1612
|
+
return {
|
|
1613
|
+
status: 'failed',
|
|
1614
|
+
reason: 'not_found'
|
|
1615
|
+
};
|
|
1520
1616
|
}
|
|
1521
1617
|
}
|
|
1522
1618
|
resolveBestAddTimePlan(addTimeProducts, targetMinutes) {
|
|
1523
|
-
return (0,
|
|
1619
|
+
return (0, _resolveBestAddTimePlan.resolveBestAddTimePlan)(addTimeProducts, targetMinutes);
|
|
1524
1620
|
}
|
|
1621
|
+
|
|
1525
1622
|
/**
|
|
1526
1623
|
* 构造一条绑定到已有 booking 的加时商品行。
|
|
1527
1624
|
*
|
|
@@ -1529,17 +1626,13 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1529
1626
|
* const line = this.buildAddTimeOrderLine({ product, product_add_schedule_time: 30 }, 'booking-1');
|
|
1530
1627
|
*/
|
|
1531
1628
|
buildAddTimeOrderLine(input, bookingUid) {
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
throw new Error("[BookingTicket] addAddTimeProductToBooking: product 不能为空");
|
|
1629
|
+
const product = input?.product;
|
|
1630
|
+
if (!product || typeof product !== 'object') {
|
|
1631
|
+
throw new Error('[BookingTicket] addAddTimeProductToBooking: product 不能为空');
|
|
1536
1632
|
}
|
|
1537
1633
|
const quantity = normalizeAddTimeQuantity(input.num ?? product.num);
|
|
1538
1634
|
const price = resolveAddTimeProductPrice(input.price, product);
|
|
1539
|
-
const addScheduleTime = resolveAddTimeScheduleMinutes(
|
|
1540
|
-
input.product_add_schedule_time,
|
|
1541
|
-
product
|
|
1542
|
-
);
|
|
1635
|
+
const addScheduleTime = resolveAddTimeScheduleMinutes(input.product_add_schedule_time, product);
|
|
1543
1636
|
const payload = {
|
|
1544
1637
|
id: product.id ?? product.product_id,
|
|
1545
1638
|
product_id: product.product_id ?? product.id,
|
|
@@ -1553,7 +1646,7 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1553
1646
|
line_total: price,
|
|
1554
1647
|
total: price,
|
|
1555
1648
|
product_sku: product.product_sku,
|
|
1556
|
-
option: product.option ?? product.options ??
|
|
1649
|
+
option: product.option ?? product.options ?? product.product_sku?.option ?? [],
|
|
1557
1650
|
bundle: product.bundle ?? product.bundles ?? product.product_bundle ?? []
|
|
1558
1651
|
};
|
|
1559
1652
|
const orderLine = this.transformBaseProductToOrderProduct({
|
|
@@ -1563,13 +1656,13 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1563
1656
|
sourceItem: product
|
|
1564
1657
|
});
|
|
1565
1658
|
if (!orderLine) {
|
|
1566
|
-
throw new Error(
|
|
1567
|
-
"[BookingTicket] addAddTimeProductToBooking: product transform failed"
|
|
1568
|
-
);
|
|
1659
|
+
throw new Error('[BookingTicket] addAddTimeProductToBooking: product transform failed');
|
|
1569
1660
|
}
|
|
1570
1661
|
const metadata = {
|
|
1571
|
-
...orderLine.metadata || {},
|
|
1572
|
-
...addScheduleTime !==
|
|
1662
|
+
...(orderLine.metadata || {}),
|
|
1663
|
+
...(addScheduleTime !== undefined ? {
|
|
1664
|
+
product_add_schedule_time: addScheduleTime
|
|
1665
|
+
} : {}),
|
|
1573
1666
|
booking_uid: bookingUid
|
|
1574
1667
|
};
|
|
1575
1668
|
return {
|
|
@@ -1578,6 +1671,7 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1578
1671
|
metadata
|
|
1579
1672
|
};
|
|
1580
1673
|
}
|
|
1674
|
+
|
|
1581
1675
|
/**
|
|
1582
1676
|
* 将加时商品作为独立商品行绑定到已有 booking。
|
|
1583
1677
|
*
|
|
@@ -1601,6 +1695,7 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1601
1695
|
bookingPatch: input.bookingPatch
|
|
1602
1696
|
});
|
|
1603
1697
|
}
|
|
1698
|
+
|
|
1604
1699
|
/**
|
|
1605
1700
|
* 批量将加时商品作为独立商品行绑定到已有 booking,并只触发一次购物车重算。
|
|
1606
1701
|
*
|
|
@@ -1611,17 +1706,14 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1611
1706
|
* });
|
|
1612
1707
|
*/
|
|
1613
1708
|
async addAddTimeProductsToBooking(input) {
|
|
1614
|
-
const bookingUid = resolveBookingUidForAddTime(input
|
|
1709
|
+
const bookingUid = resolveBookingUidForAddTime(input?.booking);
|
|
1615
1710
|
if (!bookingUid) {
|
|
1616
|
-
throw new Error(
|
|
1617
|
-
"[BookingTicket] addAddTimeProductToBooking: booking.metadata.unique_identification_number 缺失"
|
|
1618
|
-
);
|
|
1711
|
+
throw new Error('[BookingTicket] addAddTimeProductToBooking: booking.metadata.unique_identification_number 缺失');
|
|
1619
1712
|
}
|
|
1620
|
-
const orderLines = (input.products || []).map(
|
|
1713
|
+
const orderLines = (input.products || []).map(line => ({
|
|
1621
1714
|
product: this.buildAddTimeOrderLine(line, bookingUid)
|
|
1622
1715
|
}));
|
|
1623
|
-
if (!this.store.order)
|
|
1624
|
-
throw new Error("order 模块未初始化");
|
|
1716
|
+
if (!this.store.order) throw new Error('order 模块未初始化');
|
|
1625
1717
|
const coveredMinutes = normalizeCoveredMinutes(input.coveredMinutes);
|
|
1626
1718
|
const bookingTimePatch = input.bookingPatch ?? buildAddTimeBookingTimePatch(input.booking, coveredMinutes);
|
|
1627
1719
|
if (bookingTimePatch) {
|
|
@@ -1630,34 +1722,37 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1630
1722
|
updates: bookingTimePatch
|
|
1631
1723
|
});
|
|
1632
1724
|
}
|
|
1633
|
-
if (typeof this.store.order.addProductsToOrder ===
|
|
1725
|
+
if (typeof this.store.order.addProductsToOrder === 'function') {
|
|
1634
1726
|
return this.store.order.addProductsToOrder(orderLines);
|
|
1635
1727
|
}
|
|
1636
1728
|
const result = [];
|
|
1637
1729
|
for (const line of orderLines) {
|
|
1638
|
-
result.splice(0, result.length, ...await this.addProductToOrder(line.product));
|
|
1730
|
+
result.splice(0, result.length, ...(await this.addProductToOrder(line.product)));
|
|
1639
1731
|
}
|
|
1640
1732
|
return result;
|
|
1641
1733
|
}
|
|
1642
|
-
async setOtherParams(params, {
|
|
1643
|
-
|
|
1644
|
-
|
|
1734
|
+
async setOtherParams(params, {
|
|
1735
|
+
cover = false
|
|
1736
|
+
} = {}) {
|
|
1737
|
+
await super.setOtherParams(params, {
|
|
1738
|
+
cover
|
|
1739
|
+
});
|
|
1740
|
+
if (params?.businessCode !== undefined || params?.business_code !== undefined) {
|
|
1645
1741
|
await this.configureIdGeneratorFromOpenData();
|
|
1646
1742
|
}
|
|
1647
1743
|
}
|
|
1648
1744
|
getDeviceTaskPlugin() {
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
return ((_a = app == null ? void 0 : app.getApp()) == null ? void 0 : _a.getPlugin("deviceTask")) || null;
|
|
1745
|
+
const app = this.core.getPlugin('app');
|
|
1746
|
+
return app?.getApp()?.getPlugin('deviceTask') || null;
|
|
1652
1747
|
}
|
|
1748
|
+
|
|
1653
1749
|
// 打印手环,单个或批量都可以
|
|
1654
1750
|
async handlePrintWristband(params) {
|
|
1655
|
-
var _a;
|
|
1656
1751
|
const deviceTask = this.getDeviceTaskPlugin();
|
|
1657
|
-
if (!
|
|
1752
|
+
if (!deviceTask?.dispatch) {
|
|
1658
1753
|
this.logger.addLog({
|
|
1659
|
-
type:
|
|
1660
|
-
title:
|
|
1754
|
+
type: 'info',
|
|
1755
|
+
title: '[BookingTicket] handlePrintWristband: deviceTask.dispatch 不可用',
|
|
1661
1756
|
metadata: {
|
|
1662
1757
|
voucher_ids: Array.isArray(params.voucher_ids) ? params.voucher_ids : [params.voucher_ids]
|
|
1663
1758
|
}
|
|
@@ -1665,51 +1760,50 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1665
1760
|
return;
|
|
1666
1761
|
}
|
|
1667
1762
|
this.logger.addLog({
|
|
1668
|
-
type:
|
|
1669
|
-
title:
|
|
1763
|
+
type: 'info',
|
|
1764
|
+
title: '[BookingTicket] handlePrintWristband',
|
|
1670
1765
|
metadata: {
|
|
1671
1766
|
voucher_ids: Array.isArray(params.voucher_ids) ? params.voucher_ids : [params.voucher_ids]
|
|
1672
1767
|
}
|
|
1673
1768
|
});
|
|
1674
1769
|
const deviceId = await this.getShortNumberOrDeviceId();
|
|
1675
|
-
const idempotencyKey = (0,
|
|
1770
|
+
const idempotencyKey = (0, _utils.createUuidV4)();
|
|
1676
1771
|
deviceTask.dispatch({
|
|
1677
|
-
action:
|
|
1772
|
+
action: 'print_all',
|
|
1678
1773
|
device_id: deviceId,
|
|
1679
1774
|
payload: {
|
|
1680
|
-
type:
|
|
1775
|
+
type: 'WRISTBAND',
|
|
1681
1776
|
data: {
|
|
1682
|
-
order_id:
|
|
1777
|
+
order_id: this.getOrderIdentity()?.orderId,
|
|
1683
1778
|
voucher_ids: Array.isArray(params.voucher_ids) ? params.voucher_ids : [params.voucher_ids]
|
|
1684
1779
|
}
|
|
1685
1780
|
},
|
|
1686
1781
|
idempotency_key: idempotencyKey,
|
|
1687
|
-
name:
|
|
1688
|
-
source:
|
|
1689
|
-
source_type:
|
|
1782
|
+
name: 'PRINT_WRISTBAND',
|
|
1783
|
+
source: 'bookingTicket',
|
|
1784
|
+
source_type: 'handlePrintWristband',
|
|
1690
1785
|
source_id: idempotencyKey
|
|
1691
1786
|
});
|
|
1692
1787
|
}
|
|
1788
|
+
|
|
1693
1789
|
// 触发核销
|
|
1694
1790
|
async handleRedeem(params) {
|
|
1695
|
-
var _a, _b, _c;
|
|
1696
1791
|
const voucherIds = Array.isArray(params.voucher_ids) ? params.voucher_ids : [];
|
|
1697
|
-
const status = params.is_checkin ?
|
|
1792
|
+
const status = params.is_checkin ? 'used' : 'unused';
|
|
1698
1793
|
this.logger.addLog({
|
|
1699
|
-
type:
|
|
1700
|
-
title:
|
|
1794
|
+
type: 'info',
|
|
1795
|
+
title: '[BookingTicket] handleRedeem',
|
|
1701
1796
|
metadata: {
|
|
1702
1797
|
voucher_ids: voucherIds,
|
|
1703
1798
|
status
|
|
1704
1799
|
}
|
|
1705
1800
|
});
|
|
1706
1801
|
const voucherIdSet = new Set(voucherIds);
|
|
1707
|
-
const tempOrder =
|
|
1708
|
-
const vouchers =
|
|
1802
|
+
const tempOrder = this.store.order?.getTempOrder?.();
|
|
1803
|
+
const vouchers = tempOrder?.vouchers || this.store.order?.getVouchers() || [];
|
|
1709
1804
|
let hasUpdatedVoucher = false;
|
|
1710
|
-
const nextVouchers = vouchers.map(
|
|
1711
|
-
if (!voucherIdSet.has(voucher.voucher_id))
|
|
1712
|
-
return voucher;
|
|
1805
|
+
const nextVouchers = vouchers.map(voucher => {
|
|
1806
|
+
if (!voucherIdSet.has(voucher.voucher_id)) return voucher;
|
|
1713
1807
|
hasUpdatedVoucher = true;
|
|
1714
1808
|
return {
|
|
1715
1809
|
...voucher,
|
|
@@ -1727,15 +1821,15 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1727
1821
|
return {
|
|
1728
1822
|
code: 200,
|
|
1729
1823
|
status: true,
|
|
1730
|
-
message:
|
|
1824
|
+
message: '',
|
|
1731
1825
|
data: []
|
|
1732
1826
|
};
|
|
1733
1827
|
}
|
|
1734
1828
|
const identity = this.getOrderIdentity();
|
|
1735
|
-
const externalSaleNumber =
|
|
1736
|
-
const orderId =
|
|
1737
|
-
const orderLookup = externalSaleNumber || orderId ||
|
|
1738
|
-
return this.request.post(
|
|
1829
|
+
const externalSaleNumber = tempOrder?.external_sale_number || identity?.externalSaleNumber || undefined;
|
|
1830
|
+
const orderId = tempOrder?.order_id ?? identity?.orderId ?? undefined;
|
|
1831
|
+
const orderLookup = externalSaleNumber || orderId || identity?.orderNumber || identity?.shopOrderNumber || identity?.shopFullOrderNumber || undefined;
|
|
1832
|
+
return this.request.post('/machinecode/batch', {
|
|
1739
1833
|
ids: voucherIds,
|
|
1740
1834
|
status,
|
|
1741
1835
|
order_lookup: orderLookup,
|
|
@@ -1745,24 +1839,21 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1745
1839
|
osServer: true
|
|
1746
1840
|
});
|
|
1747
1841
|
}
|
|
1842
|
+
|
|
1748
1843
|
/**
|
|
1749
1844
|
* 销毁模块:先调用父类(销毁所有 store 内子模块 + emit destroy + super.destroy()),
|
|
1750
1845
|
* 再清理 BookingTicket 自有资源(scan 监听 + scan 内存缓存)。
|
|
1751
1846
|
*/
|
|
1752
1847
|
async destroy() {
|
|
1753
|
-
var _a;
|
|
1754
1848
|
await super.destroy();
|
|
1755
1849
|
try {
|
|
1756
|
-
|
|
1850
|
+
this.scan?.removeAllListeners();
|
|
1757
1851
|
} catch (error) {
|
|
1758
|
-
console.warn(
|
|
1852
|
+
console.warn('[BookingTicket] scan removeAllListeners 失败', error);
|
|
1759
1853
|
}
|
|
1760
|
-
|
|
1854
|
+
_scanCache.default.clear();
|
|
1761
1855
|
}
|
|
1762
|
-
}
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
BookingTicketImpl,
|
|
1767
|
-
...require("./types")
|
|
1768
|
-
});
|
|
1856
|
+
}
|
|
1857
|
+
|
|
1858
|
+
// 导出相关类型和实现
|
|
1859
|
+
exports.BookingTicket = exports.BookingTicketImpl = BookingTicketImpl;
|