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