@endora-commerce/mod-carts 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 (155) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +62 -0
  3. package/dist/admin/components/CartApprovalPolicyPanel.d.ts +51 -0
  4. package/dist/admin/components/CartApprovalPolicyPanel.d.ts.map +1 -0
  5. package/dist/admin/components/CartApprovalPolicyPanel.js +59 -0
  6. package/dist/admin/components/CartApprovalPolicyPanel.js.map +1 -0
  7. package/dist/admin/index.d.ts +38 -0
  8. package/dist/admin/index.d.ts.map +1 -0
  9. package/dist/admin/index.js +73 -0
  10. package/dist/admin/index.js.map +1 -0
  11. package/dist/admin/pages/CartDetail.d.ts +3 -0
  12. package/dist/admin/pages/CartDetail.d.ts.map +1 -0
  13. package/dist/admin/pages/CartDetail.js +74 -0
  14. package/dist/admin/pages/CartDetail.js.map +1 -0
  15. package/dist/admin/pages/CartsList.d.ts +3 -0
  16. package/dist/admin/pages/CartsList.d.ts.map +1 -0
  17. package/dist/admin/pages/CartsList.js +90 -0
  18. package/dist/admin/pages/CartsList.js.map +1 -0
  19. package/dist/admin/zones/CartApprovalPolicy.d.ts +29 -0
  20. package/dist/admin/zones/CartApprovalPolicy.d.ts.map +1 -0
  21. package/dist/admin/zones/CartApprovalPolicy.js +11 -0
  22. package/dist/admin/zones/CartApprovalPolicy.js.map +1 -0
  23. package/dist/backend/cli/abandonment-sweep.d.ts +64 -0
  24. package/dist/backend/cli/abandonment-sweep.d.ts.map +1 -0
  25. package/dist/backend/cli/abandonment-sweep.js +17 -0
  26. package/dist/backend/cli/abandonment-sweep.js.map +1 -0
  27. package/dist/backend/entities/cart-audit-entry.entity.d.ts +29 -0
  28. package/dist/backend/entities/cart-audit-entry.entity.d.ts.map +1 -0
  29. package/dist/backend/entities/cart-audit-entry.entity.js +109 -0
  30. package/dist/backend/entities/cart-audit-entry.entity.js.map +1 -0
  31. package/dist/backend/entities/cart-item.entity.d.ts +42 -0
  32. package/dist/backend/entities/cart-item.entity.d.ts.map +1 -0
  33. package/dist/backend/entities/cart-item.entity.js +119 -0
  34. package/dist/backend/entities/cart-item.entity.js.map +1 -0
  35. package/dist/backend/entities/cart.entity.d.ts +96 -0
  36. package/dist/backend/entities/cart.entity.d.ts.map +1 -0
  37. package/dist/backend/entities/cart.entity.js +207 -0
  38. package/dist/backend/entities/cart.entity.js.map +1 -0
  39. package/dist/backend/index.d.ts +122 -0
  40. package/dist/backend/index.d.ts.map +1 -0
  41. package/dist/backend/index.js +184 -0
  42. package/dist/backend/index.js.map +1 -0
  43. package/dist/backend/routes.admin.d.ts +31 -0
  44. package/dist/backend/routes.admin.d.ts.map +1 -0
  45. package/dist/backend/routes.admin.js +95 -0
  46. package/dist/backend/routes.admin.js.map +1 -0
  47. package/dist/backend/routes.d.ts +101 -0
  48. package/dist/backend/routes.d.ts.map +1 -0
  49. package/dist/backend/routes.js +620 -0
  50. package/dist/backend/routes.js.map +1 -0
  51. package/dist/backend/routes.organization.d.ts +29 -0
  52. package/dist/backend/routes.organization.d.ts.map +1 -0
  53. package/dist/backend/routes.organization.js +150 -0
  54. package/dist/backend/routes.organization.js.map +1 -0
  55. package/dist/backend/services/cart-abandonment-settings.d.ts +34 -0
  56. package/dist/backend/services/cart-abandonment-settings.d.ts.map +1 -0
  57. package/dist/backend/services/cart-abandonment-settings.js +55 -0
  58. package/dist/backend/services/cart-abandonment-settings.js.map +1 -0
  59. package/dist/backend/services/cart-abandonment-worker.d.ts +110 -0
  60. package/dist/backend/services/cart-abandonment-worker.d.ts.map +1 -0
  61. package/dist/backend/services/cart-abandonment-worker.js +185 -0
  62. package/dist/backend/services/cart-abandonment-worker.js.map +1 -0
  63. package/dist/backend/services/cart-admin-service.d.ts +58 -0
  64. package/dist/backend/services/cart-admin-service.d.ts.map +1 -0
  65. package/dist/backend/services/cart-admin-service.js +397 -0
  66. package/dist/backend/services/cart-admin-service.js.map +1 -0
  67. package/dist/backend/services/cart-approval-service.d.ts +147 -0
  68. package/dist/backend/services/cart-approval-service.d.ts.map +1 -0
  69. package/dist/backend/services/cart-approval-service.js +242 -0
  70. package/dist/backend/services/cart-approval-service.js.map +1 -0
  71. package/dist/backend/services/cart-audit-service.d.ts +75 -0
  72. package/dist/backend/services/cart-audit-service.d.ts.map +1 -0
  73. package/dist/backend/services/cart-audit-service.js +70 -0
  74. package/dist/backend/services/cart-audit-service.js.map +1 -0
  75. package/dist/backend/services/cart-conversion-service.d.ts +104 -0
  76. package/dist/backend/services/cart-conversion-service.d.ts.map +1 -0
  77. package/dist/backend/services/cart-conversion-service.js +175 -0
  78. package/dist/backend/services/cart-conversion-service.js.map +1 -0
  79. package/dist/backend/services/cart-coupon-service.d.ts +129 -0
  80. package/dist/backend/services/cart-coupon-service.d.ts.map +1 -0
  81. package/dist/backend/services/cart-coupon-service.js +244 -0
  82. package/dist/backend/services/cart-coupon-service.js.map +1 -0
  83. package/dist/backend/services/cart-organization-visibility-service.d.ts +43 -0
  84. package/dist/backend/services/cart-organization-visibility-service.d.ts.map +1 -0
  85. package/dist/backend/services/cart-organization-visibility-service.js +98 -0
  86. package/dist/backend/services/cart-organization-visibility-service.js.map +1 -0
  87. package/dist/backend/services/cart-placement-apply-port.d.ts +38 -0
  88. package/dist/backend/services/cart-placement-apply-port.d.ts.map +1 -0
  89. package/dist/backend/services/cart-placement-apply-port.js +71 -0
  90. package/dist/backend/services/cart-placement-apply-port.js.map +1 -0
  91. package/dist/backend/services/cart-pricing-recompute.d.ts +62 -0
  92. package/dist/backend/services/cart-pricing-recompute.d.ts.map +1 -0
  93. package/dist/backend/services/cart-pricing-recompute.js +131 -0
  94. package/dist/backend/services/cart-pricing-recompute.js.map +1 -0
  95. package/dist/backend/services/cart-query-service.d.ts +29 -0
  96. package/dist/backend/services/cart-query-service.d.ts.map +1 -0
  97. package/dist/backend/services/cart-query-service.js +40 -0
  98. package/dist/backend/services/cart-query-service.js.map +1 -0
  99. package/dist/backend/services/cart-read-port.d.ts +40 -0
  100. package/dist/backend/services/cart-read-port.d.ts.map +1 -0
  101. package/dist/backend/services/cart-read-port.js +144 -0
  102. package/dist/backend/services/cart-read-port.js.map +1 -0
  103. package/dist/backend/services/cart-recompute-cache.d.ts +49 -0
  104. package/dist/backend/services/cart-recompute-cache.d.ts.map +1 -0
  105. package/dist/backend/services/cart-recompute-cache.js +56 -0
  106. package/dist/backend/services/cart-recompute-cache.js.map +1 -0
  107. package/dist/backend/services/cart-service.d.ts +165 -0
  108. package/dist/backend/services/cart-service.d.ts.map +1 -0
  109. package/dist/backend/services/cart-service.js +556 -0
  110. package/dist/backend/services/cart-service.js.map +1 -0
  111. package/dist/backend/services/cart-state-machine.d.ts +51 -0
  112. package/dist/backend/services/cart-state-machine.d.ts.map +1 -0
  113. package/dist/backend/services/cart-state-machine.js +74 -0
  114. package/dist/backend/services/cart-state-machine.js.map +1 -0
  115. package/dist/backend/services/cart-upsell-service.d.ts +57 -0
  116. package/dist/backend/services/cart-upsell-service.d.ts.map +1 -0
  117. package/dist/backend/services/cart-upsell-service.js +100 -0
  118. package/dist/backend/services/cart-upsell-service.js.map +1 -0
  119. package/dist/backend/services/customer-group-resolver.d.ts +27 -0
  120. package/dist/backend/services/customer-group-resolver.d.ts.map +1 -0
  121. package/dist/backend/services/customer-group-resolver.js +32 -0
  122. package/dist/backend/services/customer-group-resolver.js.map +1 -0
  123. package/dist/manifest.d.ts +221 -0
  124. package/dist/manifest.d.ts.map +1 -0
  125. package/dist/manifest.js +224 -0
  126. package/dist/manifest.js.map +1 -0
  127. package/dist/migrations/20260611T140352_carts_consolidation.d.ts +43 -0
  128. package/dist/migrations/20260611T140352_carts_consolidation.d.ts.map +1 -0
  129. package/dist/migrations/20260611T140352_carts_consolidation.js +237 -0
  130. package/dist/migrations/20260611T140352_carts_consolidation.js.map +1 -0
  131. package/dist/migrations/20260611T140413_carts_cart_item_packaging.d.ts +12 -0
  132. package/dist/migrations/20260611T140413_carts_cart_item_packaging.d.ts.map +1 -0
  133. package/dist/migrations/20260611T140413_carts_cart_item_packaging.js +20 -0
  134. package/dist/migrations/20260611T140413_carts_cart_item_packaging.js.map +1 -0
  135. package/dist/migrations/20260818T081253_carts_cart_completed_order_fk.d.ts +50 -0
  136. package/dist/migrations/20260818T081253_carts_cart_completed_order_fk.d.ts.map +1 -0
  137. package/dist/migrations/20260818T081253_carts_cart_completed_order_fk.js +62 -0
  138. package/dist/migrations/20260818T081253_carts_cart_completed_order_fk.js.map +1 -0
  139. package/dist/migrations/20260830T112911_carts_organization_attribution_check.d.ts +67 -0
  140. package/dist/migrations/20260830T112911_carts_organization_attribution_check.d.ts.map +1 -0
  141. package/dist/migrations/20260830T112911_carts_organization_attribution_check.js +121 -0
  142. package/dist/migrations/20260830T112911_carts_organization_attribution_check.js.map +1 -0
  143. package/dist/migrations/index.d.ts +30 -0
  144. package/dist/migrations/index.d.ts.map +1 -0
  145. package/dist/migrations/index.js +35 -0
  146. package/dist/migrations/index.js.map +1 -0
  147. package/dist/ports/index.d.ts +106 -0
  148. package/dist/ports/index.d.ts.map +1 -0
  149. package/dist/ports/index.js +2 -0
  150. package/dist/ports/index.js.map +1 -0
  151. package/docs/carts.md +232 -0
  152. package/i18n/en.json +96 -0
  153. package/i18n/pl.json +96 -0
  154. package/package.json +107 -0
  155. package/tailwind.css +14 -0
