@pisell/pisellos 2.2.283 → 2.2.284
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/promotion/index.js +9 -0
- 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 +1 -1
- package/dist/modules/Payment/index.js +97 -162
- 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/modules/Summary/utils.d.ts +1 -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 +100 -72
- 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 +1 -13
- package/dist/solution/BookingTicket/index.js +0 -2
- 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 +1 -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 +1 -1
- package/lib/modules/Order/types.js +87 -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 +113 -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.d.ts +1 -1
- 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 +1209 -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 +1 -13
- package/lib/solution/BookingTicket/index.js +594 -514
- 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,56 @@ 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
|
this.setOrderCustomer(customer);
|
|
353
|
+
// await this.store.order.saveDraft();
|
|
347
354
|
}
|
|
348
355
|
return sales;
|
|
349
356
|
}
|
|
350
357
|
async scanPromotionCode(code, customerId) {
|
|
351
|
-
if (!this.store.order)
|
|
352
|
-
throw new Error("order 模块未初始化");
|
|
358
|
+
if (!this.store.order) throw new Error('order 模块未初始化');
|
|
353
359
|
const raw = await this.store.order.scanCode(code, customerId);
|
|
354
360
|
const scannedList = raw.scannedDiscountList || [];
|
|
355
361
|
const extractedCustomerId = this.getDiscountCustomerId(scannedList);
|
|
356
362
|
const hasOrderCustomer = Boolean(this.store.order.getOrderCustomer());
|
|
357
363
|
const isUserPlatform = USER_PLATFORM.includes(this.otherParams.platform);
|
|
364
|
+
|
|
365
|
+
// 缺 Holder 等场景 isAvailable=false,但仍需把 Pass 归属客户带入订单,供 Holder 弹窗使用。
|
|
358
366
|
if (!hasOrderCustomer && extractedCustomerId && !isUserPlatform) {
|
|
359
367
|
await this.hydrateOrderCustomerFromScanDiscounts(scannedList);
|
|
360
368
|
}
|
|
361
369
|
if (raw.isAvailable) {
|
|
362
|
-
await this.store.order.recalculateSummary({
|
|
370
|
+
await this.store.order.recalculateSummary({
|
|
371
|
+
createIfMissing: true
|
|
372
|
+
});
|
|
363
373
|
this.store.order.persistTempOrder();
|
|
364
374
|
const tempOrder = this.store.order.ensureTempOrder();
|
|
365
|
-
await this.effectsEmit(
|
|
375
|
+
await this.effectsEmit('onDiscountApplied', {
|
|
366
376
|
productList: tempOrder.products || [],
|
|
367
377
|
discountList: this.store.order.getDiscountList(),
|
|
368
378
|
selectedDiscountList: tempOrder.discount_list || [],
|
|
@@ -371,7 +381,9 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
371
381
|
}
|
|
372
382
|
return {
|
|
373
383
|
isAvailable: raw.isAvailable,
|
|
374
|
-
...raw.isAccepted !==
|
|
384
|
+
...(raw.isAccepted !== undefined ? {
|
|
385
|
+
isAccepted: raw.isAccepted
|
|
386
|
+
} : {}),
|
|
375
387
|
type: raw.type,
|
|
376
388
|
unavailableReason: raw.unavailableReason,
|
|
377
389
|
scannedDiscountList: raw.scannedDiscountList
|
|
@@ -379,21 +391,20 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
379
391
|
}
|
|
380
392
|
async hydrateOrderCustomerFromScanDiscounts(discounts) {
|
|
381
393
|
const currentOrderCustomer = this.store.order.getOrderCustomer();
|
|
382
|
-
if (currentOrderCustomer)
|
|
383
|
-
return;
|
|
394
|
+
if (currentOrderCustomer) return;
|
|
384
395
|
const customerId = this.getDiscountCustomerId(discounts);
|
|
385
|
-
if (!customerId)
|
|
386
|
-
return;
|
|
396
|
+
if (!customerId) return;
|
|
387
397
|
const customer = await this.resolveCustomerByDiscountCustomerId(customerId);
|
|
388
|
-
if (!customer)
|
|
389
|
-
return;
|
|
398
|
+
if (!customer) return;
|
|
390
399
|
this.store.customer.setSelectedCustomer(customer);
|
|
391
400
|
this.setOrderCustomer(customer);
|
|
392
401
|
}
|
|
393
402
|
getDiscountCustomerId(discounts) {
|
|
394
403
|
for (const item of discounts) {
|
|
395
404
|
const rawCustomerId = item.customer_id;
|
|
396
|
-
if (!rawCustomerId || (0,
|
|
405
|
+
if (!rawCustomerId || (0, _cartView.isWalkInCustomer)({
|
|
406
|
+
id: rawCustomerId
|
|
407
|
+
})) {
|
|
397
408
|
continue;
|
|
398
409
|
}
|
|
399
410
|
const topLevelId = Number(rawCustomerId);
|
|
@@ -404,7 +415,6 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
404
415
|
return null;
|
|
405
416
|
}
|
|
406
417
|
async resolveCustomerById(customerId) {
|
|
407
|
-
var _a;
|
|
408
418
|
const localCustomers = this.store.customer.getCustomers();
|
|
409
419
|
const localCustomer = this.findCustomerById(localCustomers, customerId);
|
|
410
420
|
const normalizedLocalCustomer = localCustomer ? this.normalizeCustomer(localCustomer) : null;
|
|
@@ -416,7 +426,7 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
416
426
|
skip: 1,
|
|
417
427
|
num: 1
|
|
418
428
|
});
|
|
419
|
-
const remoteCustomer = this.findCustomerById(
|
|
429
|
+
const remoteCustomer = this.findCustomerById(result?.list || [], customerId) || result?.list?.[0] || null;
|
|
420
430
|
if (remoteCustomer) {
|
|
421
431
|
return this.normalizeCustomer(remoteCustomer);
|
|
422
432
|
}
|
|
@@ -424,19 +434,20 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
424
434
|
const detailCustomer = await this.store.customer.queryCustomerDetail(customerId);
|
|
425
435
|
return detailCustomer ? this.normalizeCustomer(detailCustomer) : null;
|
|
426
436
|
} catch (error) {
|
|
427
|
-
console.warn(
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
);
|
|
437
|
+
console.warn('[BookingTicket] resolveCustomerById detail request failed', {
|
|
438
|
+
customerId,
|
|
439
|
+
error
|
|
440
|
+
});
|
|
431
441
|
return null;
|
|
432
442
|
}
|
|
433
443
|
}
|
|
444
|
+
|
|
434
445
|
/** 兼容既有优惠码扫码逻辑。 */
|
|
435
446
|
resolveCustomerByDiscountCustomerId(customerId) {
|
|
436
447
|
return this.resolveCustomerById(customerId);
|
|
437
448
|
}
|
|
438
449
|
findCustomerById(customers = [], customerId) {
|
|
439
|
-
return customers.find(
|
|
450
|
+
return customers.find(customer => {
|
|
440
451
|
const rawId = this.getRawCustomerId(customer);
|
|
441
452
|
return rawId !== null && String(rawId) === String(customerId);
|
|
442
453
|
}) || null;
|
|
@@ -444,14 +455,14 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
444
455
|
normalizeCustomer(customer) {
|
|
445
456
|
const raw = customer;
|
|
446
457
|
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(
|
|
458
|
+
const name = customer.name || raw.display_name || raw.nickname || raw.customer_name || [raw.first_name, raw.last_name].filter(Boolean).join(' ') || '';
|
|
448
459
|
return {
|
|
449
460
|
...customer,
|
|
450
461
|
id: rawId ?? customer.id,
|
|
451
462
|
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 ??
|
|
463
|
+
phone: customer.phone ?? raw.phone ?? raw.mobile ?? '',
|
|
464
|
+
email: customer.email ?? raw.email ?? '',
|
|
465
|
+
country_calling_code: customer.country_calling_code ?? raw.country_calling_code ?? ''
|
|
455
466
|
};
|
|
456
467
|
}
|
|
457
468
|
getRawCustomerId(customer) {
|
|
@@ -461,6 +472,7 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
461
472
|
hasUsableCustomerDetails(customer) {
|
|
462
473
|
return !!(customer.name || customer.phone || customer.email || customer.display_name || customer.customer_name);
|
|
463
474
|
}
|
|
475
|
+
|
|
464
476
|
/**
|
|
465
477
|
* 更新当前预约的 appointment_status。
|
|
466
478
|
*
|
|
@@ -476,39 +488,36 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
476
488
|
* @returns 接口返回的 data
|
|
477
489
|
*/
|
|
478
490
|
async setBookingStatus(status) {
|
|
479
|
-
|
|
480
|
-
const tempOrder = (_b = (_a = this.store.order) == null ? void 0 : _a.getTempOrder) == null ? void 0 : _b.call(_a);
|
|
491
|
+
const tempOrder = this.store.order?.getTempOrder?.();
|
|
481
492
|
if (!tempOrder) {
|
|
482
|
-
throw new Error(
|
|
493
|
+
throw new Error('setBookingStatus: tempOrder 未加载');
|
|
483
494
|
}
|
|
484
495
|
const orderId = tempOrder.order_id;
|
|
485
|
-
if (orderId ===
|
|
486
|
-
throw new Error(
|
|
496
|
+
if (orderId === undefined || orderId === null) {
|
|
497
|
+
throw new Error('setBookingStatus: tempOrder.order_id 缺失');
|
|
487
498
|
}
|
|
488
|
-
const scheduleId = (0,
|
|
499
|
+
const scheduleId = (0, _bookingStatus.resolveScheduleId)(tempOrder);
|
|
489
500
|
if (scheduleId === null) {
|
|
490
|
-
throw new Error(
|
|
491
|
-
"setBookingStatus: 无法解析 schedule id(metadata 与 root booking 均缺失)"
|
|
492
|
-
);
|
|
501
|
+
throw new Error('setBookingStatus: 无法解析 schedule id(metadata 与 root booking 均缺失)');
|
|
493
502
|
}
|
|
494
503
|
const bookings = Array.isArray(tempOrder.bookings) ? tempOrder.bookings : [];
|
|
495
|
-
const previous = (0,
|
|
504
|
+
const previous = (0, _bookingStatus.applyBookingsStatus)(bookings, status);
|
|
496
505
|
try {
|
|
497
|
-
const res = await this.request.put(
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
);
|
|
506
|
+
const res = await this.request.put(`/schedule/booking/appointment-status/${scheduleId}`, {
|
|
507
|
+
appointment_status: status
|
|
508
|
+
});
|
|
501
509
|
await this.refreshSalesDetail();
|
|
502
510
|
this.core.effects.emit(`${this.name}:onBookingStatusChange`, {
|
|
503
511
|
orderId,
|
|
504
512
|
status
|
|
505
513
|
});
|
|
506
|
-
return
|
|
514
|
+
return res?.data ?? res;
|
|
507
515
|
} catch (error) {
|
|
508
|
-
(0,
|
|
516
|
+
(0, _bookingStatus.restoreBookingsStatus)(bookings, previous);
|
|
509
517
|
throw error;
|
|
510
518
|
}
|
|
511
519
|
}
|
|
520
|
+
|
|
512
521
|
/**
|
|
513
522
|
* 子预约状态机转移(POST /schedule/booking-transition/{schedule_event_id})。
|
|
514
523
|
*
|
|
@@ -530,30 +539,31 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
530
539
|
* });
|
|
531
540
|
*/
|
|
532
541
|
async transitionChildBooking(params) {
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
542
|
+
const {
|
|
543
|
+
schedule_event_id,
|
|
544
|
+
action
|
|
545
|
+
} = params;
|
|
546
|
+
if (schedule_event_id === undefined || schedule_event_id === null || schedule_event_id === '') {
|
|
547
|
+
throw new Error('transitionChildBooking: schedule_event_id 不能为空');
|
|
537
548
|
}
|
|
538
549
|
if (!action) {
|
|
539
|
-
throw new Error(
|
|
550
|
+
throw new Error('transitionChildBooking: action 不能为空');
|
|
540
551
|
}
|
|
541
|
-
const tempOrder =
|
|
552
|
+
const tempOrder = this.store.order?.getTempOrder?.();
|
|
542
553
|
if (!tempOrder) {
|
|
543
|
-
throw new Error(
|
|
554
|
+
throw new Error('transitionChildBooking: tempOrder 未加载');
|
|
544
555
|
}
|
|
545
556
|
const orderId = tempOrder.order_id;
|
|
546
|
-
if (orderId ===
|
|
547
|
-
throw new Error(
|
|
557
|
+
if (orderId === undefined || orderId === null) {
|
|
558
|
+
throw new Error('transitionChildBooking: tempOrder.order_id 缺失');
|
|
548
559
|
}
|
|
549
560
|
const bookings = Array.isArray(tempOrder.bookings) ? tempOrder.bookings : [];
|
|
550
|
-
const targetStatus = (0,
|
|
551
|
-
const previous = targetStatus !== null ? (0,
|
|
561
|
+
const targetStatus = (0, _bookingStatus.resolveStatusAfterTransition)(action);
|
|
562
|
+
const previous = targetStatus !== null ? (0, _bookingStatus.applyChildBookingStatus)(bookings, schedule_event_id, targetStatus) : undefined;
|
|
552
563
|
try {
|
|
553
|
-
const res = await this.request.post(
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
);
|
|
564
|
+
const res = await this.request.post(`/schedule/booking-transition/${schedule_event_id}`, {
|
|
565
|
+
action
|
|
566
|
+
});
|
|
557
567
|
await this.refreshSalesDetail();
|
|
558
568
|
this.core.effects.emit(`${this.name}:onChildBookingStatusChange`, {
|
|
559
569
|
orderId,
|
|
@@ -561,14 +571,15 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
561
571
|
action,
|
|
562
572
|
status: targetStatus
|
|
563
573
|
});
|
|
564
|
-
return
|
|
574
|
+
return res?.data ?? res;
|
|
565
575
|
} catch (error) {
|
|
566
|
-
if (previous !==
|
|
567
|
-
(0,
|
|
576
|
+
if (previous !== undefined) {
|
|
577
|
+
(0, _bookingStatus.restoreChildBookingStatus)(bookings, schedule_event_id, previous);
|
|
568
578
|
}
|
|
569
579
|
throw error;
|
|
570
580
|
}
|
|
571
581
|
}
|
|
582
|
+
|
|
572
583
|
/**
|
|
573
584
|
* 基于当前 tempOrder.order_id 强制从远端重新拉取销售详情。
|
|
574
585
|
*
|
|
@@ -580,36 +591,44 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
580
591
|
* @returns loadSalesDetail 的返回值
|
|
581
592
|
*/
|
|
582
593
|
async refreshSalesDetail(params = {}) {
|
|
583
|
-
|
|
584
|
-
const tempOrder = (_b = (_a = this.store.order) == null ? void 0 : _a.getTempOrder) == null ? void 0 : _b.call(_a);
|
|
594
|
+
const tempOrder = this.store.order?.getTempOrder?.();
|
|
585
595
|
if (!tempOrder) {
|
|
586
|
-
throw new Error(
|
|
596
|
+
throw new Error('refreshSalesDetail: tempOrder 未加载');
|
|
587
597
|
}
|
|
588
598
|
debugger;
|
|
589
599
|
const orderId = tempOrder.order_id || tempOrder.external_sale_number;
|
|
590
|
-
if (orderId ===
|
|
600
|
+
if (orderId === undefined || orderId === null) {
|
|
591
601
|
return {};
|
|
592
602
|
}
|
|
593
603
|
return this.loadSalesDetail({
|
|
594
|
-
orderId,
|
|
604
|
+
orderId: orderId,
|
|
595
605
|
// merge: true
|
|
596
606
|
forceRemote: params.forceRemote
|
|
597
607
|
});
|
|
598
608
|
}
|
|
609
|
+
|
|
599
610
|
/**
|
|
600
611
|
* 获取商品列表
|
|
601
612
|
* @param params 包含 schedule_date 的参数
|
|
602
613
|
* @returns 商品列表
|
|
603
614
|
*/
|
|
604
615
|
async loadProducts(params = {}, options) {
|
|
605
|
-
const {
|
|
606
|
-
|
|
616
|
+
const {
|
|
617
|
+
schedule_date,
|
|
618
|
+
customer_id,
|
|
619
|
+
menu_list_ids,
|
|
620
|
+
schedule_datetime
|
|
621
|
+
} = params;
|
|
622
|
+
|
|
623
|
+
// 优先写入 schedule_datetime(含时分),供加购 presetStartTime 与 TimeBar 对齐;
|
|
624
|
+
// requiresDetail 弹窗仍通过 formatBookingDateForUI 只取日历日 YYYY-MM-DD。
|
|
625
|
+
const bookingDate = schedule_datetime || schedule_date || '';
|
|
607
626
|
if (bookingDate) {
|
|
608
627
|
this.setBookingDate(bookingDate);
|
|
609
628
|
}
|
|
610
629
|
try {
|
|
611
630
|
const result = await this.store.products.loadProducts({
|
|
612
|
-
with_count: [
|
|
631
|
+
with_count: ['bundleGroup', 'optionGroup'],
|
|
613
632
|
with_schedule: 1,
|
|
614
633
|
...params,
|
|
615
634
|
cacheId: this.cacheId
|
|
@@ -618,10 +637,11 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
618
637
|
this.core.effects.emit(`${this.name}:onProductsLoaded`, result);
|
|
619
638
|
return result;
|
|
620
639
|
} catch (error) {
|
|
621
|
-
console.error(
|
|
640
|
+
console.error('Failed to load products:', error);
|
|
622
641
|
throw error;
|
|
623
642
|
}
|
|
624
643
|
}
|
|
644
|
+
|
|
625
645
|
/**
|
|
626
646
|
* 获取加时商品列表。
|
|
627
647
|
*
|
|
@@ -636,6 +656,7 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
636
656
|
this.addTimeProductsCatalog = Array.isArray(result) ? [...result] : [];
|
|
637
657
|
return result;
|
|
638
658
|
}
|
|
659
|
+
|
|
639
660
|
/**
|
|
640
661
|
* 只读查询单商品详情:走 ProductList 报价查询,但不写 productCatalog、
|
|
641
662
|
* 不 emit onProductsLoaded、不修改 BookingDate。
|
|
@@ -651,52 +672,57 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
651
672
|
* });
|
|
652
673
|
*/
|
|
653
674
|
async queryProductDetail(params, options) {
|
|
654
|
-
const {
|
|
675
|
+
const {
|
|
676
|
+
product_id,
|
|
677
|
+
...queryParams
|
|
678
|
+
} = params;
|
|
655
679
|
try {
|
|
656
680
|
const result = await this.store.products.loadProducts({
|
|
657
|
-
with_count: [
|
|
681
|
+
with_count: ['bundleGroup', 'optionGroup'],
|
|
658
682
|
with_schedule: 1,
|
|
659
683
|
...queryParams,
|
|
660
684
|
product_ids: [product_id],
|
|
661
685
|
cacheId: this.cacheId
|
|
662
686
|
}, options);
|
|
663
687
|
const list = Array.isArray(result) ? result : [];
|
|
664
|
-
return list.find(
|
|
665
|
-
(product) => Number(product.id) === Number(product_id)
|
|
666
|
-
);
|
|
688
|
+
return list.find(product => Number(product.id) === Number(product_id));
|
|
667
689
|
} catch (error) {
|
|
668
|
-
console.error(
|
|
690
|
+
console.error('Failed to query product detail:', error);
|
|
669
691
|
throw error;
|
|
670
692
|
}
|
|
671
693
|
}
|
|
694
|
+
|
|
672
695
|
/**
|
|
673
696
|
* 按预约时间加载单个商品详情。
|
|
674
697
|
* 价格仍由 server products 的报价单桥接统一计算,避免 solution 实例重复请求报价单。
|
|
675
698
|
*/
|
|
676
699
|
async loadProductDetail(params, options) {
|
|
677
|
-
const {
|
|
700
|
+
const {
|
|
701
|
+
product_id,
|
|
702
|
+
...queryParams
|
|
703
|
+
} = params;
|
|
678
704
|
const products = await this.loadProducts({
|
|
679
705
|
...queryParams,
|
|
680
706
|
product_ids: [product_id]
|
|
681
707
|
}, options);
|
|
682
|
-
return products.find(
|
|
683
|
-
(product) => Number(product.id) === Number(product_id)
|
|
684
|
-
);
|
|
708
|
+
return products.find(product => Number(product.id) === Number(product_id));
|
|
685
709
|
}
|
|
710
|
+
|
|
686
711
|
/**
|
|
687
712
|
* 取消商品查询订阅
|
|
688
713
|
* @param subscriberId 订阅时传入的 subscriberId
|
|
689
714
|
*/
|
|
690
715
|
unsubscribeProductQuery(subscriberId) {
|
|
691
|
-
|
|
692
|
-
(_a = this.core.server) == null ? void 0 : _a.removeProductQuerySubscriber(subscriberId);
|
|
716
|
+
this.core.server?.removeProductQuerySubscriber(subscriberId);
|
|
693
717
|
}
|
|
718
|
+
|
|
694
719
|
/**
|
|
695
720
|
* 初始化外设扫码结果监听
|
|
696
721
|
*/
|
|
697
722
|
initPeripheralsListener() {
|
|
698
723
|
this.scan.initPeripheralsListener();
|
|
699
724
|
}
|
|
725
|
+
|
|
700
726
|
/**
|
|
701
727
|
* 获取商品列表(不加载到模块中)
|
|
702
728
|
* @returns 商品列表
|
|
@@ -704,6 +730,7 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
704
730
|
async getProducts() {
|
|
705
731
|
return this.store.products.getProducts();
|
|
706
732
|
}
|
|
733
|
+
|
|
707
734
|
/**
|
|
708
735
|
* 获取当前已加载的商品池 UI 视图。
|
|
709
736
|
*
|
|
@@ -715,98 +742,93 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
715
742
|
products: [...this.productCatalog]
|
|
716
743
|
};
|
|
717
744
|
}
|
|
745
|
+
|
|
718
746
|
/**
|
|
719
747
|
* 获取购物车 UI 视图。
|
|
720
748
|
*
|
|
721
749
|
* tempOrder 仍是 checkout 协议对象;商品行直接透传 products,bookings 附带关联商品。
|
|
722
750
|
*/
|
|
723
751
|
getCart() {
|
|
724
|
-
|
|
725
|
-
const tempOrder = ((_a = this.store.order) == null ? void 0 : _a.getTempOrder()) ?? null;
|
|
752
|
+
const tempOrder = this.store.order?.getTempOrder() ?? null;
|
|
726
753
|
const salesDetail = this.getSalesOrder();
|
|
727
|
-
const bookings =
|
|
754
|
+
const bookings = salesDetail?.bookings ?? (tempOrder?.bookings || []);
|
|
728
755
|
let operatingDayBoundary;
|
|
729
756
|
try {
|
|
730
|
-
operatingDayBoundary = this.getAppData(
|
|
757
|
+
operatingDayBoundary = this.getAppData('operating_day_boundary');
|
|
731
758
|
} catch {
|
|
732
|
-
operatingDayBoundary =
|
|
759
|
+
operatingDayBoundary = undefined;
|
|
733
760
|
}
|
|
734
|
-
const shopOpeningHours =
|
|
735
|
-
return (0,
|
|
761
|
+
const shopOpeningHours = operatingDayBoundary?.type === 'start_time' ? '23:59' : operatingDayBoundary?.time;
|
|
762
|
+
return (0, _cartView.buildCartView)(tempOrder?.products || [], bookings, {
|
|
736
763
|
addTimeProducts: this.addTimeProductsCatalog,
|
|
737
764
|
bookingConfig: this.getBookingConfig(),
|
|
738
|
-
productsByUid:
|
|
765
|
+
productsByUid: tempOrder?._extend?.productsByUid,
|
|
739
766
|
shopOpeningHours
|
|
740
767
|
});
|
|
741
768
|
}
|
|
769
|
+
|
|
742
770
|
/**
|
|
743
771
|
* 获取当前下单客户(与 OrderModule.tempOrder snapshot 一致)。
|
|
744
772
|
*/
|
|
745
773
|
getCustomer() {
|
|
746
774
|
return this.getOrderCustomerSnapshot();
|
|
747
775
|
}
|
|
776
|
+
|
|
748
777
|
/**
|
|
749
778
|
* 通过 ids 获取商品列表;默认只读取内存,显式开启 loadMissing 时按当前订单上下文补查缺失商品。
|
|
750
779
|
* 补查直接写入 ProductList,不更新 BookingTicket.productCatalog,避免当前商品列表被查询子集覆盖。
|
|
751
780
|
*/
|
|
752
781
|
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)) {
|
|
782
|
+
const normalizedIds = Array.from(new Set((ids || []).map(id => Number(id)).filter(id => Number.isFinite(id))));
|
|
783
|
+
const localProducts = (await this.store.products.getProductByIds(normalizedIds)) || [];
|
|
784
|
+
if (!options?.loadMissing) {
|
|
761
785
|
return localProducts;
|
|
762
786
|
}
|
|
763
|
-
const localProductIds = new Set(
|
|
764
|
-
|
|
765
|
-
);
|
|
766
|
-
const missingIds = normalizedIds.filter(
|
|
767
|
-
(id) => !localProductIds.has(id)
|
|
768
|
-
);
|
|
787
|
+
const localProductIds = new Set(localProducts.map(product => Number(product.id)));
|
|
788
|
+
const missingIds = normalizedIds.filter(id => !localProductIds.has(id));
|
|
769
789
|
if (!missingIds.length) {
|
|
770
790
|
return localProducts;
|
|
771
791
|
}
|
|
772
792
|
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
|
-
);
|
|
793
|
+
const bookingDate = rawBookingDate && (0, _dayjs.default)(rawBookingDate).isValid() ? (0, _dayjs.default)(rawBookingDate) : null;
|
|
794
|
+
const customerId = Number(this.getOrderCustomerSnapshot()?.id ?? this.getOrderCustomer()?.customer_id);
|
|
777
795
|
const loadedProducts = await this.store.products.loadProducts({
|
|
778
796
|
product_ids: missingIds,
|
|
779
|
-
with_count: [
|
|
797
|
+
with_count: ['bundleGroup', 'optionGroup'],
|
|
780
798
|
with_schedule: 1,
|
|
781
799
|
cacheId: this.cacheId,
|
|
782
|
-
...bookingDate ? {
|
|
783
|
-
schedule_date: bookingDate.format(
|
|
784
|
-
schedule_datetime: bookingDate.format(
|
|
785
|
-
} : {},
|
|
786
|
-
...Number.isFinite(customerId) && customerId > 0 ? {
|
|
800
|
+
...(bookingDate ? {
|
|
801
|
+
schedule_date: bookingDate.format('YYYY-MM-DD'),
|
|
802
|
+
schedule_datetime: bookingDate.format('YYYY-MM-DD HH:mm:ss')
|
|
803
|
+
} : {}),
|
|
804
|
+
...(Number.isFinite(customerId) && customerId > 0 ? {
|
|
805
|
+
customer_id: customerId
|
|
806
|
+
} : {})
|
|
787
807
|
});
|
|
788
|
-
const productById =
|
|
789
|
-
[...localProducts, ...loadedProducts || []].forEach(
|
|
808
|
+
const productById = new Map();
|
|
809
|
+
[...localProducts, ...(loadedProducts || [])].forEach(product => {
|
|
790
810
|
const productId = Number(product.id);
|
|
791
811
|
if (Number.isFinite(productId)) {
|
|
792
812
|
productById.set(productId, product);
|
|
793
813
|
}
|
|
794
814
|
});
|
|
795
|
-
return normalizedIds.map(
|
|
815
|
+
return normalizedIds.map(id => productById.get(id)).filter(product => Boolean(product));
|
|
796
816
|
}
|
|
817
|
+
|
|
797
818
|
/**
|
|
798
819
|
* 获取日程时间段点
|
|
799
820
|
* @param params 参数
|
|
800
821
|
* @returns 日程时间段点
|
|
801
822
|
*/
|
|
802
823
|
async getScheduleTimePoints(params) {
|
|
803
|
-
const result = await this.request.post(
|
|
824
|
+
const result = await this.request.post('/menu/schedule-time-points', {
|
|
804
825
|
menu_list_ids: params.menu_list_ids
|
|
805
826
|
}, {
|
|
806
827
|
osServer: true
|
|
807
828
|
});
|
|
808
829
|
return result.data || [];
|
|
809
830
|
}
|
|
831
|
+
|
|
810
832
|
/**
|
|
811
833
|
* 获取客户列表
|
|
812
834
|
* @param params 查询参数
|
|
@@ -817,10 +839,11 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
817
839
|
const result = await this.store.customer.getCustomerList(params);
|
|
818
840
|
return result;
|
|
819
841
|
} catch (error) {
|
|
820
|
-
console.error(
|
|
842
|
+
console.error('Failed to get customer list:', error);
|
|
821
843
|
throw error;
|
|
822
844
|
}
|
|
823
845
|
}
|
|
846
|
+
|
|
824
847
|
/**
|
|
825
848
|
* 设置活跃客户
|
|
826
849
|
* @param customer 客户信息
|
|
@@ -831,6 +854,7 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
831
854
|
customer
|
|
832
855
|
});
|
|
833
856
|
}
|
|
857
|
+
|
|
834
858
|
/**
|
|
835
859
|
* 获取当前活跃客户
|
|
836
860
|
* @returns 当前活跃客户
|
|
@@ -838,6 +862,7 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
838
862
|
getActiveCustomer() {
|
|
839
863
|
return this.store.customer.getSelectedCustomer();
|
|
840
864
|
}
|
|
865
|
+
|
|
841
866
|
/**
|
|
842
867
|
* 根据ID设置选中的客户
|
|
843
868
|
* @param customerId 客户ID
|
|
@@ -851,6 +876,7 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
851
876
|
});
|
|
852
877
|
}
|
|
853
878
|
}
|
|
879
|
+
|
|
854
880
|
/**
|
|
855
881
|
* 获取所有客户
|
|
856
882
|
* @returns 客户列表
|
|
@@ -858,6 +884,7 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
858
884
|
getCustomers() {
|
|
859
885
|
return this.store.customer.getCustomers();
|
|
860
886
|
}
|
|
887
|
+
|
|
861
888
|
/**
|
|
862
889
|
* 根据ID获取客户
|
|
863
890
|
* @param customerId 客户ID
|
|
@@ -866,12 +893,14 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
866
893
|
getCustomerById(customerId) {
|
|
867
894
|
return this.store.customer.getCustomerById(customerId);
|
|
868
895
|
}
|
|
896
|
+
|
|
869
897
|
/**
|
|
870
898
|
* 清空客户列表
|
|
871
899
|
*/
|
|
872
900
|
clearCustomers() {
|
|
873
901
|
this.store.customer.clearCustomers();
|
|
874
902
|
}
|
|
903
|
+
|
|
875
904
|
/**
|
|
876
905
|
* 添加客户到列表第一位
|
|
877
906
|
* @param customer 要添加的客户信息
|
|
@@ -879,11 +908,13 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
879
908
|
addCustomerToFirst(customer) {
|
|
880
909
|
this.store.customer.addCustomerToFirst(customer);
|
|
881
910
|
}
|
|
911
|
+
|
|
882
912
|
// ─── 下单客户(基于 OrderModule.tempOrder,单一真源)───
|
|
883
913
|
// 与老的 setActiveCustomer/getActiveCustomer 解耦:
|
|
884
914
|
// - 老路:写入 CustomerModule.selectedCustomer(保留兼容,存量调用方不动)
|
|
885
915
|
// - 新路:写入 tempOrder 的 customer 协议字段 + _extend.customerSnapshot
|
|
886
916
|
// 新业务(如 SalesSdk)应优先使用本组方法。
|
|
917
|
+
|
|
887
918
|
/**
|
|
888
919
|
* 设置当前下单客户。
|
|
889
920
|
*
|
|
@@ -896,14 +927,13 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
896
927
|
* 在 BookingTicket 命名空间也 emit 一次,方便上层统一从 Solution 订阅。
|
|
897
928
|
*/
|
|
898
929
|
setOrderCustomer(customer) {
|
|
899
|
-
var _a;
|
|
900
930
|
if (!customer) {
|
|
901
931
|
this.clearOrderCustomer();
|
|
902
932
|
return;
|
|
903
933
|
}
|
|
904
|
-
const previousCustomerId =
|
|
934
|
+
const previousCustomerId = this.store.order.getOrderCustomer()?.customer_id;
|
|
905
935
|
const snapshotBeforeSet = this.store.order.getOrderCustomerSnapshot();
|
|
906
|
-
const patch = (0,
|
|
936
|
+
const patch = (0, _orderCustomer.formatOrderCustomerPatch)(customer);
|
|
907
937
|
const customerUnchanged = Number(previousCustomerId || 0) === Number(patch.customer_id || 0);
|
|
908
938
|
if (!customerUnchanged) {
|
|
909
939
|
this.discountConfigCacheKey = null;
|
|
@@ -912,72 +942,74 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
912
942
|
this.store.order.setOrderCustomer(patch, customer);
|
|
913
943
|
const snapshotAfterOrderSet = this.store.order.getOrderCustomerSnapshot();
|
|
914
944
|
if (customerUnchanged) {
|
|
945
|
+
// hydrate 后 customer_id 已存在但 _extend.customerSnapshot 仍为空时,
|
|
946
|
+
// 须通知 SalesSdk 刷新 selected(否则会一直停在 onSalesOrderLoaded 时的 null)。
|
|
915
947
|
const snapshotReplenished = !snapshotBeforeSet && Boolean(snapshotAfterOrderSet);
|
|
916
948
|
if (snapshotReplenished) {
|
|
917
|
-
const
|
|
918
|
-
this.core.effects.emit(`${this.name}:onOrderCustomerChange`,
|
|
949
|
+
const next = this.buildOrderCustomerPayload();
|
|
950
|
+
this.core.effects.emit(`${this.name}:onOrderCustomerChange`, next);
|
|
919
951
|
}
|
|
920
952
|
return;
|
|
921
953
|
}
|
|
922
954
|
const next = this.buildOrderCustomerPayload();
|
|
923
955
|
this.core.effects.emit(`${this.name}:onOrderCustomerChange`, next);
|
|
924
956
|
this.refreshDiscountConfigAfterOrderCustomerChange(patch.customer_id);
|
|
925
|
-
|
|
957
|
+
// 客户切换可能改变可用促销/赠品;触发一次重算(recursion-safe)。
|
|
958
|
+
const promotionRefreshTask = this.store.order.applyPromotion().then(() => undefined);
|
|
926
959
|
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
|
-
);
|
|
960
|
+
void promotionRefreshTask.then(() => {
|
|
961
|
+
if (this.orderCustomerPromotionRefreshInFlight !== promotionRefreshTask) return;
|
|
962
|
+
this.orderCustomerPromotionRefreshInFlight = null;
|
|
963
|
+
}, error => {
|
|
964
|
+
console.error('[BookingTicket] applyPromotion after customer change failed', error);
|
|
965
|
+
if (this.orderCustomerPromotionRefreshInFlight !== promotionRefreshTask) return;
|
|
966
|
+
this.orderCustomerPromotionRefreshInFlight = null;
|
|
967
|
+
});
|
|
940
968
|
}
|
|
969
|
+
|
|
941
970
|
/**
|
|
942
971
|
* 读取 tempOrder 上的下单客户协议字段;customer_id 缺失时返回 null。
|
|
943
972
|
*/
|
|
944
973
|
getOrderCustomer() {
|
|
945
974
|
return this.store.order.getOrderCustomer();
|
|
946
975
|
}
|
|
976
|
+
|
|
947
977
|
/**
|
|
948
978
|
* 读取 tempOrder._extend.customerSnapshot 中的完整客户对象。
|
|
949
979
|
*/
|
|
950
980
|
getOrderCustomerSnapshot() {
|
|
951
981
|
return this.store.order.getOrderCustomerSnapshot();
|
|
952
982
|
}
|
|
983
|
+
|
|
953
984
|
/**
|
|
954
985
|
* 清空下单客户(协议字段 + snapshot)。
|
|
955
986
|
*/
|
|
956
987
|
clearOrderCustomer() {
|
|
957
|
-
var _a, _b;
|
|
958
988
|
this.store.order.clearOrderCustomer();
|
|
959
989
|
this.discountConfigCacheKey = null;
|
|
960
990
|
this.hasManualDiscountSelection = false;
|
|
961
991
|
const orderStore = this.store.order.store || {};
|
|
962
992
|
const discountModule = orderStore.discount;
|
|
963
|
-
void
|
|
964
|
-
void
|
|
993
|
+
void discountModule?.setOriginalDiscountList?.([]);
|
|
994
|
+
void discountModule?.setDiscountList?.([]);
|
|
965
995
|
this.store.order.applyDiscount();
|
|
966
|
-
void this.store.order.recalculateSummary({
|
|
967
|
-
|
|
996
|
+
void this.store.order.recalculateSummary({
|
|
997
|
+
createIfMissing: true
|
|
998
|
+
}).then(() => {
|
|
968
999
|
const tempOrder = this.store.order.ensureTempOrder();
|
|
969
1000
|
this.store.order.persistTempOrder();
|
|
970
|
-
return this.effectsEmit(
|
|
1001
|
+
return this.effectsEmit('onDiscountApplied', {
|
|
971
1002
|
productList: tempOrder.products || [],
|
|
972
|
-
discountList:
|
|
1003
|
+
discountList: discountModule?.getDiscountList?.() || [],
|
|
973
1004
|
selectedDiscountList: tempOrder.discount_list || [],
|
|
974
1005
|
tempOrder
|
|
975
1006
|
});
|
|
976
|
-
}).catch(
|
|
977
|
-
console.error(
|
|
1007
|
+
}).catch(error => {
|
|
1008
|
+
console.error('Failed to recalculate summary after clearing customer:', error);
|
|
978
1009
|
});
|
|
979
1010
|
this.core.effects.emit(`${this.name}:onOrderCustomerChange`, null);
|
|
980
1011
|
}
|
|
1012
|
+
|
|
981
1013
|
/**
|
|
982
1014
|
* 重置 tempOrder,并同步清空下单客户运行态。
|
|
983
1015
|
*
|
|
@@ -988,50 +1020,49 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
988
1020
|
* 因此在 super.restoreOrder 之后显式清客户,保证 SalesSdk / ticketBooking 订阅方与 tempOrder 一致。
|
|
989
1021
|
*/
|
|
990
1022
|
async restoreOrder() {
|
|
991
|
-
var _a;
|
|
992
1023
|
const tempOrder = await super.restoreOrder();
|
|
993
1024
|
this.clearOrderCustomer();
|
|
994
|
-
|
|
1025
|
+
this.store.customer?.setSelectedCustomer(null);
|
|
995
1026
|
return tempOrder;
|
|
996
1027
|
}
|
|
1028
|
+
|
|
997
1029
|
/** 内部:基于 OrderModule 当前状态构造一份 OrderCustomerChangePayload。 */
|
|
998
1030
|
buildOrderCustomerPayload() {
|
|
999
1031
|
const patch = this.store.order.getOrderCustomer();
|
|
1000
|
-
if (!patch)
|
|
1001
|
-
return null;
|
|
1032
|
+
if (!patch) return null;
|
|
1002
1033
|
return {
|
|
1003
1034
|
patch,
|
|
1004
1035
|
snapshot: this.store.order.getOrderCustomerSnapshot()
|
|
1005
1036
|
};
|
|
1006
1037
|
}
|
|
1007
1038
|
refreshDiscountConfigAfterOrderCustomerChange(customerId) {
|
|
1008
|
-
if (!customerId || customerId === 1)
|
|
1009
|
-
return Promise.resolve();
|
|
1039
|
+
if (!customerId || customerId === 1) return Promise.resolve();
|
|
1010
1040
|
if (this.orderCustomerDiscountRefreshInFlight && this.orderCustomerDiscountRefreshCustomerId === customerId) {
|
|
1011
1041
|
return this.orderCustomerDiscountRefreshInFlight;
|
|
1012
1042
|
}
|
|
1013
1043
|
const previousRefresh = this.orderCustomerDiscountRefreshInFlight;
|
|
1014
1044
|
const refreshTask = (async () => {
|
|
1015
|
-
var _a, _b, _c, _d;
|
|
1016
1045
|
if (previousRefresh) {
|
|
1017
|
-
await previousRefresh.catch(() =>
|
|
1046
|
+
await previousRefresh.catch(() => undefined);
|
|
1018
1047
|
}
|
|
1019
1048
|
const currentCustomer = this.store.order.getOrderCustomer();
|
|
1020
1049
|
if (!currentCustomer || Number(currentCustomer.customer_id) !== customerId) {
|
|
1021
1050
|
return;
|
|
1022
1051
|
}
|
|
1023
|
-
const tempOrder =
|
|
1024
|
-
const orderId =
|
|
1025
|
-
const action = !orderId || String(orderId).startsWith(
|
|
1026
|
-
await this.loadDiscountConfig({
|
|
1052
|
+
const tempOrder = this.store.order.getTempOrder?.();
|
|
1053
|
+
const orderId = tempOrder?.order_id || this.getOrderIdentity?.()?.orderId;
|
|
1054
|
+
const action = !orderId || String(orderId).startsWith('local_order') ? 'create' : 'edit';
|
|
1055
|
+
await this.loadDiscountConfig({
|
|
1056
|
+
customerId,
|
|
1057
|
+
action
|
|
1058
|
+
});
|
|
1027
1059
|
})();
|
|
1028
1060
|
this.orderCustomerDiscountRefreshInFlight = refreshTask;
|
|
1029
1061
|
this.orderCustomerDiscountRefreshCustomerId = customerId;
|
|
1030
|
-
refreshTask.catch(
|
|
1031
|
-
console.error(
|
|
1062
|
+
refreshTask.catch(error => {
|
|
1063
|
+
console.error('Failed to load discount config after customer change:', error);
|
|
1032
1064
|
}).finally(() => {
|
|
1033
|
-
if (this.orderCustomerDiscountRefreshInFlight !== refreshTask)
|
|
1034
|
-
return;
|
|
1065
|
+
if (this.orderCustomerDiscountRefreshInFlight !== refreshTask) return;
|
|
1035
1066
|
this.orderCustomerDiscountRefreshInFlight = null;
|
|
1036
1067
|
this.orderCustomerDiscountRefreshCustomerId = null;
|
|
1037
1068
|
});
|
|
@@ -1041,6 +1072,8 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1041
1072
|
return this.orderCustomerPromotionRefreshInFlight || Promise.resolve();
|
|
1042
1073
|
}
|
|
1043
1074
|
async prepareProductPriceQueryContext(customerId) {
|
|
1075
|
+
// onOrderCustomerChange 的订阅回调会立即开始重报价,而客户 Wallet/优惠资产
|
|
1076
|
+
// 在事件派发后才创建异步刷新任务。先让出一个微任务,确保能观察到该任务。
|
|
1044
1077
|
await Promise.resolve();
|
|
1045
1078
|
const normalizedCustomerId = Number(customerId || 0);
|
|
1046
1079
|
const refreshTask = this.orderCustomerDiscountRefreshInFlight;
|
|
@@ -1050,8 +1083,11 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1050
1083
|
}
|
|
1051
1084
|
}
|
|
1052
1085
|
preferAuthoritativeProductQueryPrice() {
|
|
1086
|
+
// BookingTicket 的 /product/query 已按预约时间、客户及 Wallet 上下文执行
|
|
1087
|
+
// 智能定价;再次应用 legacy quotation 会把最终价覆盖成另一套时段价格。
|
|
1053
1088
|
return true;
|
|
1054
1089
|
}
|
|
1090
|
+
|
|
1055
1091
|
/**
|
|
1056
1092
|
* 获取客户分页信息
|
|
1057
1093
|
* @returns 分页信息
|
|
@@ -1059,6 +1095,7 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1059
1095
|
getCustomerPaginationInfo() {
|
|
1060
1096
|
return this.store.customer.getPaginationInfo();
|
|
1061
1097
|
}
|
|
1098
|
+
|
|
1062
1099
|
/**
|
|
1063
1100
|
* 获取客户列表总数
|
|
1064
1101
|
* @returns 总数
|
|
@@ -1066,6 +1103,7 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1066
1103
|
getCustomerTotal() {
|
|
1067
1104
|
return this.store.customer.getState().total;
|
|
1068
1105
|
}
|
|
1106
|
+
|
|
1069
1107
|
/**
|
|
1070
1108
|
* 设置客户分页信息
|
|
1071
1109
|
* @param page 页码
|
|
@@ -1074,6 +1112,7 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1074
1112
|
setCustomerPaginationInfo(page, pageSize) {
|
|
1075
1113
|
this.store.customer.setPaginationInfo(page, pageSize);
|
|
1076
1114
|
}
|
|
1115
|
+
|
|
1077
1116
|
/**
|
|
1078
1117
|
* 便捷方法:切换客户分页并自动获取数据
|
|
1079
1118
|
* @param page 页码
|
|
@@ -1082,16 +1121,14 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1082
1121
|
*/
|
|
1083
1122
|
async changeCustomerPage(page, pageSize) {
|
|
1084
1123
|
try {
|
|
1085
|
-
const result = await this.store.customer.changeCustomerPage(
|
|
1086
|
-
page,
|
|
1087
|
-
pageSize
|
|
1088
|
-
);
|
|
1124
|
+
const result = await this.store.customer.changeCustomerPage(page, pageSize);
|
|
1089
1125
|
return result;
|
|
1090
1126
|
} catch (error) {
|
|
1091
|
-
console.error(
|
|
1127
|
+
console.error('Failed to change customer page:', error);
|
|
1092
1128
|
throw error;
|
|
1093
1129
|
}
|
|
1094
1130
|
}
|
|
1131
|
+
|
|
1095
1132
|
/**
|
|
1096
1133
|
* 滚动加载更多客户数据 - 数据会追加到现有列表中
|
|
1097
1134
|
* @returns 客户列表响应
|
|
@@ -1102,10 +1139,11 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1102
1139
|
this.core.effects.emit(`${this.name}:onCustomerListUpdate`, result);
|
|
1103
1140
|
return result;
|
|
1104
1141
|
} catch (error) {
|
|
1105
|
-
console.error(
|
|
1142
|
+
console.error('Failed to load more customers:', error);
|
|
1106
1143
|
throw error;
|
|
1107
1144
|
}
|
|
1108
1145
|
}
|
|
1146
|
+
|
|
1109
1147
|
/**
|
|
1110
1148
|
* 重置并重新开始滚动加载客户数据
|
|
1111
1149
|
* @param params 查询参数
|
|
@@ -1117,10 +1155,11 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1117
1155
|
this.core.effects.emit(`${this.name}:onCustomerListReset`, result);
|
|
1118
1156
|
return result;
|
|
1119
1157
|
} catch (error) {
|
|
1120
|
-
console.error(
|
|
1158
|
+
console.error('Failed to reset and load customers:', error);
|
|
1121
1159
|
throw error;
|
|
1122
1160
|
}
|
|
1123
1161
|
}
|
|
1162
|
+
|
|
1124
1163
|
/**
|
|
1125
1164
|
* 检查是否还有更多客户数据可以加载
|
|
1126
1165
|
* @returns 是否还有更多数据
|
|
@@ -1128,6 +1167,7 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1128
1167
|
hasMoreCustomers() {
|
|
1129
1168
|
return this.store.customer.hasMoreCustomers();
|
|
1130
1169
|
}
|
|
1170
|
+
|
|
1131
1171
|
/**
|
|
1132
1172
|
* 获取当前的客户搜索条件
|
|
1133
1173
|
* @returns 当前搜索条件
|
|
@@ -1135,6 +1175,7 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1135
1175
|
getCurrentCustomerSearchParams() {
|
|
1136
1176
|
return this.store.customer.getCurrentSearchParams();
|
|
1137
1177
|
}
|
|
1178
|
+
|
|
1138
1179
|
/**
|
|
1139
1180
|
* 获取客户列表状态(包含滚动加载相关状态)
|
|
1140
1181
|
* @returns 客户状态
|
|
@@ -1142,96 +1183,105 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1142
1183
|
getCustomerState() {
|
|
1143
1184
|
return this.store.customer.getState();
|
|
1144
1185
|
}
|
|
1186
|
+
|
|
1145
1187
|
/**
|
|
1146
1188
|
* 全局扫描监听
|
|
1147
1189
|
* @param callback 回调
|
|
1148
1190
|
*/
|
|
1149
1191
|
scanGlobalListener(callback) {
|
|
1150
|
-
const localSearch =
|
|
1151
|
-
const scanCallback = (0,
|
|
1152
|
-
|
|
1153
|
-
localSearch,
|
|
1154
|
-
this.getSubmitOrderSalesChannel()
|
|
1155
|
-
);
|
|
1156
|
-
const safeCallback = (d) => {
|
|
1192
|
+
const localSearch = v => this.store.products.findProductsByCodeOrBarcode(v);
|
|
1193
|
+
const scanCallback = (0, _handleScan.handleGlobalScan)(this.request, localSearch, this.getSubmitOrderSalesChannel());
|
|
1194
|
+
const safeCallback = d => {
|
|
1157
1195
|
try {
|
|
1158
1196
|
callback(d);
|
|
1159
1197
|
} catch (error) {
|
|
1160
|
-
console.error(
|
|
1198
|
+
console.error('scanGlobalListener传入的回调函数异常', error);
|
|
1161
1199
|
}
|
|
1162
1200
|
};
|
|
1163
|
-
const listener = {
|
|
1201
|
+
const listener = {
|
|
1202
|
+
key: 'global',
|
|
1203
|
+
callback: safeCallback
|
|
1204
|
+
};
|
|
1164
1205
|
const removeListener = this.scan.addListener(listener, scanCallback);
|
|
1165
1206
|
return removeListener;
|
|
1166
1207
|
}
|
|
1208
|
+
|
|
1167
1209
|
/**
|
|
1168
1210
|
* 客户扫描监听
|
|
1169
1211
|
* @param callback 回调
|
|
1170
1212
|
*/
|
|
1171
1213
|
scanCustomerListener(callback) {
|
|
1172
|
-
const scanCallback = (0,
|
|
1173
|
-
const safeCallback =
|
|
1214
|
+
const scanCallback = (0, _handleScan.handleCustomerScan)();
|
|
1215
|
+
const safeCallback = d => {
|
|
1174
1216
|
try {
|
|
1175
1217
|
callback(d);
|
|
1176
1218
|
} catch (error) {
|
|
1177
|
-
console.error(
|
|
1219
|
+
console.error('scanCustomerListener传入的回调函数异常', error);
|
|
1178
1220
|
}
|
|
1179
1221
|
};
|
|
1180
|
-
const listener = {
|
|
1222
|
+
const listener = {
|
|
1223
|
+
key: 'customer',
|
|
1224
|
+
callback: safeCallback
|
|
1225
|
+
};
|
|
1181
1226
|
const removeListener = this.scan.addListener(listener, scanCallback);
|
|
1182
1227
|
return removeListener;
|
|
1183
1228
|
}
|
|
1229
|
+
|
|
1184
1230
|
/**
|
|
1185
1231
|
* @title 通用扫描监听
|
|
1186
1232
|
* @description 直接将扫描结果返回给调用方
|
|
1187
1233
|
* @param callback 回调
|
|
1188
1234
|
*/
|
|
1189
1235
|
scanUniversalListener(callback, key) {
|
|
1190
|
-
const scanCallback = (0,
|
|
1191
|
-
const safeCallback =
|
|
1236
|
+
const scanCallback = (0, _handleScan.handleUniversalScan)();
|
|
1237
|
+
const safeCallback = d => {
|
|
1192
1238
|
try {
|
|
1193
1239
|
callback(d);
|
|
1194
1240
|
} catch (error) {
|
|
1195
|
-
console.error(
|
|
1196
|
-
`scanUniversalListener传入的回调函数异常, key: ${key}`,
|
|
1197
|
-
error
|
|
1198
|
-
);
|
|
1241
|
+
console.error(`scanUniversalListener传入的回调函数异常, key: ${key}`, error);
|
|
1199
1242
|
}
|
|
1200
1243
|
};
|
|
1201
|
-
const listener = {
|
|
1244
|
+
const listener = {
|
|
1245
|
+
key,
|
|
1246
|
+
callback: safeCallback
|
|
1247
|
+
};
|
|
1202
1248
|
const removeListener = this.scan.addListener(listener, scanCallback);
|
|
1203
1249
|
return removeListener;
|
|
1204
1250
|
}
|
|
1251
|
+
|
|
1205
1252
|
/**
|
|
1206
1253
|
* 调用摄像头
|
|
1207
1254
|
* @param data 用户自定义数据
|
|
1208
1255
|
*/
|
|
1209
1256
|
activateCamera(data) {
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
key: "active_native_scanner",
|
|
1257
|
+
this.window?.interaction?.utils?.postMessageToApp?.({
|
|
1258
|
+
module: 'global',
|
|
1259
|
+
key: 'active_native_scanner',
|
|
1214
1260
|
data
|
|
1215
1261
|
});
|
|
1216
1262
|
}
|
|
1263
|
+
|
|
1217
1264
|
/**
|
|
1218
1265
|
* 禁用所有扫描监听
|
|
1219
1266
|
*/
|
|
1220
1267
|
disableAllScanListeners() {
|
|
1221
1268
|
this.scan.disableAllListeners();
|
|
1222
1269
|
}
|
|
1270
|
+
|
|
1223
1271
|
/**
|
|
1224
1272
|
* 启用所有扫描监听
|
|
1225
1273
|
*/
|
|
1226
1274
|
enableAllScanListeners() {
|
|
1227
1275
|
this.scan.enableAllListeners();
|
|
1228
1276
|
}
|
|
1277
|
+
|
|
1229
1278
|
/**
|
|
1230
1279
|
* 清空所有扫描监听对应的任务执行队列
|
|
1231
1280
|
*/
|
|
1232
1281
|
clearAllScanListenersTaskQueue() {
|
|
1233
1282
|
this.scan.clearTaskQueue();
|
|
1234
1283
|
}
|
|
1284
|
+
|
|
1235
1285
|
/**
|
|
1236
1286
|
* 获取其他参数
|
|
1237
1287
|
* @returns 其他参数
|
|
@@ -1239,110 +1289,128 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1239
1289
|
async getOtherParams() {
|
|
1240
1290
|
return this.otherParams;
|
|
1241
1291
|
}
|
|
1292
|
+
|
|
1242
1293
|
// ─── BookingContext API(透传给 BookingContextModule) ──────────────────────
|
|
1243
1294
|
// SalesSdkProvider 挂载时默认调 initBookingContext;也可由 UI 显式 set* 灌入已有数据。
|
|
1295
|
+
|
|
1244
1296
|
/** 拉取 board config 并写入 BookingContext。 */
|
|
1245
1297
|
loadBookingConfig(params) {
|
|
1246
1298
|
return this.store.bookingContext.loadBookingConfig(params);
|
|
1247
1299
|
}
|
|
1300
|
+
|
|
1248
1301
|
/** 拉取资源全集并写入 BookingContext。 */
|
|
1249
1302
|
loadBookingResources(params) {
|
|
1250
1303
|
return this.store.bookingContext.loadResources(params);
|
|
1251
1304
|
}
|
|
1305
|
+
|
|
1252
1306
|
/** 初始化 BookingContext(date + config + resources)。 */
|
|
1253
1307
|
initBookingContext(params) {
|
|
1254
1308
|
return this.store.bookingContext.initBookingContext(params);
|
|
1255
1309
|
}
|
|
1310
|
+
|
|
1256
1311
|
/** 当前 store 是否已具备与入参等价的 config / resources(无需再请求接口)。 */
|
|
1257
1312
|
isBookingContextReady(params) {
|
|
1258
1313
|
return this.store.bookingContext.isBookingContextReady(params);
|
|
1259
1314
|
}
|
|
1315
|
+
|
|
1260
1316
|
/** 写入 booking config(来源:`/core/board/management/config`)。 */
|
|
1261
1317
|
setBookingConfig(config) {
|
|
1262
1318
|
this.store.bookingContext.setBookingConfig(config);
|
|
1263
1319
|
}
|
|
1320
|
+
|
|
1264
1321
|
/** 读取当前 booking config。 */
|
|
1265
1322
|
getBookingConfig() {
|
|
1266
|
-
|
|
1267
|
-
return (_a = this.store.bookingContext) == null ? void 0 : _a.getBookingConfig();
|
|
1323
|
+
return this.store.bookingContext?.getBookingConfig();
|
|
1268
1324
|
}
|
|
1325
|
+
|
|
1269
1326
|
/** 写入资源全集(来源:`/form/schedule`),同步派生 resourcesOriginMap。 */
|
|
1270
1327
|
setResources(resources) {
|
|
1271
1328
|
this.store.bookingContext.setResources(resources);
|
|
1272
1329
|
}
|
|
1330
|
+
|
|
1273
1331
|
/** 读取资源全集(浅克隆)。 */
|
|
1274
1332
|
getResourcesOrigin() {
|
|
1275
1333
|
return this.store.bookingContext.getResourcesOrigin();
|
|
1276
1334
|
}
|
|
1335
|
+
|
|
1277
1336
|
/** 读取资源全集 map(id → resource)。 */
|
|
1278
1337
|
getResourcesOriginMap() {
|
|
1279
1338
|
return this.store.bookingContext.getResourcesOriginMap();
|
|
1280
1339
|
}
|
|
1340
|
+
|
|
1281
1341
|
/** 写入当前选择的日期;支持 dayjs / Date / string。 */
|
|
1282
1342
|
setBookingDate(date) {
|
|
1283
1343
|
this.store.bookingContext.setDate(date);
|
|
1284
1344
|
}
|
|
1345
|
+
|
|
1285
1346
|
/** 读取当前选择的日期(统一 string)。 */
|
|
1286
1347
|
getBookingDate() {
|
|
1287
1348
|
return this.store.bookingContext.getDate();
|
|
1288
1349
|
}
|
|
1350
|
+
|
|
1289
1351
|
/** 读取 BookingContext 完整 store(调试 / 测试 / 透传给 SDK 使用)。 */
|
|
1290
1352
|
getBookingContextState() {
|
|
1291
1353
|
return this.store.bookingContext.getState();
|
|
1292
1354
|
}
|
|
1355
|
+
|
|
1293
1356
|
/** 清空 BookingContext(切租户 / destroy 场景)。 */
|
|
1294
1357
|
clearBookingContext() {
|
|
1295
1358
|
this.store.bookingContext.clear();
|
|
1296
1359
|
}
|
|
1360
|
+
|
|
1297
1361
|
/**
|
|
1298
1362
|
* 构造 BookingContext 计算上下文(供 getProductExtend / getResourceByIds 等读 API 复用)。
|
|
1299
1363
|
*/
|
|
1300
1364
|
buildBookingCalcContext(extra) {
|
|
1301
1365
|
const state = this.store.bookingContext.getState();
|
|
1302
|
-
const date =
|
|
1366
|
+
const date = extra?.date ?? state.date;
|
|
1303
1367
|
return {
|
|
1304
1368
|
bookingConfig: state.bookingConfig,
|
|
1305
1369
|
resourcesOrigin: state.resourcesOrigin,
|
|
1306
1370
|
resourcesOriginMap: state.resourcesOriginMap,
|
|
1307
1371
|
date,
|
|
1308
|
-
presetStartTime:
|
|
1309
|
-
...extra || {}
|
|
1372
|
+
presetStartTime: extra?.presetStartTime ?? (0, _BookingContext.derivePresetStartTimeFromDate)(date),
|
|
1373
|
+
...(extra || {})
|
|
1310
1374
|
};
|
|
1311
1375
|
}
|
|
1376
|
+
|
|
1312
1377
|
/**
|
|
1313
1378
|
* 取商品当前可选资源列表(透传 OS BookingContext utils#getResourceByIds)。
|
|
1314
1379
|
* `extraResources` 用于把拖入未绑定的资源也展示出来。
|
|
1315
1380
|
*/
|
|
1316
1381
|
getResourcesForProduct(product, options) {
|
|
1317
|
-
var _a, _b;
|
|
1318
1382
|
const ctx = this.buildBookingCalcContext();
|
|
1319
|
-
return (0,
|
|
1320
|
-
resourceTab:
|
|
1383
|
+
return (0, _BookingContext.getResourceByIds)(ctx.resourcesOriginMap || {}, product, {
|
|
1384
|
+
resourceTab: ctx.bookingConfig?.config?.resource_tab,
|
|
1321
1385
|
resourcesOrigin: ctx.resourcesOrigin,
|
|
1322
|
-
extraResources:
|
|
1386
|
+
extraResources: options?.extraResources || []
|
|
1323
1387
|
});
|
|
1324
1388
|
}
|
|
1389
|
+
|
|
1325
1390
|
/**
|
|
1326
1391
|
* 拼装 cacheItem 的 _extend / _data(资源 / 容量 / timeObj),与 info2 `getProductExtend` 等价。
|
|
1327
1392
|
*/
|
|
1328
1393
|
getProductExtend(cacheItem, extra) {
|
|
1329
1394
|
const preparedCacheItem = withProductOptionString(cacheItem);
|
|
1330
|
-
const result = (0,
|
|
1395
|
+
const result = (0, _BookingContext.getProductExtend)({
|
|
1331
1396
|
cacheItem: preparedCacheItem,
|
|
1332
1397
|
ctx: this.buildBookingCalcContext(extra)
|
|
1333
1398
|
});
|
|
1334
1399
|
return result;
|
|
1335
1400
|
}
|
|
1401
|
+
|
|
1336
1402
|
/**
|
|
1337
1403
|
* 取资源不可用原因列表(结构化 enum + params,i18n 文案由 UI 渲染)。
|
|
1338
1404
|
*/
|
|
1339
1405
|
getResourceErrors(resource, cacheItem) {
|
|
1340
|
-
return (0,
|
|
1406
|
+
return (0, _BookingContext.getResourceErrors)(resource, cacheItem);
|
|
1341
1407
|
}
|
|
1408
|
+
|
|
1342
1409
|
// ─── addProduct 决策 / 转换 API(SDK 加车下沉所需) ─────────────────────────
|
|
1343
1410
|
// 这一组方法是 SalesSdkCartContext.addProduct / confirmDetail 的 OS 后端。
|
|
1344
1411
|
// 调用方传入 ProductData,OS 自取 bookingContext / customer / date 等上下文,
|
|
1345
1412
|
// 输出 (a) autoClose 决策结果或 (b) `{ product, booking }` 协议入参。
|
|
1413
|
+
|
|
1346
1414
|
/**
|
|
1347
1415
|
* session 商品 catalog 日期与 TimeBar 不一致时写业务日志。
|
|
1348
1416
|
*
|
|
@@ -1350,51 +1418,53 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1350
1418
|
* this.logSessionCatalogDateMismatch(product, ctx.date);
|
|
1351
1419
|
*/
|
|
1352
1420
|
logSessionCatalogDateMismatch(item, bookingDate) {
|
|
1353
|
-
var _a, _b;
|
|
1354
1421
|
const logger = this.logger;
|
|
1355
|
-
if (!
|
|
1356
|
-
|
|
1357
|
-
const
|
|
1358
|
-
const staleInfo = (0, import_sessionCatalogStale.buildSessionCatalogStaleInfo)(item, bookingDate);
|
|
1422
|
+
if (!logger?.addLog) return;
|
|
1423
|
+
const tempOrder = this.getTempOrder?.();
|
|
1424
|
+
const staleInfo = (0, _sessionCatalogStale.buildSessionCatalogStaleInfo)(item, bookingDate);
|
|
1359
1425
|
logger.addLog({
|
|
1360
|
-
type:
|
|
1426
|
+
type: 'warning',
|
|
1361
1427
|
title: `[BookingTicket] session catalog date mismatch, reload products`,
|
|
1362
1428
|
metadata: {
|
|
1363
|
-
order_id:
|
|
1364
|
-
external_sale_number:
|
|
1429
|
+
order_id: tempOrder?.order_id ?? null,
|
|
1430
|
+
external_sale_number: tempOrder?.external_sale_number ?? null,
|
|
1365
1431
|
...staleInfo,
|
|
1366
|
-
cartDetailValueSession:
|
|
1432
|
+
cartDetailValueSession: item?.cartDetailValue?.session ?? null
|
|
1367
1433
|
}
|
|
1368
1434
|
});
|
|
1369
1435
|
}
|
|
1436
|
+
|
|
1370
1437
|
/**
|
|
1371
1438
|
* 加车前:session 商品 catalog 日历日与 bookingDate 不一致时中断加购,交由 SDK reload products。
|
|
1372
1439
|
*/
|
|
1373
1440
|
resolveSessionCatalogBeforeAdd(item, ctx) {
|
|
1374
|
-
if (!(0,
|
|
1441
|
+
if (!(0, _sessionCatalogStale.isSessionCatalogDateStale)(item, ctx.date)) {
|
|
1375
1442
|
return null;
|
|
1376
1443
|
}
|
|
1377
1444
|
this.logSessionCatalogDateMismatch(item, ctx.date);
|
|
1378
|
-
return {
|
|
1445
|
+
return {
|
|
1446
|
+
action: 'reloadCatalog'
|
|
1447
|
+
};
|
|
1379
1448
|
}
|
|
1449
|
+
|
|
1380
1450
|
/**
|
|
1381
1451
|
* 拼装 addProductDecision 通用上下文(从 store 自取)。
|
|
1382
1452
|
*/
|
|
1383
1453
|
buildAddProductCtx(extra) {
|
|
1384
|
-
var _a, _b;
|
|
1385
1454
|
const bookingContextState = this.store.bookingContext.getState();
|
|
1386
|
-
const date =
|
|
1387
|
-
const orderCustomerId =
|
|
1455
|
+
const date = extra?.date ?? bookingContextState.date;
|
|
1456
|
+
const orderCustomerId = this.getOrderCustomerSnapshot()?.id ?? this.store.order.getTempOrder()?.customer_id ?? undefined;
|
|
1388
1457
|
return {
|
|
1389
1458
|
bookingConfig: bookingContextState.bookingConfig,
|
|
1390
1459
|
resourcesOrigin: bookingContextState.resourcesOrigin,
|
|
1391
1460
|
resourcesOriginMap: bookingContextState.resourcesOriginMap,
|
|
1392
1461
|
date,
|
|
1393
|
-
presetStartTime:
|
|
1462
|
+
presetStartTime: extra?.presetStartTime ?? (0, _BookingContext.derivePresetStartTimeFromDate)(date),
|
|
1394
1463
|
customerId: orderCustomerId,
|
|
1395
|
-
...extra || {}
|
|
1464
|
+
...(extra || {})
|
|
1396
1465
|
};
|
|
1397
1466
|
}
|
|
1467
|
+
|
|
1398
1468
|
/**
|
|
1399
1469
|
* 加车两阶段主决策(规格弹窗 / 资源编辑 / 直接加车)。
|
|
1400
1470
|
* 与 ticketBooking `handleSelectProduct` + `handleBooking4Service` 等价。
|
|
@@ -1405,60 +1475,75 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1405
1475
|
if (staleDecision) {
|
|
1406
1476
|
return staleDecision;
|
|
1407
1477
|
}
|
|
1408
|
-
return (0,
|
|
1478
|
+
return (0, _addProductDecision.decideAddProduct)(item, ctx);
|
|
1409
1479
|
}
|
|
1480
|
+
|
|
1410
1481
|
/** 规格弹窗 callback 后的第二段决策。 */
|
|
1411
1482
|
decideAfterDetail(cacheItem, options) {
|
|
1412
|
-
return (0,
|
|
1483
|
+
return (0, _addProductDecision.decideAfterDetail)(cacheItem, this.buildAddProductCtx(options));
|
|
1413
1484
|
}
|
|
1485
|
+
|
|
1414
1486
|
/**
|
|
1415
1487
|
* @deprecated 请用 `decideAddProduct`;`autoClose=true` 仅当 action=add。
|
|
1416
1488
|
*/
|
|
1417
1489
|
decideAutoClose(item, options) {
|
|
1418
|
-
return (0,
|
|
1490
|
+
return (0, _addProductDecision.decideAutoClose)(item, this.buildAddProductCtx(options));
|
|
1419
1491
|
}
|
|
1492
|
+
|
|
1420
1493
|
/** 替代 info2 `getIsEject`:商品是否需要弹窗(0/1)。 */
|
|
1421
|
-
getIsEject(item, type =
|
|
1422
|
-
return (0,
|
|
1494
|
+
getIsEject(item, type = 'select') {
|
|
1495
|
+
return (0, _addProductDecision.getIsEject)(item, type);
|
|
1423
1496
|
}
|
|
1497
|
+
|
|
1424
1498
|
/** 仅 session 商品(无 variant/option/package)→ true。 */
|
|
1425
1499
|
getIsOnlySession(item) {
|
|
1426
|
-
return (0,
|
|
1500
|
+
return (0, _addProductDecision.getIsOnlySession)(item);
|
|
1427
1501
|
}
|
|
1502
|
+
|
|
1428
1503
|
/**
|
|
1429
1504
|
* 拼装 requiresDetail payload(给 SDK 直接 return 给 UI 用)。
|
|
1430
1505
|
*/
|
|
1431
1506
|
buildRequiresDetailPayload(item, options) {
|
|
1432
1507
|
const ctx = this.buildAddProductCtx(options);
|
|
1433
|
-
return (0,
|
|
1508
|
+
return (0, _addProductDecision.buildRequiresDetailPayload)(item, ctx);
|
|
1434
1509
|
}
|
|
1510
|
+
|
|
1435
1511
|
/**
|
|
1436
1512
|
* 把 detail 弹窗回调结果(e, extension_type, detail)转换为 `(product, booking)` 入参。
|
|
1437
1513
|
* 内部会先拼 cacheItem,再走 cacheItemToBookingInput 严格协议对齐。
|
|
1438
1514
|
*/
|
|
1439
1515
|
transformDetailToProductAndBooking(input) {
|
|
1440
|
-
const {
|
|
1516
|
+
const {
|
|
1517
|
+
item,
|
|
1518
|
+
cacheItem: preparedCacheItem,
|
|
1519
|
+
detailResult,
|
|
1520
|
+
options
|
|
1521
|
+
} = input;
|
|
1441
1522
|
const ctx = this.buildAddProductCtx(options);
|
|
1442
|
-
const cacheItem = preparedCacheItem || (detailResult ? (0,
|
|
1443
|
-
return (0,
|
|
1523
|
+
const cacheItem = preparedCacheItem || (detailResult ? (0, _addProductDecision.buildCacheItemFromDetail)(item, detailResult, ctx) : (0, _addProductDecision.buildCacheItemFromCartDetail)(item, ctx));
|
|
1524
|
+
return (0, _addProductDecision.transformDetailToProductAndBooking)(cacheItem, ctx);
|
|
1444
1525
|
}
|
|
1526
|
+
|
|
1445
1527
|
/**
|
|
1446
1528
|
* 从已加车的 order line + booking 反查资源编辑抽屉所需的 cacheItem。
|
|
1447
1529
|
* 供 SalesSdk「编辑资源」等场景使用;字段语义与 buildCacheItemFromDetail 产出对齐。
|
|
1448
1530
|
*/
|
|
1449
1531
|
buildCacheItemFromOrderLine(input) {
|
|
1450
|
-
return (0,
|
|
1532
|
+
return (0, _buildCacheItemFromOrderLine.buildCacheItemFromOrderLine)(input);
|
|
1451
1533
|
}
|
|
1534
|
+
|
|
1452
1535
|
/**
|
|
1453
1536
|
* 从已加车的普通商品 order line 反查 SkuDetailModal edit 所需的 cacheItem。
|
|
1454
1537
|
*/
|
|
1455
1538
|
buildNormalProductCacheItemFromOrderLine(input) {
|
|
1456
|
-
return (0,
|
|
1539
|
+
return (0, _buildNormalProductCacheItemFromOrderLine.buildNormalProductCacheItemFromOrderLine)(input);
|
|
1457
1540
|
}
|
|
1541
|
+
|
|
1458
1542
|
/** 文档别名:与 OrderModule.updateOrderProduct 一致。 */
|
|
1459
1543
|
async updateProductInOrder(params) {
|
|
1460
1544
|
return this.updateOrderProduct(params);
|
|
1461
1545
|
}
|
|
1546
|
+
|
|
1462
1547
|
/**
|
|
1463
1548
|
* 全局扫码 pubsub 入口:解析码值 → 搜索 → 业务分发(客户 / 加车 / 开单)。
|
|
1464
1549
|
* UI 层在 pubsub 订阅回调里注入 `bridge`(uiHosts / action / cart.confirm*)。
|
|
@@ -1473,55 +1558,56 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1473
1558
|
* ```
|
|
1474
1559
|
*/
|
|
1475
1560
|
async handleGlobalScanCode(code, bridge) {
|
|
1476
|
-
|
|
1477
|
-
const trimmed = typeof code === "string" ? code.trim() : "";
|
|
1561
|
+
const trimmed = typeof code === 'string' ? code.trim() : '';
|
|
1478
1562
|
if (!trimmed) {
|
|
1479
|
-
|
|
1480
|
-
return {
|
|
1563
|
+
bridge?.onNotify?.('fail', 'pisell2.text.scan-global-failed');
|
|
1564
|
+
return {
|
|
1565
|
+
status: 'failed',
|
|
1566
|
+
reason: 'empty_code'
|
|
1567
|
+
};
|
|
1481
1568
|
}
|
|
1482
1569
|
try {
|
|
1483
|
-
const localSearch =
|
|
1484
|
-
const scanCallback = (0,
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
);
|
|
1489
|
-
const
|
|
1490
|
-
const formatted = (0, import_formatGlobalScan.formatGlobalScanResult)(raw, trimmed);
|
|
1570
|
+
const localSearch = v => this.store.products.findProductsByCodeOrBarcode(v);
|
|
1571
|
+
const scanCallback = (0, _handleScan.handleGlobalScan)(this.request, localSearch, this.getSubmitOrderSalesChannel());
|
|
1572
|
+
const raw = await scanCallback({
|
|
1573
|
+
type: 'nativeScanner',
|
|
1574
|
+
value: trimmed
|
|
1575
|
+
});
|
|
1576
|
+
const formatted = (0, _formatGlobalScan.formatGlobalScanResult)(raw, trimmed);
|
|
1491
1577
|
if (!formatted) {
|
|
1492
|
-
|
|
1493
|
-
return {
|
|
1578
|
+
bridge?.onNotify?.('fail', 'pisell2.text.scan-global-failed');
|
|
1579
|
+
return {
|
|
1580
|
+
status: 'failed',
|
|
1581
|
+
reason: 'not_found'
|
|
1582
|
+
};
|
|
1494
1583
|
}
|
|
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);
|
|
1584
|
+
const result = await (0, _applyGlobalScan.applyGlobalScan)({
|
|
1585
|
+
setOrderCustomer: customer => this.setOrderCustomer(customer),
|
|
1586
|
+
getOrderCustomerSnapshot: () => this.getOrderCustomerSnapshot(),
|
|
1587
|
+
getBusinessCode: () => this.otherParams?.businessCode,
|
|
1588
|
+
buildAddProductCtx: extra => this.buildAddProductCtx(extra),
|
|
1589
|
+
decideAddProduct: (item, options) => this.decideAddProduct(item, options),
|
|
1590
|
+
decideAfterDetail: (cacheItem, options) => this.decideAfterDetail(cacheItem, options),
|
|
1591
|
+
transformDetailToProductAndBooking: input => this.transformDetailToProductAndBooking(input),
|
|
1592
|
+
addProductToOrder: (product, booking) => this.addProductToOrder(product, booking),
|
|
1593
|
+
refreshWalletAssets: params => this.refreshWalletAssets(params),
|
|
1594
|
+
scanWalletAsset: scanCode => this.scanWalletAsset(scanCode)
|
|
1595
|
+
}, formatted, bridge);
|
|
1596
|
+
bridge?.refresh?.();
|
|
1515
1597
|
return result;
|
|
1516
1598
|
} catch (error) {
|
|
1517
|
-
console.error(
|
|
1518
|
-
|
|
1519
|
-
return {
|
|
1599
|
+
console.error('[BookingTicket] handleGlobalScanCode failed', error);
|
|
1600
|
+
bridge?.onNotify?.('fail', 'pisell2.text.scan-global-failed');
|
|
1601
|
+
return {
|
|
1602
|
+
status: 'failed',
|
|
1603
|
+
reason: 'not_found'
|
|
1604
|
+
};
|
|
1520
1605
|
}
|
|
1521
1606
|
}
|
|
1522
1607
|
resolveBestAddTimePlan(addTimeProducts, targetMinutes) {
|
|
1523
|
-
return (0,
|
|
1608
|
+
return (0, _resolveBestAddTimePlan.resolveBestAddTimePlan)(addTimeProducts, targetMinutes);
|
|
1524
1609
|
}
|
|
1610
|
+
|
|
1525
1611
|
/**
|
|
1526
1612
|
* 构造一条绑定到已有 booking 的加时商品行。
|
|
1527
1613
|
*
|
|
@@ -1529,17 +1615,13 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1529
1615
|
* const line = this.buildAddTimeOrderLine({ product, product_add_schedule_time: 30 }, 'booking-1');
|
|
1530
1616
|
*/
|
|
1531
1617
|
buildAddTimeOrderLine(input, bookingUid) {
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
throw new Error("[BookingTicket] addAddTimeProductToBooking: product 不能为空");
|
|
1618
|
+
const product = input?.product;
|
|
1619
|
+
if (!product || typeof product !== 'object') {
|
|
1620
|
+
throw new Error('[BookingTicket] addAddTimeProductToBooking: product 不能为空');
|
|
1536
1621
|
}
|
|
1537
1622
|
const quantity = normalizeAddTimeQuantity(input.num ?? product.num);
|
|
1538
1623
|
const price = resolveAddTimeProductPrice(input.price, product);
|
|
1539
|
-
const addScheduleTime = resolveAddTimeScheduleMinutes(
|
|
1540
|
-
input.product_add_schedule_time,
|
|
1541
|
-
product
|
|
1542
|
-
);
|
|
1624
|
+
const addScheduleTime = resolveAddTimeScheduleMinutes(input.product_add_schedule_time, product);
|
|
1543
1625
|
const payload = {
|
|
1544
1626
|
id: product.id ?? product.product_id,
|
|
1545
1627
|
product_id: product.product_id ?? product.id,
|
|
@@ -1553,7 +1635,7 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1553
1635
|
line_total: price,
|
|
1554
1636
|
total: price,
|
|
1555
1637
|
product_sku: product.product_sku,
|
|
1556
|
-
option: product.option ?? product.options ??
|
|
1638
|
+
option: product.option ?? product.options ?? product.product_sku?.option ?? [],
|
|
1557
1639
|
bundle: product.bundle ?? product.bundles ?? product.product_bundle ?? []
|
|
1558
1640
|
};
|
|
1559
1641
|
const orderLine = this.transformBaseProductToOrderProduct({
|
|
@@ -1563,13 +1645,13 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1563
1645
|
sourceItem: product
|
|
1564
1646
|
});
|
|
1565
1647
|
if (!orderLine) {
|
|
1566
|
-
throw new Error(
|
|
1567
|
-
"[BookingTicket] addAddTimeProductToBooking: product transform failed"
|
|
1568
|
-
);
|
|
1648
|
+
throw new Error('[BookingTicket] addAddTimeProductToBooking: product transform failed');
|
|
1569
1649
|
}
|
|
1570
1650
|
const metadata = {
|
|
1571
|
-
...orderLine.metadata || {},
|
|
1572
|
-
...addScheduleTime !==
|
|
1651
|
+
...(orderLine.metadata || {}),
|
|
1652
|
+
...(addScheduleTime !== undefined ? {
|
|
1653
|
+
product_add_schedule_time: addScheduleTime
|
|
1654
|
+
} : {}),
|
|
1573
1655
|
booking_uid: bookingUid
|
|
1574
1656
|
};
|
|
1575
1657
|
return {
|
|
@@ -1578,6 +1660,7 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1578
1660
|
metadata
|
|
1579
1661
|
};
|
|
1580
1662
|
}
|
|
1663
|
+
|
|
1581
1664
|
/**
|
|
1582
1665
|
* 将加时商品作为独立商品行绑定到已有 booking。
|
|
1583
1666
|
*
|
|
@@ -1601,6 +1684,7 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1601
1684
|
bookingPatch: input.bookingPatch
|
|
1602
1685
|
});
|
|
1603
1686
|
}
|
|
1687
|
+
|
|
1604
1688
|
/**
|
|
1605
1689
|
* 批量将加时商品作为独立商品行绑定到已有 booking,并只触发一次购物车重算。
|
|
1606
1690
|
*
|
|
@@ -1611,17 +1695,14 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1611
1695
|
* });
|
|
1612
1696
|
*/
|
|
1613
1697
|
async addAddTimeProductsToBooking(input) {
|
|
1614
|
-
const bookingUid = resolveBookingUidForAddTime(input
|
|
1698
|
+
const bookingUid = resolveBookingUidForAddTime(input?.booking);
|
|
1615
1699
|
if (!bookingUid) {
|
|
1616
|
-
throw new Error(
|
|
1617
|
-
"[BookingTicket] addAddTimeProductToBooking: booking.metadata.unique_identification_number 缺失"
|
|
1618
|
-
);
|
|
1700
|
+
throw new Error('[BookingTicket] addAddTimeProductToBooking: booking.metadata.unique_identification_number 缺失');
|
|
1619
1701
|
}
|
|
1620
|
-
const orderLines = (input.products || []).map(
|
|
1702
|
+
const orderLines = (input.products || []).map(line => ({
|
|
1621
1703
|
product: this.buildAddTimeOrderLine(line, bookingUid)
|
|
1622
1704
|
}));
|
|
1623
|
-
if (!this.store.order)
|
|
1624
|
-
throw new Error("order 模块未初始化");
|
|
1705
|
+
if (!this.store.order) throw new Error('order 模块未初始化');
|
|
1625
1706
|
const coveredMinutes = normalizeCoveredMinutes(input.coveredMinutes);
|
|
1626
1707
|
const bookingTimePatch = input.bookingPatch ?? buildAddTimeBookingTimePatch(input.booking, coveredMinutes);
|
|
1627
1708
|
if (bookingTimePatch) {
|
|
@@ -1630,34 +1711,37 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1630
1711
|
updates: bookingTimePatch
|
|
1631
1712
|
});
|
|
1632
1713
|
}
|
|
1633
|
-
if (typeof this.store.order.addProductsToOrder ===
|
|
1714
|
+
if (typeof this.store.order.addProductsToOrder === 'function') {
|
|
1634
1715
|
return this.store.order.addProductsToOrder(orderLines);
|
|
1635
1716
|
}
|
|
1636
1717
|
const result = [];
|
|
1637
1718
|
for (const line of orderLines) {
|
|
1638
|
-
result.splice(0, result.length, ...await this.addProductToOrder(line.product));
|
|
1719
|
+
result.splice(0, result.length, ...(await this.addProductToOrder(line.product)));
|
|
1639
1720
|
}
|
|
1640
1721
|
return result;
|
|
1641
1722
|
}
|
|
1642
|
-
async setOtherParams(params, {
|
|
1643
|
-
|
|
1644
|
-
|
|
1723
|
+
async setOtherParams(params, {
|
|
1724
|
+
cover = false
|
|
1725
|
+
} = {}) {
|
|
1726
|
+
await super.setOtherParams(params, {
|
|
1727
|
+
cover
|
|
1728
|
+
});
|
|
1729
|
+
if (params?.businessCode !== undefined || params?.business_code !== undefined) {
|
|
1645
1730
|
await this.configureIdGeneratorFromOpenData();
|
|
1646
1731
|
}
|
|
1647
1732
|
}
|
|
1648
1733
|
getDeviceTaskPlugin() {
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
return ((_a = app == null ? void 0 : app.getApp()) == null ? void 0 : _a.getPlugin("deviceTask")) || null;
|
|
1734
|
+
const app = this.core.getPlugin('app');
|
|
1735
|
+
return app?.getApp()?.getPlugin('deviceTask') || null;
|
|
1652
1736
|
}
|
|
1737
|
+
|
|
1653
1738
|
// 打印手环,单个或批量都可以
|
|
1654
1739
|
async handlePrintWristband(params) {
|
|
1655
|
-
var _a;
|
|
1656
1740
|
const deviceTask = this.getDeviceTaskPlugin();
|
|
1657
|
-
if (!
|
|
1741
|
+
if (!deviceTask?.dispatch) {
|
|
1658
1742
|
this.logger.addLog({
|
|
1659
|
-
type:
|
|
1660
|
-
title:
|
|
1743
|
+
type: 'info',
|
|
1744
|
+
title: '[BookingTicket] handlePrintWristband: deviceTask.dispatch 不可用',
|
|
1661
1745
|
metadata: {
|
|
1662
1746
|
voucher_ids: Array.isArray(params.voucher_ids) ? params.voucher_ids : [params.voucher_ids]
|
|
1663
1747
|
}
|
|
@@ -1665,51 +1749,50 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1665
1749
|
return;
|
|
1666
1750
|
}
|
|
1667
1751
|
this.logger.addLog({
|
|
1668
|
-
type:
|
|
1669
|
-
title:
|
|
1752
|
+
type: 'info',
|
|
1753
|
+
title: '[BookingTicket] handlePrintWristband',
|
|
1670
1754
|
metadata: {
|
|
1671
1755
|
voucher_ids: Array.isArray(params.voucher_ids) ? params.voucher_ids : [params.voucher_ids]
|
|
1672
1756
|
}
|
|
1673
1757
|
});
|
|
1674
1758
|
const deviceId = await this.getShortNumberOrDeviceId();
|
|
1675
|
-
const idempotencyKey = (0,
|
|
1759
|
+
const idempotencyKey = (0, _utils.createUuidV4)();
|
|
1676
1760
|
deviceTask.dispatch({
|
|
1677
|
-
action:
|
|
1761
|
+
action: 'print_all',
|
|
1678
1762
|
device_id: deviceId,
|
|
1679
1763
|
payload: {
|
|
1680
|
-
type:
|
|
1764
|
+
type: 'WRISTBAND',
|
|
1681
1765
|
data: {
|
|
1682
|
-
order_id:
|
|
1766
|
+
order_id: this.getOrderIdentity()?.orderId,
|
|
1683
1767
|
voucher_ids: Array.isArray(params.voucher_ids) ? params.voucher_ids : [params.voucher_ids]
|
|
1684
1768
|
}
|
|
1685
1769
|
},
|
|
1686
1770
|
idempotency_key: idempotencyKey,
|
|
1687
|
-
name:
|
|
1688
|
-
source:
|
|
1689
|
-
source_type:
|
|
1771
|
+
name: 'PRINT_WRISTBAND',
|
|
1772
|
+
source: 'bookingTicket',
|
|
1773
|
+
source_type: 'handlePrintWristband',
|
|
1690
1774
|
source_id: idempotencyKey
|
|
1691
1775
|
});
|
|
1692
1776
|
}
|
|
1777
|
+
|
|
1693
1778
|
// 触发核销
|
|
1694
1779
|
async handleRedeem(params) {
|
|
1695
|
-
var _a, _b, _c;
|
|
1696
1780
|
const voucherIds = Array.isArray(params.voucher_ids) ? params.voucher_ids : [];
|
|
1697
|
-
const status = params.is_checkin ?
|
|
1781
|
+
const status = params.is_checkin ? 'used' : 'unused';
|
|
1698
1782
|
this.logger.addLog({
|
|
1699
|
-
type:
|
|
1700
|
-
title:
|
|
1783
|
+
type: 'info',
|
|
1784
|
+
title: '[BookingTicket] handleRedeem',
|
|
1701
1785
|
metadata: {
|
|
1702
1786
|
voucher_ids: voucherIds,
|
|
1703
1787
|
status
|
|
1704
1788
|
}
|
|
1705
1789
|
});
|
|
1706
1790
|
const voucherIdSet = new Set(voucherIds);
|
|
1707
|
-
const tempOrder =
|
|
1708
|
-
const vouchers =
|
|
1791
|
+
const tempOrder = this.store.order?.getTempOrder?.();
|
|
1792
|
+
const vouchers = tempOrder?.vouchers || this.store.order?.getVouchers() || [];
|
|
1709
1793
|
let hasUpdatedVoucher = false;
|
|
1710
|
-
const nextVouchers = vouchers.map(
|
|
1711
|
-
if (!voucherIdSet.has(voucher.voucher_id))
|
|
1712
|
-
return voucher;
|
|
1794
|
+
const nextVouchers = vouchers.map(voucher => {
|
|
1795
|
+
if (!voucherIdSet.has(voucher.voucher_id)) return voucher;
|
|
1713
1796
|
hasUpdatedVoucher = true;
|
|
1714
1797
|
return {
|
|
1715
1798
|
...voucher,
|
|
@@ -1727,15 +1810,15 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1727
1810
|
return {
|
|
1728
1811
|
code: 200,
|
|
1729
1812
|
status: true,
|
|
1730
|
-
message:
|
|
1813
|
+
message: '',
|
|
1731
1814
|
data: []
|
|
1732
1815
|
};
|
|
1733
1816
|
}
|
|
1734
1817
|
const identity = this.getOrderIdentity();
|
|
1735
|
-
const externalSaleNumber =
|
|
1736
|
-
const orderId =
|
|
1737
|
-
const orderLookup = externalSaleNumber || orderId ||
|
|
1738
|
-
return this.request.post(
|
|
1818
|
+
const externalSaleNumber = tempOrder?.external_sale_number || identity?.externalSaleNumber || undefined;
|
|
1819
|
+
const orderId = tempOrder?.order_id ?? identity?.orderId ?? undefined;
|
|
1820
|
+
const orderLookup = externalSaleNumber || orderId || identity?.orderNumber || identity?.shopOrderNumber || identity?.shopFullOrderNumber || undefined;
|
|
1821
|
+
return this.request.post('/machinecode/batch', {
|
|
1739
1822
|
ids: voucherIds,
|
|
1740
1823
|
status,
|
|
1741
1824
|
order_lookup: orderLookup,
|
|
@@ -1745,24 +1828,21 @@ var BookingTicketImpl = class extends import_BaseSales.BaseSalesImpl {
|
|
|
1745
1828
|
osServer: true
|
|
1746
1829
|
});
|
|
1747
1830
|
}
|
|
1831
|
+
|
|
1748
1832
|
/**
|
|
1749
1833
|
* 销毁模块:先调用父类(销毁所有 store 内子模块 + emit destroy + super.destroy()),
|
|
1750
1834
|
* 再清理 BookingTicket 自有资源(scan 监听 + scan 内存缓存)。
|
|
1751
1835
|
*/
|
|
1752
1836
|
async destroy() {
|
|
1753
|
-
var _a;
|
|
1754
1837
|
await super.destroy();
|
|
1755
1838
|
try {
|
|
1756
|
-
|
|
1839
|
+
this.scan?.removeAllListeners();
|
|
1757
1840
|
} catch (error) {
|
|
1758
|
-
console.warn(
|
|
1841
|
+
console.warn('[BookingTicket] scan removeAllListeners 失败', error);
|
|
1759
1842
|
}
|
|
1760
|
-
|
|
1843
|
+
_scanCache.default.clear();
|
|
1761
1844
|
}
|
|
1762
|
-
}
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
BookingTicketImpl,
|
|
1767
|
-
...require("./types")
|
|
1768
|
-
});
|
|
1845
|
+
}
|
|
1846
|
+
|
|
1847
|
+
// 导出相关类型和实现
|
|
1848
|
+
exports.BookingTicket = exports.BookingTicketImpl = BookingTicketImpl;
|