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