@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.
- package/LICENSE +21 -0
- package/README.md +62 -0
- package/dist/admin/components/CartApprovalPolicyPanel.d.ts +51 -0
- package/dist/admin/components/CartApprovalPolicyPanel.d.ts.map +1 -0
- package/dist/admin/components/CartApprovalPolicyPanel.js +59 -0
- package/dist/admin/components/CartApprovalPolicyPanel.js.map +1 -0
- package/dist/admin/index.d.ts +38 -0
- package/dist/admin/index.d.ts.map +1 -0
- package/dist/admin/index.js +73 -0
- package/dist/admin/index.js.map +1 -0
- package/dist/admin/pages/CartDetail.d.ts +3 -0
- package/dist/admin/pages/CartDetail.d.ts.map +1 -0
- package/dist/admin/pages/CartDetail.js +74 -0
- package/dist/admin/pages/CartDetail.js.map +1 -0
- package/dist/admin/pages/CartsList.d.ts +3 -0
- package/dist/admin/pages/CartsList.d.ts.map +1 -0
- package/dist/admin/pages/CartsList.js +90 -0
- package/dist/admin/pages/CartsList.js.map +1 -0
- package/dist/admin/zones/CartApprovalPolicy.d.ts +29 -0
- package/dist/admin/zones/CartApprovalPolicy.d.ts.map +1 -0
- package/dist/admin/zones/CartApprovalPolicy.js +11 -0
- package/dist/admin/zones/CartApprovalPolicy.js.map +1 -0
- package/dist/backend/cli/abandonment-sweep.d.ts +64 -0
- package/dist/backend/cli/abandonment-sweep.d.ts.map +1 -0
- package/dist/backend/cli/abandonment-sweep.js +17 -0
- package/dist/backend/cli/abandonment-sweep.js.map +1 -0
- package/dist/backend/entities/cart-audit-entry.entity.d.ts +29 -0
- package/dist/backend/entities/cart-audit-entry.entity.d.ts.map +1 -0
- package/dist/backend/entities/cart-audit-entry.entity.js +109 -0
- package/dist/backend/entities/cart-audit-entry.entity.js.map +1 -0
- package/dist/backend/entities/cart-item.entity.d.ts +42 -0
- package/dist/backend/entities/cart-item.entity.d.ts.map +1 -0
- package/dist/backend/entities/cart-item.entity.js +119 -0
- package/dist/backend/entities/cart-item.entity.js.map +1 -0
- package/dist/backend/entities/cart.entity.d.ts +96 -0
- package/dist/backend/entities/cart.entity.d.ts.map +1 -0
- package/dist/backend/entities/cart.entity.js +207 -0
- package/dist/backend/entities/cart.entity.js.map +1 -0
- package/dist/backend/index.d.ts +122 -0
- package/dist/backend/index.d.ts.map +1 -0
- package/dist/backend/index.js +184 -0
- package/dist/backend/index.js.map +1 -0
- package/dist/backend/routes.admin.d.ts +31 -0
- package/dist/backend/routes.admin.d.ts.map +1 -0
- package/dist/backend/routes.admin.js +95 -0
- package/dist/backend/routes.admin.js.map +1 -0
- package/dist/backend/routes.d.ts +101 -0
- package/dist/backend/routes.d.ts.map +1 -0
- package/dist/backend/routes.js +620 -0
- package/dist/backend/routes.js.map +1 -0
- package/dist/backend/routes.organization.d.ts +29 -0
- package/dist/backend/routes.organization.d.ts.map +1 -0
- package/dist/backend/routes.organization.js +150 -0
- package/dist/backend/routes.organization.js.map +1 -0
- package/dist/backend/services/cart-abandonment-settings.d.ts +34 -0
- package/dist/backend/services/cart-abandonment-settings.d.ts.map +1 -0
- package/dist/backend/services/cart-abandonment-settings.js +55 -0
- package/dist/backend/services/cart-abandonment-settings.js.map +1 -0
- package/dist/backend/services/cart-abandonment-worker.d.ts +110 -0
- package/dist/backend/services/cart-abandonment-worker.d.ts.map +1 -0
- package/dist/backend/services/cart-abandonment-worker.js +185 -0
- package/dist/backend/services/cart-abandonment-worker.js.map +1 -0
- package/dist/backend/services/cart-admin-service.d.ts +58 -0
- package/dist/backend/services/cart-admin-service.d.ts.map +1 -0
- package/dist/backend/services/cart-admin-service.js +397 -0
- package/dist/backend/services/cart-admin-service.js.map +1 -0
- package/dist/backend/services/cart-approval-service.d.ts +147 -0
- package/dist/backend/services/cart-approval-service.d.ts.map +1 -0
- package/dist/backend/services/cart-approval-service.js +242 -0
- package/dist/backend/services/cart-approval-service.js.map +1 -0
- package/dist/backend/services/cart-audit-service.d.ts +75 -0
- package/dist/backend/services/cart-audit-service.d.ts.map +1 -0
- package/dist/backend/services/cart-audit-service.js +70 -0
- package/dist/backend/services/cart-audit-service.js.map +1 -0
- package/dist/backend/services/cart-conversion-service.d.ts +104 -0
- package/dist/backend/services/cart-conversion-service.d.ts.map +1 -0
- package/dist/backend/services/cart-conversion-service.js +175 -0
- package/dist/backend/services/cart-conversion-service.js.map +1 -0
- package/dist/backend/services/cart-coupon-service.d.ts +129 -0
- package/dist/backend/services/cart-coupon-service.d.ts.map +1 -0
- package/dist/backend/services/cart-coupon-service.js +244 -0
- package/dist/backend/services/cart-coupon-service.js.map +1 -0
- package/dist/backend/services/cart-organization-visibility-service.d.ts +43 -0
- package/dist/backend/services/cart-organization-visibility-service.d.ts.map +1 -0
- package/dist/backend/services/cart-organization-visibility-service.js +98 -0
- package/dist/backend/services/cart-organization-visibility-service.js.map +1 -0
- package/dist/backend/services/cart-placement-apply-port.d.ts +38 -0
- package/dist/backend/services/cart-placement-apply-port.d.ts.map +1 -0
- package/dist/backend/services/cart-placement-apply-port.js +71 -0
- package/dist/backend/services/cart-placement-apply-port.js.map +1 -0
- package/dist/backend/services/cart-pricing-recompute.d.ts +62 -0
- package/dist/backend/services/cart-pricing-recompute.d.ts.map +1 -0
- package/dist/backend/services/cart-pricing-recompute.js +131 -0
- package/dist/backend/services/cart-pricing-recompute.js.map +1 -0
- package/dist/backend/services/cart-query-service.d.ts +29 -0
- package/dist/backend/services/cart-query-service.d.ts.map +1 -0
- package/dist/backend/services/cart-query-service.js +40 -0
- package/dist/backend/services/cart-query-service.js.map +1 -0
- package/dist/backend/services/cart-read-port.d.ts +40 -0
- package/dist/backend/services/cart-read-port.d.ts.map +1 -0
- package/dist/backend/services/cart-read-port.js +144 -0
- package/dist/backend/services/cart-read-port.js.map +1 -0
- package/dist/backend/services/cart-recompute-cache.d.ts +49 -0
- package/dist/backend/services/cart-recompute-cache.d.ts.map +1 -0
- package/dist/backend/services/cart-recompute-cache.js +56 -0
- package/dist/backend/services/cart-recompute-cache.js.map +1 -0
- package/dist/backend/services/cart-service.d.ts +165 -0
- package/dist/backend/services/cart-service.d.ts.map +1 -0
- package/dist/backend/services/cart-service.js +556 -0
- package/dist/backend/services/cart-service.js.map +1 -0
- package/dist/backend/services/cart-state-machine.d.ts +51 -0
- package/dist/backend/services/cart-state-machine.d.ts.map +1 -0
- package/dist/backend/services/cart-state-machine.js +74 -0
- package/dist/backend/services/cart-state-machine.js.map +1 -0
- package/dist/backend/services/cart-upsell-service.d.ts +57 -0
- package/dist/backend/services/cart-upsell-service.d.ts.map +1 -0
- package/dist/backend/services/cart-upsell-service.js +100 -0
- package/dist/backend/services/cart-upsell-service.js.map +1 -0
- package/dist/backend/services/customer-group-resolver.d.ts +27 -0
- package/dist/backend/services/customer-group-resolver.d.ts.map +1 -0
- package/dist/backend/services/customer-group-resolver.js +32 -0
- package/dist/backend/services/customer-group-resolver.js.map +1 -0
- package/dist/manifest.d.ts +221 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +224 -0
- package/dist/manifest.js.map +1 -0
- package/dist/migrations/20260611T140352_carts_consolidation.d.ts +43 -0
- package/dist/migrations/20260611T140352_carts_consolidation.d.ts.map +1 -0
- package/dist/migrations/20260611T140352_carts_consolidation.js +237 -0
- package/dist/migrations/20260611T140352_carts_consolidation.js.map +1 -0
- package/dist/migrations/20260611T140413_carts_cart_item_packaging.d.ts +12 -0
- package/dist/migrations/20260611T140413_carts_cart_item_packaging.d.ts.map +1 -0
- package/dist/migrations/20260611T140413_carts_cart_item_packaging.js +20 -0
- package/dist/migrations/20260611T140413_carts_cart_item_packaging.js.map +1 -0
- package/dist/migrations/20260818T081253_carts_cart_completed_order_fk.d.ts +50 -0
- package/dist/migrations/20260818T081253_carts_cart_completed_order_fk.d.ts.map +1 -0
- package/dist/migrations/20260818T081253_carts_cart_completed_order_fk.js +62 -0
- package/dist/migrations/20260818T081253_carts_cart_completed_order_fk.js.map +1 -0
- package/dist/migrations/20260830T112911_carts_organization_attribution_check.d.ts +67 -0
- package/dist/migrations/20260830T112911_carts_organization_attribution_check.d.ts.map +1 -0
- package/dist/migrations/20260830T112911_carts_organization_attribution_check.js +121 -0
- package/dist/migrations/20260830T112911_carts_organization_attribution_check.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/dist/ports/index.d.ts +106 -0
- package/dist/ports/index.d.ts.map +1 -0
- package/dist/ports/index.js +2 -0
- package/dist/ports/index.js.map +1 -0
- package/docs/carts.md +232 -0
- package/i18n/en.json +96 -0
- package/i18n/pl.json +96 -0
- package/package.json +107 -0
- package/tailwind.css +14 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `carts abandonment-sweep` — one pass of `CartAbandonmentWorker.sweep()`
|
|
3
|
+
* against the live database (feature 027 US5).
|
|
4
|
+
*
|
|
5
|
+
* Intended for a cron job or a deploy hook, and safe to run manually:
|
|
6
|
+
*
|
|
7
|
+
* pnpm --filter backend run cart:abandonment-sweep
|
|
8
|
+
*
|
|
9
|
+
* Idempotent: subsequent invocations within the same threshold window are a
|
|
10
|
+
* no-op, because the eligibility filter excludes carts that already carry
|
|
11
|
+
* `abandonment_notified_at`.
|
|
12
|
+
*
|
|
13
|
+
* ## Why this file no longer asks the gate itself (feature 080, T042b)
|
|
14
|
+
*
|
|
15
|
+
* It used to, and the header it carried was the best statement in the tree of
|
|
16
|
+
* the question D-157 answered:
|
|
17
|
+
*
|
|
18
|
+
* > It used to run whatever the platform's opinion of `carts` was, because there
|
|
19
|
+
* > is nothing here for the gate to hang on: `ctx.routes` / `ctx.worker` /
|
|
20
|
+
* > `ctx.subscribe` gate at a registration seam and `providePort` gates at a
|
|
21
|
+
* > resolution, and a CLI has none of the three.
|
|
22
|
+
*
|
|
23
|
+
* There is a seam now, and it is the **declaration**: the host knows which
|
|
24
|
+
* module declared the command it is about to run and asks
|
|
25
|
+
* `requireModuleEnabled` about that module — first, before it builds a context
|
|
26
|
+
* and outside every `try` — in `src/cli/module-commands.ts`. That is the same
|
|
27
|
+
* call at the same point in the same order; what changed is that it is applied
|
|
28
|
+
* once, by the host, for every command, instead of being a line each command's
|
|
29
|
+
* author has to remember. Constitution XVII item 3 states the reason in the
|
|
30
|
+
* general case: *"A gate the registration applies cannot be forgotten in the one
|
|
31
|
+
* service somebody adds later, which a hand-placed call can and did."*
|
|
32
|
+
*
|
|
33
|
+
* ## What the conversion fixed
|
|
34
|
+
*
|
|
35
|
+
* The old file's *"What it still does not do"* section named it: *"It builds its
|
|
36
|
+
* services by hand, so a deployment **decoration** over `cartAuditService` or
|
|
37
|
+
* `cartAbandonmentWorker` does not reach it."* That is a client not getting an
|
|
38
|
+
* override they paid for, and it is fixed by resolving the module's own
|
|
39
|
+
* registration instead of running `new CartAbandonmentWorker(…)` here.
|
|
40
|
+
*
|
|
41
|
+
* The same section refused composition on the ground that `composeApp()`
|
|
42
|
+
* *"starts every queue consumer in the platform"*. That was false and
|
|
43
|
+
* `worker.ts` says so in its own comment — a composition without `buildServer`
|
|
44
|
+
* starts no BullMQ worker and arms no timer, because all three `ctx.worker(`
|
|
45
|
+
* call sites and both module timers sit inside `ctx.routes(…)` bodies that run
|
|
46
|
+
* at Fastify registration (D-157.2, measured three ways). The claim is retired
|
|
47
|
+
* here rather than left for the next author to re-derive.
|
|
48
|
+
*
|
|
49
|
+
* ## Notification dispatch
|
|
50
|
+
*
|
|
51
|
+
* The old file said no e-mail is dispatched in the CLI variant, and that *"the
|
|
52
|
+
* HTTP-bootstrap path in `composition.ts` injects the real
|
|
53
|
+
* `dispatchCartAbandonmentNotification`"*. The second half is stale: measured on
|
|
54
|
+
* this tree, `cartAbandonmentNotifier` is a contribution point that **nobody
|
|
55
|
+
* contributes** — neither composition root writes it — so it defaults to
|
|
56
|
+
* `undefined` and the composed worker dispatches nothing either. Behaviour is
|
|
57
|
+
* therefore unchanged by the conversion, and the day a deployment does
|
|
58
|
+
* contribute a notifier, this command and the platform will agree about it,
|
|
59
|
+
* which they could not before.
|
|
60
|
+
*/
|
|
61
|
+
import type { ModuleCliCommandContext } from '@endora-commerce/contracts';
|
|
62
|
+
import type { ModuleContext } from '@endora-commerce/platform/kernel';
|
|
63
|
+
export declare function abandonmentSweep({ ctx, out, }: ModuleCliCommandContext<ModuleContext>): Promise<number>;
|
|
64
|
+
//# sourceMappingURL=abandonment-sweep.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"abandonment-sweep.d.ts","sourceRoot":"","sources":["../../../src/backend/cli/abandonment-sweep.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2DG;AACH,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AAC1E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kCAAkC,CAAC;AAQtE,wBAAsB,gBAAgB,CAAC,EACrC,GAAG,EACH,GAAG,GACJ,EAAE,uBAAuB,CAAC,aAAa,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAiB1D"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export async function abandonmentSweep({ ctx, out, }) {
|
|
2
|
+
// This module's own registration, so a deployment decoration over it reaches
|
|
3
|
+
// the command — and so the settings thresholds come from the one file
|
|
4
|
+
// `backend.ts` composes the worker from, which is what stopped the CLI and the
|
|
5
|
+
// server disagreeing about them (D-41/D-43).
|
|
6
|
+
//
|
|
7
|
+
// A cradle read rather than `lazyPort`, because `cartAbandonmentWorker` is a
|
|
8
|
+
// plain `ctx.di.register` and not a `providePort`: spelling it as a port here
|
|
9
|
+
// would suggest a presence gate that this name does not carry. Presence for
|
|
10
|
+
// this module is decided by the host before the command is invoked.
|
|
11
|
+
const worker = ctx.cradle().cartAbandonmentWorker;
|
|
12
|
+
const result = await worker.sweep();
|
|
13
|
+
out(`[cart abandonment-sweep] abandoned=${result.abandonedCount} ` +
|
|
14
|
+
`notified=${result.notifiedCount}`);
|
|
15
|
+
return 0;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=abandonment-sweep.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"abandonment-sweep.js","sourceRoot":"","sources":["../../../src/backend/cli/abandonment-sweep.ts"],"names":[],"mappings":"AAqEA,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,EACrC,GAAG,EACH,GAAG,GACoC;IACvC,6EAA6E;IAC7E,sEAAsE;IACtE,+EAA+E;IAC/E,6CAA6C;IAC7C,EAAE;IACF,6EAA6E;IAC7E,8EAA8E;IAC9E,4EAA4E;IAC5E,oEAAoE;IACpE,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,EAA0B,CAAC,qBAAqB,CAAC;IAC1E,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACpC,GAAG,CACD,sCAAsC,MAAM,CAAC,cAAc,GAAG;QAC5D,YAAY,MAAM,CAAC,aAAa,EAAE,CACrC,CAAC;IACF,OAAO,CAAC,CAAC;AACX,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { OptionalProps } from '@mikro-orm/core';
|
|
2
|
+
/**
|
|
3
|
+
* One audit row on a cart's typed feed (feature 027). Backs the cart-
|
|
4
|
+
* detail-page audit panel for both Org-Admin and platform-admin views.
|
|
5
|
+
*
|
|
6
|
+
* Companion to `audit_log_entries` — every cart-state transition also
|
|
7
|
+
* lands a row there via AuditPort.record(...), so the platform-wide
|
|
8
|
+
* audit timeline stays whole. Splitting the two tables keeps the cart UI
|
|
9
|
+
* tight (typed `from_state` / `to_state` / `metadata`) without bloating
|
|
10
|
+
* the generic audit feed.
|
|
11
|
+
*/
|
|
12
|
+
export declare class CartAuditEntry {
|
|
13
|
+
[OptionalProps]?: 'id' | 'occurredAt' | 'actorId' | 'fromState' | 'toState' | 'reason' | 'metadata';
|
|
14
|
+
id: string;
|
|
15
|
+
cartId: string;
|
|
16
|
+
occurredAt: Date;
|
|
17
|
+
actorType: CartAuditActorType;
|
|
18
|
+
actorId?: string | null;
|
|
19
|
+
action: CartAuditAction;
|
|
20
|
+
fromState?: string | null;
|
|
21
|
+
toState?: string | null;
|
|
22
|
+
reason?: string | null;
|
|
23
|
+
metadata: Record<string, unknown>;
|
|
24
|
+
}
|
|
25
|
+
export type CartAuditActorType = 'customer' | 'org_admin' | 'platform_admin' | 'system' | 'sweep';
|
|
26
|
+
export declare const CART_AUDIT_ACTOR_TYPES: readonly CartAuditActorType[];
|
|
27
|
+
export type CartAuditAction = 'status_changed' | 'approval_submitted' | 'approval_approved' | 'approval_rejected' | 'approval_policy_reset' | 'approval_resubmission_required' | 'coupon_applied' | 'coupon_dropped' | 'converted_to_qr' | 'created_from_qr' | 'created_from_shopping_list' | 'admin_rejected' | 'abandonment_swept' | 'abandonment_reactivated' | 'line_added' | 'line_removed' | 'line_qty_changed' | 'cart_merged_from_anon';
|
|
28
|
+
export declare const CART_AUDIT_ACTIONS: readonly CartAuditAction[];
|
|
29
|
+
//# sourceMappingURL=cart-audit-entry.entity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cart-audit-entry.entity.d.ts","sourceRoot":"","sources":["../../../src/backend/entities/cart-audit-entry.entity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,aAAa,EAAwB,MAAM,iBAAiB,CAAC;AAIrF;;;;;;;;;GASG;AACH,qBAEa,cAAc;IACzB,CAAC,aAAa,CAAC,CAAC,EACZ,IAAI,GACJ,YAAY,GACZ,SAAS,GACT,WAAW,GACX,SAAS,GACT,QAAQ,GACR,UAAU,CAAC;IAGf,EAAE,EAAE,MAAM,CAAgB;IAI1B,MAAM,EAAG,MAAM,CAAC;IAGhB,UAAU,EAAE,IAAI,CAAc;IAG9B,SAAS,EAAG,kBAAkB,CAAC;IAG/B,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAGxB,MAAM,EAAG,eAAe,CAAC;IAGzB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAG1B,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAGxB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAGvB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAM;CACxC;AAED,MAAM,MAAM,kBAAkB,GAC1B,UAAU,GACV,WAAW,GACX,gBAAgB,GAChB,QAAQ,GACR,OAAO,CAAC;AAEZ,eAAO,MAAM,sBAAsB,EAAE,SAAS,kBAAkB,EAMtD,CAAC;AAEX,MAAM,MAAM,eAAe,GACvB,gBAAgB,GAChB,oBAAoB,GACpB,mBAAmB,GACnB,mBAAmB,GACnB,uBAAuB,GACvB,gCAAgC,GAChC,gBAAgB,GAChB,gBAAgB,GAChB,iBAAiB,GACjB,iBAAiB,GACjB,4BAA4B,GAC5B,gBAAgB,GAChB,mBAAmB,GACnB,yBAAyB,GACzB,YAAY,GACZ,cAAc,GACd,kBAAkB,GAClB,uBAAuB,CAAC;AAE5B,eAAO,MAAM,kBAAkB,EAAE,SAAS,eAAe,EAmB/C,CAAC"}
|
|
@@ -0,0 +1,109 @@
|
|
|
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 } from '@mikro-orm/core';
|
|
11
|
+
import { GlobalEntity } from '@endora-commerce/platform/tenancy';
|
|
12
|
+
import { randomUUID } from 'crypto';
|
|
13
|
+
/**
|
|
14
|
+
* One audit row on a cart's typed feed (feature 027). Backs the cart-
|
|
15
|
+
* detail-page audit panel for both Org-Admin and platform-admin views.
|
|
16
|
+
*
|
|
17
|
+
* Companion to `audit_log_entries` — every cart-state transition also
|
|
18
|
+
* lands a row there via AuditPort.record(...), so the platform-wide
|
|
19
|
+
* audit timeline stays whole. Splitting the two tables keeps the cart UI
|
|
20
|
+
* tight (typed `from_state` / `to_state` / `metadata`) without bloating
|
|
21
|
+
* the generic audit feed.
|
|
22
|
+
*/
|
|
23
|
+
let CartAuditEntry = class CartAuditEntry {
|
|
24
|
+
[OptionalProps];
|
|
25
|
+
id = randomUUID();
|
|
26
|
+
cartId;
|
|
27
|
+
occurredAt = new Date();
|
|
28
|
+
actorType;
|
|
29
|
+
actorId;
|
|
30
|
+
action;
|
|
31
|
+
fromState;
|
|
32
|
+
toState;
|
|
33
|
+
reason;
|
|
34
|
+
metadata = {};
|
|
35
|
+
};
|
|
36
|
+
__decorate([
|
|
37
|
+
PrimaryKey({ type: 'uuid' }),
|
|
38
|
+
__metadata("design:type", String)
|
|
39
|
+
], CartAuditEntry.prototype, "id", void 0);
|
|
40
|
+
__decorate([
|
|
41
|
+
Property({ type: 'uuid' }),
|
|
42
|
+
Index(),
|
|
43
|
+
__metadata("design:type", String)
|
|
44
|
+
], CartAuditEntry.prototype, "cartId", void 0);
|
|
45
|
+
__decorate([
|
|
46
|
+
Property({ type: 'datetime' }),
|
|
47
|
+
__metadata("design:type", Date)
|
|
48
|
+
], CartAuditEntry.prototype, "occurredAt", void 0);
|
|
49
|
+
__decorate([
|
|
50
|
+
Property({ type: 'string', length: 32 }),
|
|
51
|
+
__metadata("design:type", String)
|
|
52
|
+
], CartAuditEntry.prototype, "actorType", void 0);
|
|
53
|
+
__decorate([
|
|
54
|
+
Property({ type: 'uuid', nullable: true }),
|
|
55
|
+
__metadata("design:type", Object)
|
|
56
|
+
], CartAuditEntry.prototype, "actorId", void 0);
|
|
57
|
+
__decorate([
|
|
58
|
+
Property({ type: 'string', length: 64 }),
|
|
59
|
+
__metadata("design:type", String)
|
|
60
|
+
], CartAuditEntry.prototype, "action", void 0);
|
|
61
|
+
__decorate([
|
|
62
|
+
Property({ type: 'string', length: 32, nullable: true }),
|
|
63
|
+
__metadata("design:type", Object)
|
|
64
|
+
], CartAuditEntry.prototype, "fromState", void 0);
|
|
65
|
+
__decorate([
|
|
66
|
+
Property({ type: 'string', length: 32, nullable: true }),
|
|
67
|
+
__metadata("design:type", Object)
|
|
68
|
+
], CartAuditEntry.prototype, "toState", void 0);
|
|
69
|
+
__decorate([
|
|
70
|
+
Property({ type: 'text', nullable: true }),
|
|
71
|
+
__metadata("design:type", Object)
|
|
72
|
+
], CartAuditEntry.prototype, "reason", void 0);
|
|
73
|
+
__decorate([
|
|
74
|
+
Property({ type: 'json' }),
|
|
75
|
+
__metadata("design:type", Object)
|
|
76
|
+
], CartAuditEntry.prototype, "metadata", void 0);
|
|
77
|
+
CartAuditEntry = __decorate([
|
|
78
|
+
GlobalEntity(),
|
|
79
|
+
Entity({ tableName: 'cart_audit_entries' })
|
|
80
|
+
], CartAuditEntry);
|
|
81
|
+
export { CartAuditEntry };
|
|
82
|
+
export const CART_AUDIT_ACTOR_TYPES = [
|
|
83
|
+
'customer',
|
|
84
|
+
'org_admin',
|
|
85
|
+
'platform_admin',
|
|
86
|
+
'system',
|
|
87
|
+
'sweep',
|
|
88
|
+
];
|
|
89
|
+
export const CART_AUDIT_ACTIONS = [
|
|
90
|
+
'status_changed',
|
|
91
|
+
'approval_submitted',
|
|
92
|
+
'approval_approved',
|
|
93
|
+
'approval_rejected',
|
|
94
|
+
'approval_policy_reset',
|
|
95
|
+
'approval_resubmission_required',
|
|
96
|
+
'coupon_applied',
|
|
97
|
+
'coupon_dropped',
|
|
98
|
+
'converted_to_qr',
|
|
99
|
+
'created_from_qr',
|
|
100
|
+
'created_from_shopping_list',
|
|
101
|
+
'admin_rejected',
|
|
102
|
+
'abandonment_swept',
|
|
103
|
+
'abandonment_reactivated',
|
|
104
|
+
'line_added',
|
|
105
|
+
'line_removed',
|
|
106
|
+
'line_qty_changed',
|
|
107
|
+
'cart_merged_from_anon',
|
|
108
|
+
];
|
|
109
|
+
//# sourceMappingURL=cart-audit-entry.entity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cart-audit-entry.entity.js","sourceRoot":"","sources":["../../../src/backend/entities/cart-audit-entry.entity.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AACrF,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAEpC;;;;;;;;;GASG;AAGI,IAAM,cAAc,GAApB,MAAM,cAAc;IACzB,CAAC,aAAa,CAAC,CAOA;IAGf,EAAE,GAAW,UAAU,EAAE,CAAC;IAI1B,MAAM,CAAU;IAGhB,UAAU,GAAS,IAAI,IAAI,EAAE,CAAC;IAG9B,SAAS,CAAsB;IAG/B,OAAO,CAAiB;IAGxB,MAAM,CAAmB;IAGzB,SAAS,CAAiB;IAG1B,OAAO,CAAiB;IAGxB,MAAM,CAAiB;IAGvB,QAAQ,GAA4B,EAAE,CAAC;CACxC,CAAA;AA7BC;IADC,UAAU,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;0CACH;AAI1B;IAFC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAC1B,KAAK,EAAE;;8CACQ;AAGhB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;8BACnB,IAAI;kDAAc;AAG9B;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;;iDACV;AAG/B;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;+CACnB;AAGxB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;;8CAChB;AAGzB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;iDAC/B;AAG1B;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;+CACjC;AAGxB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;8CACpB;AAGvB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;gDACY;AAvC5B,cAAc;IAF1B,YAAY,EAAE;IACd,MAAM,CAAC,EAAE,SAAS,EAAE,oBAAoB,EAAE,CAAC;GAC/B,cAAc,CAwC1B;;AASD,MAAM,CAAC,MAAM,sBAAsB,GAAkC;IACnE,UAAU;IACV,WAAW;IACX,gBAAgB;IAChB,QAAQ;IACR,OAAO;CACC,CAAC;AAsBX,MAAM,CAAC,MAAM,kBAAkB,GAA+B;IAC5D,gBAAgB;IAChB,oBAAoB;IACpB,mBAAmB;IACnB,mBAAmB;IACnB,uBAAuB;IACvB,gCAAgC;IAChC,gBAAgB;IAChB,gBAAgB;IAChB,iBAAiB;IACjB,iBAAiB;IACjB,4BAA4B;IAC5B,gBAAgB;IAChB,mBAAmB;IACnB,yBAAyB;IACzB,YAAY;IACZ,cAAc;IACd,kBAAkB;IAClB,uBAAuB;CACf,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { OptionalProps } from '@mikro-orm/core';
|
|
2
|
+
/**
|
|
3
|
+
* A line in a Cart. Two-layer pricing snapshot (feature 027):
|
|
4
|
+
* - `unitPrice` / `currency`: the price the line was added at. Read-only
|
|
5
|
+
* after add; useful for audit / diff and for the "added at" column in
|
|
6
|
+
* cart_audit_entries metadata.
|
|
7
|
+
* - `recomputedUnitPrice` / `recomputedAt` / `recomputedCurrency`: the
|
|
8
|
+
* most recent re-resolved price. The Cart-Pricing-Recompute helper
|
|
9
|
+
* refreshes these on every full-cart-view read (with a 30 s Redis
|
|
10
|
+
* cache between mini-cart / full-cart / checkout-entry walks).
|
|
11
|
+
* Cleared on any cart-side write.
|
|
12
|
+
*/
|
|
13
|
+
export declare class CartItem {
|
|
14
|
+
[OptionalProps]?: 'id' | 'createdAt' | 'updatedAt' | 'variantId' | 'recomputedUnitPrice' | 'recomputedAt' | 'recomputedCurrency' | 'packagingUnitId' | 'packagingUnitName' | 'packagingUnitBaseQuantity';
|
|
15
|
+
id: string;
|
|
16
|
+
cartId: string;
|
|
17
|
+
productId: string;
|
|
18
|
+
variantId?: string | null;
|
|
19
|
+
quantity: number;
|
|
20
|
+
/** Price snapshot at time of add — services recalculate on read. */
|
|
21
|
+
unitPrice: string;
|
|
22
|
+
currency: string;
|
|
23
|
+
/**
|
|
24
|
+
* Most-recent re-resolved unit price (per feature 011 PricingService).
|
|
25
|
+
* Stale beyond the cache TTL → re-resolve on next read. Cleared on every
|
|
26
|
+
* cart-side write so the next read forces a fresh resolution.
|
|
27
|
+
*/
|
|
28
|
+
recomputedUnitPrice?: string | null;
|
|
29
|
+
recomputedAt?: Date | null;
|
|
30
|
+
recomputedCurrency?: string | null;
|
|
31
|
+
/**
|
|
32
|
+
* Feature 043 — when this line was added as a packaging unit (e.g. a
|
|
33
|
+
* pallet), these snapshot the unit it came from. `quantity` above already
|
|
34
|
+
* holds the resulting base-piece count. Null for plain single-piece lines.
|
|
35
|
+
*/
|
|
36
|
+
packagingUnitId?: string | null;
|
|
37
|
+
packagingUnitName?: string | null;
|
|
38
|
+
packagingUnitBaseQuantity?: number | null;
|
|
39
|
+
createdAt: Date;
|
|
40
|
+
updatedAt: Date;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=cart-item.entity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cart-item.entity.d.ts","sourceRoot":"","sources":["../../../src/backend/entities/cart-item.entity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,aAAa,EAAwB,MAAM,iBAAiB,CAAC;AAIrF;;;;;;;;;;GAUG;AACH,qBAEa,QAAQ;IACnB,CAAC,aAAa,CAAC,CAAC,EACZ,IAAI,GACJ,WAAW,GACX,WAAW,GACX,WAAW,GACX,qBAAqB,GACrB,cAAc,GACd,oBAAoB,GACpB,iBAAiB,GACjB,mBAAmB,GACnB,2BAA2B,CAAC;IAGhC,EAAE,EAAE,MAAM,CAAgB;IAI1B,MAAM,EAAG,MAAM,CAAC;IAGhB,SAAS,EAAG,MAAM,CAAC;IAGnB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAG1B,QAAQ,EAAG,MAAM,CAAC;IAElB,oEAAoE;IAEpE,SAAS,EAAG,MAAM,CAAC;IAGnB,QAAQ,EAAG,MAAM,CAAC;IAElB;;;;OAIG;IAEH,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAGpC,YAAY,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IAG3B,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAEnC;;;;OAIG;IAEH,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAGhC,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAGlC,yBAAyB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAG1C,SAAS,EAAE,IAAI,CAAc;IAG7B,SAAS,EAAE,IAAI,CAAc;CAC9B"}
|
|
@@ -0,0 +1,119 @@
|
|
|
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 } from '@mikro-orm/core';
|
|
11
|
+
import { GlobalEntity } from '@endora-commerce/platform/tenancy';
|
|
12
|
+
import { randomUUID } from 'crypto';
|
|
13
|
+
/**
|
|
14
|
+
* A line in a Cart. Two-layer pricing snapshot (feature 027):
|
|
15
|
+
* - `unitPrice` / `currency`: the price the line was added at. Read-only
|
|
16
|
+
* after add; useful for audit / diff and for the "added at" column in
|
|
17
|
+
* cart_audit_entries metadata.
|
|
18
|
+
* - `recomputedUnitPrice` / `recomputedAt` / `recomputedCurrency`: the
|
|
19
|
+
* most recent re-resolved price. The Cart-Pricing-Recompute helper
|
|
20
|
+
* refreshes these on every full-cart-view read (with a 30 s Redis
|
|
21
|
+
* cache between mini-cart / full-cart / checkout-entry walks).
|
|
22
|
+
* Cleared on any cart-side write.
|
|
23
|
+
*/
|
|
24
|
+
let CartItem = class CartItem {
|
|
25
|
+
[OptionalProps];
|
|
26
|
+
id = randomUUID();
|
|
27
|
+
cartId;
|
|
28
|
+
productId;
|
|
29
|
+
variantId;
|
|
30
|
+
quantity;
|
|
31
|
+
/** Price snapshot at time of add — services recalculate on read. */
|
|
32
|
+
unitPrice;
|
|
33
|
+
currency;
|
|
34
|
+
/**
|
|
35
|
+
* Most-recent re-resolved unit price (per feature 011 PricingService).
|
|
36
|
+
* Stale beyond the cache TTL → re-resolve on next read. Cleared on every
|
|
37
|
+
* cart-side write so the next read forces a fresh resolution.
|
|
38
|
+
*/
|
|
39
|
+
recomputedUnitPrice;
|
|
40
|
+
recomputedAt;
|
|
41
|
+
recomputedCurrency;
|
|
42
|
+
/**
|
|
43
|
+
* Feature 043 — when this line was added as a packaging unit (e.g. a
|
|
44
|
+
* pallet), these snapshot the unit it came from. `quantity` above already
|
|
45
|
+
* holds the resulting base-piece count. Null for plain single-piece lines.
|
|
46
|
+
*/
|
|
47
|
+
packagingUnitId;
|
|
48
|
+
packagingUnitName;
|
|
49
|
+
packagingUnitBaseQuantity;
|
|
50
|
+
createdAt = new Date();
|
|
51
|
+
updatedAt = new Date();
|
|
52
|
+
};
|
|
53
|
+
__decorate([
|
|
54
|
+
PrimaryKey({ type: 'uuid' }),
|
|
55
|
+
__metadata("design:type", String)
|
|
56
|
+
], CartItem.prototype, "id", void 0);
|
|
57
|
+
__decorate([
|
|
58
|
+
Property({ type: 'uuid' }),
|
|
59
|
+
Index(),
|
|
60
|
+
__metadata("design:type", String)
|
|
61
|
+
], CartItem.prototype, "cartId", void 0);
|
|
62
|
+
__decorate([
|
|
63
|
+
Property({ type: 'uuid' }),
|
|
64
|
+
__metadata("design:type", String)
|
|
65
|
+
], CartItem.prototype, "productId", void 0);
|
|
66
|
+
__decorate([
|
|
67
|
+
Property({ type: 'uuid', nullable: true }),
|
|
68
|
+
__metadata("design:type", Object)
|
|
69
|
+
], CartItem.prototype, "variantId", void 0);
|
|
70
|
+
__decorate([
|
|
71
|
+
Property({ type: 'integer' }),
|
|
72
|
+
__metadata("design:type", Number)
|
|
73
|
+
], CartItem.prototype, "quantity", void 0);
|
|
74
|
+
__decorate([
|
|
75
|
+
Property({ type: 'decimal', precision: 12, scale: 2 }),
|
|
76
|
+
__metadata("design:type", String)
|
|
77
|
+
], CartItem.prototype, "unitPrice", void 0);
|
|
78
|
+
__decorate([
|
|
79
|
+
Property({ type: 'string', length: 3 }),
|
|
80
|
+
__metadata("design:type", String)
|
|
81
|
+
], CartItem.prototype, "currency", void 0);
|
|
82
|
+
__decorate([
|
|
83
|
+
Property({ type: 'decimal', precision: 12, scale: 2, nullable: true }),
|
|
84
|
+
__metadata("design:type", Object)
|
|
85
|
+
], CartItem.prototype, "recomputedUnitPrice", void 0);
|
|
86
|
+
__decorate([
|
|
87
|
+
Property({ type: 'datetime', nullable: true }),
|
|
88
|
+
__metadata("design:type", Object)
|
|
89
|
+
], CartItem.prototype, "recomputedAt", void 0);
|
|
90
|
+
__decorate([
|
|
91
|
+
Property({ type: 'string', length: 3, nullable: true }),
|
|
92
|
+
__metadata("design:type", Object)
|
|
93
|
+
], CartItem.prototype, "recomputedCurrency", void 0);
|
|
94
|
+
__decorate([
|
|
95
|
+
Property({ type: 'uuid', nullable: true }),
|
|
96
|
+
__metadata("design:type", Object)
|
|
97
|
+
], CartItem.prototype, "packagingUnitId", void 0);
|
|
98
|
+
__decorate([
|
|
99
|
+
Property({ type: 'string', length: 160, nullable: true }),
|
|
100
|
+
__metadata("design:type", Object)
|
|
101
|
+
], CartItem.prototype, "packagingUnitName", void 0);
|
|
102
|
+
__decorate([
|
|
103
|
+
Property({ type: 'integer', nullable: true }),
|
|
104
|
+
__metadata("design:type", Object)
|
|
105
|
+
], CartItem.prototype, "packagingUnitBaseQuantity", void 0);
|
|
106
|
+
__decorate([
|
|
107
|
+
Property({ type: 'datetime', onCreate: () => new Date() }),
|
|
108
|
+
__metadata("design:type", Date)
|
|
109
|
+
], CartItem.prototype, "createdAt", void 0);
|
|
110
|
+
__decorate([
|
|
111
|
+
Property({ type: 'datetime', onUpdate: () => new Date() }),
|
|
112
|
+
__metadata("design:type", Date)
|
|
113
|
+
], CartItem.prototype, "updatedAt", void 0);
|
|
114
|
+
CartItem = __decorate([
|
|
115
|
+
GlobalEntity(),
|
|
116
|
+
Entity({ tableName: 'cart_items' })
|
|
117
|
+
], CartItem);
|
|
118
|
+
export { CartItem };
|
|
119
|
+
//# sourceMappingURL=cart-item.entity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cart-item.entity.js","sourceRoot":"","sources":["../../../src/backend/entities/cart-item.entity.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AACrF,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAEpC;;;;;;;;;;GAUG;AAGI,IAAM,QAAQ,GAAd,MAAM,QAAQ;IACnB,CAAC,aAAa,CAAC,CAUiB;IAGhC,EAAE,GAAW,UAAU,EAAE,CAAC;IAI1B,MAAM,CAAU;IAGhB,SAAS,CAAU;IAGnB,SAAS,CAAiB;IAG1B,QAAQ,CAAU;IAElB,oEAAoE;IAEpE,SAAS,CAAU;IAGnB,QAAQ,CAAU;IAElB;;;;OAIG;IAEH,mBAAmB,CAAiB;IAGpC,YAAY,CAAe;IAG3B,kBAAkB,CAAiB;IAEnC;;;;OAIG;IAEH,eAAe,CAAiB;IAGhC,iBAAiB,CAAiB;IAGlC,yBAAyB,CAAiB;IAG1C,SAAS,GAAS,IAAI,IAAI,EAAE,CAAC;IAG7B,SAAS,GAAS,IAAI,IAAI,EAAE,CAAC;CAC9B,CAAA;AAvDC;IADC,UAAU,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;oCACH;AAI1B;IAFC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAC1B,KAAK,EAAE;;wCACQ;AAGhB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;2CACR;AAGnB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;2CACjB;AAG1B;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;;0CACZ;AAIlB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;;2CACpC;AAGnB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;;0CACtB;AAQlB;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;qDACnC;AAGpC;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;8CACpB;AAG3B;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;oDACrB;AAQnC;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;iDACX;AAGhC;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;mDACxB;AAGlC;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;2DACJ;AAG1C;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC;8BAChD,IAAI;2CAAc;AAG7B;IADC,QAAQ,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC;8BAChD,IAAI;2CAAc;AApElB,QAAQ;IAFpB,YAAY,EAAE;IACd,MAAM,CAAC,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC;GACvB,QAAQ,CAqEpB"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { OptionalProps } from '@mikro-orm/core';
|
|
2
|
+
/**
|
|
3
|
+
* Cart — a buyer's in-progress basket. Owned by a Customer (authenticated)
|
|
4
|
+
* or an anonymous session (cookie-token addressable). Scoped to a Sales
|
|
5
|
+
* Channel (feature 027) so the spec's "one active cart per
|
|
6
|
+
* (Customer, Sales Channel)" rule holds.
|
|
7
|
+
*
|
|
8
|
+
* Status lifecycle (feature 027):
|
|
9
|
+
* active → abandoned (sweep: last_activity_at past threshold)
|
|
10
|
+
* abandoned → active (owner activity)
|
|
11
|
+
* active → completed (checkout success OR cart→QR conversion)
|
|
12
|
+
* active → rejected (org-admin reject OR platform-admin reject)
|
|
13
|
+
*
|
|
14
|
+
* Legacy `converted` was migrated to `completed` by migration 050. Mass
|
|
15
|
+
* code in the repo that previously wrote `'converted'` now writes
|
|
16
|
+
* `'completed'` (CartService.clearForCustomer).
|
|
17
|
+
*
|
|
18
|
+
* `approval_status` is the orthogonal sub-state that gates checkout when
|
|
19
|
+
* the Organization's `requires_cart_approval` policy is `true`. Self-
|
|
20
|
+
* approval exemption: a cart created by an Org Admin is born with
|
|
21
|
+
* `approval_status='not_required'` regardless of the policy. Post-approval
|
|
22
|
+
* mutation re-arms `approved → pending` (see CartApprovalService).
|
|
23
|
+
*
|
|
24
|
+
* `version` is the optimistic-lock token used by the approval / mutation
|
|
25
|
+
* race (buyer-vs-Org-Admin) — aligned with the convention shared by
|
|
26
|
+
* features 003 / 026.
|
|
27
|
+
*/
|
|
28
|
+
export declare class Cart {
|
|
29
|
+
[OptionalProps]?: 'id' | 'createdAt' | 'updatedAt' | 'customerAccountId' | 'organizationId' | 'anonymousCartToken' | 'salesChannelId' | 'status' | 'approvalStatus' | 'submittedForApprovalAt' | 'approvedAt' | 'approvedByCustomerAccountId' | 'rejectedAt' | 'rejectedByActor' | 'rejectedReason' | 'appliedPromotionCode' | 'completedOrderId' | 'convertedToQuoteRequestId' | 'abandonmentNotifiedAt' | 'lastActivityAt' | 'version';
|
|
30
|
+
id: string;
|
|
31
|
+
customerAccountId?: string | null;
|
|
32
|
+
organizationId?: string | null;
|
|
33
|
+
anonymousCartToken?: string | null;
|
|
34
|
+
/**
|
|
35
|
+
* Sales channel the cart is scoped to. Backfilled to the system-default
|
|
36
|
+
* channel by migration 050; NULL is read as "system default" until the
|
|
37
|
+
* next consolidation tightens it (see research.md §R3).
|
|
38
|
+
*/
|
|
39
|
+
salesChannelId?: string | null;
|
|
40
|
+
status: CartStatus;
|
|
41
|
+
approvalStatus: CartApprovalStatus;
|
|
42
|
+
submittedForApprovalAt?: Date | null;
|
|
43
|
+
approvedAt?: Date | null;
|
|
44
|
+
approvedByCustomerAccountId?: string | null;
|
|
45
|
+
rejectedAt?: Date | null;
|
|
46
|
+
/** Free-form `customer:<uuid>` / `admin:<uuid>` / `org_admin:<uuid>`. */
|
|
47
|
+
rejectedByActor?: string | null;
|
|
48
|
+
rejectedReason?: string | null;
|
|
49
|
+
/**
|
|
50
|
+
* The Promotion.code the buyer most recently applied to this cart. The
|
|
51
|
+
* resolver in PromotionService.applyToCart consumes this on every read.
|
|
52
|
+
* Persisted even on terminal carts for audit / analytics.
|
|
53
|
+
*/
|
|
54
|
+
appliedPromotionCode?: string | null;
|
|
55
|
+
/**
|
|
56
|
+
* The order this cart produced, set by `placeOrder` beside
|
|
57
|
+
* `status = 'completed'` and inside the placement transaction (D-94.1).
|
|
58
|
+
*
|
|
59
|
+
* The twin of {@link convertedToQuoteRequestId}: the two terminal artefacts
|
|
60
|
+
* a cart can leave behind, and until D-94 only one of them was recorded —
|
|
61
|
+
* asked which order emptied a completed cart, the platform answered by
|
|
62
|
+
* correlating timestamps. `carts_completed_order_fk` holds it
|
|
63
|
+
* (`on delete set null`), for the reason the QR pointer's migration wrote
|
|
64
|
+
* down for its own: deleting the order does not invalidate the fact that
|
|
65
|
+
* the cart was once completed.
|
|
66
|
+
*
|
|
67
|
+
* Nullable, and it stays nullable. It cannot be backfilled — no surviving
|
|
68
|
+
* record says which order emptied which historical cart — and
|
|
69
|
+
* `status = 'completed'` does not imply it: `CartService.clearForCustomer`,
|
|
70
|
+
* the anonymous-merge source and the quote-request conversion all reach
|
|
71
|
+
* `completed` without an order.
|
|
72
|
+
*/
|
|
73
|
+
completedOrderId?: string | null;
|
|
74
|
+
/** Set on Cart → Quote Request conversion (feature 027 US3). */
|
|
75
|
+
convertedToQuoteRequestId?: string | null;
|
|
76
|
+
/**
|
|
77
|
+
* Idempotency stamp for the abandonment-sweep notification. Cleared on
|
|
78
|
+
* reactivation so the next abandonment cycle can notify again.
|
|
79
|
+
*/
|
|
80
|
+
abandonmentNotifiedAt?: Date | null;
|
|
81
|
+
/**
|
|
82
|
+
* Bumped by every buyer-driven add / remove / qty / coupon / explicit
|
|
83
|
+
* page-open. Drives the abandonment sweep. NOT bumped by mini-cart
|
|
84
|
+
* hovers or non-owner inspections (Org-Admin / platform-admin reads).
|
|
85
|
+
*/
|
|
86
|
+
lastActivityAt: Date;
|
|
87
|
+
/** Optimistic-lock token (auto-incremented by MikroORM on every update). */
|
|
88
|
+
version: number;
|
|
89
|
+
createdAt: Date;
|
|
90
|
+
updatedAt: Date;
|
|
91
|
+
}
|
|
92
|
+
export type CartStatus = 'active' | 'abandoned' | 'completed' | 'rejected';
|
|
93
|
+
export declare const CART_STATUSES: readonly CartStatus[];
|
|
94
|
+
export type CartApprovalStatus = 'not_required' | 'pending' | 'approved' | 'rejected_by_org_admin';
|
|
95
|
+
export declare const CART_APPROVAL_STATUSES: readonly CartApprovalStatus[];
|
|
96
|
+
//# sourceMappingURL=cart.entity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cart.entity.d.ts","sourceRoot":"","sources":["../../../src/backend/entities/cart.entity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,aAAa,EAAgC,MAAM,iBAAiB,CAAC;AAI7F;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,qBAEa,IAAI;IACf,CAAC,aAAa,CAAC,CAAC,EACZ,IAAI,GACJ,WAAW,GACX,WAAW,GACX,mBAAmB,GACnB,gBAAgB,GAChB,oBAAoB,GACpB,gBAAgB,GAChB,QAAQ,GACR,gBAAgB,GAChB,wBAAwB,GACxB,YAAY,GACZ,6BAA6B,GAC7B,YAAY,GACZ,iBAAiB,GACjB,gBAAgB,GAChB,sBAAsB,GACtB,kBAAkB,GAClB,2BAA2B,GAC3B,uBAAuB,GACvB,gBAAgB,GAChB,SAAS,CAAC;IAGd,EAAE,EAAE,MAAM,CAAgB;IAI1B,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAIlC,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAI/B,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAEnC;;;;OAIG;IAEH,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAG/B,MAAM,EAAE,UAAU,CAAY;IAG9B,cAAc,EAAE,kBAAkB,CAAkB;IAGpD,sBAAsB,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IAGrC,UAAU,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IAGzB,2BAA2B,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAG5C,UAAU,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IAEzB,yEAAyE;IAEzE,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAGhC,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAE/B;;;;OAIG;IAEH,oBAAoB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAErC;;;;;;;;;;;;;;;;;OAiBG;IAEH,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAEjC,gEAAgE;IAEhE,yBAAyB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAE1C;;;OAGG;IAEH,qBAAqB,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IAEpC;;;;OAIG;IAEH,cAAc,EAAE,IAAI,CAAc;IAElC,4EAA4E;IAE5E,OAAO,EAAG,MAAM,CAAC;IAGjB,SAAS,EAAE,IAAI,CAAc;IAG7B,SAAS,EAAE,IAAI,CAAc;CAC9B;AAED,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,WAAW,GAAG,WAAW,GAAG,UAAU,CAAC;AAE3E,eAAO,MAAM,aAAa,EAAE,SAAS,UAAU,EAKrC,CAAC;AAEX,MAAM,MAAM,kBAAkB,GAC1B,cAAc,GACd,SAAS,GACT,UAAU,GACV,uBAAuB,CAAC;AAE5B,eAAO,MAAM,sBAAsB,EAAE,SAAS,kBAAkB,EAKtD,CAAC"}
|