@endora-commerce/mod-quick-order 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.
Files changed (119) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +58 -0
  3. package/dist/admin/api/quick-order-client.d.ts +76 -0
  4. package/dist/admin/api/quick-order-client.d.ts.map +1 -0
  5. package/dist/admin/api/quick-order-client.js +18 -0
  6. package/dist/admin/api/quick-order-client.js.map +1 -0
  7. package/dist/admin/components/DefaultPreferencesPanel.d.ts +44 -0
  8. package/dist/admin/components/DefaultPreferencesPanel.d.ts.map +1 -0
  9. package/dist/admin/components/DefaultPreferencesPanel.js +107 -0
  10. package/dist/admin/components/DefaultPreferencesPanel.js.map +1 -0
  11. package/dist/admin/index.d.ts +48 -0
  12. package/dist/admin/index.d.ts.map +1 -0
  13. package/dist/admin/index.js +120 -0
  14. package/dist/admin/index.js.map +1 -0
  15. package/dist/admin/pages/QuickOrderOnBehalfPage.d.ts +16 -0
  16. package/dist/admin/pages/QuickOrderOnBehalfPage.d.ts.map +1 -0
  17. package/dist/admin/pages/QuickOrderOnBehalfPage.js +85 -0
  18. package/dist/admin/pages/QuickOrderOnBehalfPage.js.map +1 -0
  19. package/dist/admin/zones/CustomerDefaults.d.ts +27 -0
  20. package/dist/admin/zones/CustomerDefaults.d.ts.map +1 -0
  21. package/dist/admin/zones/CustomerDefaults.js +11 -0
  22. package/dist/admin/zones/CustomerDefaults.js.map +1 -0
  23. package/dist/admin/zones/OrderEntryQuickTab.d.ts +21 -0
  24. package/dist/admin/zones/OrderEntryQuickTab.d.ts.map +1 -0
  25. package/dist/admin/zones/OrderEntryQuickTab.js +26 -0
  26. package/dist/admin/zones/OrderEntryQuickTab.js.map +1 -0
  27. package/dist/admin/zones/OrganizationDefaults.d.ts +30 -0
  28. package/dist/admin/zones/OrganizationDefaults.d.ts.map +1 -0
  29. package/dist/admin/zones/OrganizationDefaults.js +11 -0
  30. package/dist/admin/zones/OrganizationDefaults.js.map +1 -0
  31. package/dist/backend/entities/quick-order-default-preference.entity.d.ts +22 -0
  32. package/dist/backend/entities/quick-order-default-preference.entity.d.ts.map +1 -0
  33. package/dist/backend/entities/quick-order-default-preference.entity.js +76 -0
  34. package/dist/backend/entities/quick-order-default-preference.entity.js.map +1 -0
  35. package/dist/backend/index.d.ts +88 -0
  36. package/dist/backend/index.d.ts.map +1 -0
  37. package/dist/backend/index.js +235 -0
  38. package/dist/backend/index.js.map +1 -0
  39. package/dist/backend/routes.admin.d.ts +35 -0
  40. package/dist/backend/routes.admin.d.ts.map +1 -0
  41. package/dist/backend/routes.admin.js +64 -0
  42. package/dist/backend/routes.admin.js.map +1 -0
  43. package/dist/backend/routes.d.ts +35 -0
  44. package/dist/backend/routes.d.ts.map +1 -0
  45. package/dist/backend/routes.js +77 -0
  46. package/dist/backend/routes.js.map +1 -0
  47. package/dist/backend/routes.one-click.d.ts +22 -0
  48. package/dist/backend/routes.one-click.d.ts.map +1 -0
  49. package/dist/backend/routes.one-click.js +35 -0
  50. package/dist/backend/routes.one-click.js.map +1 -0
  51. package/dist/backend/routes.preferences.admin.d.ts +23 -0
  52. package/dist/backend/routes.preferences.admin.d.ts.map +1 -0
  53. package/dist/backend/routes.preferences.admin.js +40 -0
  54. package/dist/backend/routes.preferences.admin.js.map +1 -0
  55. package/dist/backend/routes.preferences.d.ts +21 -0
  56. package/dist/backend/routes.preferences.d.ts.map +1 -0
  57. package/dist/backend/routes.preferences.js +42 -0
  58. package/dist/backend/routes.preferences.js.map +1 -0
  59. package/dist/backend/services/catalog-lookup.d.ts +39 -0
  60. package/dist/backend/services/catalog-lookup.d.ts.map +1 -0
  61. package/dist/backend/services/catalog-lookup.js +104 -0
  62. package/dist/backend/services/catalog-lookup.js.map +1 -0
  63. package/dist/backend/services/default-preference-authz.d.ts +31 -0
  64. package/dist/backend/services/default-preference-authz.d.ts.map +1 -0
  65. package/dist/backend/services/default-preference-authz.js +26 -0
  66. package/dist/backend/services/default-preference-authz.js.map +1 -0
  67. package/dist/backend/services/default-preference-resolver.d.ts +28 -0
  68. package/dist/backend/services/default-preference-resolver.d.ts.map +1 -0
  69. package/dist/backend/services/default-preference-resolver.js +27 -0
  70. package/dist/backend/services/default-preference-resolver.js.map +1 -0
  71. package/dist/backend/services/default-preference-service.d.ts +63 -0
  72. package/dist/backend/services/default-preference-service.d.ts.map +1 -0
  73. package/dist/backend/services/default-preference-service.js +176 -0
  74. package/dist/backend/services/default-preference-service.js.map +1 -0
  75. package/dist/backend/services/excel-importer.d.ts +11 -0
  76. package/dist/backend/services/excel-importer.d.ts.map +1 -0
  77. package/dist/backend/services/excel-importer.js +47 -0
  78. package/dist/backend/services/excel-importer.js.map +1 -0
  79. package/dist/backend/services/import-from-request.d.ts +9 -0
  80. package/dist/backend/services/import-from-request.d.ts.map +1 -0
  81. package/dist/backend/services/import-from-request.js +17 -0
  82. package/dist/backend/services/import-from-request.js.map +1 -0
  83. package/dist/backend/services/import-pipeline.d.ts +89 -0
  84. package/dist/backend/services/import-pipeline.d.ts.map +1 -0
  85. package/dist/backend/services/import-pipeline.js +188 -0
  86. package/dist/backend/services/import-pipeline.js.map +1 -0
  87. package/dist/backend/services/import-rows.d.ts +43 -0
  88. package/dist/backend/services/import-rows.d.ts.map +1 -0
  89. package/dist/backend/services/import-rows.js +102 -0
  90. package/dist/backend/services/import-rows.js.map +1 -0
  91. package/dist/backend/services/one-click-service.d.ts +50 -0
  92. package/dist/backend/services/one-click-service.d.ts.map +1 -0
  93. package/dist/backend/services/one-click-service.js +83 -0
  94. package/dist/backend/services/one-click-service.js.map +1 -0
  95. package/dist/backend/services/quick-order-build-service.d.ts +35 -0
  96. package/dist/backend/services/quick-order-build-service.d.ts.map +1 -0
  97. package/dist/backend/services/quick-order-build-service.js +61 -0
  98. package/dist/backend/services/quick-order-build-service.js.map +1 -0
  99. package/dist/backend/services/variant-resolver.d.ts +40 -0
  100. package/dist/backend/services/variant-resolver.d.ts.map +1 -0
  101. package/dist/backend/services/variant-resolver.js +47 -0
  102. package/dist/backend/services/variant-resolver.js.map +1 -0
  103. package/dist/manifest.d.ts +190 -0
  104. package/dist/manifest.d.ts.map +1 -0
  105. package/dist/manifest.js +129 -0
  106. package/dist/manifest.js.map +1 -0
  107. package/dist/migrations/20260611T140359_quick_order_default_preferences.d.ts +15 -0
  108. package/dist/migrations/20260611T140359_quick_order_default_preferences.d.ts.map +1 -0
  109. package/dist/migrations/20260611T140359_quick_order_default_preferences.js +53 -0
  110. package/dist/migrations/20260611T140359_quick_order_default_preferences.js.map +1 -0
  111. package/dist/migrations/index.d.ts +27 -0
  112. package/dist/migrations/index.d.ts.map +1 -0
  113. package/dist/migrations/index.js +29 -0
  114. package/dist/migrations/index.js.map +1 -0
  115. package/docs/quick_order.md +98 -0
  116. package/i18n/en.json +47 -0
  117. package/i18n/pl.json +47 -0
  118. package/package.json +91 -0
  119. package/tailwind.css +14 -0