@@ -0,0 +1,207 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ import { Entity, Index, OptionalProps, PrimaryKey, Property, Unique } from '@mikro-orm/core';
11
+ import { CustomerScoped } from '@endora-commerce/platform/tenancy';
12
+ import { randomUUID } from 'crypto';
13
+ /**
14
+ * Cart — a buyer's in-progress basket. Owned by a Customer (authenticated)
15
+ * or an anonymous session (cookie-token addressable). Scoped to a Sales
16
+ * Channel (feature 027) so the spec's "one active cart per
17
+ * (Customer, Sales Channel)" rule holds.
18
+ *
19
+ * Status lifecycle (feature 027):
20
+ * active → abandoned (sweep: last_activity_at past threshold)
21
+ * abandoned → active (owner activity)
22
+ * active → completed (checkout success OR cart→QR conversion)
23
+ * active → rejected (org-admin reject OR platform-admin reject)
24
+ *
25
+ * Legacy `converted` was migrated to `completed` by migration 050. Mass
26
+ * code in the repo that previously wrote `'converted'` now writes
27
+ * `'completed'` (CartService.clearForCustomer).
28
+ *
29
+ * `approval_status` is the orthogonal sub-state that gates checkout when
30
+ * the Organization's `requires_cart_approval` policy is `true`. Self-
31
+ * approval exemption: a cart created by an Org Admin is born with
32
+ * `approval_status='not_required'` regardless of the policy. Post-approval
33
+ * mutation re-arms `approved → pending` (see CartApprovalService).
34
+ *
35
+ * `version` is the optimistic-lock token used by the approval / mutation
36
+ * race (buyer-vs-Org-Admin) — aligned with the convention shared by
37
+ * features 003 / 026.
38
+ */
39
+ let Cart = class Cart {
40
+ [OptionalProps];
41
+ id = randomUUID();
42
+ customerAccountId;
43
+ organizationId;
44
+ anonymousCartToken;
45
+ /**
46
+ * Sales channel the cart is scoped to. Backfilled to the system-default
47
+ * channel by migration 050; NULL is read as "system default" until the
48
+ * next consolidation tightens it (see research.md §R3).
49
+ */
50
+ salesChannelId;
51
+ status = 'active';
52
+ approvalStatus = 'not_required';
53
+ submittedForApprovalAt;
54
+ approvedAt;
55
+ approvedByCustomerAccountId;
56
+ rejectedAt;
57
+ /** Free-form `customer:<uuid>` / `admin:<uuid>` / `org_admin:<uuid>`. */
58
+ rejectedByActor;
59
+ rejectedReason;
60
+ /**
61
+ * The Promotion.code the buyer most recently applied to this cart. The
62
+ * resolver in PromotionService.applyToCart consumes this on every read.
63
+ * Persisted even on terminal carts for audit / analytics.
64
+ */
65
+ appliedPromotionCode;
66
+ /**
67
+ * The order this cart produced, set by `placeOrder` beside
68
+ * `status = 'completed'` and inside the placement transaction (D-94.1).
69
+ *
70
+ * The twin of {@link convertedToQuoteRequestId}: the two terminal artefacts
71
+ * a cart can leave behind, and until D-94 only one of them was recorded —
72
+ * asked which order emptied a completed cart, the platform answered by
73
+ * correlating timestamps. `carts_completed_order_fk` holds it
74
+ * (`on delete set null`), for the reason the QR pointer's migration wrote
75
+ * down for its own: deleting the order does not invalidate the fact that
76
+ * the cart was once completed.
77
+ *
78
+ * Nullable, and it stays nullable. It cannot be backfilled — no surviving
79
+ * record says which order emptied which historical cart — and
80
+ * `status = 'completed'` does not imply it: `CartService.clearForCustomer`,
81
+ * the anonymous-merge source and the quote-request conversion all reach
82
+ * `completed` without an order.
83
+ */
84
+ completedOrderId;
85
+ /** Set on Cart → Quote Request conversion (feature 027 US3). */
86
+ convertedToQuoteRequestId;
87
+ /**
88
+ * Idempotency stamp for the abandonment-sweep notification. Cleared on
89
+ * reactivation so the next abandonment cycle can notify again.
90
+ */
91
+ abandonmentNotifiedAt;
92
+ /**
93
+ * Bumped by every buyer-driven add / remove / qty / coupon / explicit
94
+ * page-open. Drives the abandonment sweep. NOT bumped by mini-cart
95
+ * hovers or non-owner inspections (Org-Admin / platform-admin reads).
96
+ */
97
+ lastActivityAt = new Date();
98
+ /** Optimistic-lock token (auto-incremented by MikroORM on every update). */
99
+ version;
100
+ createdAt = new Date();
101
+ updatedAt = new Date();
102
+ };
103
+ __decorate([
104
+ PrimaryKey({ type: 'uuid' }),
105
+ __metadata("design:type", String)
106
+ ], Cart.prototype, "id", void 0);
107
+ __decorate([
108
+ Property({ type: 'uuid', nullable: true }),
109
+ Index(),
110
+ __metadata("design:type", Object)
111
+ ], Cart.prototype, "customerAccountId", void 0);
112
+ __decorate([
113
+ Property({ type: 'uuid', nullable: true }),
114
+ Index(),
115
+ __metadata("design:type", Object)
116
+ ], Cart.prototype, "organizationId", void 0);
117
+ __decorate([
118
+ Property({ type: 'string', length: 64, nullable: true }),
119
+ Unique(),
120
+ __metadata("design:type", Object)
121
+ ], Cart.prototype, "anonymousCartToken", void 0);
122
+ __decorate([
123
+ Property({ type: 'uuid', nullable: true }),
124
+ __metadata("design:type", Object)
125
+ ], Cart.prototype, "salesChannelId", void 0);
126
+ __decorate([
127
+ Property({ type: 'string', length: 16 }),
128
+ __metadata("design:type", String)
129
+ ], Cart.prototype, "status", void 0);
130
+ __decorate([
131
+ Property({ type: 'string', length: 32 }),
132
+ __metadata("design:type", String)
133
+ ], Cart.prototype, "approvalStatus", void 0);
134
+ __decorate([
135
+ Property({ type: 'datetime', nullable: true }),
136
+ __metadata("design:type", Object)
137
+ ], Cart.prototype, "submittedForApprovalAt", void 0);
138
+ __decorate([
139
+ Property({ type: 'datetime', nullable: true }),
140
+ __metadata("design:type", Object)
141
+ ], Cart.prototype, "approvedAt", void 0);
142
+ __decorate([
143
+ Property({ type: 'uuid', nullable: true }),
144
+ __metadata("design:type", Object)
145
+ ], Cart.prototype, "approvedByCustomerAccountId", void 0);
146
+ __decorate([
147
+ Property({ type: 'datetime', nullable: true }),
148
+ __metadata("design:type", Object)
149
+ ], Cart.prototype, "rejectedAt", void 0);
150
+ __decorate([
151
+ Property({ type: 'string', length: 48, nullable: true }),
152
+ __metadata("design:type", Object)
153
+ ], Cart.prototype, "rejectedByActor", void 0);
154
+ __decorate([
155
+ Property({ type: 'text', nullable: true }),
156
+ __metadata("design:type", Object)
157
+ ], Cart.prototype, "rejectedReason", void 0);
158
+ __decorate([
159
+ Property({ type: 'string', length: 64, nullable: true }),
160
+ __metadata("design:type", Object)
161
+ ], Cart.prototype, "appliedPromotionCode", void 0);
162
+ __decorate([
163
+ Property({ type: 'uuid', nullable: true }),
164
+ __metadata("design:type", Object)
165
+ ], Cart.prototype, "completedOrderId", void 0);
166
+ __decorate([
167
+ Property({ type: 'uuid', nullable: true }),
168
+ __metadata("design:type", Object)
169
+ ], Cart.prototype, "convertedToQuoteRequestId", void 0);
170
+ __decorate([
171
+ Property({ type: 'datetime', nullable: true }),
172
+ __metadata("design:type", Object)
173
+ ], Cart.prototype, "abandonmentNotifiedAt", void 0);
174
+ __decorate([
175
+ Property({ type: 'datetime' }),
176
+ __metadata("design:type", Date)
177
+ ], Cart.prototype, "lastActivityAt", void 0);
178
+ __decorate([
179
+ Property({ type: 'integer', version: true }),
180
+ __metadata("design:type", Number)
181
+ ], Cart.prototype, "version", void 0);
182
+ __decorate([
183
+ Property({ type: 'datetime', onCreate: () => new Date() }),
184
+ __metadata("design:type", Date)
185
+ ], Cart.prototype, "createdAt", void 0);
186
+ __decorate([
187
+ Property({ type: 'datetime', onUpdate: () => new Date() }),
188
+ __metadata("design:type", Date)
189
+ ], Cart.prototype, "updatedAt", void 0);
190
+ Cart = __decorate([
191
+ CustomerScoped(),
192
+ Entity({ tableName: 'carts' })
193
+ ], Cart);
194
+ export { Cart };
195
+ export const CART_STATUSES = [
196
+ 'active',
197
+ 'abandoned',
198
+ 'completed',
199
+ 'rejected',
200
+ ];
201
+ export const CART_APPROVAL_STATUSES = [
202
+ 'not_required',
203
+ 'pending',
204
+ 'approved',
205
+ 'rejected_by_org_admin',
206
+ ];
207
+ //# sourceMappingURL=cart.entity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cart.entity.js","sourceRoot":"","sources":["../../../src/backend/entities/cart.entity.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,122 @@
1
+ import type { EntityManager } from '@mikro-orm/postgresql';
2
+ import type { Redis } from 'ioredis';
3
+ import type { AuditPort } from '@endora-commerce/platform/kernel';
4
+ import type { CatalogProductReadPort, CustomerAccountReadPort, LinePricePort, OrganizationDetailsPort, PromotionApplyPort, PromotionCodePort, QuoteRequestReadPort, RfqCustomerPort } from '@endora-commerce/contracts';
5
+ import type { ModuleContext } from '@endora-commerce/platform/kernel';
6
+ import type { OrganizationReadPort } from '@endora-commerce/platform/kernel';
7
+ import type { RequireAdminFactory } from '@endora-commerce/platform/kernel';
8
+ import type { SettingsReadPort } from '@endora-commerce/platform/kernel';
9
+ import { CartService } from './services/cart-service.js';
10
+ import { CartAuditService } from './services/cart-audit-service.js';
11
+ import { CartApprovalService } from './services/cart-approval-service.js';
12
+ import { CartRecomputeCache } from './services/cart-recompute-cache.js';
13
+ import { CartAbandonmentWorker } from './services/cart-abandonment-worker.js';
14
+ import { type CartsDeps } from './routes.js';
15
+ import { CartAuditEntry } from './entities/cart-audit-entry.entity.js';
16
+ import { CartItem } from './entities/cart-item.entity.js';
17
+ import { Cart } from './entities/cart.entity.js';
18
+ /**
19
+ * `carts` — the module that owned 4593 lines and registered none of them
20
+ * (feature 072, wave 3, T136).
21
+ *
22
+ * Every service here was constructed inside `orders/plugin.ts`, and most of them
23
+ * **conditionally**: `options.auditLogService ? new CartAuditService(…) :
24
+ * undefined`, and so on down a chain where each `undefined` disabled the next
25
+ * thing. That made feature availability a function of which arguments a
26
+ * composition root happened to pass, which is the defect T141's task text names
27
+ * for `orders` and which `languages` produced in wave 1 as a live bug.
28
+ *
29
+ * The stake was not theoretical. Without `CartRecomputeCache` there is no
30
+ * `CartPricingRecompute`, so every full-cart read returns the snapshotted
31
+ * `unit_price` instead of a re-resolved engine price. Without `CartAuditService`
32
+ * there is no `CartApprovalService`, so the organization approval routes never
33
+ * registered at all — the route *surface* was a function of arguments, the same
34
+ * finding `shopping_lists` produced in T133.
35
+ *
36
+ * All thirteen registrations are unconditional now. `auditLogService` and
37
+ * `redis` are kernel-owned names, so there is nothing left to branch on.
38
+ *
39
+ * **`cartService` is a port, and the outward edge is a different one.** Four
40
+ * modules read the cart service — `orders`, `shopping_lists`, `quick_order` and
41
+ * this module's own routes — and all four sit downstream in the manifest graph,
42
+ * so it is an ordinary `providePort`. What points *outward* is
43
+ * `pushLineToShoppingList` / `appendShoppingListToCart`: `carts` reaching into
44
+ * `shopping_lists`, which cannot be a port because `shopping_lists → orders →
45
+ * carts` would close a cycle. That is {@link CartsCradle.cartShoppingListBridge}
46
+ * — a contribution point **this module owns**, defaulted to a refusal naming the
47
+ * absent module, which is the direction `shipmentEmailSender` uses and the
48
+ * mirror image of the `shoppingListServiceSink` this conversion retires.
49
+ *
50
+ * The `RfqService` `Proxy` that lived in `orders/plugin.ts` is gone with it:
51
+ * it existed only to late-bind a service that `quote_requests` has provided as
52
+ * a real port since T132.
53
+ *
54
+ * The two abandonment settings are read here, through the settings port, rather
55
+ * than resolved by each root. They are `carts.abandonment.*` — this module's own
56
+ * knobs — and the identical try/catch-to-default stood in both compositions.
57
+ */
58
+ /**
59
+ * How this composition reaches `shopping_lists`, which `carts` may not import.
60
+ *
61
+ * Both shapes are taken from the route module's own option types rather than
62
+ * restated, so a change there is a type error here instead of a drift.
63
+ */
64
+ export interface CartShoppingListBridge {
65
+ readonly pushLineToShoppingList: NonNullable<CartsDeps['pushLineToShoppingList']>;
66
+ readonly appendShoppingListToCart: NonNullable<CartsDeps['appendShoppingListToCart']>;
67
+ }
68
+ /** What `carts` resolves from the container, and the names it owns. */
69
+ export interface CartsCradle {
70
+ readonly emFactory: () => EntityManager;
71
+ readonly auditLogService: AuditPort;
72
+ readonly redis: Redis;
73
+ readonly requireAdmin: RequireAdminFactory;
74
+ readonly settingsReadPort: SettingsReadPort;
75
+ /**
76
+ * Feature 075, Phase C — the six ports every service here used to reach by
77
+ * importing another module's class or entity. Each is a contract type from
78
+ * `@endora-commerce/contracts`, never the provider's class, and each is resolved lazily
79
+ * by a string literal so a switched-off owner answers at the call.
80
+ */
81
+ readonly pricingService: LinePricePort;
82
+ readonly promotionService: PromotionApplyPort;
83
+ readonly promotionCodePort: PromotionCodePort;
84
+ readonly rfqService: RfqCustomerPort;
85
+ readonly quoteRequestReadPort: QuoteRequestReadPort;
86
+ readonly catalogProductReadPort: CatalogProductReadPort;
87
+ readonly customerAccountReadPort: CustomerAccountReadPort;
88
+ readonly organizationDetailsPort: OrganizationDetailsPort;
89
+ /** Root-shaped: production reads `request.actor`, the harness `request.testActor`. */
90
+ readonly cartActorResolver: CartsDeps['resolveCartActor'];
91
+ /**
92
+ * The tenancy read port (T138). Was `organizationTransactGuard`, a closure
93
+ * each root wrote over `OrganizationContextService` — and which the harness
94
+ * registered as `async () => undefined`, so feature 026's rule that an
95
+ * unapproved Organization may not transact was enforced in production and by
96
+ * no test at all.
97
+ */
98
+ readonly organizationReadPort: OrganizationReadPort;
99
+ /** Contribution point: absent means save-to-list and list-to-cart refuse. */
100
+ readonly cartShoppingListBridge: CartShoppingListBridge;
101
+ /** Contribution point: absent means the sweep flips status and sends nothing. */
102
+ readonly cartAbandonmentNotifier: ConstructorParameters<typeof CartAbandonmentWorker>[0]['dispatchNotification'] | undefined;
103
+ readonly cartService: CartService;
104
+ readonly cartAuditService: CartAuditService;
105
+ readonly cartApprovalService: CartApprovalService;
106
+ readonly cartRecomputeCache: CartRecomputeCache;
107
+ readonly cartAbandonmentWorker: CartAbandonmentWorker;
108
+ }
109
+ export declare function registerModule(ctx: ModuleContext): void;
110
+ /**
111
+ * The module's persisted entity classes, on the `./backend` subpath, as one
112
+ * array and **no named class export** (D-168).
113
+ *
114
+ * This is the shape the platform reads when the package is *installed*: the
115
+ * boot-time loader (`src/packages/package-runtime.ts`, `exported['entities']`)
116
+ * and the static declaration reader (`scripts/lib/package-declarations.ts`),
117
+ * which is the third source of `check:module-boundary`'s `table→owner` map and
118
+ * the package pass of `check-entity-tenant-classification`. A missing array is
119
+ * answered with `[]` — zero entities registered, no error anywhere.
120
+ */
121
+ export declare const entities: (typeof Cart | typeof CartItem | typeof CartAuditEntry)[];
122
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/backend/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,184 @@
1
+ import { ERROR_CODES } from '@endora-commerce/contracts';
2
+ import { HttpError } from '@endora-commerce/platform/http';
3
+ import { lazyPort } from '@endora-commerce/platform/kernel';
4
+ import { abandonmentSettingsReaders } from './services/cart-abandonment-settings.js';
5
+ import { CartQueryService } from './services/cart-query-service.js';
6
+ import { CartPlacementApplyService } from './services/cart-placement-apply-port.js';
7
+ import { CartReadService, createCartWritePort } from './services/cart-read-port.js';
8
+ import { CartService } from './services/cart-service.js';
9
+ import { CartUpsellService } from './services/cart-upsell-service.js';
10
+ import { CartCouponService } from './services/cart-coupon-service.js';
11
+ import { CartConversionService } from './services/cart-conversion-service.js';
12
+ import { CartAdminService } from './services/cart-admin-service.js';
13
+ import { CartAuditService } from './services/cart-audit-service.js';
14
+ import { CartApprovalService } from './services/cart-approval-service.js';
15
+ import { CartOrganizationVisibilityService } from './services/cart-organization-visibility-service.js';
16
+ import { CartRecomputeCache } from './services/cart-recompute-cache.js';
17
+ import { CartPricingRecompute } from './services/cart-pricing-recompute.js';
18
+ import { CartAbandonmentWorker } from './services/cart-abandonment-worker.js';
19
+ import { registerCartRoutes } from './routes.js';
20
+ import { registerCartsAdminRoutes } from './routes.admin.js';
21
+ import { registerCartsOrganizationRoutes } from './routes.organization.js';
22
+ import { CartAuditEntry } from './entities/cart-audit-entry.entity.js';
23
+ import { CartItem } from './entities/cart-item.entity.js';
24
+ import { Cart } from './entities/cart.entity.js';
25
+ /** Refuses in the shape Constitution XVII item 3 requires: an explicit 503. */
26
+ function refuseShoppingList() {
27
+ const refuse = async () => {
28
+ throw new HttpError(503, ERROR_CODES.MODULE_DISABLED, 'Shopping lists are not available in this deployment.', { module: 'shopping_lists' });
29
+ };
30
+ return { pushLineToShoppingList: refuse, appendShoppingListToCart: refuse };
31
+ }
32
+ export function registerModule(ctx) {
33
+ ctx.di.register({
34
+ // Contribution point, defaulted to a refusal that names the absent module
35
+ // rather than a 404 that does not.
36
+ cartShoppingListBridge: ctx
37
+ .asFunction(() => refuseShoppingList())
38
+ .singleton(),
39
+ // Contribution point: a deployment with no outbound mail flips the cart's
40
+ // status and sends nothing, which is a coherent state.
41
+ cartAbandonmentNotifier: ctx
42
+ .asFunction(() => undefined)
43
+ .singleton(),
44
+ cartRecomputeCache: ctx
45
+ .asFunction(({ redis }) => new CartRecomputeCache(redis))
46
+ .singleton(),
47
+ cartAuditService: ctx
48
+ .asFunction(({ emFactory, auditLogService }) => new CartAuditService(emFactory, auditLogService))
49
+ .singleton(),
50
+ cartApprovalService: ctx
51
+ .asFunction(({ emFactory, cartAuditService }) => new CartApprovalService(emFactory, cartAuditService, lazyPort(ctx, 'organizationDetailsPort'), lazyPort(ctx, 'organizationCartApprovalWritePort'), lazyPort(ctx, 'customerAccountReadPort')))
52
+ .singleton(),
53
+ cartAbandonmentWorker: ctx
54
+ .asFunction(({ emFactory, cartAuditService }) => new CartAbandonmentWorker({
55
+ emFactory,
56
+ cartAuditService,
57
+ /**
58
+ * This module's own settings, read through the port it holds — the
59
+ * identical try/catch-to-default stood in both roots before T136,
60
+ * and in the ops CLI until issue #54. It lives in one file now
61
+ * (`services/cart-abandonment-settings.ts`), which also carries the
62
+ * D-41/D-43 history of what these two reads used to get wrong.
63
+ *
64
+ * The thunk is what keeps the port read lazy: a gate captured into
65
+ * this singleton would keep answering after `settings` is switched
66
+ * off.
67
+ */
68
+ ...abandonmentSettingsReaders(() => ctx.cradle().settingsReadPort),
69
+ dispatchNotification: async (input) => {
70
+ await ctx.cradle().cartAbandonmentNotifier?.(input);
71
+ },
72
+ }))
73
+ .singleton(),
74
+ });
75
+ ctx.di.providePort('cartService', ctx
76
+ .asFunction(({ emFactory, cartApprovalService, cartAuditService, cartRecomputeCache }) => new CartService(emFactory, lazyPort(ctx, 'pricingService'), lazyPort(ctx, 'catalogProductReadPort'), lazyPort(ctx, 'organizationDetailsPort'), lazyPort(ctx, 'salesChannelMembershipPort'), cartApprovalService, cartAuditService, cartRecomputeCache))
77
+ .singleton());
78
+ // ---------------------------------------------------------------------------
79
+ // Feature 075, Phase P — the published surface.
80
+ //
81
+ // `cartService` above hands out the class, and five modules type themselves
82
+ // against it. These three are what they rewire to: none carries a `Cart` or
83
+ // a `CartItem` across the boundary, and `cartWritePort` adds the one
84
+ // operation two of them were writing by hand — clear the customer's active
85
+ // cart and seed it with these lines, which `orders`' reorder and
86
+ // `quote_requests`' quote conversion each spelled out with `em.create(Cart,
87
+ // …)` against this module's tables.
88
+ // ---------------------------------------------------------------------------
89
+ ctx.di.providePort('cartReadPort', ctx.asFunction(({ emFactory }) => new CartReadService(emFactory)).singleton());
90
+ ctx.di.providePort('cartWritePort', ctx
91
+ .asFunction(({ emFactory }) => createCartWritePort(emFactory, () => ctx.cradle().cartService))
92
+ .singleton());
93
+ /**
94
+ * The basket half of order placement, on the **caller's** `EntityManager`
95
+ * (feature 080, T048; D-169).
96
+ *
97
+ * `orders` imported this module's `Cart` and `CartItem` classes for it until
98
+ * T048 — a co-transactional seam D-78 point 2 ruled permanent and D-94.1
99
+ * settled with `carts_completed_order_fk`. The constraint and the transaction
100
+ * are unchanged; what moved is the four statements, to the module that owns
101
+ * the two tables. `CartPlacementApplyPort` is declared in this module's
102
+ * `ports/` directory rather than in `@endora-commerce/contracts`, because its
103
+ * methods take a MikroORM `EntityManager` and FR-034 keeps that package free
104
+ * of them.
105
+ *
106
+ * It sits beside `cartReadPort` rather than replacing it: that port is the
107
+ * standalone read, on this module's own `EntityManager`, and `orders`' total
108
+ * preview is its consumer. The doc block on `CartReadPort` predicted both
109
+ * halves of this arrangement and asked whoever settled the escalation to
110
+ * write the real consumer down; T048 is that settlement.
111
+ */
112
+ ctx.di.providePort('cartPlacementApplyPort', ctx.asFunction(() => new CartPlacementApplyService()).singleton());
113
+ ctx.di.providePort('cartQueryPort', ctx.asFunction(({ emFactory }) => new CartQueryService(emFactory)).singleton());
114
+ ctx.routes(async (app) => {
115
+ const cradle = ctx.cradle();
116
+ const emFactory = cradle.emFactory;
117
+ const resolveCartActor = (req) => ctx.cradle().cartActorResolver(req);
118
+ // Lazily, even though the module owns this port: route *registration* runs
119
+ // inside `buildServer` whatever the module's effective state is, so reading
120
+ // the gate here — through the cradle alias above, which is how it stayed
121
+ // invisible to `check-port-dependencies` — would stop the next start
122
+ // instead of stopping the routes (D-40).
123
+ const cartService = lazyPort(ctx, 'cartService');
124
+ await registerCartRoutes(app, {
125
+ emFactory,
126
+ resolveCartActor,
127
+ cartService,
128
+ catalogProducts: lazyPort(ctx, 'catalogProductReadPort'),
129
+ cartUpsellService: new CartUpsellService(emFactory, lazyPort(ctx, 'catalogProductReadPort')),
130
+ cartCouponService: new CartCouponService(emFactory, lazyPort(ctx, 'promotionService'), lazyPort(ctx, 'promotionCodePort'), lazyPort(ctx, 'customerAccountReadPort'), lazyPort(ctx, 'organizationDetailsPort'), cradle.cartApprovalService),
131
+ cartConversionService: new CartConversionService(emFactory, cartService, lazyPort(ctx, 'rfqService'), lazyPort(ctx, 'quoteRequestReadPort'), lazyPort(ctx, 'catalogProductReadPort'), lazyPort(ctx, 'salesChannelMembershipPort')),
132
+ cartPricingRecompute: new CartPricingRecompute(emFactory, lazyPort(ctx, 'pricingService'), cradle.cartRecomputeCache, lazyPort(ctx, 'catalogProductReadPort'), lazyPort(ctx, 'organizationDetailsPort')),
133
+ assertOrganizationCanTransact: async (organizationId) => {
134
+ await ctx.cradle().organizationReadPort.assertCanTransact(organizationId);
135
+ },
136
+ pushLineToShoppingList: (input) => ctx.cradle().cartShoppingListBridge.pushLineToShoppingList(input),
137
+ appendShoppingListToCart: (input) => ctx.cradle().cartShoppingListBridge.appendShoppingListToCart(input),
138
+ });
139
+ // Registered unconditionally. Before T136 these two mounted only when the
140
+ // chain of optional arguments happened to reach them, so an approval or
141
+ // admin surface could be absent with nothing saying so; the module's own
142
+ // activation control is the intentional gate now.
143
+ await registerCartsOrganizationRoutes(app, {
144
+ emFactory,
145
+ resolveCartActor,
146
+ cartService,
147
+ cartApprovalService: cradle.cartApprovalService,
148
+ customerAccounts: lazyPort(ctx, 'customerAccountReadPort'),
149
+ visibilityService: new CartOrganizationVisibilityService(emFactory, lazyPort(ctx, 'customerAccountReadPort')),
150
+ });
151
+ await registerCartsAdminRoutes(app, {
152
+ requireAdmin: cradle.requireAdmin,
153
+ cartAdminService: new CartAdminService(emFactory, cradle.cartAuditService, lazyPort(ctx, 'customerAccountReadPort'), lazyPort(ctx, 'organizationDetailsPort'), lazyPort(ctx, 'catalogProductReadPort'), lazyPort(ctx, 'promotionService')),
154
+ cartApprovalService: cradle.cartApprovalService,
155
+ resolveAdminUserId: (req) => {
156
+ const prodActor = req.actor;
157
+ if (prodActor?.kind === 'admin' && prodActor.adminUserId)
158
+ return prodActor.adminUserId;
159
+ const testActor = req
160
+ .testActor;
161
+ if (testActor?.kind === 'admin' && testActor.adminUserId)
162
+ return testActor.adminUserId;
163
+ return null;
164
+ },
165
+ });
166
+ });
167
+ }
168
+ /**
169
+ * The module's persisted entity classes, on the `./backend` subpath, as one
170
+ * array and **no named class export** (D-168).
171
+ *
172
+ * This is the shape the platform reads when the package is *installed*: the
173
+ * boot-time loader (`src/packages/package-runtime.ts`, `exported['entities']`)
174
+ * and the static declaration reader (`scripts/lib/package-declarations.ts`),
175
+ * which is the third source of `check:module-boundary`'s `table→owner` map and
176
+ * the package pass of `check-entity-tenant-classification`. A missing array is
177
+ * answered with `[]` — zero entities registered, no error anywhere.
178
+ */
179
+ export const entities = [
180
+ CartAuditEntry,
181
+ CartItem,
182
+ Cart,
183
+ ];
184
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/backend/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ import type { FastifyInstance, FastifyRequest } from 'fastify';
2
+ import type { CartAdminService } from './services/cart-admin-service.js';
3
+ import type { CartApprovalService } from './services/cart-approval-service.js';
4
+ import type { RequireAdminFactory } from '@endora-commerce/platform/kernel';
5
+ /**
6
+ * Admin Carts routes (feature 027 US6).
7
+ *
8
+ * - GET /api/v1/admin/carts carts:read
9
+ * - GET /api/v1/admin/carts/:id carts:read
10
+ * - GET /api/v1/admin/carts/:id/audit carts:read
11
+ * - POST /api/v1/admin/carts/:id/reject carts:reject
12
+ * - GET /api/v1/admin/organizations/:id/cart-approval-policy customers:manage
13
+ * - PATCH /api/v1/admin/organizations/:id/cart-approval-policy customers:manage
14
+ */
15
+ export interface CartsAdminRoutesDeps {
16
+ cartAdminService: CartAdminService;
17
+ /**
18
+ * Feature 027 US4 — platform-admin proxy for the per-Organization
19
+ * `requires_cart_approval` policy. Optional so legacy compositions
20
+ * still build; production wires it.
21
+ */
22
+ cartApprovalService?: CartApprovalService;
23
+ requireAdmin: RequireAdminFactory;
24
+ /**
25
+ * Resolves the admin user id from the authenticated session. Used as
26
+ * the `actor` on the audit-log row for the reject action.
27
+ */
28
+ resolveAdminUserId: (req: FastifyRequest) => string | null;
29
+ }
30
+ export declare function registerCartsAdminRoutes(app: FastifyInstance, deps: CartsAdminRoutesDeps): Promise<void>;
31
+ //# sourceMappingURL=routes.admin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.admin.d.ts","sourceRoot":"","sources":["../../src/backend/routes.admin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAO/D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACzE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAC;AAE/E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAE5E;;;;;;;;;GASG;AAEH,MAAM,WAAW,oBAAoB;IACnC,gBAAgB,EAAE,gBAAgB,CAAC;IACnC;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,mBAAmB,CAAC;IAC1C,YAAY,EAAE,mBAAmB,CAAC;IAClC;;;OAGG;IACH,kBAAkB,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,MAAM,GAAG,IAAI,CAAC;CAC5D;AAED,wBAAsB,wBAAwB,CAC5C,GAAG,EAAE,eAAe,EACpB,IAAI,EAAE,oBAAoB,GACzB,OAAO,CAAC,IAAI,CAAC,CA6Hf"}