@pisell/pisellos 2.3.1 → 2.3.3
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/model/strategy/adapter/promotion/index.js +9 -0
- package/dist/modules/Order/index.d.ts +9 -0
- package/dist/modules/Order/index.js +448 -371
- package/dist/modules/Order/types.d.ts +2 -0
- package/dist/modules/Quotation/index.d.ts +16 -2
- package/dist/modules/Quotation/index.js +71 -38
- package/dist/modules/Quotation/types.d.ts +14 -0
- package/dist/modules/SalesSummary/index.d.ts +1 -0
- package/dist/modules/SalesSummary/index.js +7 -4
- package/dist/modules/Schedule/index.d.ts +4 -0
- package/dist/modules/Schedule/index.js +31 -1
- package/dist/modules/Schedule/types.d.ts +2 -0
- package/dist/server/index.js +13 -13
- package/dist/server/modules/order/index.d.ts +25 -7
- package/dist/server/modules/order/index.js +370 -309
- package/dist/server/modules/products/index.d.ts +4 -0
- package/dist/server/modules/products/index.js +76 -45
- package/dist/server/modules/quotation/index.d.ts +39 -0
- package/dist/server/modules/quotation/index.js +278 -66
- package/dist/server/modules/schedule/index.d.ts +2 -0
- package/dist/server/modules/schedule/index.js +10 -2
- package/dist/solution/BaseSales/index.d.ts +10 -1
- package/dist/solution/BaseSales/index.js +825 -528
- package/dist/solution/BaseSales/types.d.ts +7 -0
- package/dist/solution/BaseSales/utils/quotationPrice.d.ts +12 -1
- package/dist/solution/BaseSales/utils/quotationPrice.js +16 -3
- package/dist/solution/BookingByStep/index.d.ts +1 -1
- package/lib/modules/Order/index.d.ts +9 -0
- package/lib/modules/Order/index.js +48 -9
- package/lib/modules/Order/types.d.ts +2 -0
- package/lib/modules/Quotation/index.d.ts +16 -2
- package/lib/modules/Quotation/index.js +49 -13
- package/lib/modules/Quotation/types.d.ts +14 -0
- package/lib/modules/SalesSummary/index.d.ts +1 -0
- package/lib/modules/SalesSummary/index.js +4 -3
- package/lib/modules/Schedule/index.d.ts +4 -0
- package/lib/modules/Schedule/index.js +21 -0
- package/lib/modules/Schedule/types.d.ts +2 -0
- package/lib/server/index.js +1 -1
- package/lib/server/modules/order/index.d.ts +25 -7
- package/lib/server/modules/order/index.js +88 -54
- package/lib/server/modules/products/index.d.ts +4 -0
- package/lib/server/modules/products/index.js +43 -19
- package/lib/server/modules/quotation/index.d.ts +39 -0
- package/lib/server/modules/quotation/index.js +179 -1
- package/lib/server/modules/schedule/index.d.ts +2 -0
- package/lib/server/modules/schedule/index.js +8 -1
- package/lib/solution/BaseSales/index.d.ts +10 -1
- package/lib/solution/BaseSales/index.js +218 -19
- package/lib/solution/BaseSales/types.d.ts +7 -0
- package/lib/solution/BaseSales/utils/quotationPrice.d.ts +12 -1
- package/lib/solution/BaseSales/utils/quotationPrice.js +15 -3
- package/lib/solution/BookingByStep/index.d.ts +1 -1
- package/package.json +1 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { OrderModule, ProductList, QuotationModule, SalesSummaryModule, ScanOrderLoggerModule as BaseSalesLoggerModule, ScheduleModule } from '../../modules';
|
|
2
2
|
import type { ScanOrderLogInput as BaseSalesLogInput, ScanOrderLoggerProviderConfig as BaseSalesLoggerProviderConfig, ScanOrderLoggerProviderType as BaseSalesLoggerProviderType } from '../../modules/ScanOrderLogger/types';
|
|
3
3
|
import type { QuantityCheckResult, QuantityLimitResult } from '../../model/strategy/adapter/itemRule';
|
|
4
|
+
import type { QuotationCustomerScopeInfo } from '../../modules/Quotation/types';
|
|
4
5
|
/**
|
|
5
6
|
* BaseSales 流程 hook 后缀。
|
|
6
7
|
* 完整事件名应由当前模块名动态拼接,避免多个实例共享固定事件 key。
|
|
@@ -278,6 +279,12 @@ export interface BaseSalesProductBookingPriceResult {
|
|
|
278
279
|
segments: BaseSalesProductBookingPriceSegment[];
|
|
279
280
|
product_bundle?: BaseSalesBundleProductBookingPriceResult[];
|
|
280
281
|
}
|
|
282
|
+
export type BaseSalesQuotationCustomerScopeInfo = QuotationCustomerScopeInfo;
|
|
283
|
+
export interface BaseSalesPriceRecalculationContextChange {
|
|
284
|
+
previousCustomerId?: number | string | null;
|
|
285
|
+
nextCustomerId?: number | string | null;
|
|
286
|
+
[key: string]: any;
|
|
287
|
+
}
|
|
281
288
|
export type BaseSalesAvailabilityMode = 'idle' | 'shop_closed' | 'submit_disabled' | 'resource_busy' | 'additional_order_with_code' | 'additional_order';
|
|
282
289
|
export interface BaseSalesTableFormRecord {
|
|
283
290
|
policy?: string | null;
|
|
@@ -1,7 +1,18 @@
|
|
|
1
1
|
import type { QuotationModule } from '../../../modules/Quotation';
|
|
2
2
|
import type { BaseSalesCalculateProductBookingPriceParams, BaseSalesProductBookingPriceResult } from '../types';
|
|
3
3
|
interface BuildBaseSalesQuotationPriceParams extends BaseSalesCalculateProductBookingPriceParams {
|
|
4
|
-
quotation?: Pick<QuotationModule, 'getPriceForProduct' | 'getQuotationShelfId'>
|
|
4
|
+
quotation?: (Pick<QuotationModule, 'getPriceForProduct' | 'getQuotationShelfId'> & {
|
|
5
|
+
getQuotationMatchForProduct?: (params: {
|
|
6
|
+
productId: number;
|
|
7
|
+
variantId?: number;
|
|
8
|
+
datetime: string;
|
|
9
|
+
channel?: string;
|
|
10
|
+
customer_id?: number | string;
|
|
11
|
+
}) => {
|
|
12
|
+
price: string | null;
|
|
13
|
+
quotationShelfId: number;
|
|
14
|
+
} | null;
|
|
15
|
+
}) | null;
|
|
5
16
|
}
|
|
6
17
|
export declare function calculateBaseSalesProductBookingPrice(params: BuildBaseSalesQuotationPriceParams): BaseSalesProductBookingPriceResult;
|
|
7
18
|
export {};
|
|
@@ -118,20 +118,30 @@ function formatTimePoint(datetime) {
|
|
|
118
118
|
return datetime.format('YYYY-MM-DD HH:mm:ss');
|
|
119
119
|
}
|
|
120
120
|
function buildPriceSegment(params) {
|
|
121
|
+
var _match$quotationShelf;
|
|
121
122
|
var timePoint = formatTimePoint(params.segment.start);
|
|
122
|
-
var
|
|
123
|
+
var match = params.quotation && params.productId !== null && params.quotation.getQuotationMatchForProduct ? params.quotation.getQuotationMatchForProduct({
|
|
123
124
|
productId: params.productId,
|
|
124
125
|
variantId: params.variantId,
|
|
125
126
|
datetime: timePoint,
|
|
127
|
+
channel: params.channel,
|
|
128
|
+
customer_id: params.customerId
|
|
129
|
+
}) : null;
|
|
130
|
+
var quotedPrice = match ? match.price : params.quotation && params.productId !== null ? params.quotation.getPriceForProduct({
|
|
131
|
+
productId: params.productId,
|
|
132
|
+
variantId: params.variantId,
|
|
133
|
+
datetime: timePoint,
|
|
134
|
+
channel: params.channel,
|
|
126
135
|
customer_id: params.customerId
|
|
127
136
|
}) : null;
|
|
128
137
|
var unitPrice = toPriceString(quotedPrice !== null && quotedPrice !== void 0 ? quotedPrice : params.fallbackPrice);
|
|
129
|
-
var quotationShelfId = quotedPrice !== null && params.quotation && params.productId !== null ? params.quotation.getQuotationShelfId({
|
|
138
|
+
var quotationShelfId = quotedPrice !== null ? (_match$quotationShelf = match === null || match === void 0 ? void 0 : match.quotationShelfId) !== null && _match$quotationShelf !== void 0 ? _match$quotationShelf : params.quotation && params.productId !== null ? params.quotation.getQuotationShelfId({
|
|
130
139
|
productId: params.productId,
|
|
131
140
|
variantId: params.variantId,
|
|
132
141
|
datetime: timePoint,
|
|
142
|
+
channel: params.channel,
|
|
133
143
|
customer_id: params.customerId
|
|
134
|
-
}) : 0;
|
|
144
|
+
}) : 0 : 0;
|
|
135
145
|
return {
|
|
136
146
|
start_datetime: timePoint,
|
|
137
147
|
end_datetime: params.segment.end ? formatTimePoint(params.segment.end) : undefined,
|
|
@@ -151,6 +161,7 @@ function calculatePriceForProduct(params) {
|
|
|
151
161
|
productId: params.productId,
|
|
152
162
|
variantId: params.variantId,
|
|
153
163
|
customerId: params.customerId,
|
|
164
|
+
channel: params.channel,
|
|
154
165
|
fallbackPrice: params.fallbackPrice,
|
|
155
166
|
segment: segment
|
|
156
167
|
});
|
|
@@ -183,6 +194,7 @@ function calculateBundlePrices(params, segments) {
|
|
|
183
194
|
productId: productId,
|
|
184
195
|
variantId: variantId,
|
|
185
196
|
customerId: params.customer_id,
|
|
197
|
+
channel: params.channel,
|
|
186
198
|
quantity: quantity,
|
|
187
199
|
fallbackPrice: getBundleFallbackPrice(bundle),
|
|
188
200
|
segments: segments
|
|
@@ -216,6 +228,7 @@ export function calculateBaseSalesProductBookingPrice(params) {
|
|
|
216
228
|
productId: productId,
|
|
217
229
|
variantId: variantId,
|
|
218
230
|
customerId: params.customer_id,
|
|
231
|
+
channel: params.channel,
|
|
219
232
|
quantity: productQuantity,
|
|
220
233
|
fallbackPrice: fallbackPrice,
|
|
221
234
|
segments: timeSegments
|
|
@@ -311,7 +311,7 @@ export declare class BookingByStepImpl extends BaseModule implements Module {
|
|
|
311
311
|
date: string;
|
|
312
312
|
status: string;
|
|
313
313
|
week: string;
|
|
314
|
-
weekNum: 0 |
|
|
314
|
+
weekNum: 0 | 2 | 1 | 6 | 3 | 4 | 5;
|
|
315
315
|
}[]>;
|
|
316
316
|
submitTimeSlot(timeSlots: TimeSliceItem): void;
|
|
317
317
|
private getScheduleDataByIds;
|
|
@@ -358,7 +358,9 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
|
|
|
358
358
|
private hasGoodPassDiscount;
|
|
359
359
|
private getBundleRuntimeIdentity;
|
|
360
360
|
private preservePersistedBundlePriceFields;
|
|
361
|
+
private applyOrderProductUpdateToTempOrder;
|
|
361
362
|
updateOrderProduct(params: UpdateOrderProductParams): Promise<OrderProduct[]>;
|
|
363
|
+
updateOrderProducts(paramsList: UpdateOrderProductParams[]): Promise<OrderProduct[]>;
|
|
362
364
|
updateOrderProductQuantity(params: UpdateOrderProductQuantityParams): Promise<OrderProduct[]>;
|
|
363
365
|
updateOrderBooking(params: UpdateOrderBookingParams): any[];
|
|
364
366
|
/**
|
|
@@ -479,6 +481,13 @@ export declare class OrderModule extends BaseModule implements Module, OrderModu
|
|
|
479
481
|
hydrateTempOrderFromRecord(record: Record<string, any>, options?: {
|
|
480
482
|
recalcOnHydrate?: boolean;
|
|
481
483
|
}): Promise<OrderTempOrder>;
|
|
484
|
+
/**
|
|
485
|
+
* 兼容后端详情将 holder 放在 metadata.holder 的历史形态,统一补到运行时展示路径。
|
|
486
|
+
*
|
|
487
|
+
* @example
|
|
488
|
+
* this.normalizeHydratedBookingHolder({ metadata: { holder: { form_record: [1] } } });
|
|
489
|
+
*/
|
|
490
|
+
private normalizeHydratedBookingHolder;
|
|
482
491
|
private normalizeTempOrderForRuntime;
|
|
483
492
|
private hydrateLinkedBookingIdentity;
|
|
484
493
|
private pickHydratedDisplayText;
|
|
@@ -2683,7 +2683,7 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
2683
2683
|
};
|
|
2684
2684
|
});
|
|
2685
2685
|
}
|
|
2686
|
-
|
|
2686
|
+
applyOrderProductUpdateToTempOrder(tempOrder, params) {
|
|
2687
2687
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q;
|
|
2688
2688
|
const {
|
|
2689
2689
|
product_id,
|
|
@@ -2695,7 +2695,6 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
2695
2695
|
product_bundle,
|
|
2696
2696
|
booking
|
|
2697
2697
|
} = params;
|
|
2698
|
-
const tempOrder = this.ensureTempOrder();
|
|
2699
2698
|
const identityLookup = {
|
|
2700
2699
|
product_id,
|
|
2701
2700
|
product_variant_id
|
|
@@ -2839,6 +2838,10 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
2839
2838
|
tempOrder.products[productIndex],
|
|
2840
2839
|
(_q = tempOrder.products[productIndex].metadata) == null ? void 0 : _q.unique_identification_number
|
|
2841
2840
|
);
|
|
2841
|
+
}
|
|
2842
|
+
async updateOrderProduct(params) {
|
|
2843
|
+
const tempOrder = this.ensureTempOrder();
|
|
2844
|
+
this.applyOrderProductUpdateToTempOrder(tempOrder, params);
|
|
2842
2845
|
await this.applyPromotion();
|
|
2843
2846
|
this.applyDiscount();
|
|
2844
2847
|
this.sanitizeTempOrderProducts(tempOrder);
|
|
@@ -2846,6 +2849,17 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
2846
2849
|
this.persistTempOrder();
|
|
2847
2850
|
return tempOrder.products;
|
|
2848
2851
|
}
|
|
2852
|
+
async updateOrderProducts(paramsList) {
|
|
2853
|
+
const tempOrder = this.ensureTempOrder();
|
|
2854
|
+
if (!paramsList.length) {
|
|
2855
|
+
return tempOrder.products;
|
|
2856
|
+
}
|
|
2857
|
+
paramsList.forEach((params) => {
|
|
2858
|
+
this.applyOrderProductUpdateToTempOrder(tempOrder, params);
|
|
2859
|
+
});
|
|
2860
|
+
await this.finalizeAfterProductsMutation(tempOrder);
|
|
2861
|
+
return tempOrder.products;
|
|
2862
|
+
}
|
|
2849
2863
|
async updateOrderProductQuantity(params) {
|
|
2850
2864
|
var _a;
|
|
2851
2865
|
const {
|
|
@@ -3634,6 +3648,30 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
3634
3648
|
this.persistTempOrder();
|
|
3635
3649
|
return nextTempOrder;
|
|
3636
3650
|
}
|
|
3651
|
+
/**
|
|
3652
|
+
* 兼容后端详情将 holder 放在 metadata.holder 的历史形态,统一补到运行时展示路径。
|
|
3653
|
+
*
|
|
3654
|
+
* @example
|
|
3655
|
+
* this.normalizeHydratedBookingHolder({ metadata: { holder: { form_record: [1] } } });
|
|
3656
|
+
*/
|
|
3657
|
+
normalizeHydratedBookingHolder(booking) {
|
|
3658
|
+
const next = { ...booking || {} };
|
|
3659
|
+
const metadata = next.metadata && typeof next.metadata === "object" && !Array.isArray(next.metadata) ? { ...next.metadata } : {};
|
|
3660
|
+
const metadataHolder = metadata.holder && typeof metadata.holder === "object" && !Array.isArray(metadata.holder) ? metadata.holder : null;
|
|
3661
|
+
if (!next.holder && metadataHolder) {
|
|
3662
|
+
next.holder = { ...metadataHolder };
|
|
3663
|
+
}
|
|
3664
|
+
const holder = next.holder && typeof next.holder === "object" && !Array.isArray(next.holder) ? next.holder : null;
|
|
3665
|
+
const holderRecords = Array.isArray(holder == null ? void 0 : holder.form_record) ? holder.form_record.filter((id) => id !== void 0 && id !== null && id !== "") : [];
|
|
3666
|
+
const hasMetadataHolderId = metadata.holder_id !== void 0 && metadata.holder_id !== null && metadata.holder_id !== "" && (!Array.isArray(metadata.holder_id) || metadata.holder_id.length > 0);
|
|
3667
|
+
if (!hasMetadataHolderId && holderRecords.length > 0) {
|
|
3668
|
+
metadata.holder_id = holderRecords;
|
|
3669
|
+
}
|
|
3670
|
+
if (Object.keys(metadata).length > 0) {
|
|
3671
|
+
next.metadata = metadata;
|
|
3672
|
+
}
|
|
3673
|
+
return next;
|
|
3674
|
+
}
|
|
3637
3675
|
normalizeTempOrderForRuntime(raw, options) {
|
|
3638
3676
|
var _a, _b;
|
|
3639
3677
|
const nextTempOrder = {
|
|
@@ -3660,11 +3698,14 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
3660
3698
|
nextTempOrder.holder = raw.holder && typeof raw.holder === "object" ? { ...raw.holder } : null;
|
|
3661
3699
|
const rawProducts = Array.isArray(raw.products) ? raw.products : [];
|
|
3662
3700
|
nextTempOrder.products = rawProducts.length > 0 ? rawProducts.map((p) => this.normalizeHydratedOrderProduct(p)) : [];
|
|
3663
|
-
nextTempOrder.bookings = Array.isArray(raw.bookings) ? raw.bookings.map((b) =>
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
|
|
3701
|
+
nextTempOrder.bookings = Array.isArray(raw.bookings) ? raw.bookings.map((b) => {
|
|
3702
|
+
const booking = this.normalizeHydratedBookingHolder(b || {});
|
|
3703
|
+
return {
|
|
3704
|
+
...booking,
|
|
3705
|
+
is_all: (0, import_utils.normalizeBookingIsAll)(booking),
|
|
3706
|
+
sub_type: (0, import_utils.normalizeBookingSubType)(booking)
|
|
3707
|
+
};
|
|
3708
|
+
}) : [];
|
|
3668
3709
|
nextTempOrder.payments = Array.isArray(raw.payments) ? raw.payments.map((p) => ({ ...p || {} })) : [];
|
|
3669
3710
|
nextTempOrder.surcharges = Array.isArray(raw.surcharges) ? raw.surcharges.map((s) => ({ ...s || {} })) : [];
|
|
3670
3711
|
nextTempOrder.relation_forms = Array.isArray(raw.relation_forms) ? raw.relation_forms.map((f) => ({ ...f || {} })) : [];
|
|
@@ -3851,8 +3892,6 @@ var OrderModule = class extends import_BaseModule.BaseModule {
|
|
|
3851
3892
|
async getOrderInfo(order_id) {
|
|
3852
3893
|
const res = await this.request.get(`/order/sales/${order_id}`, {
|
|
3853
3894
|
with: ["products", "bookings"]
|
|
3854
|
-
}, {
|
|
3855
|
-
osServer: true
|
|
3856
3895
|
});
|
|
3857
3896
|
return res;
|
|
3858
3897
|
}
|
|
@@ -666,6 +666,8 @@ export interface OrderModuleAPI {
|
|
|
666
666
|
updateTempOrderContactsInfo: (contactsInfo: Record<string, any> | null) => Record<string, any> | null;
|
|
667
667
|
addProductToOrder: (product: Partial<OrderProduct> & OrderProductIdentity, booking?: AddProductBookingInput) => Promise<OrderProduct[]>;
|
|
668
668
|
updateOrderProduct: (params: UpdateOrderProductParams) => Promise<OrderProduct[]>;
|
|
669
|
+
/** 批量更新购物车行,末尾仅触发一次促销重算与 summary 刷新 */
|
|
670
|
+
updateOrderProducts: (paramsList: UpdateOrderProductParams[]) => Promise<OrderProduct[]>;
|
|
669
671
|
updateOrderProductQuantity: (params: UpdateOrderProductQuantityParams) => Promise<OrderProduct[]>;
|
|
670
672
|
updateOrderBooking: (params: UpdateOrderBookingParams) => any[];
|
|
671
673
|
removeProductFromOrder: (identity: OrderProductIdentity) => Promise<OrderProduct[]>;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Module, PisellCore, ModuleOptions } from '../../types';
|
|
2
2
|
import { BaseModule } from '../BaseModule';
|
|
3
3
|
import type { ScheduleItem } from '../Schedule/types';
|
|
4
|
-
import type { QuotationItem } from './types';
|
|
5
|
-
export type { QuotationItem, QuotationProductData, QuotationSchedule, QuotationState, QuotationCustomer } from './types';
|
|
4
|
+
import type { QuotationItem, QuotationCustomerScopeInfo } from './types';
|
|
5
|
+
export type { QuotationItem, QuotationProductData, QuotationSchedule, QuotationState, QuotationCustomer, QuotationCustomerScope, QuotationCustomerScopeInfo, } from './types';
|
|
6
6
|
export declare class QuotationModule extends BaseModule implements Module {
|
|
7
7
|
protected defaultName: string;
|
|
8
8
|
protected defaultVersion: string;
|
|
@@ -16,6 +16,7 @@ export declare class QuotationModule extends BaseModule implements Module {
|
|
|
16
16
|
customer_id?: number | string;
|
|
17
17
|
}): Promise<void>;
|
|
18
18
|
getQuotationList(): QuotationItem[];
|
|
19
|
+
getQuotationCustomerScopeInfo(): QuotationCustomerScopeInfo;
|
|
19
20
|
/**
|
|
20
21
|
* Look up the quotation price for a specific product (+ optional variant) at a given datetime.
|
|
21
22
|
* Returns the price as a string (e.g. "300.00"), or null if no quotation applies.
|
|
@@ -28,12 +29,24 @@ export declare class QuotationModule extends BaseModule implements Module {
|
|
|
28
29
|
productId: number;
|
|
29
30
|
variantId?: number;
|
|
30
31
|
datetime: string;
|
|
32
|
+
channel?: string;
|
|
31
33
|
customer_id?: number | string;
|
|
32
34
|
}): string | null;
|
|
35
|
+
getQuotationMatchForProduct(params: {
|
|
36
|
+
productId: number;
|
|
37
|
+
variantId?: number;
|
|
38
|
+
datetime: string;
|
|
39
|
+
channel?: string;
|
|
40
|
+
customer_id?: number | string;
|
|
41
|
+
}): {
|
|
42
|
+
price: string | null;
|
|
43
|
+
quotationShelfId: number;
|
|
44
|
+
} | null;
|
|
33
45
|
getQuotationShelfId(params: {
|
|
34
46
|
productId: number;
|
|
35
47
|
variantId?: number;
|
|
36
48
|
datetime: string;
|
|
49
|
+
channel?: string;
|
|
37
50
|
customer_id?: number | string;
|
|
38
51
|
}): number;
|
|
39
52
|
/**
|
|
@@ -49,6 +62,7 @@ export declare class QuotationModule extends BaseModule implements Module {
|
|
|
49
62
|
setScheduleResolver(resolver: (id: number) => ScheduleItem | undefined): void;
|
|
50
63
|
private isQuotationVisibleForCustomer;
|
|
51
64
|
private hasValidCustomerId;
|
|
65
|
+
private normalizeCustomerId;
|
|
52
66
|
private isQuotationActiveAt;
|
|
53
67
|
private findProductData;
|
|
54
68
|
}
|
|
@@ -58,6 +58,40 @@ var QuotationModule = class extends import_BaseModule.BaseModule {
|
|
|
58
58
|
getQuotationList() {
|
|
59
59
|
return this.store.list;
|
|
60
60
|
}
|
|
61
|
+
getQuotationCustomerScopeInfo() {
|
|
62
|
+
const customerById = /* @__PURE__ */ new Map();
|
|
63
|
+
const quotationScopes = this.store.list.filter((quotation) => Array.isArray(quotation.customer) && quotation.customer.length > 0).map((quotation) => {
|
|
64
|
+
const customerIds = [];
|
|
65
|
+
const customers = [];
|
|
66
|
+
const localSeen = /* @__PURE__ */ new Set();
|
|
67
|
+
const quotationCustomers = quotation.customer || [];
|
|
68
|
+
quotationCustomers.forEach((customer) => {
|
|
69
|
+
const customerId = this.normalizeCustomerId(customer == null ? void 0 : customer.id);
|
|
70
|
+
if (!customerId || localSeen.has(customerId))
|
|
71
|
+
return;
|
|
72
|
+
localSeen.add(customerId);
|
|
73
|
+
customerIds.push(customerId);
|
|
74
|
+
customers.push(customer);
|
|
75
|
+
if (!customerById.has(customerId))
|
|
76
|
+
customerById.set(customerId, customer);
|
|
77
|
+
});
|
|
78
|
+
return {
|
|
79
|
+
quotationId: quotation.id,
|
|
80
|
+
quotationName: quotation.name,
|
|
81
|
+
customerIds,
|
|
82
|
+
customers
|
|
83
|
+
};
|
|
84
|
+
});
|
|
85
|
+
const result = {
|
|
86
|
+
quotationCount: this.store.list.length,
|
|
87
|
+
hasCustomerScopedQuotations: quotationScopes.length > 0,
|
|
88
|
+
allQuotationsCustomerScoped: this.store.list.length > 0 && quotationScopes.length === this.store.list.length,
|
|
89
|
+
customerIds: Array.from(customerById.keys()),
|
|
90
|
+
customers: Array.from(customerById.values()),
|
|
91
|
+
quotationScopes
|
|
92
|
+
};
|
|
93
|
+
return result;
|
|
94
|
+
}
|
|
61
95
|
/**
|
|
62
96
|
* Look up the quotation price for a specific product (+ optional variant) at a given datetime.
|
|
63
97
|
* Returns the price as a string (e.g. "300.00"), or null if no quotation applies.
|
|
@@ -67,6 +101,10 @@ var QuotationModule = class extends import_BaseModule.BaseModule {
|
|
|
67
101
|
* the requested productId wins.
|
|
68
102
|
*/
|
|
69
103
|
getPriceForProduct(params) {
|
|
104
|
+
var _a;
|
|
105
|
+
return ((_a = this.getQuotationMatchForProduct(params)) == null ? void 0 : _a.price) ?? null;
|
|
106
|
+
}
|
|
107
|
+
getQuotationMatchForProduct(params) {
|
|
70
108
|
const { productId, variantId, datetime, customer_id } = params;
|
|
71
109
|
for (const quotation of this.store.list) {
|
|
72
110
|
const visible = this.isQuotationVisibleForCustomer(quotation, customer_id);
|
|
@@ -80,23 +118,16 @@ var QuotationModule = class extends import_BaseModule.BaseModule {
|
|
|
80
118
|
continue;
|
|
81
119
|
if (match.value === 0)
|
|
82
120
|
continue;
|
|
83
|
-
return
|
|
121
|
+
return {
|
|
122
|
+
price: String(match.value),
|
|
123
|
+
quotationShelfId: quotation.id
|
|
124
|
+
};
|
|
84
125
|
}
|
|
85
126
|
return null;
|
|
86
127
|
}
|
|
87
128
|
getQuotationShelfId(params) {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
if (!this.isQuotationVisibleForCustomer(quotation, customer_id))
|
|
91
|
-
continue;
|
|
92
|
-
if (!this.isQuotationActiveAt(quotation, datetime))
|
|
93
|
-
continue;
|
|
94
|
-
const match = this.findProductData(quotation.product_data, productId, variantId);
|
|
95
|
-
if (!match || match.value === 0)
|
|
96
|
-
continue;
|
|
97
|
-
return quotation.id;
|
|
98
|
-
}
|
|
99
|
-
return 0;
|
|
129
|
+
var _a;
|
|
130
|
+
return ((_a = this.getQuotationMatchForProduct(params)) == null ? void 0 : _a.quotationShelfId) ?? 0;
|
|
100
131
|
}
|
|
101
132
|
/**
|
|
102
133
|
* Batch pre-compute quotation prices for a set of products across multiple time points.
|
|
@@ -138,6 +169,11 @@ var QuotationModule = class extends import_BaseModule.BaseModule {
|
|
|
138
169
|
return false;
|
|
139
170
|
return Number(customerId) > 0;
|
|
140
171
|
}
|
|
172
|
+
normalizeCustomerId(customerId) {
|
|
173
|
+
if (customerId === void 0 || customerId === null || customerId === "")
|
|
174
|
+
return null;
|
|
175
|
+
return String(customerId);
|
|
176
|
+
}
|
|
141
177
|
isQuotationActiveAt(quotation, datetime) {
|
|
142
178
|
var _a;
|
|
143
179
|
if (!((_a = quotation.schedule) == null ? void 0 : _a.length))
|
|
@@ -45,3 +45,17 @@ export interface QuotationItem {
|
|
|
45
45
|
export interface QuotationState {
|
|
46
46
|
list: QuotationItem[];
|
|
47
47
|
}
|
|
48
|
+
export interface QuotationCustomerScope {
|
|
49
|
+
quotationId: number;
|
|
50
|
+
quotationName: string;
|
|
51
|
+
customerIds: string[];
|
|
52
|
+
customers: QuotationCustomer[];
|
|
53
|
+
}
|
|
54
|
+
export interface QuotationCustomerScopeInfo {
|
|
55
|
+
quotationCount: number;
|
|
56
|
+
hasCustomerScopedQuotations: boolean;
|
|
57
|
+
allQuotationsCustomerScoped: boolean;
|
|
58
|
+
customerIds: string[];
|
|
59
|
+
customers: QuotationCustomer[];
|
|
60
|
+
quotationScopes: QuotationCustomerScope[];
|
|
61
|
+
}
|
|
@@ -29,6 +29,7 @@ export declare class SalesSummaryModule extends BaseModule implements Module, Sa
|
|
|
29
29
|
}): Promise<{
|
|
30
30
|
tax_title: string;
|
|
31
31
|
tax_rate: number | undefined;
|
|
32
|
+
tax_country_code: string;
|
|
32
33
|
product_quantity: number;
|
|
33
34
|
product_original_amount: string;
|
|
34
35
|
product_amount: string;
|
|
@@ -119,8 +119,8 @@ var SalesSummaryModule = class extends import_BaseModule.BaseModule {
|
|
|
119
119
|
const summarySchedule = this.core.getModule(
|
|
120
120
|
`${this.name.split("_")[0]}_schedule`
|
|
121
121
|
);
|
|
122
|
-
const needScheduleIds = (_b = (_a = this.store.surchargeList) == null ? void 0 : _a.map((item) => item.available_schedule_ids)) == null ? void 0 : _b.flat();
|
|
123
|
-
const scheduleList = summarySchedule == null ? void 0 : summarySchedule.getScheduleListByIds(needScheduleIds);
|
|
122
|
+
const needScheduleIds = (((_b = (_a = this.store.surchargeList) == null ? void 0 : _a.map((item) => item.available_schedule_ids)) == null ? void 0 : _b.flat()) || []).filter((id) => id !== void 0 && id !== null && id !== "");
|
|
123
|
+
const scheduleList = needScheduleIds.length > 0 ? summarySchedule == null ? void 0 : summarySchedule.getScheduleListByIds(needScheduleIds) : [];
|
|
124
124
|
const scheduleById = {};
|
|
125
125
|
if (Array.isArray(scheduleList)) {
|
|
126
126
|
for (const item of scheduleList) {
|
|
@@ -139,7 +139,8 @@ var SalesSummaryModule = class extends import_BaseModule.BaseModule {
|
|
|
139
139
|
const summaryWithTaxMeta = {
|
|
140
140
|
...summary,
|
|
141
141
|
tax_title: taxConfig.taxTitle || "",
|
|
142
|
-
tax_rate: taxRate ?? taxConfig.taxRate
|
|
142
|
+
tax_rate: taxRate ?? taxConfig.taxRate,
|
|
143
|
+
tax_country_code: taxConfig.taxCountryCode || ""
|
|
143
144
|
};
|
|
144
145
|
this.store.summary = summaryWithTaxMeta;
|
|
145
146
|
return summaryWithTaxMeta;
|
|
@@ -9,6 +9,7 @@ export declare class ScheduleModule extends BaseModule implements Module, Schedu
|
|
|
9
9
|
private cacheId;
|
|
10
10
|
private openCache;
|
|
11
11
|
private fatherModule;
|
|
12
|
+
private hasLoadedScheduleList;
|
|
12
13
|
constructor(name?: string, version?: string);
|
|
13
14
|
initialize(core: PisellCore, options: ModuleOptions): Promise<void>;
|
|
14
15
|
/**
|
|
@@ -25,6 +26,9 @@ export declare class ScheduleModule extends BaseModule implements Module, Schedu
|
|
|
25
26
|
*/
|
|
26
27
|
loadAllSchedule(): Promise<void>;
|
|
27
28
|
setScheduleList(list: ScheduleItem[]): void;
|
|
29
|
+
private syncScheduleMap;
|
|
30
|
+
getScheduleList(): ScheduleItem[];
|
|
31
|
+
isScheduleListLoaded(): boolean;
|
|
28
32
|
loadScheduleAvailableDate({ startDate, endDate, custom_page_id, channel, }: LoadScheduleAvailableDateParams): Promise<import("../Date/types").ITime[]>;
|
|
29
33
|
getScheduleListByIds(ids: number[]): ScheduleItem[];
|
|
30
34
|
setAvailabilityScheduleDateList(list: ScheduleAvailabilityDateItem[]): void;
|
|
@@ -49,6 +49,7 @@ var ScheduleModule = class extends import_BaseModule.BaseModule {
|
|
|
49
49
|
this.defaultVersion = "1.0.0";
|
|
50
50
|
this.store = {};
|
|
51
51
|
this.openCache = false;
|
|
52
|
+
this.hasLoadedScheduleList = false;
|
|
52
53
|
}
|
|
53
54
|
async initialize(core, options) {
|
|
54
55
|
var _a, _b;
|
|
@@ -60,10 +61,14 @@ var ScheduleModule = class extends import_BaseModule.BaseModule {
|
|
|
60
61
|
this.store = options == null ? void 0 : options.store;
|
|
61
62
|
if (options.initialState) {
|
|
62
63
|
this.store.scheduleList = options.initialState.scheduleList;
|
|
64
|
+
this.syncScheduleMap();
|
|
63
65
|
this.store.availabilityDateList = options.initialState.availabilityDateList;
|
|
66
|
+
this.hasLoadedScheduleList = Array.isArray(options.initialState.scheduleList);
|
|
64
67
|
} else {
|
|
65
68
|
this.store.scheduleList = [];
|
|
69
|
+
this.store.map = /* @__PURE__ */ new Map();
|
|
66
70
|
this.store.availabilityDateList = [];
|
|
71
|
+
this.hasLoadedScheduleList = false;
|
|
67
72
|
}
|
|
68
73
|
if ((_a = options.otherParams) == null ? void 0 : _a.cacheId) {
|
|
69
74
|
this.openCache = options.otherParams.openCache;
|
|
@@ -101,6 +106,19 @@ var ScheduleModule = class extends import_BaseModule.BaseModule {
|
|
|
101
106
|
}
|
|
102
107
|
setScheduleList(list) {
|
|
103
108
|
this.store.scheduleList = list;
|
|
109
|
+
this.syncScheduleMap();
|
|
110
|
+
this.hasLoadedScheduleList = true;
|
|
111
|
+
}
|
|
112
|
+
syncScheduleMap() {
|
|
113
|
+
this.store.map = new Map(
|
|
114
|
+
(this.store.scheduleList || []).map((schedule) => [Number(schedule.id), schedule])
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
getScheduleList() {
|
|
118
|
+
return this.store.scheduleList || [];
|
|
119
|
+
}
|
|
120
|
+
isScheduleListLoaded() {
|
|
121
|
+
return this.hasLoadedScheduleList;
|
|
104
122
|
}
|
|
105
123
|
async loadScheduleAvailableDate({
|
|
106
124
|
startDate,
|
|
@@ -150,6 +168,9 @@ var ScheduleModule = class extends import_BaseModule.BaseModule {
|
|
|
150
168
|
var _a;
|
|
151
169
|
const idSet = new Set(ids.map((id) => String(id)));
|
|
152
170
|
console.log("getScheduleListByIds", this.store.scheduleList);
|
|
171
|
+
if (this.store.map instanceof Map && this.store.map.size > 0) {
|
|
172
|
+
return ids.map((id) => this.store.map.get(Number(id))).filter(Boolean);
|
|
173
|
+
}
|
|
153
174
|
const list = (_a = this.store.scheduleList) == null ? void 0 : _a.filter((n) => idSet.has(String(n.id)));
|
|
154
175
|
return list;
|
|
155
176
|
}
|
package/lib/server/index.js
CHANGED
|
@@ -2486,6 +2486,7 @@ var Server = class {
|
|
|
2486
2486
|
const shouldClearLocalOrderId = this.isLocalCheckoutOrderId(next.order_id);
|
|
2487
2487
|
if (shouldClearLocalOrderId)
|
|
2488
2488
|
next.order_id = null;
|
|
2489
|
+
delete next.vouchers;
|
|
2489
2490
|
const hasCheckoutOrderNumbers = !this.isBlankCheckoutValue(next.shop_order_number) && !this.isBlankCheckoutValue(next.shop_full_order_number);
|
|
2490
2491
|
if (hasCheckoutOrderNumbers) {
|
|
2491
2492
|
this.logInfo(`${title}: checkout 已携带订单号,跳过查重`, {
|
|
@@ -2541,7 +2542,6 @@ var Server = class {
|
|
|
2541
2542
|
shop_order_number: next.shop_order_number,
|
|
2542
2543
|
shop_full_order_number: next.shop_full_order_number
|
|
2543
2544
|
});
|
|
2544
|
-
delete next.vouchers;
|
|
2545
2545
|
return next;
|
|
2546
2546
|
} catch (error) {
|
|
2547
2547
|
this.logWarning(`${title}: checkout 查找本地订单失败`, {
|
|
@@ -15,7 +15,6 @@ export declare class OrderModule extends BaseModule implements Module {
|
|
|
15
15
|
private syncTimer?;
|
|
16
16
|
private isProcessingSyncBatch;
|
|
17
17
|
private isIdlePhase;
|
|
18
|
-
private resourceIdIndex;
|
|
19
18
|
private logger;
|
|
20
19
|
private storage;
|
|
21
20
|
private orderSQLiteSaveQueue; /** 按 storageKey 记录最近一次 SQLite 写入来源与时间,用于去重 */
|
|
@@ -32,10 +31,10 @@ export declare class OrderModule extends BaseModule implements Module {
|
|
|
32
31
|
private emitOrdersChanged;
|
|
33
32
|
initialize(core: PisellCore, options?: ModuleOptions): Promise<void>;
|
|
34
33
|
/**
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
34
|
+
* 记录信息日志
|
|
35
|
+
* @param title 日志标题
|
|
36
|
+
* @param metadata 日志元数据
|
|
37
|
+
*/
|
|
39
38
|
private logInfo;
|
|
40
39
|
/**
|
|
41
40
|
* 记录错误日志
|
|
@@ -89,7 +88,6 @@ export declare class OrderModule extends BaseModule implements Module {
|
|
|
89
88
|
* @returns 刷新后的订单列表
|
|
90
89
|
*/
|
|
91
90
|
silentRefresh(): Promise<OrderData[]>;
|
|
92
|
-
getOrdersByResourceId(resourceId: string | number): OrderData[];
|
|
93
91
|
private normalizeOrderForMemoryList;
|
|
94
92
|
/**
|
|
95
93
|
* 仅覆盖本地已存在的订单;不存在则直接跳过,不落库、不 emit。
|
|
@@ -126,7 +124,6 @@ export declare class OrderModule extends BaseModule implements Module {
|
|
|
126
124
|
private isBlankIdentityValue;
|
|
127
125
|
private getOrderIdentityEntries;
|
|
128
126
|
private getOrderIdentityKeys;
|
|
129
|
-
private extractResourceIds;
|
|
130
127
|
private getOrderDateKey;
|
|
131
128
|
/**
|
|
132
129
|
* 初始化 OrderDataSource 实例
|
|
@@ -175,6 +172,27 @@ export declare class OrderModule extends BaseModule implements Module {
|
|
|
175
172
|
* 将增量订单合并到 store
|
|
176
173
|
*/
|
|
177
174
|
private mergeOrdersToStore;
|
|
175
|
+
/**
|
|
176
|
+
* 在身份索引中查找与目标订单共享任一身份键的已存在订单下标。
|
|
177
|
+
* 返回所有命中键里最小的下标,等价于原 findOrderIndexByIdentity 的「取首个匹配」语义。
|
|
178
|
+
*
|
|
179
|
+
* @example
|
|
180
|
+
* const idx = this.lookupOrderIndexByIdentityKeys(identityKeyToIndex, freshIdentityKeys)
|
|
181
|
+
*/
|
|
182
|
+
private lookupOrderIndexByIdentityKeys;
|
|
183
|
+
/**
|
|
184
|
+
* 将订单的全部身份键登记到索引并指向其在列表中的下标。
|
|
185
|
+
* 合并后订单新增的身份字段(如挂单同步后拿到 order_id)也会被登记。
|
|
186
|
+
*
|
|
187
|
+
* @example
|
|
188
|
+
* this.registerOrderIdentityKeys(identityKeyToIndex, mergedOrder, matchIndex)
|
|
189
|
+
*/
|
|
190
|
+
private registerOrderIdentityKeys;
|
|
191
|
+
/**
|
|
192
|
+
* 合并热路径去重兜底:默认直接返回原列表(增量索引已保证无重复)。
|
|
193
|
+
* 仅当 ORDER_MERGE_SELF_CHECK 开启时,额外做一次全表压缩并在发现残留重复时告警。
|
|
194
|
+
*/
|
|
195
|
+
private runOrderStoreSelfCheck;
|
|
178
196
|
private normalizeOrderSyncMessage;
|
|
179
197
|
private normalizeOrderSyncPayload;
|
|
180
198
|
private uniqueOrderIds;
|