@endora-commerce/mod-price-lists 0.100.0
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/LICENSE +21 -0
- package/README.md +59 -0
- package/dist/admin/components/ApplicationRuleBuilder.d.ts +24 -0
- package/dist/admin/components/ApplicationRuleBuilder.d.ts.map +1 -0
- package/dist/admin/components/ApplicationRuleBuilder.js +249 -0
- package/dist/admin/components/ApplicationRuleBuilder.js.map +1 -0
- package/dist/admin/components/BracketGrid.d.ts +29 -0
- package/dist/admin/components/BracketGrid.d.ts.map +1 -0
- package/dist/admin/components/BracketGrid.js +252 -0
- package/dist/admin/components/BracketGrid.js.map +1 -0
- package/dist/admin/components/DisplayModeOverrideRow.d.ts +46 -0
- package/dist/admin/components/DisplayModeOverrideRow.d.ts.map +1 -0
- package/dist/admin/components/DisplayModeOverrideRow.js +109 -0
- package/dist/admin/components/DisplayModeOverrideRow.js.map +1 -0
- package/dist/admin/components/LinkedPriceListsPanel.d.ts +55 -0
- package/dist/admin/components/LinkedPriceListsPanel.d.ts.map +1 -0
- package/dist/admin/components/LinkedPriceListsPanel.js +131 -0
- package/dist/admin/components/LinkedPriceListsPanel.js.map +1 -0
- package/dist/admin/index.d.ts +34 -0
- package/dist/admin/index.d.ts.map +1 -0
- package/dist/admin/index.js +119 -0
- package/dist/admin/index.js.map +1 -0
- package/dist/admin/pages/DisplayModeOverridesPage.d.ts +25 -0
- package/dist/admin/pages/DisplayModeOverridesPage.d.ts.map +1 -0
- package/dist/admin/pages/DisplayModeOverridesPage.js +266 -0
- package/dist/admin/pages/DisplayModeOverridesPage.js.map +1 -0
- package/dist/admin/pages/PriceListDetailPage.d.ts +23 -0
- package/dist/admin/pages/PriceListDetailPage.d.ts.map +1 -0
- package/dist/admin/pages/PriceListDetailPage.js +421 -0
- package/dist/admin/pages/PriceListDetailPage.js.map +1 -0
- package/dist/admin/pages/PriceListsPage.d.ts +17 -0
- package/dist/admin/pages/PriceListsPage.d.ts.map +1 -0
- package/dist/admin/pages/PriceListsPage.js +198 -0
- package/dist/admin/pages/PriceListsPage.js.map +1 -0
- package/dist/admin/zones/CategoryDisplayMode.d.ts +27 -0
- package/dist/admin/zones/CategoryDisplayMode.d.ts.map +1 -0
- package/dist/admin/zones/CategoryDisplayMode.js +11 -0
- package/dist/admin/zones/CategoryDisplayMode.js.map +1 -0
- package/dist/admin/zones/OrganizationDisplayMode.d.ts +36 -0
- package/dist/admin/zones/OrganizationDisplayMode.d.ts.map +1 -0
- package/dist/admin/zones/OrganizationDisplayMode.js +12 -0
- package/dist/admin/zones/OrganizationDisplayMode.js.map +1 -0
- package/dist/admin/zones/ProductLinkedPriceLists.d.ts +16 -0
- package/dist/admin/zones/ProductLinkedPriceLists.d.ts.map +1 -0
- package/dist/admin/zones/ProductLinkedPriceLists.js +7 -0
- package/dist/admin/zones/ProductLinkedPriceLists.js.map +1 -0
- package/dist/backend/entities/price-display-mode-override.entity.d.ts +23 -0
- package/dist/backend/entities/price-display-mode-override.entity.d.ts.map +1 -0
- package/dist/backend/entities/price-display-mode-override.entity.js +58 -0
- package/dist/backend/entities/price-display-mode-override.entity.js.map +1 -0
- package/dist/backend/entities/price-list-price-bracket.entity.d.ts +26 -0
- package/dist/backend/entities/price-list-price-bracket.entity.d.ts.map +1 -0
- package/dist/backend/entities/price-list-price-bracket.entity.js +73 -0
- package/dist/backend/entities/price-list-price-bracket.entity.js.map +1 -0
- package/dist/backend/entities/price-list-product.entity.d.ts +15 -0
- package/dist/backend/entities/price-list-product.entity.d.ts.map +1 -0
- package/dist/backend/entities/price-list-product.entity.js +43 -0
- package/dist/backend/entities/price-list-product.entity.js.map +1 -0
- package/dist/backend/entities/price-list.entity.d.ts +34 -0
- package/dist/backend/entities/price-list.entity.d.ts.map +1 -0
- package/dist/backend/entities/price-list.entity.js +115 -0
- package/dist/backend/entities/price-list.entity.js.map +1 -0
- package/dist/backend/index.d.ts +125 -0
- package/dist/backend/index.d.ts.map +1 -0
- package/dist/backend/index.js +179 -0
- package/dist/backend/index.js.map +1 -0
- package/dist/backend/plugin.d.ts +68 -0
- package/dist/backend/plugin.d.ts.map +1 -0
- package/dist/backend/plugin.js +88 -0
- package/dist/backend/plugin.js.map +1 -0
- package/dist/backend/routes.d.ts +40 -0
- package/dist/backend/routes.d.ts.map +1 -0
- package/dist/backend/routes.js +447 -0
- package/dist/backend/routes.js.map +1 -0
- package/dist/backend/routes.storefront.d.ts +47 -0
- package/dist/backend/routes.storefront.d.ts.map +1 -0
- package/dist/backend/routes.storefront.js +131 -0
- package/dist/backend/routes.storefront.js.map +1 -0
- package/dist/backend/services/application-rule-evaluator.d.ts +25 -0
- package/dist/backend/services/application-rule-evaluator.d.ts.map +1 -0
- package/dist/backend/services/application-rule-evaluator.js +2 -0
- package/dist/backend/services/application-rule-evaluator.js.map +1 -0
- package/dist/backend/services/audit-references.d.ts +11 -0
- package/dist/backend/services/audit-references.d.ts.map +1 -0
- package/dist/backend/services/audit-references.js +23 -0
- package/dist/backend/services/audit-references.js.map +1 -0
- package/dist/backend/services/default-price-list-migration.d.ts +70 -0
- package/dist/backend/services/default-price-list-migration.d.ts.map +1 -0
- package/dist/backend/services/default-price-list-migration.js +177 -0
- package/dist/backend/services/default-price-list-migration.js.map +1 -0
- package/dist/backend/services/display-mode-resolver.d.ts +78 -0
- package/dist/backend/services/display-mode-resolver.d.ts.map +1 -0
- package/dist/backend/services/display-mode-resolver.js +71 -0
- package/dist/backend/services/display-mode-resolver.js.map +1 -0
- package/dist/backend/services/listing-price-chain.d.ts +26 -0
- package/dist/backend/services/listing-price-chain.d.ts.map +1 -0
- package/dist/backend/services/listing-price-chain.js +55 -0
- package/dist/backend/services/listing-price-chain.js.map +1 -0
- package/dist/backend/services/price-bracket-resolver.d.ts +24 -0
- package/dist/backend/services/price-bracket-resolver.d.ts.map +1 -0
- package/dist/backend/services/price-bracket-resolver.js +16 -0
- package/dist/backend/services/price-bracket-resolver.js.map +1 -0
- package/dist/backend/services/price-list-candidate-vector.d.ts +116 -0
- package/dist/backend/services/price-list-candidate-vector.d.ts.map +1 -0
- package/dist/backend/services/price-list-candidate-vector.js +133 -0
- package/dist/backend/services/price-list-candidate-vector.js.map +1 -0
- package/dist/backend/services/price-list-currency-reference.d.ts +12 -0
- package/dist/backend/services/price-list-currency-reference.d.ts.map +1 -0
- package/dist/backend/services/price-list-currency-reference.js +24 -0
- package/dist/backend/services/price-list-currency-reference.js.map +1 -0
- package/dist/backend/services/price-list-read-port.d.ts +29 -0
- package/dist/backend/services/price-list-read-port.d.ts.map +1 -0
- package/dist/backend/services/price-list-read-port.js +64 -0
- package/dist/backend/services/price-list-read-port.js.map +1 -0
- package/dist/backend/services/price-list-resolver.d.ts +26 -0
- package/dist/backend/services/price-list-resolver.d.ts.map +1 -0
- package/dist/backend/services/price-list-resolver.js +37 -0
- package/dist/backend/services/price-list-resolver.js.map +1 -0
- package/dist/backend/services/price-list-service.d.ts +431 -0
- package/dist/backend/services/price-list-service.d.ts.map +1 -0
- package/dist/backend/services/price-list-service.js +1238 -0
- package/dist/backend/services/price-list-service.js.map +1 -0
- package/dist/backend/services/price-list-status-worker.d.ts +28 -0
- package/dist/backend/services/price-list-status-worker.d.ts.map +1 -0
- package/dist/backend/services/price-list-status-worker.js +38 -0
- package/dist/backend/services/price-list-status-worker.js.map +1 -0
- package/dist/backend/services/pricing-cache.d.ts +53 -0
- package/dist/backend/services/pricing-cache.d.ts.map +1 -0
- package/dist/backend/services/pricing-cache.js +88 -0
- package/dist/backend/services/pricing-cache.js.map +1 -0
- package/dist/backend/services/pricing-service.d.ts +304 -0
- package/dist/backend/services/pricing-service.d.ts.map +1 -0
- package/dist/backend/services/pricing-service.interface.d.ts +151 -0
- package/dist/backend/services/pricing-service.interface.d.ts.map +1 -0
- package/dist/backend/services/pricing-service.interface.js +10 -0
- package/dist/backend/services/pricing-service.interface.js.map +1 -0
- package/dist/backend/services/pricing-service.js +803 -0
- package/dist/backend/services/pricing-service.js.map +1 -0
- package/dist/backend/services/unit-price-ordering.d.ts +121 -0
- package/dist/backend/services/unit-price-ordering.d.ts.map +1 -0
- package/dist/backend/services/unit-price-ordering.js +164 -0
- package/dist/backend/services/unit-price-ordering.js.map +1 -0
- package/dist/manifest.d.ts +218 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +228 -0
- package/dist/manifest.js.map +1 -0
- package/dist/migrations/20260426T075235_price_lists_pricing_init.d.ts +24 -0
- package/dist/migrations/20260426T075235_price_lists_pricing_init.d.ts.map +1 -0
- package/dist/migrations/20260426T075235_price_lists_pricing_init.js +89 -0
- package/dist/migrations/20260426T075235_price_lists_pricing_init.js.map +1 -0
- package/dist/migrations/20260504T125655_price_lists_engine.d.ts +6 -0
- package/dist/migrations/20260504T125655_price_lists_engine.d.ts.map +1 -0
- package/dist/migrations/20260504T125655_price_lists_engine.js +319 -0
- package/dist/migrations/20260504T125655_price_lists_engine.js.map +1 -0
- package/dist/migrations/20260817T055457_price_lists_single_system_price_list.d.ts +15 -0
- package/dist/migrations/20260817T055457_price_lists_single_system_price_list.d.ts.map +1 -0
- package/dist/migrations/20260817T055457_price_lists_single_system_price_list.js +58 -0
- package/dist/migrations/20260817T055457_price_lists_single_system_price_list.js.map +1 -0
- package/dist/migrations/20260821T135907_price_lists_unit_price_amount_index.d.ts +40 -0
- package/dist/migrations/20260821T135907_price_lists_unit_price_amount_index.d.ts.map +1 -0
- package/dist/migrations/20260821T135907_price_lists_unit_price_amount_index.js +46 -0
- package/dist/migrations/20260821T135907_price_lists_unit_price_amount_index.js.map +1 -0
- package/dist/migrations/index.d.ts +30 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/migrations/index.js +35 -0
- package/dist/migrations/index.js.map +1 -0
- package/docs/price_lists.md +278 -0
- package/i18n/en.json +14 -0
- package/i18n/pl.json +14 -0
- package/package.json +99 -0
- package/tailwind.css +14 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { PriceListService } from './services/price-list-service.js';
|
|
2
|
+
import { PricingService } from './services/pricing-service.js';
|
|
3
|
+
import { PriceListStatusWorker } from './services/price-list-status-worker.js';
|
|
4
|
+
import { PricingCache } from './services/pricing-cache.js';
|
|
5
|
+
import { registerPricingRoutes } from './routes.js';
|
|
6
|
+
import { registerStorefrontPricingRoutes } from './routes.storefront.js';
|
|
7
|
+
import { effectiveState } from '@endora-commerce/platform/kernel';
|
|
8
|
+
import { enterSystemScope } from '@endora-commerce/platform/kernel';
|
|
9
|
+
const STATUS_SWEEP_INTERVAL_MS = 5 * 60 * 1000;
|
|
10
|
+
export function priceListsModule(options) {
|
|
11
|
+
const pricingCache = new PricingCache(options.pricingCacheTtlMs !== undefined ? { ttlMs: options.pricingCacheTtlMs } : {});
|
|
12
|
+
const priceListService = new PriceListService(options.emFactory, pricingCache, options.auditLogService, options.commandBus, options.targetReads);
|
|
13
|
+
// This module builds the engine; a deployment that overrides it wraps the
|
|
14
|
+
// `pricingService` **registration** from an overlay module's
|
|
15
|
+
// `ctx.di.decorate` (D-103), so nothing about the override reaches this
|
|
16
|
+
// factory. It used to: `decoratePricingService` was a contribution point a
|
|
17
|
+
// composition root filled from a file under `apps/<deployment>/decorations/`,
|
|
18
|
+
// and that seam is retired — one mechanism, and it is the one that needs no
|
|
19
|
+
// edit here when a second deployment overrides a second service.
|
|
20
|
+
//
|
|
21
|
+
// Consumers read `handle.pricingService` as the *contract* rather than as the
|
|
22
|
+
// class, and that still matters: what the container hands out is a wrapper
|
|
23
|
+
// whenever a deployment decorates the registration.
|
|
24
|
+
const pricingService = new PricingService(options.emFactory, pricingCache, options.resolveOrgChain, options.targetReads);
|
|
25
|
+
const statusWorker = new PriceListStatusWorker(options.emFactory);
|
|
26
|
+
return {
|
|
27
|
+
handle: { priceListService, pricingService, statusWorker },
|
|
28
|
+
plugin: async (app) => {
|
|
29
|
+
await registerPricingRoutes(app, {
|
|
30
|
+
priceListService,
|
|
31
|
+
pricingService,
|
|
32
|
+
emFactory: options.emFactory,
|
|
33
|
+
requireAdmin: options.requireAdmin,
|
|
34
|
+
catalogProductRead: options.targetReads.catalogProductRead,
|
|
35
|
+
catalogCategoryRead: options.targetReads.catalogCategoryRead,
|
|
36
|
+
organizationDetails: options.targetReads.organizationDetails,
|
|
37
|
+
customerGroupRead: options.targetReads.customerGroupRead,
|
|
38
|
+
customerAccountRead: options.customerAccountRead,
|
|
39
|
+
...(options.resolveAdminAuditContext
|
|
40
|
+
? { resolveAdminAuditContext: options.resolveAdminAuditContext }
|
|
41
|
+
: {}),
|
|
42
|
+
});
|
|
43
|
+
await registerStorefrontPricingRoutes(app, {
|
|
44
|
+
priceListService,
|
|
45
|
+
pricingService,
|
|
46
|
+
emFactory: options.emFactory,
|
|
47
|
+
catalogProductRead: options.targetReads.catalogProductRead,
|
|
48
|
+
organizationDetails: options.targetReads.organizationDetails,
|
|
49
|
+
});
|
|
50
|
+
if (options.enableStatusSweeper !== false) {
|
|
51
|
+
const handle = setInterval(() => {
|
|
52
|
+
// Presence is asked first, and outside the promise chain's `catch`
|
|
53
|
+
// (issue #126). The route seam gates *requests*; this body is not one,
|
|
54
|
+
// so it runs at boot whatever the effective state, and a timer
|
|
55
|
+
// callback has nowhere to throw to — `ModuleDisabledError` cannot
|
|
56
|
+
// propagate from here and must be *decided*, not caught. Asking it
|
|
57
|
+
// below, inside the `catch`, would make a switched-off module and a
|
|
58
|
+
// genuinely failed sweep the same silent no-op — and a sweep that runs
|
|
59
|
+
// while price lists are off changes what customers are charged.
|
|
60
|
+
if (!effectiveState.isPresent('price_lists'))
|
|
61
|
+
return;
|
|
62
|
+
// Feature 072 (T034) — the timer is the entry point, so the scope
|
|
63
|
+
// opens here and not inside `sweep()`: the same method is reachable
|
|
64
|
+
// from an admin route (`routes.ts`), where it already runs inside the
|
|
65
|
+
// request's scope and must not open a second one.
|
|
66
|
+
enterSystemScope('price_lists: status sweep', () => statusWorker.sweep(), {
|
|
67
|
+
entryPoint: 'interval',
|
|
68
|
+
})
|
|
69
|
+
.then((result) => {
|
|
70
|
+
if (result.scheduledToActive > 0 || result.activeToExpired > 0) {
|
|
71
|
+
app.log.info({ result }, 'price-list status sweep flipped lifecycle rows');
|
|
72
|
+
}
|
|
73
|
+
})
|
|
74
|
+
.catch((err) => {
|
|
75
|
+
app.log.error({ err }, 'price-list status sweep failed');
|
|
76
|
+
});
|
|
77
|
+
}, STATUS_SWEEP_INTERVAL_MS);
|
|
78
|
+
// Don't keep the Node process alive purely for the sweeper.
|
|
79
|
+
if (typeof handle.unref === 'function')
|
|
80
|
+
handle.unref();
|
|
81
|
+
app.addHook('onClose', async () => {
|
|
82
|
+
clearInterval(handle);
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../src/backend/plugin.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { FastifyInstance, FastifyRequest } from 'fastify';
|
|
2
|
+
import type { PriceListService } from './services/price-list-service.js';
|
|
3
|
+
import type { PricingServiceContract } from './services/pricing-service.interface.js';
|
|
4
|
+
import type { EntityManager } from '@mikro-orm/postgresql';
|
|
5
|
+
import type { CatalogCategoryReadPort, CatalogProductReadPort, CustomerAccountReadPort, CustomerGroupReadPort, OrganizationDetailsPort } from '@endora-commerce/contracts';
|
|
6
|
+
import type { RequireAdminFactory } from '@endora-commerce/platform/kernel';
|
|
7
|
+
export interface PricingRoutesDeps {
|
|
8
|
+
priceListService: PriceListService;
|
|
9
|
+
pricingService: PricingServiceContract;
|
|
10
|
+
emFactory: () => EntityManager;
|
|
11
|
+
requireAdmin: RequireAdminFactory;
|
|
12
|
+
/**
|
|
13
|
+
* Feature 075 Phase C — the neighbour reads these admin screens make. The
|
|
14
|
+
* rule-target pickers list organisations and categories; the product pricing
|
|
15
|
+
* panel and the resolved-price probe resolve a product. All three used to be
|
|
16
|
+
* `em.find` against tables this module does not own; each fails closed at the
|
|
17
|
+
* seam now, which is the right answer for an admin screen that would
|
|
18
|
+
* otherwise offer targets the platform cannot serve.
|
|
19
|
+
*/
|
|
20
|
+
catalogProductRead: CatalogProductReadPort;
|
|
21
|
+
catalogCategoryRead: CatalogCategoryReadPort;
|
|
22
|
+
organizationDetails: OrganizationDetailsPort;
|
|
23
|
+
/**
|
|
24
|
+
* Feature 076 (D-79) — the last two neighbour reads this module made by
|
|
25
|
+
* importing another module's entity, both of them into `customer_accounts`.
|
|
26
|
+
* The rule-target picker lists customer groups; the admin resolved-price
|
|
27
|
+
* probe reads the customer behind the price it is asked to explain. Both fail
|
|
28
|
+
* closed at the seam, which is the right answer for a probe that would
|
|
29
|
+
* otherwise price for a customer the platform will not identify.
|
|
30
|
+
*/
|
|
31
|
+
customerGroupRead: CustomerGroupReadPort;
|
|
32
|
+
customerAccountRead: CustomerAccountReadPort;
|
|
33
|
+
/** Feature 024 — resolves admin actor identity for audit entries. */
|
|
34
|
+
resolveAdminAuditContext?: (req: FastifyRequest) => {
|
|
35
|
+
actorAdminUserId: string;
|
|
36
|
+
impersonatedCustomerAccountId?: string | null;
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export declare function registerPricingRoutes(app: FastifyInstance, deps: PricingRoutesDeps): Promise<void>;
|
|
40
|
+
//# sourceMappingURL=routes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/backend/routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAY/D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACzE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,yCAAyC,CAAC;AAEtF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAE3D,OAAO,KAAK,EACV,uBAAuB,EACvB,sBAAsB,EACtB,uBAAuB,EACvB,qBAAqB,EACrB,uBAAuB,EACxB,MAAM,4BAA4B,CAAC;AACpC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAG5E,MAAM,WAAW,iBAAiB;IAChC,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,cAAc,EAAE,sBAAsB,CAAC;IACvC,SAAS,EAAE,MAAM,aAAa,CAAC;IAC/B,YAAY,EAAE,mBAAmB,CAAC;IAClC;;;;;;;OAOG;IACH,kBAAkB,EAAE,sBAAsB,CAAC;IAC3C,mBAAmB,EAAE,uBAAuB,CAAC;IAC7C,mBAAmB,EAAE,uBAAuB,CAAC;IAC7C;;;;;;;OAOG;IACH,iBAAiB,EAAE,qBAAqB,CAAC;IACzC,mBAAmB,EAAE,uBAAuB,CAAC;IAC7C,qEAAqE;IACrE,wBAAwB,CAAC,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK;QAClD,gBAAgB,EAAE,MAAM,CAAC;QACzB,6BAA6B,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KAC/C,CAAC;CACH;AAuCD,wBAAsB,qBAAqB,CACzC,GAAG,EAAE,eAAe,EACpB,IAAI,EAAE,iBAAiB,GACtB,OAAO,CAAC,IAAI,CAAC,CAklBf"}
|
|
@@ -0,0 +1,447 @@
|
|
|
1
|
+
import { createPriceListEngineRequestSchema, patchPriceListEngineRequestSchema, replaceBracketsRequestSchema, replaceProductsRequestSchema, ERROR_CODES, } from '@endora-commerce/contracts';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { HttpError } from '@endora-commerce/platform/http';
|
|
4
|
+
import { ruleVisibleForScope } from '@endora-commerce/platform/tenancy';
|
|
5
|
+
import { SalesChannel } from '@endora-commerce/platform/kernel';
|
|
6
|
+
import { PRICE_LIST_PERMISSIONS } from '../manifest.js';
|
|
7
|
+
function buildAuditCtx(request, resolver) {
|
|
8
|
+
const base = resolver?.(request);
|
|
9
|
+
if (!base)
|
|
10
|
+
return undefined;
|
|
11
|
+
return {
|
|
12
|
+
actorAdminUserId: base.actorAdminUserId,
|
|
13
|
+
impersonatedCustomerAccountId: base.impersonatedCustomerAccountId ?? null,
|
|
14
|
+
ipAddress: request.ip ?? null,
|
|
15
|
+
userAgent: typeof request.headers['user-agent'] === 'string'
|
|
16
|
+
? request.headers['user-agent']
|
|
17
|
+
: null,
|
|
18
|
+
requestId: request.id,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Feature 050 — price_lists is rule-scoped: its org targeting lives in the
|
|
23
|
+
* applicationRule AST, not a column. Collect the org ids a rule targets so a
|
|
24
|
+
* scoped admin only sees lists targeting one of their orgs (or global lists).
|
|
25
|
+
*/
|
|
26
|
+
function extractRuleOrgTargets(rule) {
|
|
27
|
+
if (!rule)
|
|
28
|
+
return [];
|
|
29
|
+
switch (rule.kind) {
|
|
30
|
+
case 'all':
|
|
31
|
+
return [];
|
|
32
|
+
case 'criterion':
|
|
33
|
+
return rule.type === 'organization' ? [...rule.values] : [];
|
|
34
|
+
case 'group':
|
|
35
|
+
return rule.children.flatMap(extractRuleOrgTargets);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
export async function registerPricingRoutes(app, deps) {
|
|
39
|
+
const { priceListService, pricingService, emFactory, requireAdmin, catalogProductRead, catalogCategoryRead, organizationDetails, customerGroupRead, customerAccountRead, } = deps;
|
|
40
|
+
/**
|
|
41
|
+
* Issue #219 — this module's own gates. Every route below used to name
|
|
42
|
+
* `catalog:write`, which bought the ability to change what customers pay with
|
|
43
|
+
* a permission granted for content work. The split is by what the route does:
|
|
44
|
+
* a listing or a picker is `price_lists:read`, anything that persists is
|
|
45
|
+
* `price_lists:write`.
|
|
46
|
+
*
|
|
47
|
+
* No compatibility shim: `catalog:write` is refused here now, so a role that
|
|
48
|
+
* needs pricing is granted a pricing code deliberately. See the first-
|
|
49
|
+
* deployment checklist item D3.
|
|
50
|
+
*/
|
|
51
|
+
const readGate = requireAdmin(PRICE_LIST_PERMISSIONS.READ);
|
|
52
|
+
const writeGate = requireAdmin(PRICE_LIST_PERMISSIONS.WRITE);
|
|
53
|
+
// ---- Engine routes (feature 011) -----------------------------------
|
|
54
|
+
app.get('/api/v1/admin/price-lists-engine', { preHandler: readGate }, async (request) => {
|
|
55
|
+
const status = toArray(request.query.status).filter((s) => s === 'draft' || s === 'active' || s === 'scheduled' || s === 'expired');
|
|
56
|
+
const type = toArray(request.query.type).filter((t) => t === 'base' || t === 'sale');
|
|
57
|
+
const filter = {};
|
|
58
|
+
if (status.length > 0)
|
|
59
|
+
filter.status = status;
|
|
60
|
+
if (type.length > 0)
|
|
61
|
+
filter.type = type;
|
|
62
|
+
if (typeof request.query.search === 'string' && request.query.search.trim().length > 0) {
|
|
63
|
+
filter.search = request.query.search.trim();
|
|
64
|
+
}
|
|
65
|
+
const rows = await priceListService.listEngine(filter);
|
|
66
|
+
// Feature 050 — hide price lists that target only orgs outside the scope.
|
|
67
|
+
const scoped = rows.filter((r) => ruleVisibleForScope(extractRuleOrgTargets(r.applicationRule)));
|
|
68
|
+
return { data: { items: scoped.map(serializePriceListEngine) } };
|
|
69
|
+
});
|
|
70
|
+
app.post('/api/v1/admin/price-lists-engine', {
|
|
71
|
+
preHandler: writeGate,
|
|
72
|
+
schema: { body: createPriceListEngineRequestSchema },
|
|
73
|
+
}, async (request, reply) => {
|
|
74
|
+
const body = createPriceListEngineRequestSchema.parse(request.body);
|
|
75
|
+
const row = await priceListService.create({
|
|
76
|
+
name: body.name,
|
|
77
|
+
type: body.type,
|
|
78
|
+
startsAt: body.startsAt ? new Date(body.startsAt) : null,
|
|
79
|
+
endsAt: body.endsAt ? new Date(body.endsAt) : null,
|
|
80
|
+
...(body.applicationRule !== undefined ? { applicationRule: body.applicationRule } : {}),
|
|
81
|
+
}, buildAuditCtx(request, deps.resolveAdminAuditContext));
|
|
82
|
+
reply.status(201);
|
|
83
|
+
return { data: serializePriceListEngine(row) };
|
|
84
|
+
});
|
|
85
|
+
app.patch('/api/v1/admin/price-lists-engine/:id', {
|
|
86
|
+
preHandler: writeGate,
|
|
87
|
+
schema: { body: patchPriceListEngineRequestSchema },
|
|
88
|
+
}, async (request) => {
|
|
89
|
+
const body = patchPriceListEngineRequestSchema.parse(request.body);
|
|
90
|
+
const patch = {};
|
|
91
|
+
if (body.name !== undefined)
|
|
92
|
+
patch.name = body.name;
|
|
93
|
+
if (body.type !== undefined)
|
|
94
|
+
patch.type = body.type;
|
|
95
|
+
if (body.startsAt !== undefined)
|
|
96
|
+
patch.startsAt = body.startsAt ? new Date(body.startsAt) : null;
|
|
97
|
+
if (body.endsAt !== undefined)
|
|
98
|
+
patch.endsAt = body.endsAt ? new Date(body.endsAt) : null;
|
|
99
|
+
if (body.applicationRule !== undefined)
|
|
100
|
+
patch.applicationRule = body.applicationRule;
|
|
101
|
+
const row = await priceListService.patch(request.params.id, patch, buildAuditCtx(request, deps.resolveAdminAuditContext));
|
|
102
|
+
return { data: serializePriceListEngine(row) };
|
|
103
|
+
});
|
|
104
|
+
app.get('/api/v1/admin/price-lists-engine/:id', { preHandler: readGate }, async (request) => {
|
|
105
|
+
const row = await priceListService.getById(request.params.id);
|
|
106
|
+
if (!ruleVisibleForScope(extractRuleOrgTargets(row.applicationRule))) {
|
|
107
|
+
throw new HttpError(404, ERROR_CODES.NOT_FOUND, `Price list ${request.params.id} not found.`);
|
|
108
|
+
}
|
|
109
|
+
return { data: serializePriceListEngine(row) };
|
|
110
|
+
});
|
|
111
|
+
app.post('/api/v1/admin/price-lists-engine/:id/activate', { preHandler: writeGate }, async (request) => {
|
|
112
|
+
const row = await priceListService.activate(request.params.id, buildAuditCtx(request, deps.resolveAdminAuditContext));
|
|
113
|
+
return { data: serializePriceListEngine(row) };
|
|
114
|
+
});
|
|
115
|
+
app.post('/api/v1/admin/price-lists-engine/:id/draftify', { preHandler: writeGate }, async (request) => {
|
|
116
|
+
const row = await priceListService.draftify(request.params.id, buildAuditCtx(request, deps.resolveAdminAuditContext));
|
|
117
|
+
return { data: serializePriceListEngine(row) };
|
|
118
|
+
});
|
|
119
|
+
app.post('/api/v1/admin/price-lists-engine/:id/duplicate', { preHandler: writeGate }, async (request, reply) => {
|
|
120
|
+
const dup = await priceListService.duplicate(request.params.id, buildAuditCtx(request, deps.resolveAdminAuditContext));
|
|
121
|
+
reply.status(201);
|
|
122
|
+
return { data: serializePriceListEngine(dup) };
|
|
123
|
+
});
|
|
124
|
+
app.delete('/api/v1/admin/price-lists-engine/:id', { preHandler: writeGate }, async (request, reply) => {
|
|
125
|
+
await priceListService.remove(request.params.id);
|
|
126
|
+
return reply.status(204).send();
|
|
127
|
+
});
|
|
128
|
+
// ---- Engine: product roster + bracket pricing (US3) ----------------
|
|
129
|
+
app.get('/api/v1/admin/price-lists-engine/:id/products', { preHandler: readGate }, async (request) => {
|
|
130
|
+
const items = await priceListService.listProducts(request.params.id);
|
|
131
|
+
return { data: { items } };
|
|
132
|
+
});
|
|
133
|
+
app.put('/api/v1/admin/price-lists-engine/:id/products', {
|
|
134
|
+
preHandler: writeGate,
|
|
135
|
+
schema: { body: replaceProductsRequestSchema },
|
|
136
|
+
}, async (request) => {
|
|
137
|
+
const body = replaceProductsRequestSchema.parse(request.body);
|
|
138
|
+
const result = await priceListService.replaceProducts(request.params.id, body.productIds, buildAuditCtx(request, deps.resolveAdminAuditContext));
|
|
139
|
+
return { data: result };
|
|
140
|
+
});
|
|
141
|
+
app.post('/api/v1/admin/price-lists-engine/:id/products', {
|
|
142
|
+
preHandler: writeGate,
|
|
143
|
+
schema: { body: z.object({ productId: z.string().uuid() }) },
|
|
144
|
+
}, async (request, reply) => {
|
|
145
|
+
const body = z.object({ productId: z.string().uuid() }).parse(request.body);
|
|
146
|
+
await priceListService.addProduct(request.params.id, body.productId);
|
|
147
|
+
reply.status(201);
|
|
148
|
+
return { data: { priceListId: request.params.id, productId: body.productId } };
|
|
149
|
+
});
|
|
150
|
+
app.delete('/api/v1/admin/price-lists-engine/:id/products/:productId', { preHandler: writeGate }, async (request, reply) => {
|
|
151
|
+
await priceListService.removeProduct(request.params.id, request.params.productId);
|
|
152
|
+
return reply.status(204).send();
|
|
153
|
+
});
|
|
154
|
+
app.get('/api/v1/admin/price-lists-engine/:id/products/:productId/brackets', { preHandler: readGate }, async (request) => {
|
|
155
|
+
const list = await priceListService.listProducts(request.params.id);
|
|
156
|
+
const entry = list.find((e) => e.productId === request.params.productId);
|
|
157
|
+
if (!entry) {
|
|
158
|
+
return { data: { bracketsByCurrency: {} } };
|
|
159
|
+
}
|
|
160
|
+
return { data: { bracketsByCurrency: entry.bracketsByCurrency } };
|
|
161
|
+
});
|
|
162
|
+
app.put('/api/v1/admin/price-lists-engine/:id/products/:productId/brackets', {
|
|
163
|
+
preHandler: writeGate,
|
|
164
|
+
schema: { body: replaceBracketsRequestSchema },
|
|
165
|
+
}, async (request) => {
|
|
166
|
+
const body = replaceBracketsRequestSchema.parse(request.body);
|
|
167
|
+
const out = await priceListService.replaceBrackets(request.params.id, request.params.productId, body.bracketsByCurrency, buildAuditCtx(request, deps.resolveAdminAuditContext));
|
|
168
|
+
return { data: { bracketsByCurrency: out } };
|
|
169
|
+
});
|
|
170
|
+
app.post('/api/v1/admin/price-lists-engine/:id/products/:productId/brackets/copy', {
|
|
171
|
+
preHandler: writeGate,
|
|
172
|
+
schema: {
|
|
173
|
+
body: z.object({
|
|
174
|
+
fromCurrency: z.string().regex(/^[A-Z]{3}$/),
|
|
175
|
+
toCurrencies: z.array(z.string().regex(/^[A-Z]{3}$/)).min(1),
|
|
176
|
+
}),
|
|
177
|
+
},
|
|
178
|
+
}, async (request) => {
|
|
179
|
+
const body = z
|
|
180
|
+
.object({
|
|
181
|
+
fromCurrency: z.string().regex(/^[A-Z]{3}$/),
|
|
182
|
+
toCurrencies: z.array(z.string().regex(/^[A-Z]{3}$/)).min(1),
|
|
183
|
+
})
|
|
184
|
+
.parse(request.body);
|
|
185
|
+
const result = await priceListService.copyCurrencyBrackets(request.params.id, request.params.productId, body.fromCurrency, body.toCurrencies);
|
|
186
|
+
return { data: result };
|
|
187
|
+
});
|
|
188
|
+
// ---- Rule-builder pickers (US4) -----------------------------------
|
|
189
|
+
app.get('/api/v1/admin/pricing/rule-targets/sales-channels', { preHandler: readGate }, async () => {
|
|
190
|
+
const em = emFactory();
|
|
191
|
+
const rows = await em.find(SalesChannel, {}, { orderBy: { code: 'asc' } });
|
|
192
|
+
return {
|
|
193
|
+
data: {
|
|
194
|
+
items: rows.map((r) => ({
|
|
195
|
+
id: r.id,
|
|
196
|
+
code: r.code,
|
|
197
|
+
name: r.name,
|
|
198
|
+
})),
|
|
199
|
+
},
|
|
200
|
+
};
|
|
201
|
+
});
|
|
202
|
+
/**
|
|
203
|
+
* Issue #180 removed `catalog:write` from the canonical customer-group
|
|
204
|
+
* endpoints and missed this copy — a pricing rule-target picker, not a
|
|
205
|
+
* catalogue surface. The `promotions` and `pwa` twins have always answered
|
|
206
|
+
* behind their own module's read code; so does this one now.
|
|
207
|
+
*/
|
|
208
|
+
app.get('/api/v1/admin/pricing/rule-targets/customer-groups', { preHandler: readGate }, async () => {
|
|
209
|
+
// Already ordered by code on the owner's side.
|
|
210
|
+
const rows = await customerGroupRead.listAll();
|
|
211
|
+
return {
|
|
212
|
+
data: {
|
|
213
|
+
items: rows.map((r) => ({ id: r.id, code: r.code, name: r.name })),
|
|
214
|
+
},
|
|
215
|
+
};
|
|
216
|
+
});
|
|
217
|
+
app.get('/api/v1/admin/pricing/rule-targets/organizations', { preHandler: readGate }, async (request) => {
|
|
218
|
+
const limit = Math.min(200, Math.max(1, Number(request.query.limit ?? '50')));
|
|
219
|
+
const search = (request.query.search ?? '').trim();
|
|
220
|
+
// `searchByName` matches the diacritic-folded `nameSearch` column, where
|
|
221
|
+
// this picker used to `$ilike` on `name` — so a search for "lodz" now
|
|
222
|
+
// finds "Łódź" here as it already did on the order list.
|
|
223
|
+
const rows = await organizationDetails.searchByName(search, limit);
|
|
224
|
+
return {
|
|
225
|
+
data: {
|
|
226
|
+
items: rows.map((r) => ({ id: r.id, name: r.name, taxId: r.taxId })),
|
|
227
|
+
nextCursor: null,
|
|
228
|
+
},
|
|
229
|
+
};
|
|
230
|
+
});
|
|
231
|
+
app.get('/api/v1/admin/pricing/rule-targets/categories', { preHandler: readGate }, async () => {
|
|
232
|
+
// The port's `listAll` is already ordered by sort order then slug.
|
|
233
|
+
const rows = await catalogCategoryRead.listAll();
|
|
234
|
+
return {
|
|
235
|
+
data: {
|
|
236
|
+
items: rows.map((r) => ({
|
|
237
|
+
id: r.id,
|
|
238
|
+
slug: r.slug,
|
|
239
|
+
name: r.name,
|
|
240
|
+
parentCategoryId: r.parentCategoryId ?? null,
|
|
241
|
+
sortOrder: r.sortOrder,
|
|
242
|
+
})),
|
|
243
|
+
},
|
|
244
|
+
};
|
|
245
|
+
});
|
|
246
|
+
app.get('/api/v1/admin/pricing/rule-targets/currencies', { preHandler: readGate }, async () => {
|
|
247
|
+
const em = emFactory();
|
|
248
|
+
const channels = await em.find(SalesChannel, {});
|
|
249
|
+
const exposed = new Map();
|
|
250
|
+
for (const ch of channels) {
|
|
251
|
+
for (const cur of ch.currencies ?? []) {
|
|
252
|
+
if (typeof cur !== 'string' || cur.length !== 3)
|
|
253
|
+
continue;
|
|
254
|
+
const key = cur.toUpperCase();
|
|
255
|
+
const list = exposed.get(key) ?? [];
|
|
256
|
+
list.push(ch.code);
|
|
257
|
+
exposed.set(key, list);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
const items = [...exposed.entries()]
|
|
261
|
+
.map(([code, exposedByChannels]) => ({ code, exposedByChannels }))
|
|
262
|
+
.sort((a, b) => a.code.localeCompare(b.code));
|
|
263
|
+
return { data: { items } };
|
|
264
|
+
});
|
|
265
|
+
// ---- Linked price-lists panel for the product editor (US8) -------
|
|
266
|
+
app.get('/api/v1/admin/products/:productId/price-lists', { preHandler: readGate }, async (request, reply) => {
|
|
267
|
+
const product = await catalogProductRead.findById(request.params.productId);
|
|
268
|
+
if (!product) {
|
|
269
|
+
reply.status(404);
|
|
270
|
+
return { error: { code: 'NOT_FOUND', message: 'Product not found.' } };
|
|
271
|
+
}
|
|
272
|
+
const items = await priceListService.summarizeBracketsForProduct(request.params.productId);
|
|
273
|
+
return {
|
|
274
|
+
data: {
|
|
275
|
+
items: items.map((it) => ({
|
|
276
|
+
list: {
|
|
277
|
+
id: it.list.id,
|
|
278
|
+
name: it.list.name,
|
|
279
|
+
type: it.list.type,
|
|
280
|
+
status: it.list.status,
|
|
281
|
+
modifiedAt: it.list.modifiedAt.toISOString(),
|
|
282
|
+
},
|
|
283
|
+
summary: it.summary,
|
|
284
|
+
deepLinkPath: it.deepLinkPath,
|
|
285
|
+
})),
|
|
286
|
+
},
|
|
287
|
+
};
|
|
288
|
+
});
|
|
289
|
+
// ---- Display-mode overrides (US7) ----------------------------------
|
|
290
|
+
app.get('/api/v1/admin/pricing/display-mode-overrides', { preHandler: readGate }, async (request) => {
|
|
291
|
+
const items = await priceListService.listDisplayModeOverrides(request.query.scope);
|
|
292
|
+
return {
|
|
293
|
+
data: {
|
|
294
|
+
items: items.map((o) => ({
|
|
295
|
+
scope: o.scope,
|
|
296
|
+
targetId: o.targetId,
|
|
297
|
+
mode: o.mode,
|
|
298
|
+
updatedAt: o.updatedAt.toISOString(),
|
|
299
|
+
})),
|
|
300
|
+
},
|
|
301
|
+
};
|
|
302
|
+
});
|
|
303
|
+
app.get('/api/v1/admin/pricing/display-mode-overrides/:scope/:targetId', { preHandler: readGate }, async (request, reply) => {
|
|
304
|
+
const row = await priceListService.getDisplayModeOverride(request.params.scope, request.params.targetId);
|
|
305
|
+
if (!row) {
|
|
306
|
+
reply.status(404);
|
|
307
|
+
return { error: { code: 'NOT_FOUND', message: 'Override not found.' } };
|
|
308
|
+
}
|
|
309
|
+
return {
|
|
310
|
+
data: {
|
|
311
|
+
scope: row.scope,
|
|
312
|
+
targetId: row.targetId,
|
|
313
|
+
mode: row.mode,
|
|
314
|
+
updatedAt: row.updatedAt.toISOString(),
|
|
315
|
+
},
|
|
316
|
+
};
|
|
317
|
+
});
|
|
318
|
+
app.put('/api/v1/admin/pricing/display-mode-overrides/:scope/:targetId', {
|
|
319
|
+
preHandler: writeGate,
|
|
320
|
+
schema: {
|
|
321
|
+
body: z.object({
|
|
322
|
+
mode: z.enum(['gross_only', 'net_only', 'both', 'none', 'inherit']),
|
|
323
|
+
}),
|
|
324
|
+
},
|
|
325
|
+
}, async (request, reply) => {
|
|
326
|
+
const body = z
|
|
327
|
+
.object({ mode: z.enum(['gross_only', 'net_only', 'both', 'none', 'inherit']) })
|
|
328
|
+
.parse(request.body);
|
|
329
|
+
const row = await priceListService.upsertDisplayModeOverride(request.params.scope, request.params.targetId, body.mode);
|
|
330
|
+
if (!row) {
|
|
331
|
+
return reply.status(204).send();
|
|
332
|
+
}
|
|
333
|
+
return {
|
|
334
|
+
data: {
|
|
335
|
+
scope: row.scope,
|
|
336
|
+
targetId: row.targetId,
|
|
337
|
+
mode: row.mode,
|
|
338
|
+
updatedAt: row.updatedAt.toISOString(),
|
|
339
|
+
},
|
|
340
|
+
};
|
|
341
|
+
});
|
|
342
|
+
// Storefront-public routes live in `routes.storefront.ts` and are mounted
|
|
343
|
+
// separately from `plugin.ts` so the admin and storefront surfaces stay
|
|
344
|
+
// independently auditable. See T025/T026.
|
|
345
|
+
// Test-only sweeper hook — the production code path runs the worker on the
|
|
346
|
+
// BullMQ queue every 5 min. This endpoint lets integration tests advance
|
|
347
|
+
// the state machine without waiting for the queue tick.
|
|
348
|
+
app.post('/api/v1/admin/price-lists-engine/internal/sweep', { preHandler: writeGate }, async () => {
|
|
349
|
+
// The worker reads/writes through the same EM as the rest of the
|
|
350
|
+
// module; constructed here so the route doesn't pin the worker to
|
|
351
|
+
// the module-level construction.
|
|
352
|
+
const { PriceListStatusWorker } = await import('./services/price-list-status-worker.js');
|
|
353
|
+
const worker = new PriceListStatusWorker(emFactory);
|
|
354
|
+
const result = await worker.sweep();
|
|
355
|
+
return { data: result };
|
|
356
|
+
});
|
|
357
|
+
// ---- Admin price resolution for a specific customer -----------------
|
|
358
|
+
// Resolves the effective unit price for a (product, customer/organization)
|
|
359
|
+
// pair so admin-side flows (notably "create quote request on behalf of a
|
|
360
|
+
// customer") can pre-fill the agreed unit price from the customer's price
|
|
361
|
+
// lists instead of leaving the field blank. Mirrors the storefront resolver
|
|
362
|
+
// but threads the customer's organization + group context.
|
|
363
|
+
//
|
|
364
|
+
// D-173 — it is gated on this module's own read code, not on `rfqs:handle`.
|
|
365
|
+
// The caller is the RFQ create screen, but what the endpoint serves is a
|
|
366
|
+
// price-list resolution, and `price_lists` declares itself
|
|
367
|
+
// `nonDeactivatable` while `quote_requests` is switchable: `rfqs:handle`
|
|
368
|
+
// leaves `/admin-roles` the moment an operator switches quote requests off,
|
|
369
|
+
// and this route, which cannot be switched off with it, went on enforcing a
|
|
370
|
+
// code nobody could be granted. That is the consequence D-166 wrote down for
|
|
371
|
+
// the sales-rep endpoints and did not generalise.
|
|
372
|
+
//
|
|
373
|
+
// The label test decides which repair applies: *"Handle quote requests"* is
|
|
374
|
+
// not a sentence about a price-resolution endpoint, so the code does not
|
|
375
|
+
// become shared — the consumer gates on a code it owns. Issue #219 already
|
|
376
|
+
// ruled that a pricing read sits behind `price_lists:read`; a role that
|
|
377
|
+
// handles RFQs and prefills agreed prices holds both, which is why
|
|
378
|
+
// `sales_representative` gains the read code in the dev seed.
|
|
379
|
+
app.get('/api/v1/admin/products/:id/resolved-price', { preHandler: readGate }, async (request, reply) => {
|
|
380
|
+
const em = emFactory();
|
|
381
|
+
const product = await catalogProductRead.findById(request.params.id);
|
|
382
|
+
if (!product) {
|
|
383
|
+
return reply
|
|
384
|
+
.status(404)
|
|
385
|
+
.send({ error: { code: 'NOT_FOUND', message: 'Product not found.' } });
|
|
386
|
+
}
|
|
387
|
+
const customer = request.query.customerAccountId
|
|
388
|
+
? await customerAccountRead.findById(request.query.customerAccountId)
|
|
389
|
+
: null;
|
|
390
|
+
const organizationId = request.query.organizationId ?? customer?.organizationId ?? null;
|
|
391
|
+
const organization = organizationId
|
|
392
|
+
? await organizationDetails.findById(organizationId)
|
|
393
|
+
: null;
|
|
394
|
+
const salesChannel = await em.findOne(SalesChannel, { systemDefault: true });
|
|
395
|
+
if (!salesChannel) {
|
|
396
|
+
return reply
|
|
397
|
+
.status(400)
|
|
398
|
+
.send({ error: { code: 'VALIDATION_FAILED', message: 'No default sales channel.' } });
|
|
399
|
+
}
|
|
400
|
+
const quantity = Math.max(1, Number(request.query.quantity ?? '1') || 1);
|
|
401
|
+
const currency = request.query.currency?.toUpperCase() ?? salesChannel.defaultCurrency;
|
|
402
|
+
const customerGroupId = customer?.customerGroupId ?? organization?.customerGroupId ?? null;
|
|
403
|
+
const resolved = await pricingService.resolveLinePrice({
|
|
404
|
+
product,
|
|
405
|
+
variantId: request.query.variantId ?? null,
|
|
406
|
+
context: {
|
|
407
|
+
quantity,
|
|
408
|
+
organization: organization ?? null,
|
|
409
|
+
customerGroupId,
|
|
410
|
+
salesChannel,
|
|
411
|
+
currencyCode: currency,
|
|
412
|
+
},
|
|
413
|
+
});
|
|
414
|
+
return {
|
|
415
|
+
data: {
|
|
416
|
+
resolvedPrice: resolved
|
|
417
|
+
? {
|
|
418
|
+
amount: resolved.amount,
|
|
419
|
+
currency: resolved.currency,
|
|
420
|
+
isSale: resolved.isSale,
|
|
421
|
+
priceListId: resolved.priceListId,
|
|
422
|
+
}
|
|
423
|
+
: null,
|
|
424
|
+
},
|
|
425
|
+
};
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
function toArray(v) {
|
|
429
|
+
if (v === undefined)
|
|
430
|
+
return [];
|
|
431
|
+
return Array.isArray(v) ? v : [v];
|
|
432
|
+
}
|
|
433
|
+
function serializePriceListEngine(row) {
|
|
434
|
+
return {
|
|
435
|
+
id: row.id,
|
|
436
|
+
name: row.name,
|
|
437
|
+
type: row.type,
|
|
438
|
+
status: row.status,
|
|
439
|
+
startsAt: row.startsAt ? row.startsAt.toISOString() : null,
|
|
440
|
+
endsAt: row.endsAt ? row.endsAt.toISOString() : null,
|
|
441
|
+
applicationRule: row.applicationRule,
|
|
442
|
+
isSystem: row.isSystem,
|
|
443
|
+
modifiedAt: row.modifiedAt.toISOString(),
|
|
444
|
+
createdAt: row.createdAt.toISOString(),
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
//# sourceMappingURL=routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../src/backend/routes.ts"],"names":[],"mappings":"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"}
|