@@ -0,0 +1,83 @@
1
+ import { ERROR_CODES, } from '@endora-commerce/contracts';
2
+ import { HttpError } from '@endora-commerce/platform/http';
3
+ /**
4
+ * OneClickService (feature 039, US5). Computes whether the one-click button
5
+ * should show, and places a one-click order by reusing the platform's
6
+ * established single-active-cart flow: clear the cart, add the chosen product,
7
+ * then run `OrderService.placeOrder` with the buyer's resolved default methods
8
+ * and addresses. All order validation (org active, minimum value, credit limit,
9
+ * stock) and the payment-routing `nextAction` come from `placeOrder` (FR-029 /
10
+ * FR-030); no parallel ordering path (FR-031).
11
+ *
12
+ * Both collaborators are `@endora-commerce/contracts` ports since feature 075's Phase C —
13
+ * `cartWritePort` and `orderPlacementPort`. The lazy `() => OrderService | null`
14
+ * accessor is gone with them: the port's gate answers 503 `MODULE_DISABLED`
15
+ * when `orders` is not present, which is the same refusal the `null` branch
16
+ * spelled by hand, except that a `null` accessor was indistinguishable from a
17
+ * wiring mistake. `placeOrder` answers `PlacedOrderRecord`, which is
18
+ * `OrderRecord` **plus** `nextAction` — the payment routing this reply exists
19
+ * to carry.
20
+ *
21
+ * **The channel is a per-call argument, not a constructor default** (issue #99,
22
+ * D-48). It used to be `salesChannelId: string = 'default'` — a fifth
23
+ * constructor parameter `backend.ts` never passed, so every deployment read the
24
+ * setting against a channel *code*, tripped the settings seam guard, and
25
+ * reported `setting_disabled` indistinguishably from an operator having
26
+ * switched one-click buy off. The routes read the channel the canonical
27
+ * resolver put on the request and hand it down; `null` means there is none, and
28
+ * then the setting is read platform-wide (D-41 case c) and the order records no
29
+ * channel rather than an invented one.
30
+ */
31
+ export class OneClickService {
32
+ preferenceService;
33
+ cartWrite;
34
+ orderPlacement;
35
+ resolveOneClickEnabled;
36
+ constructor(preferenceService, cartWrite, orderPlacement, resolveOneClickEnabled) {
37
+ this.preferenceService = preferenceService;
38
+ this.cartWrite = cartWrite;
39
+ this.orderPlacement = orderPlacement;
40
+ this.resolveOneClickEnabled = resolveOneClickEnabled;
41
+ }
42
+ async eligibility(customerAccountId, salesChannelId) {
43
+ const enabled = await this.resolveOneClickEnabled(salesChannelId);
44
+ if (!enabled)
45
+ return { enabled: false, reason: 'setting_disabled' };
46
+ const defaults = await this.preferenceService.resolveForCustomer(customerAccountId);
47
+ if (!defaults.paymentMethodId ||
48
+ !defaults.deliveryMethodId ||
49
+ !defaults.billingAddressId ||
50
+ !defaults.shippingAddressId) {
51
+ return { enabled: false, reason: 'missing_defaults' };
52
+ }
53
+ return { enabled: true, reason: null };
54
+ }
55
+ async place(ctx, input, salesChannelId) {
56
+ const eligibility = await this.eligibility(ctx.customerAccountId, salesChannelId);
57
+ if (!eligibility.enabled) {
58
+ throw new HttpError(422, ERROR_CODES.VALIDATION_FAILED, 'One-click buy is not available.', {
59
+ code: 'one_click_unavailable',
60
+ reason: eligibility.reason,
61
+ });
62
+ }
63
+ const defaults = await this.preferenceService.resolveForCustomer(ctx.customerAccountId);
64
+ const customerCtx = { customerAccountId: ctx.customerAccountId, organizationId: ctx.organizationId };
65
+ // Clear-then-seed matches the single-active-cart model used by admin
66
+ // order-create and RFQ-convert.
67
+ await this.cartWrite.clearForCustomer(customerCtx);
68
+ await this.cartWrite.addItem({ customer: customerCtx }, {
69
+ productId: input.productId,
70
+ ...(input.variantId ? { variantId: input.variantId } : {}),
71
+ quantity: input.quantity ?? 1,
72
+ });
73
+ return this.orderPlacement.placeOrder(customerCtx, {
74
+ deliveryAddressId: defaults.shippingAddressId,
75
+ billingAddressId: defaults.billingAddressId,
76
+ deliveryMethodId: defaults.deliveryMethodId,
77
+ paymentMethodId: defaults.paymentMethodId,
78
+ ...(salesChannelId ? { salesChannelId } : {}),
79
+ ...(input.idempotencyKey ? { idempotencyKey: input.idempotencyKey } : {}),
80
+ });
81
+ }
82
+ }
83
+ //# sourceMappingURL=one-click-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"one-click-service.js","sourceRoot":"","sources":["../../../src/backend/services/one-click-service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import { type CartWritePort, type QuickOrderBuildResponse, type QuickOrderTarget, type RfqCustomerPort } from '@endora-commerce/contracts';
2
+ /**
3
+ * Context for a quick-order build. `organizationId` may be null for a no-org
4
+ * customer (carts tolerate this; quote requests require an organization).
5
+ */
6
+ export interface QuickOrderBuildContext {
7
+ customerAccountId: string;
8
+ organizationId: string | null;
9
+ isOrgAdmin?: boolean;
10
+ }
11
+ export interface QuickOrderBuildLineInput {
12
+ productId: string;
13
+ variantId?: string | null;
14
+ quantity: number;
15
+ }
16
+ /**
17
+ * QuickOrderBuildService (feature 039, US1). Turns a confirmed set of
18
+ * recognized lines into either a Cart (via {@link CartWritePort}) or a Quote
19
+ * Request (via {@link RfqCustomerPort}) — reusing the owning modules' surfaces
20
+ * rather than a parallel ordering path (FR-031). Pricing is owned by those
21
+ * modules (the buyer's / organization's current price list), never the import
22
+ * file (FR-007).
23
+ */
24
+ export declare class QuickOrderBuildService {
25
+ private readonly cartWrite;
26
+ private readonly rfq;
27
+ constructor(cartWrite: CartWritePort, rfq: RfqCustomerPort);
28
+ build(ctx: QuickOrderBuildContext, input: {
29
+ target: QuickOrderTarget;
30
+ items: QuickOrderBuildLineInput[];
31
+ }): Promise<QuickOrderBuildResponse>;
32
+ private buildCart;
33
+ private buildQuoteRequest;
34
+ }
35
+ //# sourceMappingURL=quick-order-build-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quick-order-build-service.d.ts","sourceRoot":"","sources":["../../../src/backend/services/quick-order-build-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,aAAa,EAClB,KAAK,uBAAuB,EAC5B,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACrB,MAAM,4BAA4B,CAAC;AAGpC;;;GAGG;AACH,MAAM,WAAW,sBAAsB;IACrC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;GAOG;AACH,qBAAa,sBAAsB;IAE/B,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,GAAG;gBADH,SAAS,EAAE,aAAa,EACxB,GAAG,EAAE,eAAe;IAGjC,KAAK,CACT,GAAG,EAAE,sBAAsB,EAC3B,KAAK,EAAE;QAAE,MAAM,EAAE,gBAAgB,CAAC;QAAC,KAAK,EAAE,wBAAwB,EAAE,CAAA;KAAE,GACrE,OAAO,CAAC,uBAAuB,CAAC;YAWrB,SAAS;YAmBT,iBAAiB;CA+BhC"}
@@ -0,0 +1,61 @@
1
+ import { ERROR_CODES, } from '@endora-commerce/contracts';
2
+ import { HttpError } from '@endora-commerce/platform/http';
3
+ /**
4
+ * QuickOrderBuildService (feature 039, US1). Turns a confirmed set of
5
+ * recognized lines into either a Cart (via {@link CartWritePort}) or a Quote
6
+ * Request (via {@link RfqCustomerPort}) — reusing the owning modules' surfaces
7
+ * rather than a parallel ordering path (FR-031). Pricing is owned by those
8
+ * modules (the buyer's / organization's current price list), never the import
9
+ * file (FR-007).
10
+ */
11
+ export class QuickOrderBuildService {
12
+ cartWrite;
13
+ rfq;
14
+ constructor(cartWrite, rfq) {
15
+ this.cartWrite = cartWrite;
16
+ this.rfq = rfq;
17
+ }
18
+ async build(ctx, input) {
19
+ if (input.items.length === 0) {
20
+ throw new HttpError(422, ERROR_CODES.VALIDATION_FAILED, 'No items to build.');
21
+ }
22
+ if (input.target === 'cart') {
23
+ return this.buildCart(ctx, input.items);
24
+ }
25
+ return this.buildQuoteRequest(ctx, input.items);
26
+ }
27
+ async buildCart(ctx, items) {
28
+ const customer = { customerAccountId: ctx.customerAccountId, organizationId: ctx.organizationId };
29
+ const cart = await this.cartWrite.getOrCreateForCustomer(customer);
30
+ for (const item of items) {
31
+ await this.cartWrite.addItem({ customer }, {
32
+ productId: item.productId,
33
+ ...(item.variantId ? { variantId: item.variantId } : {}),
34
+ quantity: item.quantity,
35
+ });
36
+ }
37
+ return { target: 'cart', cartId: cart.id, checkoutUrl: `/checkout?cartId=${cart.id}` };
38
+ }
39
+ async buildQuoteRequest(ctx, items) {
40
+ if (!ctx.organizationId) {
41
+ throw new HttpError(422, ERROR_CODES.VALIDATION_FAILED, 'A quote request requires an organization.');
42
+ }
43
+ const rfq = await this.rfq.createForCustomer({
44
+ customerAccountId: ctx.customerAccountId,
45
+ organizationId: ctx.organizationId,
46
+ isOrgAdmin: ctx.isOrgAdmin ?? false,
47
+ }, {
48
+ items: items.map((item) => ({
49
+ productId: item.productId,
50
+ ...(item.variantId ? { variantId: item.variantId } : {}),
51
+ quantity: item.quantity,
52
+ })),
53
+ });
54
+ return {
55
+ target: 'quote_request',
56
+ quoteRequestId: rfq.id,
57
+ quoteRequestBusinessId: rfq.businessId,
58
+ };
59
+ }
60
+ }
61
+ //# sourceMappingURL=quick-order-build-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quick-order-build-service.js","sourceRoot":"","sources":["../../../src/backend/services/quick-order-build-service.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,GAKZ,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAkB3D;;;;;;;GAOG;AACH,MAAM,OAAO,sBAAsB;IAEd;IACA;IAFnB,YACmB,SAAwB,EACxB,GAAoB;QADpB,cAAS,GAAT,SAAS,CAAe;QACxB,QAAG,GAAH,GAAG,CAAiB;IACpC,CAAC;IAEJ,KAAK,CAAC,KAAK,CACT,GAA2B,EAC3B,KAAsE;QAEtE,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7B,MAAM,IAAI,SAAS,CAAC,GAAG,EAAE,WAAW,CAAC,iBAAiB,EAAE,oBAAoB,CAAC,CAAC;QAChF,CAAC;QAED,IAAI,KAAK,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;YAC5B,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;QAC1C,CAAC;QACD,OAAO,IAAI,CAAC,iBAAiB,CAAC,GAAG,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;IAClD,CAAC;IAEO,KAAK,CAAC,SAAS,CACrB,GAA2B,EAC3B,KAAiC;QAEjC,MAAM,QAAQ,GAAG,EAAE,iBAAiB,EAAE,GAAG,CAAC,iBAAiB,EAAE,cAAc,EAAE,GAAG,CAAC,cAAc,EAAE,CAAC;QAClG,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,sBAAsB,CAAC,QAAQ,CAAC,CAAC;QACnE,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,CAC1B,EAAE,QAAQ,EAAE,EACZ;gBACE,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACxD,QAAQ,EAAE,IAAI,CAAC,QAAQ;aACxB,CACF,CAAC;QACJ,CAAC;QACD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,WAAW,EAAE,oBAAoB,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC;IACzF,CAAC;IAEO,KAAK,CAAC,iBAAiB,CAC7B,GAA2B,EAC3B,KAAiC;QAEjC,IAAI,CAAC,GAAG,CAAC,cAAc,EAAE,CAAC;YACxB,MAAM,IAAI,SAAS,CACjB,GAAG,EACH,WAAW,CAAC,iBAAiB,EAC7B,2CAA2C,CAC5C,CAAC;QACJ,CAAC;QACD,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,iBAAiB,CAC1C;YACE,iBAAiB,EAAE,GAAG,CAAC,iBAAiB;YACxC,cAAc,EAAE,GAAG,CAAC,cAAc;YAClC,UAAU,EAAE,GAAG,CAAC,UAAU,IAAI,KAAK;SACpC,EACD;YACE,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;gBAC1B,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACxD,QAAQ,EAAE,IAAI,CAAC,QAAQ;aACxB,CAAC,CAAC;SACJ,CACF,CAAC;QACF,OAAO;YACL,MAAM,EAAE,eAAe;YACvB,cAAc,EAAE,GAAG,CAAC,EAAE;YACtB,sBAAsB,EAAE,GAAG,CAAC,UAAU;SACvC,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Variant resolution for quick-order imports (feature 039, FR-003).
3
+ *
4
+ * Given the variants of a parent product and the attribute values supplied
5
+ * on an import row (the columns beyond `sku` / `quantity`), decide which
6
+ * concrete variant the row refers to. Matching is exact-after-normalize
7
+ * against the parent's variant-axis attribute keys
8
+ * (`ProductVariant.variantAttributeValues`).
9
+ *
10
+ * Pure function — no DB access. The caller fetches the variants and feeds
11
+ * them in, which keeps the matching rule unit-testable.
12
+ */
13
+ export interface VariantLike {
14
+ id: string;
15
+ sku: string;
16
+ variantAttributeValues: Record<string, unknown>;
17
+ }
18
+ export type VariantResolution = {
19
+ kind: 'no_variants';
20
+ } | {
21
+ kind: 'resolved';
22
+ variantId: string;
23
+ variantSku: string;
24
+ } | {
25
+ kind: 'not_resolved';
26
+ } | {
27
+ kind: 'ambiguous';
28
+ };
29
+ /**
30
+ * Resolve a variant from the row's attribute columns.
31
+ *
32
+ * - No variants on the product → `no_variants` (caller adds the base product;
33
+ * extra attribute columns are ignored, per the spec edge case).
34
+ * - Exactly one variant matches every supplied (key, value) → `resolved`.
35
+ * - Zero matches → `not_resolved`.
36
+ * - More than one match (including the case where no axis values were
37
+ * supplied for a multi-variant product) → `ambiguous`.
38
+ */
39
+ export declare function resolveVariant(variants: VariantLike[], requestedAttributes: Record<string, string>): VariantResolution;
40
+ //# sourceMappingURL=variant-resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"variant-resolver.d.ts","sourceRoot":"","sources":["../../../src/backend/services/variant-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,sBAAsB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjD;AAED,MAAM,MAAM,iBAAiB,GACzB;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,GACvB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAC3D;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE,GACxB;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,CAAC;AAS1B;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,WAAW,EAAE,EACvB,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC1C,iBAAiB,CAsBnB"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Variant resolution for quick-order imports (feature 039, FR-003).
3
+ *
4
+ * Given the variants of a parent product and the attribute values supplied
5
+ * on an import row (the columns beyond `sku` / `quantity`), decide which
6
+ * concrete variant the row refers to. Matching is exact-after-normalize
7
+ * against the parent's variant-axis attribute keys
8
+ * (`ProductVariant.variantAttributeValues`).
9
+ *
10
+ * Pure function — no DB access. The caller fetches the variants and feeds
11
+ * them in, which keeps the matching rule unit-testable.
12
+ */
13
+ /** Lower-case + trim for case-insensitive axis comparison. */
14
+ function normalize(value) {
15
+ return String(value ?? '')
16
+ .trim()
17
+ .toLowerCase();
18
+ }
19
+ /**
20
+ * Resolve a variant from the row's attribute columns.
21
+ *
22
+ * - No variants on the product → `no_variants` (caller adds the base product;
23
+ * extra attribute columns are ignored, per the spec edge case).
24
+ * - Exactly one variant matches every supplied (key, value) → `resolved`.
25
+ * - Zero matches → `not_resolved`.
26
+ * - More than one match (including the case where no axis values were
27
+ * supplied for a multi-variant product) → `ambiguous`.
28
+ */
29
+ export function resolveVariant(variants, requestedAttributes) {
30
+ if (variants.length === 0)
31
+ return { kind: 'no_variants' };
32
+ const requested = Object.entries(requestedAttributes)
33
+ .map(([key, value]) => [key.trim().toLowerCase(), normalize(value)])
34
+ .filter(([, value]) => value.length > 0);
35
+ const matches = variants.filter((variant) => {
36
+ const axes = new Map(Object.entries(variant.variantAttributeValues).map(([key, value]) => [key.trim().toLowerCase(), normalize(value)]));
37
+ return requested.every(([key, value]) => axes.get(key) === value);
38
+ });
39
+ if (matches.length === 1) {
40
+ const [only] = matches;
41
+ return { kind: 'resolved', variantId: only.id, variantSku: only.sku };
42
+ }
43
+ if (matches.length === 0)
44
+ return { kind: 'not_resolved' };
45
+ return { kind: 'ambiguous' };
46
+ }
47
+ //# sourceMappingURL=variant-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"variant-resolver.js","sourceRoot":"","sources":["../../../src/backend/services/variant-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAcH,8DAA8D;AAC9D,SAAS,SAAS,CAAC,KAAc;IAC/B,OAAO,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC;SACvB,IAAI,EAAE;SACN,WAAW,EAAE,CAAC;AACnB,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,cAAc,CAC5B,QAAuB,EACvB,mBAA2C;IAE3C,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC;IAE1D,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,CAAC,mBAAmB,CAAC;SAClD,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,SAAS,CAAC,KAAK,CAAC,CAAU,CAAC;SAC5E,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAE3C,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE;QAC1C,MAAM,IAAI,GAAG,IAAI,GAAG,CAClB,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,sBAAsB,CAAC,CAAC,GAAG,CAChD,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,SAAS,CAAC,KAAK,CAAC,CAAU,CACxE,CACF,CAAC;QACF,OAAO,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;IAEH,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC;QACvB,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,IAAK,CAAC,EAAE,EAAE,UAAU,EAAE,IAAK,CAAC,GAAG,EAAE,CAAC;IAC1E,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC;IAC1D,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;AAC/B,CAAC"}
@@ -0,0 +1,190 @@
1
+ /**
2
+ * Quick Order module — manifest (Module Lifecycle, feature 018) extended for
3
+ * feature 039.
4
+ *
5
+ * Settings (feature 039):
6
+ * - quick_order.one_click_buy_enabled — gates the storefront one-click-buy
7
+ * button. Sales-channel-scoped (each channel may override the global
8
+ * value); default off.
9
+ * - quick_order.import_max_rows — upper bound on rows accepted by a single
10
+ * CSV / Excel import. Global.
11
+ *
12
+ * Setting codes follow the foundation regex `^[a-z][a-z0-9_][a-z0-9_.]*[a-z0-9]$`.
13
+ */
14
+ export declare const QUICK_ORDER_SETTING_CODES: {
15
+ readonly ONE_CLICK_BUY_ENABLED: "quick_order.one_click_buy_enabled";
16
+ readonly IMPORT_MAX_ROWS: "quick_order.import_max_rows";
17
+ };
18
+ /**
19
+ * The manifest default, exported so the read that has to degrade degrades to
20
+ * *this* binding (feature 072, D-43). `backend.ts` kept its own `2000`; the two
21
+ * agreed, which is the drift waiting to happen.
22
+ */
23
+ export declare const DEFAULT_IMPORT_MAX_ROWS = 2000;
24
+ /**
25
+ * Same binding, for the one-click gate (issue #99). The read that has to
26
+ * degrade degrades to *this*, not to a `false` written a second time beside the
27
+ * manifest's `defaultValue`.
28
+ */
29
+ export declare const DEFAULT_ONE_CLICK_BUY_ENABLED = false;
30
+ export declare const manifest: {
31
+ id: string;
32
+ name: string;
33
+ version: string;
34
+ dependencies: string[];
35
+ description?: string | undefined;
36
+ acknowledgedDependencies?: {
37
+ moduleId: string;
38
+ port: string;
39
+ reason: string;
40
+ }[] | undefined;
41
+ nonBindingDependencies?: {
42
+ moduleId: string;
43
+ name: string;
44
+ kind: "contributes-to" | "degrades-without" | "refuses-without";
45
+ reason: string;
46
+ whenAbsent?: string | undefined;
47
+ }[] | undefined;
48
+ activation?: {
49
+ settingCode: string;
50
+ default: boolean;
51
+ } | {
52
+ nonDeactivatable: true;
53
+ reason: string;
54
+ } | undefined;
55
+ settings?: {
56
+ moduleCode: string;
57
+ groups: {
58
+ code: string;
59
+ name: string;
60
+ salesChannelCodes?: string[] | undefined;
61
+ isSystemProtected?: boolean | undefined;
62
+ }[];
63
+ settings: {
64
+ code: string;
65
+ name: string;
66
+ valueType: "string" | "number" | "boolean" | "json" | "string_list" | "secret" | "credential_ref";
67
+ defaultValue: unknown;
68
+ description?: string | undefined;
69
+ groupCode?: string | undefined;
70
+ previousDefaultValues?: unknown[] | undefined;
71
+ salesChannelCodes?: string[] | undefined;
72
+ enumOptions?: string[] | undefined;
73
+ configurationType?: string | undefined;
74
+ hidden?: boolean | undefined;
75
+ }[];
76
+ } | undefined;
77
+ i18n?: {
78
+ bundlesDir: string;
79
+ } | undefined;
80
+ docs?: false | {
81
+ dir: string;
82
+ } | undefined;
83
+ demo?: false | {
84
+ summary: string;
85
+ seed: (context: import("@endora-commerce/contracts").ModuleDemoContext<never>) => Promise<import("@endora-commerce/contracts").DemoSeedResult>;
86
+ reset: (context: import("@endora-commerce/contracts").ModuleDemoContext<never>) => Promise<import("@endora-commerce/contracts").DemoResetResult>;
87
+ after?: readonly string[] | undefined;
88
+ package?: string | undefined;
89
+ } | undefined;
90
+ actions?: {
91
+ id: string;
92
+ labelKey: string;
93
+ icon: "Plus" | "Sparkles" | "Settings" | "Search" | "Boxes" | "Layers" | "Menu" | "PlusCircle" | "PlusSquare" | "FilePlus" | "FolderPlus" | "Upload" | "FileUp" | "CloudUpload" | "Download" | "FileDown" | "FileText" | "BookOpen" | "Rss" | "Package" | "Tag" | "ShoppingCart" | "Receipt" | "CreditCard" | "Users" | "UserPlus" | "Inbox" | "ListChecks" | "ClipboardList" | "Image" | "Video" | "LayoutDashboard" | "PanelLeft" | "KeyRound" | "ShieldCheck" | "Edit" | "Archive" | "Box" | "Truck" | "CircleDollarSign" | "Activity" | "LineChart" | "Smartphone" | "Webhook" | "Scale" | "PlugZap" | "PercentDiamond" | "Newspaper" | "Languages" | "Eraser" | "Warehouse" | "TrendingDown" | "Bell" | "PackageOpen" | "Building2" | "Store" | "ClipboardCheck";
94
+ targetRoute: string;
95
+ keywords: string[];
96
+ weight: number;
97
+ descriptionKey?: string | undefined;
98
+ requiredPermission?: string | undefined;
99
+ }[] | undefined;
100
+ permissions?: {
101
+ code: string;
102
+ label: string;
103
+ module?: string | undefined;
104
+ description?: string | undefined;
105
+ requires?: string[] | undefined;
106
+ }[] | undefined;
107
+ transactionalEmails?: {
108
+ code: string;
109
+ name: string;
110
+ variables: {
111
+ key: string;
112
+ label: string;
113
+ sampleValue?: string | undefined;
114
+ description?: string | undefined;
115
+ }[];
116
+ description?: string | undefined;
117
+ group?: string | undefined;
118
+ }[] | undefined;
119
+ capabilities?: string[] | undefined;
120
+ exclusiveCapabilities?: {
121
+ key: string;
122
+ errorCode: string;
123
+ }[] | undefined;
124
+ errorCodes?: {
125
+ code: string;
126
+ tokens?: string[] | undefined;
127
+ }[] | undefined;
128
+ blocks?: {
129
+ name: string;
130
+ labelKey: string;
131
+ category: string;
132
+ contexts: ("email" | "invoice" | "cms" | "newsletter")[];
133
+ fields: Record<string, {
134
+ type: "number" | "object" | "array" | "text" | "textarea" | "select" | "radio" | "external" | "uuid" | "richtext";
135
+ label?: string | undefined;
136
+ required?: boolean | undefined;
137
+ options?: {
138
+ label: string;
139
+ value: string | number;
140
+ }[] | undefined;
141
+ refKind?: string | undefined;
142
+ }>;
143
+ descriptionKey?: string | undefined;
144
+ defaultProps?: Record<string, unknown> | undefined;
145
+ responsiveFields?: string[] | undefined;
146
+ previewIcon?: string | undefined;
147
+ weight?: number | undefined;
148
+ }[] | undefined;
149
+ blockCategories?: {
150
+ key: string;
151
+ titleKey: string;
152
+ contexts: ("email" | "invoice" | "cms" | "newsletter")[];
153
+ weight?: number | undefined;
154
+ visible?: boolean | undefined;
155
+ }[] | undefined;
156
+ env?: {
157
+ name: string;
158
+ describes: {
159
+ en: string;
160
+ pl: string;
161
+ };
162
+ requirement: {
163
+ kind: "required";
164
+ } | {
165
+ kind: "requiredWhen";
166
+ input: string;
167
+ equals: string;
168
+ } | {
169
+ kind: "optional";
170
+ without: {
171
+ en: string;
172
+ pl: string;
173
+ };
174
+ };
175
+ secret: boolean;
176
+ generable: boolean;
177
+ owner: {
178
+ kind: "platform";
179
+ } | {
180
+ kind: "application";
181
+ application: "admin" | "backend" | "storefront";
182
+ } | {
183
+ kind: "module";
184
+ moduleId: string;
185
+ };
186
+ consumers: ("admin" | "backend" | "storefront")[];
187
+ addressOf: "admin" | "backend" | "storefront" | null;
188
+ }[] | undefined;
189
+ };
190
+ //# sourceMappingURL=manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;GAYG;AAEH,eAAO,MAAM,yBAAyB;;;CAG5B,CAAC;AAEX;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,OAAO,CAAC;AAE5C;;;;GAIG;AACH,eAAO,MAAM,6BAA6B,QAAQ,CAAC;AA2BnD,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8EnB,CAAC"}
@@ -0,0 +1,129 @@
1
+ import { defineModuleManifest, defineModuleSettingsManifest } from '@endora-commerce/contracts';
2
+ /**
3
+ * Quick Order module — manifest (Module Lifecycle, feature 018) extended for
4
+ * feature 039.
5
+ *
6
+ * Settings (feature 039):
7
+ * - quick_order.one_click_buy_enabled — gates the storefront one-click-buy
8
+ * button. Sales-channel-scoped (each channel may override the global
9
+ * value); default off.
10
+ * - quick_order.import_max_rows — upper bound on rows accepted by a single
11
+ * CSV / Excel import. Global.
12
+ *
13
+ * Setting codes follow the foundation regex `^[a-z][a-z0-9_][a-z0-9_.]*[a-z0-9]$`.
14
+ */
15
+ export const QUICK_ORDER_SETTING_CODES = {
16
+ ONE_CLICK_BUY_ENABLED: 'quick_order.one_click_buy_enabled',
17
+ IMPORT_MAX_ROWS: 'quick_order.import_max_rows',
18
+ };
19
+ /**
20
+ * The manifest default, exported so the read that has to degrade degrades to
21
+ * *this* binding (feature 072, D-43). `backend.ts` kept its own `2000`; the two
22
+ * agreed, which is the drift waiting to happen.
23
+ */
24
+ export const DEFAULT_IMPORT_MAX_ROWS = 2000;
25
+ /**
26
+ * Same binding, for the one-click gate (issue #99). The read that has to
27
+ * degrade degrades to *this*, not to a `false` written a second time beside the
28
+ * manifest's `defaultValue`.
29
+ */
30
+ export const DEFAULT_ONE_CLICK_BUY_ENABLED = false;
31
+ const settings = defineModuleSettingsManifest({
32
+ moduleCode: 'quick_order',
33
+ groups: [{ code: 'quick_order', name: 'Quick Order' }],
34
+ settings: [
35
+ {
36
+ code: QUICK_ORDER_SETTING_CODES.ONE_CLICK_BUY_ENABLED,
37
+ name: 'One-click buy enabled',
38
+ description: 'When enabled, buyers with all four default ordering preferences set see a "Buy in one click" button on product pages. The per-channel value overrides the global value.',
39
+ groupCode: 'quick_order',
40
+ valueType: 'boolean',
41
+ defaultValue: DEFAULT_ONE_CLICK_BUY_ENABLED,
42
+ },
43
+ {
44
+ code: QUICK_ORDER_SETTING_CODES.IMPORT_MAX_ROWS,
45
+ name: 'Import row limit',
46
+ description: 'Maximum number of data rows accepted by a single CSV / Excel quick-order import. Rows beyond the limit are rejected.',
47
+ groupCode: 'quick_order',
48
+ valueType: 'number',
49
+ defaultValue: DEFAULT_IMPORT_MAX_ROWS,
50
+ },
51
+ ],
52
+ });
53
+ export const manifest = defineModuleManifest({
54
+ id: 'quick_order',
55
+ name: 'Quick Order',
56
+ description: 'Bulk Cart / Quote Request import (CSV + Excel, with variants), quick product search, reorder, default ordering preferences, and one-click buy.',
57
+ version: '2.0.0',
58
+ // Feature 072 (T139) — the six edges the module actually resolves, declared
59
+ // now that it composes itself rather than being mounted by `shopping_lists`.
60
+ // `carts`, `catalog`, `orders`, `organizations` and `quote_requests` were all
61
+ // reached before through options the host passed down, which is why none of
62
+ // them appeared here.
63
+ //
64
+ // Feature 075, Phase C adds `customer_accounts`: the two preference surfaces
65
+ // read `CustomerAccount` to work out whose defaults are being managed, out of
66
+ // a table deactivation leaves in place, so an operator switching accounts off
67
+ // still got an answer. It fails closed at `customerAccountReadPort` now, and
68
+ // it belongs in `dependencies` rather than `nonBindingDependencies` — a set
69
+ // of ordering defaults resolved without knowing whose they are is worse than
70
+ // no defaults at all.
71
+ dependencies: [
72
+ 'addresses',
73
+ 'carts',
74
+ 'catalog',
75
+ 'customer_accounts',
76
+ 'delivery_methods',
77
+ 'orders',
78
+ 'organizations',
79
+ 'payment_methods',
80
+ 'quote_requests',
81
+ 'settings',
82
+ ],
83
+ // D-44 — real to the container, binding on no operator.
84
+ nonBindingDependencies: [
85
+ {
86
+ moduleId: 'customers',
87
+ name: 'customerAddressReadPort',
88
+ kind: 'degrades-without',
89
+ whenAbsent: 'a personal (buyer-owned) address stops being an eligible ordering default; the ' +
90
+ 'organisation’s shared addresses still resolve, and one-click buy hides itself for ' +
91
+ 'buyers whose default was personal',
92
+ reason: 'Issue #216 — the personal-address branch of the default-eligibility check reads ' +
93
+ '`customers`’ address book, and it is probed on every eligibility question. Failing ' +
94
+ 'closed would answer 503 for the whole preference resolution, and with it one-click ' +
95
+ 'buy for *every* buyer, because a CRM surface was switched off. The degrade is not ' +
96
+ 'invented for the occasion: Principle XVII says an absent module behaves as if never ' +
97
+ 'installed, and on a platform without `customers` there are no personal addresses — ' +
98
+ 'only org-shared ones are eligible. Dropping an ineligible default to null is what ' +
99
+ 'FR-020 already specifies. Reached through a presence probe ahead of the port, per ' +
100
+ 'call, because a closed gate throws rather than answering null and an operator ' +
101
+ 'switching the module back on must not need a restart.',
102
+ },
103
+ ],
104
+ // Feature 073 (Constitution XVII) — its own activation control at last.
105
+ // Until T139 this module had no presence of its own: `shopping_lists` mounted
106
+ // its routes, so `shopping_lists.enabled` switched both off together and
107
+ // there was no way to run CSV import without shopping lists, or the reverse.
108
+ // Deactivatable, and not close to the line — bulk import, reorder and
109
+ // one-click buy are a convenience layer over ordering, and a deployment whose
110
+ // buyers order line by line is an ordinary one.
111
+ activation: { settingCode: 'quick_order.enabled', default: true },
112
+ settings,
113
+ i18n: { bundlesDir: 'i18n' },
114
+ docs: { dir: 'docs' },
115
+ actions: [
116
+ {
117
+ id: 'open-quick-order',
118
+ labelKey: 'actions.openQuickOrder.label',
119
+ descriptionKey: 'actions.openQuickOrder.description',
120
+ icon: 'FileUp',
121
+ targetRoute: '/orders/quick-order',
122
+ // The admin quick-order routes are gated on orders:write.
123
+ requiredPermission: 'orders:write',
124
+ keywords: ['quick order', 'import', 'csv', 'szybkie zamówienie', 'import csv'],
125
+ weight: 226,
126
+ },
127
+ ],
128
+ });
129
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import { Migration } from '@mikro-orm/migrations';
2
+ /**
3
+ * Quick-order default ordering preferences (feature 039 — US2).
4
+ *
5
+ * One row per target (`scope` = organization | customer, `scope_id` = its id)
6
+ * holding four nullable default references. A customer row overrides the
7
+ * organization row per field; resolution is in the service. FKs are
8
+ * `ON DELETE SET NULL` so removing a method / address degrades the default to
9
+ * "unset" rather than blocking (FR-020).
10
+ */
11
+ export declare class Migration20260611T140359QuickOrderDefaultPreferences extends Migration {
12
+ up(): Promise<void>;
13
+ down(): Promise<void>;
14
+ }
15
+ //# sourceMappingURL=20260611T140359_quick_order_default_preferences.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"20260611T140359_quick_order_default_preferences.d.ts","sourceRoot":"","sources":["../../src/migrations/20260611T140359_quick_order_default_preferences.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAElD;;;;;;;;GAQG;AACH,qBAAa,oDAAqD,SAAQ,SAAS;IAClE,EAAE,IAAI,OAAO,CAAC,IAAI,CAAC;IAwCnB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAGrC"}