@pisell/pisellos 2.2.283 → 2.2.285
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/index.js +6 -10
- package/dist/model/strategy/adapter/walletPass/example.js +3 -26
- package/dist/model/strategy/strategy-example.js +5 -19
- package/dist/modules/Cart/index.js +0 -3
- package/dist/modules/Cart/utils/cartProduct.js +0 -1
- package/dist/modules/Date/index.js +1 -5
- package/dist/modules/Discount/index.js +2 -4
- package/dist/modules/OpenData/index.js +0 -2
- package/dist/modules/Order/index.d.ts +1 -1
- package/dist/modules/Order/index.js +64 -86
- package/dist/modules/Order/types.d.ts +3 -1
- package/dist/modules/Order/types.js +1 -0
- package/dist/modules/Payment/index.js +97 -162
- package/dist/modules/ProductList/index.js +91 -65
- package/dist/modules/Rules/index.js +1 -4
- package/dist/modules/Schedule/index.js +0 -1
- package/dist/modules/Schedule/utils.js +0 -1
- package/dist/modules/Step/index.js +0 -1
- package/dist/plugins/request.js +1 -4
- package/dist/plugins/window.js +2 -6
- package/dist/server/index.js +97 -129
- package/dist/server/modules/menu/index.js +32 -41
- package/dist/server/modules/order/index.js +2 -4
- package/dist/server/modules/products/index.js +24 -42
- package/dist/server/modules/quotation/index.js +29 -38
- package/dist/server/modules/resource/index.js +3 -4
- package/dist/server/modules/schedule/index.js +27 -35
- package/dist/server/utils/product.js +0 -1
- package/dist/solution/BaseSales/index.js +115 -76
- package/dist/solution/BookingByStep/index.d.ts +1 -1
- package/dist/solution/BookingByStep/index.js +7 -59
- package/dist/solution/BookingByStep/utils/capacity.js +1 -11
- package/dist/solution/BookingByStep/utils/resources.js +1 -3
- package/dist/solution/BookingByStep/utils/timeslots.js +2 -43
- package/dist/solution/BookingTicket/index.d.ts +6 -16
- package/dist/solution/BookingTicket/index.js +13 -6
- package/dist/solution/BookingTicket/utils/scan/cloudSearch.js +6 -7
- package/dist/solution/BookingTicket/utils/scan/handleScan.js +25 -31
- package/dist/solution/BookingTicket/utils/scan/index.js +6 -10
- package/dist/solution/BuyTickets/index.js +9 -12
- package/dist/solution/Checkout/index.js +177 -252
- package/dist/solution/Checkout/utils/index.js +4 -16
- package/dist/solution/RegisterAndLogin/index.js +30 -76
- package/dist/solution/ScanOrder/index.js +50 -60
- package/dist/solution/ShopDiscount/index.js +2 -7
- package/dist/solution/VenueBooking/index.js +45 -55
- package/dist/utils/task.js +15 -18
- package/dist/utils/watch.js +0 -1
- package/lib/apis/picoding.js +2 -0
- package/lib/core/index.js +131 -132
- package/lib/effects/index.js +46 -57
- package/lib/index.js +82 -49
- package/lib/model/index.js +14 -21
- package/lib/model/strategy/adapter/dataVariant/adapter.js +38 -50
- package/lib/model/strategy/adapter/dataVariant/evaluator.js +162 -236
- package/lib/model/strategy/adapter/dataVariant/examples.js +229 -237
- package/lib/model/strategy/adapter/dataVariant/index.js +39 -34
- package/lib/model/strategy/adapter/dataVariant/type.js +57 -28
- package/lib/model/strategy/adapter/index.js +100 -64
- package/lib/model/strategy/adapter/itemRule/adapter.js +156 -144
- package/lib/model/strategy/adapter/itemRule/evaluator.js +36 -48
- package/lib/model/strategy/adapter/itemRule/examples.js +295 -225
- package/lib/model/strategy/adapter/itemRule/index.js +83 -57
- package/lib/model/strategy/adapter/itemRule/type.js +97 -36
- package/lib/model/strategy/adapter/promotion/adapter.js +91 -69
- package/lib/model/strategy/adapter/promotion/evaluator.js +444 -310
- package/lib/model/strategy/adapter/promotion/examples.js +222 -234
- package/lib/model/strategy/adapter/promotion/index.js +46 -0
- package/lib/model/strategy/adapter/promotion/type.js +243 -36
- package/lib/model/strategy/adapter/type.js +4 -16
- package/lib/model/strategy/adapter/walletPass/evaluator.js +180 -150
- package/lib/model/strategy/adapter/walletPass/example.js +217 -190
- package/lib/model/strategy/adapter/walletPass/index.js +75 -51
- package/lib/model/strategy/adapter/walletPass/locales.js +36 -58
- package/lib/model/strategy/adapter/walletPass/type.js +4 -16
- package/lib/model/strategy/adapter/walletPass/utils.js +588 -378
- package/lib/model/strategy/engine.js +270 -168
- package/lib/model/strategy/index.js +49 -34
- package/lib/model/strategy/strategy-example.js +243 -239
- package/lib/model/strategy/type.js +100 -40
- package/lib/modules/Account/index.js +39 -53
- package/lib/modules/Account/types.js +20 -33
- package/lib/modules/AccountList/index.js +116 -154
- package/lib/modules/AccountList/types.js +30 -31
- package/lib/modules/AccountList/utils.js +18 -30
- package/lib/modules/BaseModule.js +23 -42
- package/lib/modules/BookingContext/index.js +158 -136
- package/lib/modules/BookingContext/types.js +46 -32
- package/lib/modules/BookingContext/utils/buildCacheItemFromOrderLine.js +138 -146
- package/lib/modules/BookingContext/utils/buildNormalProductCacheItemFromOrderLine.js +78 -83
- package/lib/modules/BookingContext/utils/cacheItemToBookingInput.js +170 -150
- package/lib/modules/BookingContext/utils/flexible.js +38 -55
- package/lib/modules/BookingContext/utils/formatResourceList.js +19 -34
- package/lib/modules/BookingContext/utils/index.js +124 -41
- package/lib/modules/BookingContext/utils/noResource.js +58 -70
- package/lib/modules/BookingContext/utils/orderLineDisplay.js +14 -41
- package/lib/modules/BookingContext/utils/productExtend.js +202 -155
- package/lib/modules/BookingContext/utils/resourceErrors.js +53 -53
- package/lib/modules/BookingContext/utils/resourceSelection.js +19 -41
- package/lib/modules/BookingContext/utils/resources.js +209 -167
- package/lib/modules/BookingContext/utils/serviceTimes.js +115 -116
- package/lib/modules/BookingContext/utils/timeSlices.js +76 -86
- package/lib/modules/Cart/index.js +170 -124
- package/lib/modules/Cart/types.js +46 -51
- package/lib/modules/Cart/utils/cartAccount.js +40 -39
- package/lib/modules/Cart/utils/cartDate.js +56 -61
- package/lib/modules/Cart/utils/cartDiscount.js +28 -33
- package/lib/modules/Cart/utils/cartNote.js +27 -32
- package/lib/modules/Cart/utils/cartProduct.js +321 -251
- package/lib/modules/Cart/utils/cartRelationForms.js +29 -35
- package/lib/modules/Cart/utils/cartResource.js +70 -78
- package/lib/modules/Cart/utils/changePrice.js +22 -50
- package/lib/modules/Cart/utils/index.js +106 -48
- package/lib/modules/Customer/constants.js +13 -34
- package/lib/modules/Customer/index.js +235 -172
- package/lib/modules/Customer/types.js +38 -35
- package/lib/modules/Date/index.js +116 -115
- package/lib/modules/Date/types.js +16 -28
- package/lib/modules/Date/utils.js +174 -123
- package/lib/modules/Discount/index.js +122 -127
- package/lib/modules/Discount/types.js +9 -31
- package/lib/modules/Guests/index.js +30 -56
- package/lib/modules/Guests/types.js +23 -33
- package/lib/modules/Holder/index.js +209 -189
- package/lib/modules/Holder/types.js +4 -16
- package/lib/modules/Holder/utils.js +20 -49
- package/lib/modules/OpenData/index.js +70 -76
- package/lib/modules/OpenData/types.js +4 -16
- package/lib/modules/OpenData/utils.js +44 -78
- package/lib/modules/Order/index.d.ts +1 -1
- package/lib/modules/Order/index.js +1728 -2123
- package/lib/modules/Order/payment-utils.js +77 -120
- package/lib/modules/Order/types.d.ts +3 -1
- package/lib/modules/Order/types.js +88 -35
- package/lib/modules/Order/utils/bundleDiscountHydration.js +41 -74
- package/lib/modules/Order/utils/discountProductLineIdentity.js +142 -100
- package/lib/modules/Order/utils/manualProductDiscount.js +124 -123
- package/lib/modules/Order/utils/orderCollectionIdentity.js +184 -244
- package/lib/modules/Order/utils.js +814 -647
- package/lib/modules/Payment/cash.js +20 -33
- package/lib/modules/Payment/cashRecommendationAlgorithm.js +145 -76
- package/lib/modules/Payment/eftpos.js +16 -30
- package/lib/modules/Payment/index.js +532 -399
- package/lib/modules/Payment/mx51.js +1 -0
- package/lib/modules/Payment/types.js +230 -108
- package/lib/modules/Payment/utils.js +52 -51
- package/lib/modules/Payment/walletpass.js +485 -660
- package/lib/modules/Product/index.js +51 -46
- package/lib/modules/Product/types.js +4 -16
- package/lib/modules/Product/utils.js +32 -33
- package/lib/modules/ProductList/index.js +119 -123
- package/lib/modules/ProductList/types.js +9 -31
- package/lib/modules/Quotation/index.js +66 -100
- package/lib/modules/Quotation/types.js +4 -16
- package/lib/modules/Resource/index.js +27 -59
- package/lib/modules/Resource/types.js +22 -32
- package/lib/modules/Resource/utils.js +30 -38
- package/lib/modules/ResourcePlanner/index.js +60 -61
- package/lib/modules/ResourcePlanner/planner.js +346 -384
- package/lib/modules/ResourcePlanner/types.js +4 -16
- package/lib/modules/Rules/index.js +1218 -959
- package/lib/modules/Rules/types.js +17 -40
- package/lib/modules/SalesSummary/index.js +85 -90
- package/lib/modules/SalesSummary/types.js +4 -16
- package/lib/modules/SalesSummary/utils.js +355 -430
- package/lib/modules/ScanOrderLogger/index.js +59 -79
- package/lib/modules/ScanOrderLogger/providers/feishu.js +54 -78
- package/lib/modules/ScanOrderLogger/providers/grafana.js +13 -36
- package/lib/modules/ScanOrderLogger/types.js +4 -16
- package/lib/modules/Schedule/getDateIsInSchedule.js +334 -163
- package/lib/modules/Schedule/index.js +100 -114
- package/lib/modules/Schedule/type.js +4 -16
- package/lib/modules/Schedule/types.js +4 -16
- package/lib/modules/Schedule/utils.js +433 -291
- package/lib/modules/Step/index.js +40 -52
- package/lib/modules/Step/tyeps.js +4 -16
- package/lib/modules/Summary/index.js +66 -71
- package/lib/modules/Summary/types.js +4 -16
- package/lib/modules/Summary/utils.js +773 -418
- package/lib/modules/SurchargeList/index.js +46 -60
- package/lib/modules/SurchargeList/types.js +4 -16
- package/lib/modules/index.js +245 -63
- package/lib/plugins/app.js +4 -16
- package/lib/plugins/index.js +36 -25
- package/lib/plugins/request.js +137 -126
- package/lib/plugins/shopStore.js +4 -16
- package/lib/plugins/user.js +4 -16
- package/lib/plugins/window.js +171 -179
- package/lib/server/index.js +3027 -2655
- package/lib/server/modules/floor-plan/index.js +102 -123
- package/lib/server/modules/floor-plan/types.js +15 -30
- package/lib/server/modules/index.js +106 -68
- package/lib/server/modules/menu/index.js +146 -122
- package/lib/server/modules/menu/types.js +18 -31
- package/lib/server/modules/order/index.js +758 -956
- package/lib/server/modules/order/types.js +122 -33
- package/lib/server/modules/order/utils/filterBookings.js +219 -194
- package/lib/server/modules/order/utils/filterOrders.js +118 -92
- package/lib/server/modules/payment/index.js +59 -83
- package/lib/server/modules/payment/types.js +4 -16
- package/lib/server/modules/products/index.js +575 -459
- package/lib/server/modules/products/types.js +44 -34
- package/lib/server/modules/quotation/index.js +137 -172
- package/lib/server/modules/quotation/types.js +21 -31
- package/lib/server/modules/resource/index.js +213 -184
- package/lib/server/modules/resource/types.js +42 -33
- package/lib/server/modules/schedule/index.js +135 -123
- package/lib/server/modules/schedule/types.js +14 -21
- package/lib/server/modules/schedule/utils.js +334 -163
- package/lib/server/types.js +4 -16
- package/lib/server/utils/index.js +25 -23
- package/lib/server/utils/product.js +196 -139
- package/lib/server/utils/schedule.js +34 -41
- package/lib/server/utils/small-ticket.js +479 -456
- package/lib/server/utils/time.js +40 -49
- package/lib/solution/BaseSales/index.js +1220 -1412
- package/lib/solution/BaseSales/types.js +42 -38
- package/lib/solution/BaseSales/utils/cartPromotion.js +650 -502
- package/lib/solution/BaseSales/utils/parseSalesResponse.js +85 -105
- package/lib/solution/BaseSales/utils/quotationPrice.js +56 -114
- package/lib/solution/BaseSales/utils/transformBaseProductToOrderProduct.js +108 -145
- package/lib/solution/BaseSales/utils.js +158 -143
- package/lib/solution/BookingByStep/index.d.ts +1 -1
- package/lib/solution/BookingByStep/index.js +1527 -1340
- package/lib/solution/BookingByStep/types.js +40 -99
- package/lib/solution/BookingByStep/utils/capacity.js +192 -160
- package/lib/solution/BookingByStep/utils/products.js +42 -52
- package/lib/solution/BookingByStep/utils/resources.js +527 -330
- package/lib/solution/BookingByStep/utils/stock.js +65 -44
- package/lib/solution/BookingByStep/utils/timeslots.js +129 -131
- package/lib/solution/BookingTicket/index.d.ts +6 -16
- package/lib/solution/BookingTicket/index.js +608 -517
- package/lib/solution/BookingTicket/types.js +99 -77
- package/lib/solution/BookingTicket/utils/addProductDecision.js +225 -187
- package/lib/solution/BookingTicket/utils/addTimeAvailability.js +58 -89
- package/lib/solution/BookingTicket/utils/bookingStatus.js +107 -78
- package/lib/solution/BookingTicket/utils/cartView.js +114 -99
- package/lib/solution/BookingTicket/utils/exampleData.js +185 -0
- package/lib/solution/BookingTicket/utils/orderCustomer.js +18 -41
- package/lib/solution/BookingTicket/utils/resolveBestAddTimePlan.js +219 -86
- package/lib/solution/BookingTicket/utils/scan/applyGlobalScan.js +168 -116
- package/lib/solution/BookingTicket/utils/scan/cloudSearch.js +79 -91
- package/lib/solution/BookingTicket/utils/scan/formatGlobalScan.js +54 -41
- package/lib/solution/BookingTicket/utils/scan/handleScan.js +84 -81
- package/lib/solution/BookingTicket/utils/scan/index.js +98 -104
- package/lib/solution/BookingTicket/utils/scan/scanCache.js +90 -43
- package/lib/solution/BookingTicket/utils/scan/scanProductValues.js +52 -64
- package/lib/solution/BookingTicket/utils/sessionCatalogStale.js +56 -58
- package/lib/solution/BookingTicket/utils/weighingProductSku.js +34 -48
- package/lib/solution/BuyTickets/index.js +67 -70
- package/lib/solution/BuyTickets/types.js +22 -38
- package/lib/solution/Checkout/index.js +1451 -1158
- package/lib/solution/Checkout/types.js +91 -61
- package/lib/solution/Checkout/utils/index.js +228 -156
- package/lib/solution/PlaceOrder/index.js +55 -0
- package/lib/solution/RegisterAndLogin/config.js +493 -460
- package/lib/solution/RegisterAndLogin/index.js +633 -630
- package/lib/solution/RegisterAndLogin/types.js +189 -76
- package/lib/solution/RegisterAndLogin/utils.js +183 -125
- package/lib/solution/Sales/index.js +328 -324
- package/lib/solution/Sales/types.js +27 -33
- package/lib/solution/ScanOrder/index.js +832 -864
- package/lib/solution/ScanOrder/types.js +33 -34
- package/lib/solution/ScanOrder/utils.js +409 -374
- package/lib/solution/ShopDiscount/index.js +226 -232
- package/lib/solution/ShopDiscount/types.js +15 -37
- package/lib/solution/ShopDiscount/utils.js +300 -172
- package/lib/solution/UnifiedBookingSales/index.js +437 -487
- package/lib/solution/UnifiedBookingSales/types.js +12 -31
- package/lib/solution/VenueBooking/index.js +811 -879
- package/lib/solution/VenueBooking/types.js +19 -39
- package/lib/solution/VenueBooking/utils/dateSummary.js +27 -56
- package/lib/solution/VenueBooking/utils/resource.js +31 -54
- package/lib/solution/VenueBooking/utils/slotMerge.js +94 -107
- package/lib/solution/VenueBooking/utils/timeSlot.js +132 -132
- package/lib/solution/VenueBooking/utils.js +130 -67
- package/lib/solution/index.js +124 -41
- package/lib/store/createStore.js +32 -29
- package/lib/types/index.js +4 -16
- package/lib/utils/payment-number.js +26 -46
- package/lib/utils/task.js +36 -36
- package/lib/utils/watch.js +81 -47
- package/package.json +2 -1
|
@@ -1,81 +1,74 @@
|
|
|
1
|
-
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
-
var __export = (target, all) => {
|
|
8
|
-
for (var name in all)
|
|
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;
|
|
18
|
-
};
|
|
19
|
-
var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
|
|
20
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
-
mod
|
|
27
|
-
));
|
|
28
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
1
|
+
"use strict";
|
|
29
2
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
__export(UnifiedBookingSales_exports, {
|
|
33
|
-
UnifiedBookingSales: () => UnifiedBookingSales,
|
|
34
|
-
UnifiedBookingSalesImpl: () => UnifiedBookingSalesImpl,
|
|
35
|
-
buildBookingFromAssignment: () => buildBookingFromAssignment,
|
|
36
|
-
buildBookingFromAssignments: () => buildBookingFromAssignments,
|
|
37
|
-
buildPlannerDiscountResult: () => buildPlannerDiscountResult,
|
|
38
|
-
buildPlannerLineIdentity: () => buildPlannerLineIdentity,
|
|
39
|
-
buildPlannerResourcesFromV2: () => buildPlannerResourcesFromV2,
|
|
40
|
-
collectPlannerResourceIds: () => collectPlannerResourceIds,
|
|
41
|
-
normalizeProductForPlanner: () => normalizeProductForPlanner
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
42
5
|
});
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
6
|
+
var _exportNames = {
|
|
7
|
+
buildPlannerDiscountResult: true,
|
|
8
|
+
normalizeProductForPlanner: true,
|
|
9
|
+
buildPlannerResourcesFromV2: true,
|
|
10
|
+
collectPlannerResourceIds: true,
|
|
11
|
+
buildBookingFromAssignment: true,
|
|
12
|
+
buildBookingFromAssignments: true,
|
|
13
|
+
buildPlannerLineIdentity: true,
|
|
14
|
+
UnifiedBookingSalesImpl: true,
|
|
15
|
+
UnifiedBookingSales: true
|
|
16
|
+
};
|
|
17
|
+
exports.UnifiedBookingSalesImpl = exports.UnifiedBookingSales = void 0;
|
|
18
|
+
exports.buildBookingFromAssignment = buildBookingFromAssignment;
|
|
19
|
+
exports.buildBookingFromAssignments = buildBookingFromAssignments;
|
|
20
|
+
exports.buildPlannerDiscountResult = buildPlannerDiscountResult;
|
|
21
|
+
exports.buildPlannerLineIdentity = buildPlannerLineIdentity;
|
|
22
|
+
exports.buildPlannerResourcesFromV2 = buildPlannerResourcesFromV2;
|
|
23
|
+
exports.collectPlannerResourceIds = collectPlannerResourceIds;
|
|
24
|
+
exports.normalizeProductForPlanner = normalizeProductForPlanner;
|
|
25
|
+
var _dayjs = _interopRequireDefault(require("dayjs"));
|
|
26
|
+
var _modules = require("../../modules");
|
|
27
|
+
var _getDateIsInSchedule = require("../../modules/Schedule/getDateIsInSchedule");
|
|
28
|
+
var _types = require("./types");
|
|
29
|
+
Object.keys(_types).forEach(function (key) {
|
|
30
|
+
if (key === "default" || key === "__esModule") return;
|
|
31
|
+
if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
|
|
32
|
+
if (key in exports && exports[key] === _types[key]) return;
|
|
33
|
+
Object.defineProperty(exports, key, {
|
|
34
|
+
enumerable: true,
|
|
35
|
+
get: function () {
|
|
36
|
+
return _types[key];
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
var _BookingTicket = require("../BookingTicket");
|
|
41
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
42
|
+
// import { BaseSalesImpl } from '../BaseSales';
|
|
43
|
+
|
|
44
|
+
const OPEN_DATA_SECTION_CODES = ['sale', 'reservation', 'fulfillment', 'menu', 'workflow'];
|
|
45
|
+
const OPEN_DATA_CACHE_TTL = 5 * 60 * 1000;
|
|
52
46
|
function isRecord(value) {
|
|
53
|
-
return !!value && typeof value ===
|
|
47
|
+
return !!value && typeof value === 'object' && !Array.isArray(value);
|
|
54
48
|
}
|
|
55
49
|
function pickLocalizedText(value) {
|
|
56
|
-
if (!value)
|
|
57
|
-
|
|
58
|
-
if (typeof value ===
|
|
59
|
-
return value;
|
|
60
|
-
if (typeof value === "object") {
|
|
50
|
+
if (!value) return undefined;
|
|
51
|
+
if (typeof value === 'string') return value;
|
|
52
|
+
if (typeof value === 'object') {
|
|
61
53
|
return value.en || value.zh || value.default || Object.values(value)[0];
|
|
62
54
|
}
|
|
63
55
|
return String(value);
|
|
64
56
|
}
|
|
65
57
|
function resolvePlannerDiscountId(discount) {
|
|
66
|
-
|
|
67
|
-
return ((_a = discount.discount) == null ? void 0 : _a.resource_id) ?? discount.resource_id ?? discount.id;
|
|
58
|
+
return discount.discount?.resource_id ?? discount.resource_id ?? discount.id;
|
|
68
59
|
}
|
|
69
60
|
function resolvePlannerDiscountTitle(discount) {
|
|
70
|
-
|
|
71
|
-
return pickLocalizedText(
|
|
72
|
-
discount.name || discount.format_title || ((_a = discount.discount) == null ? void 0 : _a.title) || discount.title
|
|
73
|
-
);
|
|
61
|
+
return pickLocalizedText(discount.name || discount.format_title || discount.discount?.title || discount.title);
|
|
74
62
|
}
|
|
75
63
|
function isPlannerDiscountAvailable(discount) {
|
|
76
|
-
|
|
77
|
-
return discount.isDisabled !== true && discount.isAvailable !== false && ((_a = discount.config) == null ? void 0 : _a.isAvailable) !== false;
|
|
64
|
+
return discount.isDisabled !== true && discount.isAvailable !== false && discount.config?.isAvailable !== false;
|
|
78
65
|
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Converts Rules/Order discount internals into a small UI-facing diagnostic. The result keeps
|
|
69
|
+
* candidate-card state separate from line-level applications: a selected card is not proof that
|
|
70
|
+
* it actually discounted a planner product.
|
|
71
|
+
*/
|
|
79
72
|
function buildPlannerDiscountResult(params) {
|
|
80
73
|
const {
|
|
81
74
|
customerId,
|
|
@@ -89,39 +82,34 @@ function buildPlannerDiscountResult(params) {
|
|
|
89
82
|
} = params;
|
|
90
83
|
const items = (discountList || []).reduce((result, discount) => {
|
|
91
84
|
const id = resolvePlannerDiscountId(discount);
|
|
92
|
-
if (id !==
|
|
85
|
+
if (id !== undefined && id !== null) {
|
|
93
86
|
result.push({
|
|
94
87
|
id,
|
|
95
88
|
name: resolvePlannerDiscountTitle(discount),
|
|
96
89
|
type: discount.tag || discount.type,
|
|
97
90
|
available: isPlannerDiscountAvailable(discount),
|
|
98
91
|
selected: discount.isSelected === true,
|
|
99
|
-
savedAmount: Number(discount.savedAmount || 0) ||
|
|
92
|
+
savedAmount: Number(discount.savedAmount || 0) || undefined,
|
|
100
93
|
unavailableReason: discount.unavailableReason || discount.reason
|
|
101
94
|
});
|
|
102
95
|
}
|
|
103
96
|
return result;
|
|
104
97
|
}, []);
|
|
105
|
-
const discountNameById = new Map(items.map(
|
|
98
|
+
const discountNameById = new Map(items.map(item => [String(item.id), item.name]));
|
|
106
99
|
const applications = [];
|
|
107
|
-
(products || []).forEach(
|
|
108
|
-
const productDiscounts = [
|
|
109
|
-
|
|
110
|
-
...Array.isArray(product.product_bundle) ? product.product_bundle.flatMap((bundle) => (bundle == null ? void 0 : bundle.discount_list) || []) : []
|
|
111
|
-
];
|
|
112
|
-
productDiscounts.forEach((discount) => {
|
|
113
|
-
var _a;
|
|
100
|
+
(products || []).forEach(product => {
|
|
101
|
+
const productDiscounts = [...(Array.isArray(product.discount_list) ? product.discount_list : []), ...(Array.isArray(product.product_bundle) ? product.product_bundle.flatMap(bundle => bundle?.discount_list || []) : [])];
|
|
102
|
+
productDiscounts.forEach(discount => {
|
|
114
103
|
const type = discount.tag || discount.type;
|
|
115
|
-
if (![
|
|
116
|
-
return;
|
|
104
|
+
if (!['good_pass', 'discount_card', 'product_discount_card'].includes(type)) return;
|
|
117
105
|
const discountId = resolvePlannerDiscountId(discount);
|
|
118
106
|
applications.push({
|
|
119
107
|
discountId,
|
|
120
|
-
discountName: discountId ===
|
|
108
|
+
discountName: discountId === undefined ? undefined : discountNameById.get(String(discountId)),
|
|
121
109
|
discountType: type,
|
|
122
110
|
productId: product.product_id ?? product.id,
|
|
123
111
|
productTitle: pickLocalizedText(product.title || product.name || product.product_title),
|
|
124
|
-
productUid:
|
|
112
|
+
productUid: product.metadata?.unique_identification_number || product.unique_identification_number,
|
|
125
113
|
amount: Number(discount.amount || 0)
|
|
126
114
|
});
|
|
127
115
|
});
|
|
@@ -130,17 +118,16 @@ function buildPlannerDiscountResult(params) {
|
|
|
130
118
|
status,
|
|
131
119
|
customerId,
|
|
132
120
|
preferredDiscountFound,
|
|
133
|
-
preferredDiscountApplied: preferredDiscountId ===
|
|
134
|
-
availableDiscounts: items.filter(
|
|
135
|
-
selectedDiscounts: items.filter(
|
|
121
|
+
preferredDiscountApplied: preferredDiscountId === undefined || preferredDiscountId === null ? undefined : items.some(item => String(item.id) === String(preferredDiscountId) && item.selected) && applications.some(item => String(item.discountId) === String(preferredDiscountId)),
|
|
122
|
+
availableDiscounts: items.filter(item => item.available),
|
|
123
|
+
selectedDiscounts: items.filter(item => item.selected),
|
|
136
124
|
applications,
|
|
137
125
|
summaryBefore,
|
|
138
126
|
summaryAfter
|
|
139
127
|
};
|
|
140
128
|
}
|
|
141
129
|
function toNumberId(value) {
|
|
142
|
-
if (value ===
|
|
143
|
-
return void 0;
|
|
130
|
+
if (value === undefined || value === null || value === '') return undefined;
|
|
144
131
|
const parsed = Number(value);
|
|
145
132
|
return Number.isFinite(parsed) ? parsed : String(value);
|
|
146
133
|
}
|
|
@@ -149,148 +136,134 @@ function toCustomerId(value) {
|
|
|
149
136
|
return Number.isFinite(parsed) && parsed > 1 ? parsed : null;
|
|
150
137
|
}
|
|
151
138
|
function resolveTempOrderCustomerId(tempOrder) {
|
|
152
|
-
|
|
153
|
-
return toCustomerId(
|
|
154
|
-
(tempOrder == null ? void 0 : tempOrder.customer_id) || ((_a = tempOrder == null ? void 0 : tempOrder.customer) == null ? void 0 : _a.id) || ((_c = (_b = tempOrder == null ? void 0 : tempOrder._extend) == null ? void 0 : _b.customerSnapshot) == null ? void 0 : _c.id) || ((_e = (_d = tempOrder == null ? void 0 : tempOrder._extend) == null ? void 0 : _d.customerSnapshot) == null ? void 0 : _e.customer_id)
|
|
155
|
-
);
|
|
139
|
+
return toCustomerId(tempOrder?.customer_id || tempOrder?.customer?.id || tempOrder?._extend?.customerSnapshot?.id || tempOrder?._extend?.customerSnapshot?.customer_id);
|
|
156
140
|
}
|
|
157
141
|
function isLocalOrderId(orderId) {
|
|
158
|
-
return typeof orderId ===
|
|
142
|
+
return typeof orderId === 'string' && orderId.startsWith('local_order');
|
|
159
143
|
}
|
|
160
144
|
function isCustomerBoundDiscount(discount) {
|
|
161
|
-
const type =
|
|
162
|
-
return type ===
|
|
145
|
+
const type = discount?.type ?? discount?.tag;
|
|
146
|
+
return type === 'good_pass' || type === 'discount_card' || type === 'product_discount_card';
|
|
163
147
|
}
|
|
164
148
|
function filterCustomerBoundDiscounts(discountList) {
|
|
165
|
-
if (!Array.isArray(discountList))
|
|
166
|
-
|
|
167
|
-
return discountList.filter((discount) => !isCustomerBoundDiscount(discount));
|
|
149
|
+
if (!Array.isArray(discountList)) return [];
|
|
150
|
+
return discountList.filter(discount => !isCustomerBoundDiscount(discount));
|
|
168
151
|
}
|
|
152
|
+
|
|
153
|
+
/** Maps several legacy product shapes into the Planner's small, stable vocabulary. */
|
|
169
154
|
function resolveProductKind(product) {
|
|
170
|
-
|
|
171
|
-
if (product.
|
|
172
|
-
|
|
173
|
-
if (
|
|
174
|
-
|
|
175
|
-
if (((_a = product.cartDetailValue) == null ? void 0 : _a.session) || ((_c = (_b = product._extend) == null ? void 0 : _b.other) == null ? void 0 : _c.session))
|
|
176
|
-
return "session";
|
|
177
|
-
if (Array.isArray(product["schedule.ids"]) && product["schedule.ids"].length > 0)
|
|
178
|
-
return "session";
|
|
179
|
-
return "normal";
|
|
155
|
+
if (product.duration) return 'duration';
|
|
156
|
+
if (['session_product', 'session_ticket'].includes(product.extension_type)) return 'session';
|
|
157
|
+
if (product.cartDetailValue?.session || product._extend?.other?.session) return 'session';
|
|
158
|
+
if (Array.isArray(product['schedule.ids']) && product['schedule.ids'].length > 0) return 'session';
|
|
159
|
+
return 'normal';
|
|
180
160
|
}
|
|
181
161
|
function normalizeSchedule(product) {
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
162
|
+
const session = product.cartDetailValue?.session || product._extend?.other?.session || product.session;
|
|
163
|
+
if (session?.start_at && session?.end_at) {
|
|
164
|
+
return [{
|
|
165
|
+
start_at: session.start_at,
|
|
166
|
+
end_at: session.end_at
|
|
167
|
+
}];
|
|
186
168
|
}
|
|
187
169
|
const schedules = product.schedules || product.schedule || product._schedule;
|
|
188
170
|
if (Array.isArray(schedules)) {
|
|
189
|
-
return schedules.map(
|
|
171
|
+
return schedules.map(item => ({
|
|
190
172
|
start_at: item.start_at || item.start || item.start_time,
|
|
191
173
|
end_at: item.end_at || item.end || item.end_time
|
|
192
|
-
})).filter(
|
|
174
|
+
})).filter(item => item.start_at && item.end_at);
|
|
193
175
|
}
|
|
194
176
|
return [];
|
|
195
177
|
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Preserves form ownership while flattening default/optional resource ids.
|
|
181
|
+
* `formId` must survive because the order API requires it under booking.resources[].
|
|
182
|
+
*/
|
|
196
183
|
function normalizeRequirements(product) {
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
...Array.isArray(resource.default_resource) ? resource.default_resource : [],
|
|
207
|
-
...Array.isArray(resource.optional_resource) ? resource.optional_resource : []
|
|
208
|
-
].map((id) => toNumberId(id)).filter((id) => id !== void 0),
|
|
209
|
-
resourceType: resource.type || ((_a2 = resource.select_type) == null ? void 0 : _a2.type) || "single",
|
|
210
|
-
required: resource.status === 1,
|
|
211
|
-
capacityRequired: Number(((_b = product.capacity) == null ? void 0 : _b.default) || product.capacity || 1) || 1
|
|
212
|
-
};
|
|
213
|
-
});
|
|
184
|
+
const resources = product.product_resource?.resources;
|
|
185
|
+
if (!Array.isArray(resources)) return [];
|
|
186
|
+
return resources.filter(resource => resource?.status !== 0).map(resource => ({
|
|
187
|
+
formId: toNumberId(resource.id),
|
|
188
|
+
resourceIds: [...(Array.isArray(resource.default_resource) ? resource.default_resource : []), ...(Array.isArray(resource.optional_resource) ? resource.optional_resource : [])].map(id => toNumberId(id)).filter(id => id !== undefined),
|
|
189
|
+
resourceType: resource.type || resource.select_type?.type || 'single',
|
|
190
|
+
required: resource.status === 1,
|
|
191
|
+
capacityRequired: Number(product.capacity?.default || product.capacity || 1) || 1
|
|
192
|
+
}));
|
|
214
193
|
}
|
|
194
|
+
|
|
195
|
+
/** Converts a ProductList record into the pure input shape consumed by ResourcePlanner. */
|
|
215
196
|
function normalizeProductForPlanner(product) {
|
|
216
|
-
var _a, _b;
|
|
217
197
|
const raw = product;
|
|
218
198
|
const kind = resolveProductKind(raw);
|
|
219
199
|
return {
|
|
220
200
|
id: raw.id ?? raw.product_id,
|
|
221
201
|
title: pickLocalizedText(raw.title || raw.name || raw.product_title),
|
|
222
202
|
kind,
|
|
223
|
-
durationMinutes: Number(
|
|
203
|
+
durationMinutes: Number(raw.duration?.value || raw.duration || raw.service_duration || 30) || 30,
|
|
224
204
|
schedule: normalizeSchedule(raw),
|
|
225
205
|
resourceRequirements: normalizeRequirements(raw),
|
|
226
|
-
capacityRequired: Number(
|
|
206
|
+
capacityRequired: Number(raw.capacity?.default || raw.capacity || 1) || 1,
|
|
227
207
|
quantity: Number(raw.num || raw.quantity || 1) || 1,
|
|
228
208
|
price: raw.price ?? raw.selling_price ?? raw.base_price,
|
|
229
209
|
raw
|
|
230
210
|
};
|
|
231
211
|
}
|
|
232
212
|
function normalizeResourceType(value) {
|
|
233
|
-
if (value ===
|
|
234
|
-
|
|
235
|
-
return "single";
|
|
213
|
+
if (value === 'multiple' || value === 'capacity') return value;
|
|
214
|
+
return 'single';
|
|
236
215
|
}
|
|
237
216
|
function normalizeResource(raw) {
|
|
238
|
-
var _a, _b;
|
|
239
217
|
const id = raw.resourceId ?? raw.resource_id ?? raw.id;
|
|
240
|
-
if (id ===
|
|
241
|
-
|
|
242
|
-
const combinedResourceIds = (_a = raw.combined_resource) == null ? void 0 : _a.resource_ids;
|
|
218
|
+
if (id === undefined || id === null || id === '') return null;
|
|
219
|
+
const combinedResourceIds = raw.combined_resource?.resource_ids;
|
|
243
220
|
return {
|
|
244
221
|
id,
|
|
245
222
|
formId: raw.formId ?? raw.form_id ?? raw.resource_form_id,
|
|
246
223
|
name: raw.resourceName || raw.main_field || raw.name || raw.title,
|
|
247
|
-
resourceType: normalizeResourceType(raw.type || raw.resourceType ||
|
|
224
|
+
resourceType: normalizeResourceType(raw.type || raw.resourceType || raw.select_type?.type),
|
|
248
225
|
capacity: Number(raw.capacity || raw.max_capacity || 1) || 1,
|
|
249
226
|
times: Array.isArray(raw.times) ? raw.times : [],
|
|
250
|
-
childResourceIds: Array.isArray(combinedResourceIds) ? combinedResourceIds :
|
|
227
|
+
childResourceIds: Array.isArray(combinedResourceIds) ? combinedResourceIds : undefined,
|
|
251
228
|
raw
|
|
252
229
|
};
|
|
253
230
|
}
|
|
254
231
|
function normalizeScheduleIds(raw) {
|
|
255
232
|
const ids = raw.schedule ?? raw.schedule_ids ?? raw.scheduleIds ?? [];
|
|
256
|
-
return (Array.isArray(ids) ? ids : [ids]).map(
|
|
233
|
+
return (Array.isArray(ids) ? ids : [ids]).map(id => toNumberId(id)).filter(id => id !== undefined);
|
|
257
234
|
}
|
|
258
235
|
function collectRawScheduleIds(rawResources) {
|
|
259
|
-
const ids =
|
|
260
|
-
(rawResources || []).forEach(
|
|
261
|
-
normalizeScheduleIds(resource).forEach(
|
|
236
|
+
const ids = new Map();
|
|
237
|
+
(rawResources || []).forEach(resource => {
|
|
238
|
+
normalizeScheduleIds(resource).forEach(id => {
|
|
262
239
|
ids.set(String(id), id);
|
|
263
240
|
});
|
|
264
241
|
});
|
|
265
242
|
return Array.from(ids.values());
|
|
266
243
|
}
|
|
267
244
|
function scheduleListHasIds(scheduleList, scheduleIds) {
|
|
268
|
-
if (!scheduleIds.length)
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
return scheduleIds.every((id) => existingIds.has(String(id)));
|
|
245
|
+
if (!scheduleIds.length) return true;
|
|
246
|
+
const existingIds = new Set((scheduleList || []).map(schedule => String(schedule.id)));
|
|
247
|
+
return scheduleIds.every(id => existingIds.has(String(id)));
|
|
272
248
|
}
|
|
273
249
|
function dateRangeDays(dateRange) {
|
|
274
|
-
if (!
|
|
275
|
-
return [];
|
|
250
|
+
if (!dateRange?.start || !dateRange?.end) return [];
|
|
276
251
|
const dates = [];
|
|
277
|
-
let cursor = (0,
|
|
278
|
-
const end = (0,
|
|
279
|
-
if (!cursor.isValid() || !end.isValid() || end.isBefore(cursor,
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
cursor = cursor.add(1, "day");
|
|
252
|
+
let cursor = (0, _dayjs.default)(dateRange.start);
|
|
253
|
+
const end = (0, _dayjs.default)(dateRange.end);
|
|
254
|
+
if (!cursor.isValid() || !end.isValid() || end.isBefore(cursor, 'day')) return dates;
|
|
255
|
+
while (cursor.isSame(end, 'day') || cursor.isBefore(end, 'day')) {
|
|
256
|
+
dates.push(cursor.format('YYYY-MM-DD'));
|
|
257
|
+
cursor = cursor.add(1, 'day');
|
|
284
258
|
}
|
|
285
259
|
return dates;
|
|
286
260
|
}
|
|
287
261
|
function normalizePlannerEvent(rawEvent, resourceId) {
|
|
288
262
|
const startAt = rawEvent.start_at ?? rawEvent.startAt ?? rawEvent.start_time ?? rawEvent.startTime;
|
|
289
263
|
const endAt = rawEvent.end_at ?? rawEvent.endAt ?? rawEvent.end_time ?? rawEvent.endTime;
|
|
290
|
-
if (!startAt || !endAt)
|
|
291
|
-
return null;
|
|
264
|
+
if (!startAt || !endAt) return null;
|
|
292
265
|
const rawSource = rawEvent.source;
|
|
293
|
-
const source = rawSource ===
|
|
266
|
+
const source = rawSource === 'remote' || rawSource === 'cart' || rawSource === 'selection' ? rawSource : 'remote';
|
|
294
267
|
return {
|
|
295
268
|
...rawEvent,
|
|
296
269
|
resourceId,
|
|
@@ -306,59 +279,63 @@ function normalizeResourceV2(raw) {
|
|
|
306
279
|
...raw,
|
|
307
280
|
times: []
|
|
308
281
|
});
|
|
309
|
-
if (!normalized)
|
|
310
|
-
return null;
|
|
282
|
+
if (!normalized) return null;
|
|
311
283
|
return normalized;
|
|
312
284
|
}
|
|
313
285
|
function buildResourceWindowFallbackTimes(params) {
|
|
314
|
-
const {
|
|
286
|
+
const {
|
|
287
|
+
raw,
|
|
288
|
+
dates,
|
|
289
|
+
scheduleIds
|
|
290
|
+
} = params;
|
|
315
291
|
const rawStart = raw.start_time || raw.start_at || raw.startTime;
|
|
316
292
|
const rawEnd = raw.end_time || raw.end_at || raw.endTime;
|
|
317
|
-
if (!rawStart || !rawEnd)
|
|
318
|
-
|
|
319
|
-
const
|
|
320
|
-
const endBoundary = (0, import_dayjs.default)(rawEnd);
|
|
293
|
+
if (!rawStart || !rawEnd) return [];
|
|
294
|
+
const startBoundary = (0, _dayjs.default)(rawStart);
|
|
295
|
+
const endBoundary = (0, _dayjs.default)(rawEnd);
|
|
321
296
|
if (!startBoundary.isValid() || !endBoundary.isValid() || !endBoundary.isAfter(startBoundary)) {
|
|
322
297
|
return [];
|
|
323
298
|
}
|
|
324
|
-
return dates.flatMap(
|
|
325
|
-
const dayStart = (0,
|
|
326
|
-
const dayEnd = (0,
|
|
299
|
+
return dates.flatMap(date => {
|
|
300
|
+
const dayStart = (0, _dayjs.default)(`${date} 00:00:00`);
|
|
301
|
+
const dayEnd = (0, _dayjs.default)(`${date} 23:59:59`);
|
|
327
302
|
const start = startBoundary.isAfter(dayStart) ? startBoundary : dayStart;
|
|
328
303
|
const end = endBoundary.isBefore(dayEnd) ? endBoundary : dayEnd;
|
|
329
|
-
if (!end.isAfter(start))
|
|
330
|
-
return [];
|
|
304
|
+
if (!end.isAfter(start)) return [];
|
|
331
305
|
return [{
|
|
332
|
-
start_at: start.format(
|
|
333
|
-
end_at: end.format(
|
|
306
|
+
start_at: start.format('YYYY-MM-DD HH:mm:ss'),
|
|
307
|
+
end_at: end.format('YYYY-MM-DD HH:mm:ss'),
|
|
334
308
|
schedule_ids: scheduleIds,
|
|
335
|
-
source:
|
|
309
|
+
source: 'resource_window_fallback'
|
|
336
310
|
}];
|
|
337
311
|
});
|
|
338
312
|
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Materializes resource work windows locally from v2's schedule ids, then keeps its flat
|
|
316
|
+
* event_list as planner events. This deliberately avoids the older API's times -> event_list
|
|
317
|
+
* response nesting and lets one resource response serve any requested date range.
|
|
318
|
+
*/
|
|
339
319
|
function buildPlannerResourcesFromV2(params) {
|
|
340
|
-
const scheduleMap = new Map(
|
|
341
|
-
(params.scheduleList || []).map((schedule) => [String(schedule.id), schedule])
|
|
342
|
-
);
|
|
320
|
+
const scheduleMap = new Map((params.scheduleList || []).map(schedule => [String(schedule.id), schedule]));
|
|
343
321
|
const dates = dateRangeDays(params.dateRange);
|
|
344
322
|
const externalEvents = [];
|
|
345
|
-
const resources = (params.rawResources || []).map(
|
|
323
|
+
const resources = (params.rawResources || []).map(raw => {
|
|
346
324
|
const resource = normalizeResourceV2(raw);
|
|
347
|
-
if (!resource)
|
|
348
|
-
return null;
|
|
325
|
+
if (!resource) return null;
|
|
349
326
|
const scheduleIds = normalizeScheduleIds(raw);
|
|
350
|
-
const schedules = scheduleIds.map(
|
|
351
|
-
const matchedScheduleIds = new Set(schedules.map(
|
|
352
|
-
const missingScheduleIds = scheduleIds.filter(
|
|
327
|
+
const schedules = scheduleIds.map(id => scheduleMap.get(String(id))).filter(Boolean);
|
|
328
|
+
const matchedScheduleIds = new Set(schedules.map(schedule => String(schedule.id)));
|
|
329
|
+
const missingScheduleIds = scheduleIds.filter(id => !matchedScheduleIds.has(String(id)));
|
|
353
330
|
if (missingScheduleIds.length > 0) {
|
|
354
331
|
resource.raw = {
|
|
355
|
-
...resource.raw || raw,
|
|
332
|
+
...(resource.raw || raw),
|
|
356
333
|
_plannerMissingScheduleIds: missingScheduleIds
|
|
357
334
|
};
|
|
358
335
|
}
|
|
359
|
-
resource.times = dates.flatMap(
|
|
360
|
-
start_at: (0,
|
|
361
|
-
end_at: (0,
|
|
336
|
+
resource.times = dates.flatMap(date => (0, _getDateIsInSchedule.getScheduleStartEndTimePoints)(date, schedules).map(slot => ({
|
|
337
|
+
start_at: (0, _dayjs.default)(slot.start_at).format('YYYY-MM-DD HH:mm:ss'),
|
|
338
|
+
end_at: (0, _dayjs.default)(slot.end_at).format('YYYY-MM-DD HH:mm:ss'),
|
|
362
339
|
schedule_ids: scheduleIds
|
|
363
340
|
})));
|
|
364
341
|
if (resource.times.length === 0 && missingScheduleIds.length > 0) {
|
|
@@ -369,72 +346,80 @@ function buildPlannerResourcesFromV2(params) {
|
|
|
369
346
|
});
|
|
370
347
|
}
|
|
371
348
|
const eventList = Array.isArray(raw.event_list) ? raw.event_list : [];
|
|
372
|
-
eventList.forEach(
|
|
349
|
+
eventList.forEach(event => {
|
|
373
350
|
const normalizedEvent = normalizePlannerEvent(event, resource.id);
|
|
374
|
-
if (normalizedEvent)
|
|
375
|
-
externalEvents.push(normalizedEvent);
|
|
351
|
+
if (normalizedEvent) externalEvents.push(normalizedEvent);
|
|
376
352
|
});
|
|
377
353
|
return resource;
|
|
378
|
-
}).filter(
|
|
354
|
+
}).filter(resource => resource !== null);
|
|
379
355
|
return {
|
|
380
356
|
resources,
|
|
381
357
|
externalEvents
|
|
382
358
|
};
|
|
383
359
|
}
|
|
360
|
+
|
|
361
|
+
/** Combines URL-locked resources with every resource referenced by the selected products. */
|
|
384
362
|
function collectPlannerResourceIds(products, explicitResourceIds = []) {
|
|
385
|
-
const ids =
|
|
386
|
-
const add =
|
|
387
|
-
if (value ===
|
|
388
|
-
return;
|
|
363
|
+
const ids = new Map();
|
|
364
|
+
const add = value => {
|
|
365
|
+
if (value === undefined || value === null || value === '') return;
|
|
389
366
|
ids.set(String(value), value);
|
|
390
367
|
};
|
|
391
368
|
explicitResourceIds.forEach(add);
|
|
392
|
-
products.forEach(
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
var _a2;
|
|
396
|
-
(_a2 = requirement.resourceIds) == null ? void 0 : _a2.forEach(add);
|
|
369
|
+
products.forEach(product => {
|
|
370
|
+
product.resourceRequirements?.forEach(requirement => {
|
|
371
|
+
requirement.resourceIds?.forEach(add);
|
|
397
372
|
});
|
|
398
373
|
});
|
|
399
374
|
return Array.from(ids.values());
|
|
400
375
|
}
|
|
401
376
|
function samePlannerId(left, right) {
|
|
402
|
-
if (left ===
|
|
403
|
-
return false;
|
|
377
|
+
if (left === undefined || right === undefined) return false;
|
|
404
378
|
return String(left) === String(right);
|
|
405
379
|
}
|
|
406
380
|
function findRequirementForAssignment(product, assignment) {
|
|
407
381
|
const requirements = product.resourceRequirements || [];
|
|
408
|
-
return requirements.find(
|
|
382
|
+
return requirements.find(requirement => (requirement.resourceIds || []).some(id => samePlannerId(id, assignment.resourceId))) || (requirements.length === 1 ? requirements[0] : undefined) || requirements.find(requirement => requirement.required) || requirements[0];
|
|
409
383
|
}
|
|
384
|
+
|
|
385
|
+
/** Convenience wrapper for the usual one-resource booking case. */
|
|
410
386
|
function buildBookingFromAssignment(params) {
|
|
411
387
|
return buildBookingFromAssignments({
|
|
412
388
|
assignments: [params.assignment],
|
|
413
389
|
product: params.product
|
|
414
390
|
});
|
|
415
391
|
}
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Converts all resources needed by one product/time interval into the one booking expected by
|
|
395
|
+
* OrderModule. Callers must group assignments before this function so a multi-form booking does
|
|
396
|
+
* not become several competing bookings.
|
|
397
|
+
*/
|
|
416
398
|
function buildBookingFromAssignments(params) {
|
|
417
|
-
const {
|
|
399
|
+
const {
|
|
400
|
+
assignments,
|
|
401
|
+
product
|
|
402
|
+
} = params;
|
|
418
403
|
const firstAssignment = assignments[0];
|
|
419
|
-
const start = (0,
|
|
420
|
-
const end = (0,
|
|
404
|
+
const start = (0, _dayjs.default)(firstAssignment.start_at);
|
|
405
|
+
const end = (0, _dayjs.default)(firstAssignment.end_at);
|
|
421
406
|
return {
|
|
422
|
-
start_date: start.format(
|
|
423
|
-
start_time: start.format(
|
|
424
|
-
end_date: end.format(
|
|
425
|
-
end_time: end.format(
|
|
426
|
-
duration: Math.max(1, end.diff(start,
|
|
427
|
-
like_status:
|
|
407
|
+
start_date: start.format('YYYY-MM-DD'),
|
|
408
|
+
start_time: start.format('HH:mm'),
|
|
409
|
+
end_date: end.format('YYYY-MM-DD'),
|
|
410
|
+
end_time: end.format('HH:mm'),
|
|
411
|
+
duration: Math.max(1, end.diff(start, 'minute')),
|
|
412
|
+
like_status: 'common',
|
|
428
413
|
schedule_id: 0,
|
|
429
|
-
resources: assignments.map(
|
|
414
|
+
resources: assignments.map(assignment => {
|
|
430
415
|
const requirement = findRequirementForAssignment(product, assignment);
|
|
431
416
|
return {
|
|
432
417
|
id: assignment.resourceId,
|
|
433
418
|
resource_id: assignment.resourceId,
|
|
434
|
-
form_id: requirement
|
|
435
|
-
relation_type:
|
|
419
|
+
form_id: requirement?.formId,
|
|
420
|
+
relation_type: 'form',
|
|
436
421
|
relation_id: assignment.resourceId,
|
|
437
|
-
like_status:
|
|
422
|
+
like_status: 'common',
|
|
438
423
|
capacity: assignment.capacityRequired || product.capacityRequired || 1
|
|
439
424
|
};
|
|
440
425
|
}),
|
|
@@ -445,73 +430,65 @@ function buildBookingFromAssignments(params) {
|
|
|
445
430
|
};
|
|
446
431
|
}
|
|
447
432
|
function buildAssignmentGroupKey(assignment) {
|
|
448
|
-
return [
|
|
449
|
-
assignment.productId,
|
|
450
|
-
assignment.start_at,
|
|
451
|
-
assignment.end_at
|
|
452
|
-
].join(":");
|
|
433
|
+
return [assignment.productId, assignment.start_at, assignment.end_at].join(':');
|
|
453
434
|
}
|
|
435
|
+
|
|
436
|
+
/** Builds the exact identity BaseSales needs to remove only this solution's order lines. */
|
|
454
437
|
function buildPlannerLineIdentity(product) {
|
|
455
|
-
var _a;
|
|
456
438
|
return {
|
|
457
439
|
product_id: product.product_id,
|
|
458
440
|
product_variant_id: product.product_variant_id ?? 0,
|
|
459
|
-
unique_identification_number:
|
|
441
|
+
unique_identification_number: product.metadata?.unique_identification_number || product.unique_identification_number,
|
|
460
442
|
product_sku: product.product_sku,
|
|
461
443
|
product_bundle: product.product_bundle
|
|
462
444
|
};
|
|
463
445
|
}
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
this.loadOpenDataInFlight = null;
|
|
473
|
-
this.loadOpenDataInFlightTarget = null;
|
|
474
|
-
}
|
|
446
|
+
class UnifiedBookingSalesImpl extends _BookingTicket.BookingTicket {
|
|
447
|
+
defaultName = 'unifiedBookingSales';
|
|
448
|
+
defaultVersion = '1.0.0';
|
|
449
|
+
store = {};
|
|
450
|
+
unifiedProductCatalog = [];
|
|
451
|
+
openDataTarget = null;
|
|
452
|
+
loadOpenDataInFlight = null;
|
|
453
|
+
loadOpenDataInFlightTarget = null;
|
|
475
454
|
getSubmitOrderSalesChannel() {
|
|
476
|
-
|
|
477
|
-
const channel = String(((_a = this.otherParams) == null ? void 0 : _a.channel) ?? "").trim();
|
|
455
|
+
const channel = String(this.otherParams?.channel ?? '').trim();
|
|
478
456
|
return channel || super.getSubmitOrderSalesChannel();
|
|
479
457
|
}
|
|
480
458
|
isSessionStoragePersistEnabled() {
|
|
481
|
-
|
|
482
|
-
return Boolean(
|
|
483
|
-
this.cacheId && ((_a = this.otherParams) == null ? void 0 : _a.enableSessionStoragePersist) === true
|
|
484
|
-
);
|
|
459
|
+
return Boolean(this.cacheId && this.otherParams?.enableSessionStoragePersist === true);
|
|
485
460
|
}
|
|
486
461
|
shouldUseSessionStorageForSubModule(moduleName) {
|
|
487
|
-
return this.isSessionStoragePersistEnabled() && moduleName ===
|
|
462
|
+
return this.isSessionStoragePersistEnabled() && moduleName === 'order';
|
|
488
463
|
}
|
|
464
|
+
|
|
489
465
|
/**
|
|
490
466
|
* 读取与当前 cacheId 同分桶的 Solution 会话状态。
|
|
491
467
|
* 该状态独立于 otherParams,适合页面皮肤保存短生命周期 UI 状态。
|
|
492
468
|
*/
|
|
493
469
|
getSessionStateValue(key) {
|
|
494
|
-
if (!key || !this.isSessionStoragePersistEnabled())
|
|
495
|
-
return void 0;
|
|
470
|
+
if (!key || !this.isSessionStoragePersistEnabled()) return undefined;
|
|
496
471
|
const cacheData = this.readSessionCacheData();
|
|
497
|
-
const solutionCache = cacheData
|
|
472
|
+
const solutionCache = cacheData?.[this.name];
|
|
498
473
|
if (!isRecord(solutionCache) || !isRecord(solutionCache.sessionState)) {
|
|
499
|
-
return
|
|
474
|
+
return undefined;
|
|
500
475
|
}
|
|
501
476
|
return solutionCache.sessionState[key];
|
|
502
477
|
}
|
|
478
|
+
|
|
503
479
|
/**
|
|
504
480
|
* 写入与当前 cacheId 同分桶的 Solution 会话状态。
|
|
505
481
|
* value 为 undefined 时删除该 key;存储失败不阻断业务流程。
|
|
506
482
|
*/
|
|
507
483
|
setSessionStateValue(key, value) {
|
|
508
|
-
if (!key || !this.isSessionStoragePersistEnabled())
|
|
509
|
-
return;
|
|
484
|
+
if (!key || !this.isSessionStoragePersistEnabled()) return;
|
|
510
485
|
const cacheData = this.readSessionCacheData();
|
|
511
|
-
const solutionCache = cacheData
|
|
486
|
+
const solutionCache = cacheData?.[this.name];
|
|
512
487
|
const currentSessionState = isRecord(solutionCache) && isRecord(solutionCache.sessionState) ? solutionCache.sessionState : {};
|
|
513
|
-
const nextSessionState = {
|
|
514
|
-
|
|
488
|
+
const nextSessionState = {
|
|
489
|
+
...currentSessionState
|
|
490
|
+
};
|
|
491
|
+
if (value === undefined) {
|
|
515
492
|
delete nextSessionState[key];
|
|
516
493
|
} else {
|
|
517
494
|
nextSessionState[key] = value;
|
|
@@ -519,55 +496,57 @@ var UnifiedBookingSalesImpl = class extends import_BookingTicket.BookingTicket {
|
|
|
519
496
|
this.checkSaveCache({
|
|
520
497
|
cacheId: this.cacheId,
|
|
521
498
|
fatherModule: this.name,
|
|
522
|
-
store: {
|
|
523
|
-
|
|
499
|
+
store: {
|
|
500
|
+
sessionState: nextSessionState
|
|
501
|
+
},
|
|
502
|
+
cacheKey: ['sessionState']
|
|
524
503
|
});
|
|
525
504
|
}
|
|
505
|
+
|
|
526
506
|
/**
|
|
527
507
|
* 清除当前 cacheId 的可恢复订单快照,同时保留 Solution UI sessionState。
|
|
528
508
|
* 用于支付跳转等终态场景,避免浏览器返回时恢复已提交订单。
|
|
529
509
|
*/
|
|
530
510
|
clearSessionStorageOrderSnapshot() {
|
|
531
|
-
|
|
532
|
-
(_b = (_a = this.store.order) == null ? void 0 : _a.clearSessionStoragePersistedTempOrder) == null ? void 0 : _b.call(_a);
|
|
511
|
+
this.store.order?.clearSessionStoragePersistedTempOrder?.();
|
|
533
512
|
}
|
|
513
|
+
|
|
534
514
|
/**
|
|
535
515
|
* Kiosk 不能把已收款订单留在本地等待重试:默认直接等待云端 checkout。
|
|
536
516
|
* 兼容仍需要 WebPOS 待同步模式的入口可显式传 checkoutSyncTaskEnabled: true。
|
|
537
517
|
*/
|
|
538
518
|
shouldUseCheckoutSyncTask() {
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
return typeof configured === "boolean" ? configured : false;
|
|
519
|
+
const configured = this.otherParams?.checkoutSyncTaskEnabled;
|
|
520
|
+
return typeof configured === 'boolean' ? configured : false;
|
|
542
521
|
}
|
|
522
|
+
|
|
543
523
|
/** UnifiedBookingSales 的真实结账默认请求收据数据,供云端确认后再本地打印。 */
|
|
544
524
|
getDefaultCheckoutSmallTicketDataFlag() {
|
|
545
525
|
return 1;
|
|
546
526
|
}
|
|
547
527
|
getRegisteredModuleNames() {
|
|
548
|
-
return [...super.getRegisteredModuleNames(),
|
|
528
|
+
return [...super.getRegisteredModuleNames(), 'resourcePlanner', 'openData'];
|
|
549
529
|
}
|
|
550
530
|
createSubModule(moduleName) {
|
|
551
|
-
if (moduleName ===
|
|
552
|
-
return new
|
|
531
|
+
if (moduleName === 'resourcePlanner') {
|
|
532
|
+
return new _modules.ResourcePlannerModule(`${this.name}_resourcePlanner`);
|
|
553
533
|
}
|
|
554
|
-
if (moduleName ===
|
|
555
|
-
return new
|
|
534
|
+
if (moduleName === 'openData') {
|
|
535
|
+
return new _modules.OpenDataModule(`${this.name}_openData`);
|
|
556
536
|
}
|
|
557
537
|
return super.createSubModule(moduleName);
|
|
558
538
|
}
|
|
559
539
|
async addNewOrder() {
|
|
560
|
-
|
|
561
|
-
const sessionRecord = this.isSessionStoragePersistEnabled() ? (_b = (_a = this.store.order) == null ? void 0 : _a.consumeSessionStorageRestore) == null ? void 0 : _b.call(_a) : null;
|
|
540
|
+
const sessionRecord = this.isSessionStoragePersistEnabled() ? this.store.order?.consumeSessionStorageRestore?.() : null;
|
|
562
541
|
if (sessionRecord) {
|
|
563
542
|
await this.loadSalesDetail({
|
|
564
543
|
preloadedSalesDetail: sessionRecord,
|
|
565
|
-
hydrateSource:
|
|
544
|
+
hydrateSource: 'sessionStorage'
|
|
566
545
|
});
|
|
567
546
|
}
|
|
568
547
|
const tempOrder = await super.addNewOrder();
|
|
569
548
|
if (sessionRecord) {
|
|
570
|
-
|
|
549
|
+
this.store.order?.persistTempOrder();
|
|
571
550
|
}
|
|
572
551
|
if (this.isAuthenticatedCustomerUserPlatform()) {
|
|
573
552
|
try {
|
|
@@ -576,102 +555,82 @@ var UnifiedBookingSalesImpl = class extends import_BookingTicket.BookingTicket {
|
|
|
576
555
|
await this.refreshLegacySessionCustomerDiscounts(tempOrder);
|
|
577
556
|
}
|
|
578
557
|
} catch (error) {
|
|
579
|
-
console.warn(
|
|
580
|
-
"[UnifiedBookingSales] Failed to sync authenticated order customer after addNewOrder",
|
|
581
|
-
error
|
|
582
|
-
);
|
|
558
|
+
console.warn('[UnifiedBookingSales] Failed to sync authenticated order customer after addNewOrder', error);
|
|
583
559
|
}
|
|
584
560
|
} else if (sessionRecord) {
|
|
585
561
|
try {
|
|
586
562
|
await this.refreshLegacySessionCustomerDiscounts(tempOrder);
|
|
587
563
|
} catch (error) {
|
|
588
|
-
console.warn(
|
|
589
|
-
"[UnifiedBookingSales] Failed to refresh cached customer discounts after addNewOrder",
|
|
590
|
-
error
|
|
591
|
-
);
|
|
564
|
+
console.warn('[UnifiedBookingSales] Failed to refresh cached customer discounts after addNewOrder', error);
|
|
592
565
|
}
|
|
593
566
|
}
|
|
594
|
-
return
|
|
567
|
+
return this.store.order?.getTempOrder() || tempOrder;
|
|
595
568
|
}
|
|
596
569
|
async syncAuthenticatedOrderCustomer() {
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
const authenticatedCustomerId = toCustomerId(authenticatedCustomer == null ? void 0 : authenticatedCustomer.id);
|
|
602
|
-
if (!authenticatedCustomerId)
|
|
603
|
-
return false;
|
|
570
|
+
if (!this.isAuthenticatedCustomerUserPlatform()) return false;
|
|
571
|
+
const authenticatedCustomer = this.core?.getPlugin?.('user')?.get?.();
|
|
572
|
+
const authenticatedCustomerId = toCustomerId(authenticatedCustomer?.id);
|
|
573
|
+
if (!authenticatedCustomerId) return false;
|
|
604
574
|
const tempOrder = this.getTempOrder();
|
|
605
575
|
const cachedCustomerId = resolveTempOrderCustomerId(tempOrder);
|
|
606
576
|
if (cachedCustomerId !== null && cachedCustomerId !== authenticatedCustomerId) {
|
|
607
577
|
await this.resetCachedCustomerDiscountState();
|
|
608
578
|
}
|
|
609
|
-
|
|
579
|
+
this.store.customer?.setSelectedCustomer?.(authenticatedCustomer);
|
|
610
580
|
this.setOrderCustomer(authenticatedCustomer);
|
|
611
|
-
await Promise.all([
|
|
612
|
-
this.refreshDiscountConfigAfterOrderCustomerChange(authenticatedCustomerId),
|
|
613
|
-
this.waitForOrderCustomerPromotionRefresh()
|
|
614
|
-
]);
|
|
581
|
+
await Promise.all([this.refreshDiscountConfigAfterOrderCustomerChange(authenticatedCustomerId), this.waitForOrderCustomerPromotionRefresh()]);
|
|
615
582
|
return true;
|
|
616
583
|
}
|
|
617
584
|
isAuthenticatedCustomerUserPlatform() {
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
return platform === "pc" || platform === "h5";
|
|
585
|
+
const platform = String(this.otherParams?.platform || '').toLowerCase();
|
|
586
|
+
return platform === 'pc' || platform === 'h5';
|
|
621
587
|
}
|
|
622
588
|
resolveDiscountOrderIdentity(tempOrder) {
|
|
623
|
-
|
|
624
|
-
return (tempOrder == null ? void 0 : tempOrder.order_id) || ((_c = (_b = (_a = this.store.order) == null ? void 0 : _a.getOrderIdentity) == null ? void 0 : _b.call(_a)) == null ? void 0 : _c.orderId) || null;
|
|
589
|
+
return tempOrder?.order_id || this.store.order?.getOrderIdentity?.()?.orderId || null;
|
|
625
590
|
}
|
|
626
591
|
resolveDiscountAction(orderId) {
|
|
627
|
-
if (!orderId || isLocalOrderId(orderId))
|
|
628
|
-
|
|
629
|
-
return "edit";
|
|
592
|
+
if (!orderId || isLocalOrderId(orderId)) return 'create';
|
|
593
|
+
return 'edit';
|
|
630
594
|
}
|
|
631
595
|
async resetCachedCustomerDiscountState() {
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
(_d = (_c = this.store.customer) == null ? void 0 : _c.setSelectedCustomer) == null ? void 0 : _d.call(_c, null);
|
|
596
|
+
this.store.order?.clearOrderCustomer?.();
|
|
597
|
+
this.store.customer?.setSelectedCustomer?.(null);
|
|
635
598
|
this.discountConfigCacheKey = null;
|
|
636
599
|
this.hasManualDiscountSelection = false;
|
|
637
|
-
const orderStore =
|
|
600
|
+
const orderStore = this.store.order?.store || {};
|
|
638
601
|
const discountModule = orderStore.discount;
|
|
639
|
-
const filteredOriginalDiscounts = filterCustomerBoundDiscounts(
|
|
640
|
-
|
|
641
|
-
);
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
await ((_m = (_l = this.store.order) == null ? void 0 : _l.recalculateSummary) == null ? void 0 : _m.call(_l, { createIfMissing: true }));
|
|
649
|
-
(_o = (_n = this.store.order) == null ? void 0 : _n.persistTempOrder) == null ? void 0 : _o.call(_n);
|
|
602
|
+
const filteredOriginalDiscounts = filterCustomerBoundDiscounts(discountModule?.getOriginalDiscountList?.() || []);
|
|
603
|
+
const filteredCurrentDiscounts = filterCustomerBoundDiscounts(discountModule?.getDiscountList?.() || []);
|
|
604
|
+
await discountModule?.setOriginalDiscountList?.(filteredOriginalDiscounts);
|
|
605
|
+
await discountModule?.setDiscountList?.(filteredCurrentDiscounts);
|
|
606
|
+
this.store.order?.applyDiscount?.();
|
|
607
|
+
await this.store.order?.recalculateSummary?.({
|
|
608
|
+
createIfMissing: true
|
|
609
|
+
});
|
|
610
|
+
this.store.order?.persistTempOrder?.();
|
|
650
611
|
}
|
|
651
612
|
async refreshLegacySessionCustomerDiscounts(tempOrder) {
|
|
652
613
|
const customerId = resolveTempOrderCustomerId(tempOrder);
|
|
653
|
-
if (!customerId)
|
|
654
|
-
return void 0;
|
|
614
|
+
if (!customerId) return undefined;
|
|
655
615
|
const loadDiscountConfig = super.loadDiscountConfig.bind(this);
|
|
656
616
|
return await loadDiscountConfig({
|
|
657
617
|
customerId,
|
|
658
|
-
action: this.resolveDiscountAction(
|
|
659
|
-
this.resolveDiscountOrderIdentity(tempOrder)
|
|
660
|
-
)
|
|
618
|
+
action: this.resolveDiscountAction(this.resolveDiscountOrderIdentity(tempOrder))
|
|
661
619
|
});
|
|
662
620
|
}
|
|
621
|
+
|
|
663
622
|
/**
|
|
664
623
|
* Loads OpenData without borrowing BookingTicket. Cache ownership is tied to the exact
|
|
665
624
|
* business/channel target so a reused solution instance cannot leak another entry's menus.
|
|
666
625
|
*/
|
|
667
626
|
async loadOpenData(params) {
|
|
668
627
|
if (!this.store.openData) {
|
|
669
|
-
throw new Error(
|
|
628
|
+
throw new Error('[UnifiedBookingSales] openData 模块未初始化');
|
|
670
629
|
}
|
|
671
|
-
const businessCode = String(params.businessCode ||
|
|
672
|
-
const channel = String(params.channel ||
|
|
630
|
+
const businessCode = String(params.businessCode || '').trim();
|
|
631
|
+
const channel = String(params.channel || '').trim();
|
|
673
632
|
if (!businessCode || !channel) {
|
|
674
|
-
throw new Error(
|
|
633
|
+
throw new Error('[UnifiedBookingSales] OpenData 需要 businessCode 与 channel');
|
|
675
634
|
}
|
|
676
635
|
const target = `${businessCode}+${channel}`;
|
|
677
636
|
const cachedData = this.store.openData.getOpenData();
|
|
@@ -688,7 +647,7 @@ var UnifiedBookingSalesImpl = class extends import_BookingTicket.BookingTicket {
|
|
|
688
647
|
}
|
|
689
648
|
this.loadOpenDataInFlightTarget = target;
|
|
690
649
|
this.loadOpenDataInFlight = this.store.openData.fetchOpenData({
|
|
691
|
-
scope:
|
|
650
|
+
scope: 'board',
|
|
692
651
|
target,
|
|
693
652
|
section_code: [...OPEN_DATA_SECTION_CODES]
|
|
694
653
|
});
|
|
@@ -705,28 +664,28 @@ var UnifiedBookingSalesImpl = class extends import_BookingTicket.BookingTicket {
|
|
|
705
664
|
}
|
|
706
665
|
}
|
|
707
666
|
async getOpenData() {
|
|
708
|
-
|
|
709
|
-
const
|
|
710
|
-
|
|
711
|
-
if (!businessCode || !channel)
|
|
712
|
-
return null;
|
|
667
|
+
const businessCode = String(this.otherParams?.businessCode || '').trim();
|
|
668
|
+
const channel = String(this.otherParams?.channel || '').trim();
|
|
669
|
+
if (!businessCode || !channel) return null;
|
|
713
670
|
const target = `${businessCode}+${channel}`;
|
|
714
|
-
const cachedData =
|
|
715
|
-
if (cachedData && this.openDataTarget === target)
|
|
716
|
-
|
|
717
|
-
|
|
671
|
+
const cachedData = this.store.openData?.getOpenData() || null;
|
|
672
|
+
if (cachedData && this.openDataTarget === target) return cachedData;
|
|
673
|
+
return this.loadOpenData({
|
|
674
|
+
businessCode,
|
|
675
|
+
channel
|
|
676
|
+
});
|
|
718
677
|
}
|
|
678
|
+
|
|
719
679
|
/**
|
|
720
680
|
* Loads the product catalog used by both UI and Planner. Schedule data is requested with each
|
|
721
681
|
* product because session products carry their fixed intervals there.
|
|
722
682
|
*/
|
|
723
683
|
async loadProducts(params = {}, options) {
|
|
724
|
-
if (!this.store.products)
|
|
725
|
-
|
|
726
|
-
const
|
|
727
|
-
const schedule_datetime = params.schedule_datetime || `${schedule_date} ${(0, import_dayjs.default)().format("HH:mm:ss")}`;
|
|
684
|
+
if (!this.store.products) throw new Error('[UnifiedBookingSales] products 模块未初始化');
|
|
685
|
+
const schedule_date = params.schedule_date || (0, _dayjs.default)().format('YYYY-MM-DD');
|
|
686
|
+
const schedule_datetime = params.schedule_datetime || `${schedule_date} ${(0, _dayjs.default)().format('HH:mm:ss')}`;
|
|
728
687
|
const result = await this.store.products.loadProducts({
|
|
729
|
-
with_count: [
|
|
688
|
+
with_count: ['bundleGroup', 'optionGroup'],
|
|
730
689
|
with_schedule: 1,
|
|
731
690
|
...params,
|
|
732
691
|
schedule_date,
|
|
@@ -737,19 +696,19 @@ var UnifiedBookingSalesImpl = class extends import_BookingTicket.BookingTicket {
|
|
|
737
696
|
await this.core.effects.emit(`${this.name}:onProductsLoaded`, result);
|
|
738
697
|
return result;
|
|
739
698
|
}
|
|
699
|
+
|
|
740
700
|
/** Date-first entry point. It delegates protocol details and cache ownership to ScheduleModule. */
|
|
741
701
|
async loadScheduleAvailableDate(params) {
|
|
742
|
-
if (!this.store.schedule)
|
|
743
|
-
throw new Error("[UnifiedBookingSales] schedule 模块未初始化");
|
|
702
|
+
if (!this.store.schedule) throw new Error('[UnifiedBookingSales] schedule 模块未初始化');
|
|
744
703
|
return this.store.schedule.loadScheduleAvailableDate(params);
|
|
745
704
|
}
|
|
705
|
+
|
|
746
706
|
/**
|
|
747
707
|
* Implements the date-first product pool: the chosen date's product ids plus globally sellable
|
|
748
708
|
* other_product_ids. If a batch product query is unexpectedly empty, retry one id at a time so
|
|
749
709
|
* a partial backend incompatibility does not hide the entire date's catalog.
|
|
750
710
|
*/
|
|
751
711
|
async loadProductsByScheduleDate(params) {
|
|
752
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
753
712
|
const {
|
|
754
713
|
date,
|
|
755
714
|
custom_page_id,
|
|
@@ -757,11 +716,10 @@ var UnifiedBookingSalesImpl = class extends import_BookingTicket.BookingTicket {
|
|
|
757
716
|
product_ids,
|
|
758
717
|
...productLoadParams
|
|
759
718
|
} = params;
|
|
760
|
-
if (!this.store.schedule)
|
|
761
|
-
|
|
762
|
-
const
|
|
763
|
-
const
|
|
764
|
-
const hasOtherProducts = (((_d = (_c = this.store.schedule).getOtherProductsIds) == null ? void 0 : _d.call(_c)) || []).length > 0;
|
|
719
|
+
if (!this.store.schedule) throw new Error('[UnifiedBookingSales] schedule 模块未初始化');
|
|
720
|
+
const cachedDates = this.store.schedule.getAvailabilityScheduleDateList?.() || [];
|
|
721
|
+
const hasCachedDate = cachedDates.some(item => item.date === date);
|
|
722
|
+
const hasOtherProducts = (this.store.schedule.getOtherProductsIds?.() || []).length > 0;
|
|
765
723
|
if (!hasCachedDate && !hasOtherProducts) {
|
|
766
724
|
await this.loadScheduleAvailableDate({
|
|
767
725
|
startDate: date,
|
|
@@ -770,12 +728,9 @@ var UnifiedBookingSalesImpl = class extends import_BookingTicket.BookingTicket {
|
|
|
770
728
|
channel
|
|
771
729
|
});
|
|
772
730
|
}
|
|
773
|
-
const scheduleDate =
|
|
774
|
-
const productIdFilter =
|
|
775
|
-
const availableProductIds = [
|
|
776
|
-
...(scheduleDate == null ? void 0 : scheduleDate.product_ids) || [],
|
|
777
|
-
...((_i = (_h = this.store.schedule).getOtherProductsIds) == null ? void 0 : _i.call(_h)) || []
|
|
778
|
-
].filter((id, index, self) => self.indexOf(id) === index).filter((id) => !productIdFilter || productIdFilter.has(String(id)));
|
|
731
|
+
const scheduleDate = this.store.schedule.getAvailabilityScheduleDateList?.()?.find(item => item.date === date);
|
|
732
|
+
const productIdFilter = product_ids?.length ? new Set(product_ids.map(id => String(id))) : null;
|
|
733
|
+
const availableProductIds = [...(scheduleDate?.product_ids || []), ...(this.store.schedule.getOtherProductsIds?.() || [])].filter((id, index, self) => self.indexOf(id) === index).filter(id => !productIdFilter || productIdFilter.has(String(id)));
|
|
779
734
|
if (!availableProductIds.length) {
|
|
780
735
|
this.unifiedProductCatalog = [];
|
|
781
736
|
await this.core.effects.emit(`${this.name}:onProductsLoaded`, []);
|
|
@@ -786,8 +741,7 @@ var UnifiedBookingSalesImpl = class extends import_BookingTicket.BookingTicket {
|
|
|
786
741
|
product_ids: availableProductIds,
|
|
787
742
|
schedule_date: date
|
|
788
743
|
});
|
|
789
|
-
if (products.length || availableProductIds.length <= 1)
|
|
790
|
-
return products;
|
|
744
|
+
if (products.length || availableProductIds.length <= 1) return products;
|
|
791
745
|
const fallbackProducts = [];
|
|
792
746
|
for (const productId of availableProductIds) {
|
|
793
747
|
const result = await this.loadProducts({
|
|
@@ -795,9 +749,9 @@ var UnifiedBookingSalesImpl = class extends import_BookingTicket.BookingTicket {
|
|
|
795
749
|
product_ids: [productId],
|
|
796
750
|
schedule_date: date
|
|
797
751
|
});
|
|
798
|
-
result.forEach(
|
|
799
|
-
const id =
|
|
800
|
-
if (!fallbackProducts.some(
|
|
752
|
+
result.forEach(product => {
|
|
753
|
+
const id = product?.id ?? product?.product_id;
|
|
754
|
+
if (!fallbackProducts.some(item => String(item?.id ?? item?.product_id) === String(id))) {
|
|
801
755
|
fallbackProducts.push(product);
|
|
802
756
|
}
|
|
803
757
|
});
|
|
@@ -806,10 +760,14 @@ var UnifiedBookingSalesImpl = class extends import_BookingTicket.BookingTicket {
|
|
|
806
760
|
await this.core.effects.emit(`${this.name}:onProductsLoaded`, fallbackProducts);
|
|
807
761
|
return fallbackProducts;
|
|
808
762
|
}
|
|
763
|
+
|
|
809
764
|
/** Returns a copy so UI consumers cannot accidentally mutate the solution's product cache. */
|
|
810
765
|
getProductCatalog() {
|
|
811
|
-
return {
|
|
766
|
+
return {
|
|
767
|
+
products: [...this.unifiedProductCatalog]
|
|
768
|
+
};
|
|
812
769
|
}
|
|
770
|
+
|
|
813
771
|
/**
|
|
814
772
|
* Read-only compatibility view for salesSdk skins. It reconnects a booking to its product but
|
|
815
773
|
* must not be used to mutate tempOrder; all writes go through BaseSales / planner APIs.
|
|
@@ -841,6 +799,7 @@ var UnifiedBookingSalesImpl = class extends import_BookingTicket.BookingTicket {
|
|
|
841
799
|
// }),
|
|
842
800
|
// };
|
|
843
801
|
// }
|
|
802
|
+
|
|
844
803
|
/**
|
|
845
804
|
* Loads the current customer's product coupons and discount cards after planner lines exist,
|
|
846
805
|
* then optionally lets the existing Rules engine select the best valid combination. This is a
|
|
@@ -848,7 +807,7 @@ var UnifiedBookingSalesImpl = class extends import_BookingTicket.BookingTicket {
|
|
|
848
807
|
*/
|
|
849
808
|
async applyPlannerDiscounts(params = {}) {
|
|
850
809
|
const tempOrder = this.getTempOrder();
|
|
851
|
-
const requestedCustomerId = params.customerId ??
|
|
810
|
+
const requestedCustomerId = params.customerId ?? tempOrder?.customer_id;
|
|
852
811
|
const parsedCustomerId = Number(requestedCustomerId);
|
|
853
812
|
const customerId = Number.isFinite(parsedCustomerId) && parsedCustomerId > 1 ? parsedCustomerId : null;
|
|
854
813
|
const summaryBefore = await this.getSummary();
|
|
@@ -856,31 +815,39 @@ var UnifiedBookingSalesImpl = class extends import_BookingTicket.BookingTicket {
|
|
|
856
815
|
return buildPlannerDiscountResult({
|
|
857
816
|
customerId: null,
|
|
858
817
|
discountList: this.getDiscountList(),
|
|
859
|
-
products:
|
|
818
|
+
products: tempOrder?.products || [],
|
|
860
819
|
summaryBefore,
|
|
861
820
|
summaryAfter: summaryBefore,
|
|
862
|
-
status:
|
|
821
|
+
status: 'no_customer'
|
|
863
822
|
});
|
|
864
823
|
}
|
|
865
|
-
await this.loadDiscountConfig({
|
|
824
|
+
await this.loadDiscountConfig({
|
|
825
|
+
customerId,
|
|
826
|
+
action: 'create'
|
|
827
|
+
});
|
|
866
828
|
const preferredDiscountId = params.preferredDiscountId;
|
|
867
|
-
const preferredDiscount = preferredDiscountId ===
|
|
829
|
+
const preferredDiscount = preferredDiscountId === undefined || preferredDiscountId === null ? undefined : this.getDiscountList().find(discount => String(resolvePlannerDiscountId(discount) ?? '') === String(preferredDiscountId));
|
|
868
830
|
if (preferredDiscount) {
|
|
831
|
+
// A requested card is an explicit UI choice, not a best-effort preference. Clear prior
|
|
832
|
+
// automatic selections first; otherwise Rules may keep the old selected card and silently
|
|
833
|
+
// apply it instead of the card the customer clicked.
|
|
869
834
|
const preferredId = resolvePlannerDiscountId(preferredDiscount);
|
|
870
|
-
const selectedOtherDiscounts = this.getDiscountList().filter(
|
|
835
|
+
const selectedOtherDiscounts = this.getDiscountList().filter(discount => discount.isSelected === true && String(resolvePlannerDiscountId(discount) ?? '') !== String(preferredId));
|
|
871
836
|
for (const discount of selectedOtherDiscounts) {
|
|
872
837
|
const discountId = Number(resolvePlannerDiscountId(discount));
|
|
873
838
|
if (Number.isFinite(discountId)) {
|
|
874
|
-
await this.setDiscountSelected({
|
|
839
|
+
await this.setDiscountSelected({
|
|
840
|
+
discountId,
|
|
841
|
+
isSelected: false
|
|
842
|
+
});
|
|
875
843
|
}
|
|
876
844
|
}
|
|
877
845
|
await this.setDiscountSelected({
|
|
878
846
|
discountId: Number(preferredId),
|
|
879
847
|
isSelected: true
|
|
880
848
|
});
|
|
881
|
-
} else if (preferredDiscountId ===
|
|
882
|
-
if (params.applyBestDiscount !== false)
|
|
883
|
-
await this.bestDiscount();
|
|
849
|
+
} else if (preferredDiscountId === undefined || preferredDiscountId === null) {
|
|
850
|
+
if (params.applyBestDiscount !== false) await this.bestDiscount();
|
|
884
851
|
} else if (params.applyBestDiscount !== false) {
|
|
885
852
|
await this.bestDiscount();
|
|
886
853
|
}
|
|
@@ -888,18 +855,19 @@ var UnifiedBookingSalesImpl = class extends import_BookingTicket.BookingTicket {
|
|
|
888
855
|
return buildPlannerDiscountResult({
|
|
889
856
|
customerId,
|
|
890
857
|
discountList: this.getDiscountList(),
|
|
891
|
-
products:
|
|
858
|
+
products: nextTempOrder?.products || [],
|
|
892
859
|
summaryBefore,
|
|
893
860
|
summaryAfter: await this.getSummary(),
|
|
894
|
-
status: params.applyBestDiscount === false && !preferredDiscount ?
|
|
861
|
+
status: params.applyBestDiscount === false && !preferredDiscount ? 'loaded' : 'applied',
|
|
895
862
|
preferredDiscountId,
|
|
896
|
-
preferredDiscountFound: preferredDiscountId ===
|
|
863
|
+
preferredDiscountFound: preferredDiscountId === undefined || preferredDiscountId === null ? undefined : Boolean(preferredDiscount)
|
|
897
864
|
});
|
|
898
865
|
}
|
|
866
|
+
|
|
899
867
|
/** ResourcePlanner is a required child module; fail early instead of producing partial availability. */
|
|
900
868
|
getPlanner() {
|
|
901
869
|
if (!this.store.resourcePlanner) {
|
|
902
|
-
throw new Error(
|
|
870
|
+
throw new Error('[UnifiedBookingSales] resourcePlanner 模块未初始化');
|
|
903
871
|
}
|
|
904
872
|
return this.store.resourcePlanner;
|
|
905
873
|
}
|
|
@@ -907,169 +875,162 @@ var UnifiedBookingSalesImpl = class extends import_BookingTicket.BookingTicket {
|
|
|
907
875
|
const orderProduct = this.transformBaseProductToOrderProduct({
|
|
908
876
|
payload: {
|
|
909
877
|
...sourceProduct,
|
|
910
|
-
id: sourceProduct.id ??
|
|
911
|
-
product_id: sourceProduct.product_id ?? sourceProduct.id ??
|
|
912
|
-
quantity: sourceProduct.quantity ?? sourceProduct.num ??
|
|
913
|
-
price: sourceProduct.price ??
|
|
914
|
-
selling_price: sourceProduct.selling_price ?? sourceProduct.price ??
|
|
878
|
+
id: sourceProduct.id ?? product?.id,
|
|
879
|
+
product_id: sourceProduct.product_id ?? sourceProduct.id ?? product?.id,
|
|
880
|
+
quantity: sourceProduct.quantity ?? sourceProduct.num ?? product?.quantity ?? 1,
|
|
881
|
+
price: sourceProduct.price ?? product?.price,
|
|
882
|
+
selling_price: sourceProduct.selling_price ?? sourceProduct.price ?? product?.price,
|
|
915
883
|
metadata: {
|
|
916
|
-
...sourceProduct.metadata || {},
|
|
884
|
+
...(sourceProduct.metadata || {}),
|
|
917
885
|
[ownershipKey]: true
|
|
918
886
|
}
|
|
919
887
|
},
|
|
920
888
|
sourceProduct
|
|
921
889
|
});
|
|
922
|
-
if (orderProduct && typeof orderProduct ===
|
|
890
|
+
if (orderProduct && typeof orderProduct === 'object') {
|
|
891
|
+
// BaseSales may rebuild metadata from its price source. Stamp ownership after that transform
|
|
892
|
+
// so each UnifiedBookingSales entry point can replace only its own temporary lines.
|
|
923
893
|
orderProduct.metadata = {
|
|
924
|
-
...orderProduct.metadata || {},
|
|
894
|
+
...(orderProduct.metadata || {}),
|
|
925
895
|
[ownershipKey]: true
|
|
926
896
|
};
|
|
927
897
|
}
|
|
928
898
|
return orderProduct;
|
|
929
899
|
}
|
|
900
|
+
|
|
930
901
|
/** Replacing a staged selection is idempotent and never removes unrelated cart lines. */
|
|
931
902
|
async removeExistingStagedLines(ownershipKey) {
|
|
932
|
-
|
|
933
|
-
const existingLines = (((_a = this.getTempOrder()) == null ? void 0 : _a.products) || []).filter((product) => {
|
|
934
|
-
var _a2;
|
|
935
|
-
return ((_a2 = product == null ? void 0 : product.metadata) == null ? void 0 : _a2[ownershipKey]) === true;
|
|
936
|
-
});
|
|
903
|
+
const existingLines = (this.getTempOrder()?.products || []).filter(product => product?.metadata?.[ownershipKey] === true);
|
|
937
904
|
if (existingLines.length > 0) {
|
|
938
905
|
await this.removeProductsFromOrder(existingLines.map(buildPlannerLineIdentity));
|
|
939
906
|
}
|
|
940
907
|
}
|
|
941
908
|
async stageProducts(params, ownershipKey) {
|
|
942
|
-
var _a;
|
|
943
909
|
const productIds = params.productIds || [];
|
|
944
|
-
if (!productIds.length)
|
|
945
|
-
|
|
946
|
-
if ((_a = params.rawProducts) == null ? void 0 : _a.length) {
|
|
910
|
+
if (!productIds.length) return this.getTempOrder();
|
|
911
|
+
if (params.rawProducts?.length) {
|
|
947
912
|
this.unifiedProductCatalog = params.rawProducts;
|
|
948
913
|
} else {
|
|
949
|
-
const existingIds = new Set((this.unifiedProductCatalog || []).map(
|
|
950
|
-
const missingIds = productIds.filter(
|
|
914
|
+
const existingIds = new Set((this.unifiedProductCatalog || []).map(product => String(product.id ?? product.product_id)));
|
|
915
|
+
const missingIds = productIds.filter(id => !existingIds.has(String(id)));
|
|
951
916
|
if (missingIds.length || params.productLoadParams) {
|
|
952
917
|
await this.loadProducts({
|
|
953
|
-
...params.productLoadParams || {},
|
|
918
|
+
...(params.productLoadParams || {}),
|
|
954
919
|
product_ids: productIds.map(Number).filter(Number.isFinite)
|
|
955
920
|
});
|
|
956
921
|
}
|
|
957
922
|
}
|
|
958
923
|
await this.removeExistingStagedLines(ownershipKey);
|
|
959
|
-
const productIdSet = new Set(productIds.map(
|
|
960
|
-
const selectedProducts = (this.unifiedProductCatalog || []).filter(
|
|
924
|
+
const productIdSet = new Set(productIds.map(id => String(id)));
|
|
925
|
+
const selectedProducts = (this.unifiedProductCatalog || []).filter(product => productIdSet.has(String(product.id ?? product.product_id)));
|
|
961
926
|
for (const sourceProduct of selectedProducts) {
|
|
962
927
|
const productInput = this.buildUnifiedOrderProduct(sourceProduct, ownershipKey);
|
|
963
|
-
if (productInput)
|
|
964
|
-
await this.addProductToOrder(productInput);
|
|
928
|
+
if (productInput) await this.addProductToOrder(productInput);
|
|
965
929
|
}
|
|
966
930
|
return this.getTempOrder();
|
|
967
931
|
}
|
|
932
|
+
|
|
968
933
|
/**
|
|
969
934
|
* Adds the current product choice to an otherwise clean planner cart without creating bookings.
|
|
970
935
|
* This separates "what the customer wants" from the later time/resource confirmation step.
|
|
971
936
|
*/
|
|
972
937
|
async stagePlannerProducts(params) {
|
|
973
|
-
return this.stageProducts(params,
|
|
938
|
+
return this.stageProducts(params, 'unified_booking_sales');
|
|
974
939
|
}
|
|
940
|
+
|
|
975
941
|
/**
|
|
976
942
|
* Adds ordinary retail products without asking ResourcePlanner for booking facts.
|
|
977
943
|
* Its staged lines have separate ownership so planner and retail skins can coexist safely.
|
|
978
944
|
*/
|
|
979
945
|
async stageRetailProducts(params) {
|
|
980
|
-
return this.stageProducts(params,
|
|
946
|
+
return this.stageProducts(params, 'unified_booking_sales_retail');
|
|
981
947
|
}
|
|
948
|
+
|
|
982
949
|
/**
|
|
983
950
|
* Adds one retail line without replacing the cart's existing retail selection.
|
|
984
951
|
* This is intentionally separate from stageRetailProducts(), whose contract is
|
|
985
952
|
* "replace the staged selection" for demo and wizard-like callers.
|
|
986
953
|
*/
|
|
987
954
|
async addRetailProduct(params) {
|
|
988
|
-
var _a, _b;
|
|
989
955
|
const quantity = Math.floor(Number(params.quantity ?? 1));
|
|
990
956
|
if (!Number.isFinite(quantity) || quantity <= 0) {
|
|
991
|
-
throw new Error(
|
|
957
|
+
throw new Error('[UnifiedBookingSales] retail 商品数量必须大于 0');
|
|
992
958
|
}
|
|
993
|
-
const productId = params.productId ??
|
|
959
|
+
const productId = params.productId ?? params.product?.id ?? params.product?.product_id;
|
|
994
960
|
let sourceProduct = params.product;
|
|
995
|
-
if (!sourceProduct && productId !==
|
|
996
|
-
sourceProduct = this.unifiedProductCatalog.find(
|
|
997
|
-
(product) => String(product.id ?? product.product_id) === String(productId)
|
|
998
|
-
);
|
|
961
|
+
if (!sourceProduct && productId !== undefined && productId !== null) {
|
|
962
|
+
sourceProduct = this.unifiedProductCatalog.find(product => String(product.id ?? product.product_id) === String(productId));
|
|
999
963
|
}
|
|
1000
|
-
if (!sourceProduct && productId !==
|
|
964
|
+
if (!sourceProduct && productId !== undefined && productId !== null) {
|
|
1001
965
|
const products = await this.loadProducts({
|
|
1002
|
-
...params.productLoadParams || {},
|
|
966
|
+
...(params.productLoadParams || {}),
|
|
1003
967
|
product_ids: [Number(productId)].filter(Number.isFinite)
|
|
1004
968
|
});
|
|
1005
|
-
sourceProduct = products.find(
|
|
1006
|
-
(product) => String(product.id ?? product.product_id) === String(productId)
|
|
1007
|
-
);
|
|
969
|
+
sourceProduct = products.find(product => String(product.id ?? product.product_id) === String(productId));
|
|
1008
970
|
}
|
|
1009
971
|
if (!sourceProduct) {
|
|
1010
|
-
throw new Error(`[UnifiedBookingSales] 未找到零售商品 ${String(productId ??
|
|
972
|
+
throw new Error(`[UnifiedBookingSales] 未找到零售商品 ${String(productId ?? '')}`.trim());
|
|
1011
973
|
}
|
|
1012
|
-
const orderProduct = this.buildUnifiedOrderProduct(
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
},
|
|
1017
|
-
"unified_booking_sales_retail"
|
|
1018
|
-
);
|
|
974
|
+
const orderProduct = this.buildUnifiedOrderProduct({
|
|
975
|
+
...sourceProduct,
|
|
976
|
+
quantity
|
|
977
|
+
}, 'unified_booking_sales_retail');
|
|
1019
978
|
if (!orderProduct) {
|
|
1020
|
-
throw new Error(
|
|
979
|
+
throw new Error('[UnifiedBookingSales] 无法生成零售商品订单行');
|
|
1021
980
|
}
|
|
1022
981
|
return this.addProductToOrder(orderProduct);
|
|
1023
982
|
}
|
|
983
|
+
|
|
1024
984
|
/** Normalizes caller-provided products or loads the catalog before any resource request is made. */
|
|
1025
985
|
async loadPlannerProducts(params) {
|
|
1026
|
-
|
|
1027
|
-
if (
|
|
1028
|
-
|
|
1029
|
-
if ((_c = params.rawProducts) == null ? void 0 : _c.length)
|
|
1030
|
-
return params.rawProducts.map(normalizeProductForPlanner);
|
|
1031
|
-
const productIds = params.productIds || ((_d = params.productLoadParams) == null ? void 0 : _d.product_ids) || [];
|
|
986
|
+
if (params.context?.products?.length) return params.context.products;
|
|
987
|
+
if (params.rawProducts?.length) return params.rawProducts.map(normalizeProductForPlanner);
|
|
988
|
+
const productIds = params.productIds || params.productLoadParams?.product_ids || [];
|
|
1032
989
|
if (productIds.length > 0 || params.productLoadParams) {
|
|
1033
990
|
await this.loadProducts({
|
|
1034
|
-
...params.date ? {
|
|
1035
|
-
|
|
1036
|
-
|
|
991
|
+
...(params.date ? {
|
|
992
|
+
schedule_date: params.date
|
|
993
|
+
} : {}),
|
|
994
|
+
...(params.productLoadParams || {}),
|
|
995
|
+
product_ids: productIds.length ? productIds.map(Number).filter(Number.isFinite) : params.productLoadParams?.product_ids
|
|
1037
996
|
});
|
|
1038
997
|
}
|
|
1039
|
-
return (
|
|
998
|
+
return (this.getProductCatalog?.().products || []).map(normalizeProductForPlanner);
|
|
1040
999
|
}
|
|
1000
|
+
|
|
1041
1001
|
/** Loads the reusable store-level schedule catalog on demand. */
|
|
1042
1002
|
async ensurePlannerSchedulesLoaded() {
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
const scheduleList = ((_b = (_a = this.store.schedule).getScheduleList) == null ? void 0 : _b.call(_a)) || [];
|
|
1047
|
-
if (!((_d = (_c = this.store.schedule).isScheduleListLoaded) == null ? void 0 : _d.call(_c)) || scheduleList.length === 0) {
|
|
1003
|
+
if (!this.store.schedule) throw new Error('[UnifiedBookingSales] schedule 模块未初始化');
|
|
1004
|
+
const scheduleList = this.store.schedule.getScheduleList?.() || [];
|
|
1005
|
+
if (!this.store.schedule.isScheduleListLoaded?.() || scheduleList.length === 0) {
|
|
1048
1006
|
await this.store.schedule.loadAllSchedule();
|
|
1049
1007
|
}
|
|
1050
|
-
return
|
|
1008
|
+
return this.store.schedule.getScheduleList?.() || [];
|
|
1051
1009
|
}
|
|
1010
|
+
|
|
1052
1011
|
/**
|
|
1053
1012
|
* v2 resources reference schedule ids rather than expanded work times. Refresh once when the
|
|
1054
1013
|
* cached schedule catalog cannot materialize all referenced ids.
|
|
1055
1014
|
*/
|
|
1056
1015
|
async ensurePlannerSchedulesForResources(rawResources) {
|
|
1057
|
-
var _a, _b;
|
|
1058
1016
|
let scheduleList = await this.ensurePlannerSchedulesLoaded();
|
|
1059
1017
|
const scheduleIds = collectRawScheduleIds(rawResources);
|
|
1060
1018
|
if (!scheduleListHasIds(scheduleList, scheduleIds)) {
|
|
1061
|
-
await this.store.schedule.loadAllSchedule({
|
|
1062
|
-
|
|
1019
|
+
await this.store.schedule.loadAllSchedule({
|
|
1020
|
+
useCache: false
|
|
1021
|
+
});
|
|
1022
|
+
scheduleList = this.store.schedule.getScheduleList?.() || [];
|
|
1063
1023
|
}
|
|
1064
1024
|
return scheduleList;
|
|
1065
1025
|
}
|
|
1026
|
+
|
|
1066
1027
|
/**
|
|
1067
1028
|
* Fetches resource metadata plus flat occupied events. Work windows are intentionally derived
|
|
1068
1029
|
* locally in buildPlannerResourcesFromV2 from /schedule, rather than requested from the legacy
|
|
1069
1030
|
* resource dates endpoint.
|
|
1070
1031
|
*/
|
|
1071
1032
|
async fetchPlannerResourcesV2(params) {
|
|
1072
|
-
const response = await this.request.get(
|
|
1033
|
+
const response = await this.request.get('/schedule/resource/list/v2', {
|
|
1073
1034
|
start_date: params.dateRange.start,
|
|
1074
1035
|
end_date: params.dateRange.end,
|
|
1075
1036
|
resource_ids: params.resourceIds,
|
|
@@ -1077,36 +1038,34 @@ var UnifiedBookingSalesImpl = class extends import_BookingTicket.BookingTicket {
|
|
|
1077
1038
|
}, {
|
|
1078
1039
|
useCache: false
|
|
1079
1040
|
});
|
|
1080
|
-
const data = response
|
|
1081
|
-
if (Array.isArray(data))
|
|
1082
|
-
|
|
1083
|
-
if (Array.isArray(data == null ? void 0 : data.list))
|
|
1084
|
-
return data.list;
|
|
1041
|
+
const data = response?.data;
|
|
1042
|
+
if (Array.isArray(data)) return data;
|
|
1043
|
+
if (Array.isArray(data?.list)) return data.list;
|
|
1085
1044
|
return [];
|
|
1086
1045
|
}
|
|
1046
|
+
|
|
1087
1047
|
/**
|
|
1088
1048
|
* Resolves the Planner context in precedence order: explicit normalized context, test raw data,
|
|
1089
1049
|
* then the v2 resource API inferred from selected product requirements and any URL lock.
|
|
1090
1050
|
*/
|
|
1091
1051
|
async loadPlannerResources(params, products = []) {
|
|
1092
|
-
|
|
1093
|
-
if ((_b = (_a = params.context) == null ? void 0 : _a.resources) == null ? void 0 : _b.length) {
|
|
1052
|
+
if (params.context?.resources?.length) {
|
|
1094
1053
|
return {
|
|
1095
1054
|
resources: params.context.resources,
|
|
1096
1055
|
externalEvents: params.context.externalEvents || []
|
|
1097
1056
|
};
|
|
1098
1057
|
}
|
|
1099
|
-
if (
|
|
1058
|
+
if (params.rawResources?.length) {
|
|
1100
1059
|
return {
|
|
1101
|
-
resources: params.rawResources.map(normalizeResource).filter(
|
|
1102
|
-
externalEvents:
|
|
1060
|
+
resources: params.rawResources.map(normalizeResource).filter(resource => resource !== null),
|
|
1061
|
+
externalEvents: params.context?.externalEvents || []
|
|
1103
1062
|
};
|
|
1104
1063
|
}
|
|
1105
1064
|
const resourceIds = collectPlannerResourceIds(products, params.resourceIds || []);
|
|
1106
1065
|
if (!params.useResourceDateApi || !params.dateRange || resourceIds.length === 0) {
|
|
1107
1066
|
return {
|
|
1108
1067
|
resources: [],
|
|
1109
|
-
externalEvents:
|
|
1068
|
+
externalEvents: params.context?.externalEvents || []
|
|
1110
1069
|
};
|
|
1111
1070
|
}
|
|
1112
1071
|
const rawResources = await this.fetchPlannerResourcesV2({
|
|
@@ -1121,12 +1080,10 @@ var UnifiedBookingSalesImpl = class extends import_BookingTicket.BookingTicket {
|
|
|
1121
1080
|
});
|
|
1122
1081
|
return {
|
|
1123
1082
|
resources: materialized.resources,
|
|
1124
|
-
externalEvents: [
|
|
1125
|
-
...((_f = params.context) == null ? void 0 : _f.externalEvents) || [],
|
|
1126
|
-
...materialized.externalEvents
|
|
1127
|
-
]
|
|
1083
|
+
externalEvents: [...(params.context?.externalEvents || []), ...materialized.externalEvents]
|
|
1128
1084
|
};
|
|
1129
1085
|
}
|
|
1086
|
+
|
|
1130
1087
|
/**
|
|
1131
1088
|
* Boundary between IO and pure planning. Once this returns, all later availability/slot calls
|
|
1132
1089
|
* operate on the ResourcePlanner snapshot and do not issue resource requests themselves.
|
|
@@ -1135,7 +1092,7 @@ var UnifiedBookingSalesImpl = class extends import_BookingTicket.BookingTicket {
|
|
|
1135
1092
|
const products = await this.loadPlannerProducts(params);
|
|
1136
1093
|
const plannerResources = await this.loadPlannerResources(params, products);
|
|
1137
1094
|
const context = {
|
|
1138
|
-
...params.context || {},
|
|
1095
|
+
...(params.context || {}),
|
|
1139
1096
|
products,
|
|
1140
1097
|
resources: plannerResources.resources,
|
|
1141
1098
|
externalEvents: plannerResources.externalEvents
|
|
@@ -1149,21 +1106,25 @@ var UnifiedBookingSalesImpl = class extends import_BookingTicket.BookingTicket {
|
|
|
1149
1106
|
endTime: params.endTime,
|
|
1150
1107
|
resourceIds: params.resourceIds || []
|
|
1151
1108
|
});
|
|
1152
|
-
await this.core.effects.emit(`${this.name}:${
|
|
1109
|
+
await this.core.effects.emit(`${this.name}:${_types.UnifiedBookingSalesHooks.onPlannerContextLoaded}`, snapshot);
|
|
1153
1110
|
return this.getPlanner().getSnapshot();
|
|
1154
1111
|
}
|
|
1112
|
+
|
|
1155
1113
|
/** Returns cells, date summaries and a derived grid; cells are continuous ranges, not UI slots. */
|
|
1156
1114
|
async queryPlannerAvailability(query = {}) {
|
|
1157
1115
|
return this.getPlanner().queryAvailability(query);
|
|
1158
1116
|
}
|
|
1117
|
+
|
|
1159
1118
|
/** Turns compatible availability ranges into user-selectable intervals and ready-to-commit assignments. */
|
|
1160
1119
|
resolveAssignableSlots(query = {}) {
|
|
1161
1120
|
return this.getPlanner().resolveAssignableSlots(query);
|
|
1162
1121
|
}
|
|
1122
|
+
|
|
1163
1123
|
/** Stores a UI choice only. It is deliberately side-effect free with respect to tempOrder. */
|
|
1164
1124
|
setPlannerSelection(patch) {
|
|
1165
1125
|
return this.getPlanner().setSelectionPatch(patch);
|
|
1166
1126
|
}
|
|
1127
|
+
|
|
1167
1128
|
/**
|
|
1168
1129
|
* Legacy-friendly automatic assignment for already fixed intervals. Duration products without a
|
|
1169
1130
|
* start time intentionally remain unresolved; callers offering a picker should use slots.
|
|
@@ -1171,18 +1132,21 @@ var UnifiedBookingSalesImpl = class extends import_BookingTicket.BookingTicket {
|
|
|
1171
1132
|
async autoAssignPlanner(query = {}) {
|
|
1172
1133
|
const result = this.getPlanner().autoAssign(query);
|
|
1173
1134
|
if (result.conflicts.length) {
|
|
1174
|
-
console.warn(
|
|
1135
|
+
console.warn('[UnifiedBookingSales] autoAssignPlanner 存在未分配项', result.conflicts);
|
|
1175
1136
|
}
|
|
1176
1137
|
return this.getPlanner().getSnapshot();
|
|
1177
1138
|
}
|
|
1139
|
+
|
|
1178
1140
|
/** Rechecks remote events, capacity and conflicts among the current selection before committing. */
|
|
1179
1141
|
validatePlannerSelection() {
|
|
1180
1142
|
return this.getPlanner().validateSelection();
|
|
1181
1143
|
}
|
|
1144
|
+
|
|
1182
1145
|
/** Read-only snapshot for UI diagnostics and progressive flow steps. */
|
|
1183
1146
|
getPlannerSnapshot() {
|
|
1184
1147
|
return this.getPlanner().getSnapshot();
|
|
1185
1148
|
}
|
|
1149
|
+
|
|
1186
1150
|
/**
|
|
1187
1151
|
* Validates then writes assignments to tempOrder. Real order submission is opt-in so UI callers
|
|
1188
1152
|
* can safely preview the cart; pass submitAfterCommit only after an explicit confirmation.
|
|
@@ -1192,7 +1156,9 @@ var UnifiedBookingSalesImpl = class extends import_BookingTicket.BookingTicket {
|
|
|
1192
1156
|
this.setPlannerSelection(params.selection);
|
|
1193
1157
|
}
|
|
1194
1158
|
if (params.assignments) {
|
|
1195
|
-
this.setPlannerSelection({
|
|
1159
|
+
this.setPlannerSelection({
|
|
1160
|
+
assignments: params.assignments
|
|
1161
|
+
});
|
|
1196
1162
|
}
|
|
1197
1163
|
const snapshot = this.getPlannerSnapshot();
|
|
1198
1164
|
const assignments = snapshot.selection.assignments || [];
|
|
@@ -1203,8 +1169,8 @@ var UnifiedBookingSalesImpl = class extends import_BookingTicket.BookingTicket {
|
|
|
1203
1169
|
validation: {
|
|
1204
1170
|
ok: false,
|
|
1205
1171
|
conflicts: [{
|
|
1206
|
-
type:
|
|
1207
|
-
message:
|
|
1172
|
+
type: 'missing_assignment',
|
|
1173
|
+
message: '没有可提交的 planner assignment,请先执行 autoAssignPlanner 或传入 assignments'
|
|
1208
1174
|
}]
|
|
1209
1175
|
}
|
|
1210
1176
|
};
|
|
@@ -1217,27 +1183,23 @@ var UnifiedBookingSalesImpl = class extends import_BookingTicket.BookingTicket {
|
|
|
1217
1183
|
validation
|
|
1218
1184
|
};
|
|
1219
1185
|
}
|
|
1220
|
-
const productsById = new Map(
|
|
1221
|
-
|
|
1222
|
-
);
|
|
1223
|
-
|
|
1224
|
-
const assignmentGroups = /* @__PURE__ */ new Map();
|
|
1225
|
-
assignments.forEach((assignment) => {
|
|
1186
|
+
const productsById = new Map(snapshot.context.products.map(product => [String(product.id), product]));
|
|
1187
|
+
await this.removeExistingStagedLines('unified_booking_sales');
|
|
1188
|
+
const assignmentGroups = new Map();
|
|
1189
|
+
assignments.forEach(assignment => {
|
|
1226
1190
|
const key = buildAssignmentGroupKey(assignment);
|
|
1227
|
-
assignmentGroups.set(key, [...assignmentGroups.get(key) || [], assignment]);
|
|
1191
|
+
assignmentGroups.set(key, [...(assignmentGroups.get(key) || []), assignment]);
|
|
1228
1192
|
});
|
|
1229
1193
|
for (const groupAssignments of assignmentGroups.values()) {
|
|
1230
1194
|
const product = productsById.get(String(groupAssignments[0].productId));
|
|
1231
|
-
if (!product)
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
);
|
|
1239
|
-
if (!productInput)
|
|
1240
|
-
continue;
|
|
1195
|
+
if (!product) continue;
|
|
1196
|
+
const sourceProduct = product.raw || {
|
|
1197
|
+
id: product.id,
|
|
1198
|
+
title: product.title,
|
|
1199
|
+
price: product.price
|
|
1200
|
+
};
|
|
1201
|
+
const productInput = this.buildUnifiedOrderProduct(sourceProduct, 'unified_booking_sales', product);
|
|
1202
|
+
if (!productInput) continue;
|
|
1241
1203
|
await this.addProductToOrder(productInput, buildBookingFromAssignments({
|
|
1242
1204
|
assignments: groupAssignments,
|
|
1243
1205
|
product
|
|
@@ -1253,21 +1215,9 @@ var UnifiedBookingSalesImpl = class extends import_BookingTicket.BookingTicket {
|
|
|
1253
1215
|
validation,
|
|
1254
1216
|
submitResult
|
|
1255
1217
|
};
|
|
1256
|
-
await this.core.effects.emit(`${this.name}:${
|
|
1218
|
+
await this.core.effects.emit(`${this.name}:${_types.UnifiedBookingSalesHooks.onPlannerCommitted}`, result);
|
|
1257
1219
|
return result;
|
|
1258
1220
|
}
|
|
1259
|
-
}
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
0 && (module.exports = {
|
|
1263
|
-
UnifiedBookingSales,
|
|
1264
|
-
UnifiedBookingSalesImpl,
|
|
1265
|
-
buildBookingFromAssignment,
|
|
1266
|
-
buildBookingFromAssignments,
|
|
1267
|
-
buildPlannerDiscountResult,
|
|
1268
|
-
buildPlannerLineIdentity,
|
|
1269
|
-
buildPlannerResourcesFromV2,
|
|
1270
|
-
collectPlannerResourceIds,
|
|
1271
|
-
normalizeProductForPlanner,
|
|
1272
|
-
...require("./types")
|
|
1273
|
-
});
|
|
1221
|
+
}
|
|
1222
|
+
exports.UnifiedBookingSalesImpl = UnifiedBookingSalesImpl;
|
|
1223
|
+
const UnifiedBookingSales = exports.UnifiedBookingSales = UnifiedBookingSalesImpl;
|