@unifiedcommerce/plugin-pos 0.0.1

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 (77) hide show
  1. package/dist/hooks/checkout-pos.d.ts +29 -0
  2. package/dist/hooks/checkout-pos.d.ts.map +1 -0
  3. package/dist/hooks/checkout-pos.js +69 -0
  4. package/dist/index.d.ts +26 -0
  5. package/dist/index.d.ts.map +1 -0
  6. package/dist/index.js +109 -0
  7. package/dist/payment-adapter.d.ts +33 -0
  8. package/dist/payment-adapter.d.ts.map +1 -0
  9. package/dist/payment-adapter.js +37 -0
  10. package/dist/routes/lookup.d.ts +9 -0
  11. package/dist/routes/lookup.d.ts.map +1 -0
  12. package/dist/routes/lookup.js +37 -0
  13. package/dist/routes/payments.d.ts +10 -0
  14. package/dist/routes/payments.d.ts.map +1 -0
  15. package/dist/routes/payments.js +62 -0
  16. package/dist/routes/receipts.d.ts +9 -0
  17. package/dist/routes/receipts.d.ts.map +1 -0
  18. package/dist/routes/receipts.js +28 -0
  19. package/dist/routes/returns.d.ts +21 -0
  20. package/dist/routes/returns.d.ts.map +1 -0
  21. package/dist/routes/returns.js +83 -0
  22. package/dist/routes/shifts.d.ts +9 -0
  23. package/dist/routes/shifts.d.ts.map +1 -0
  24. package/dist/routes/shifts.js +91 -0
  25. package/dist/routes/terminals.d.ts +9 -0
  26. package/dist/routes/terminals.d.ts.map +1 -0
  27. package/dist/routes/terminals.js +55 -0
  28. package/dist/routes/transactions.d.ts +19 -0
  29. package/dist/routes/transactions.d.ts.map +1 -0
  30. package/dist/routes/transactions.js +175 -0
  31. package/dist/schema.d.ts +1337 -0
  32. package/dist/schema.d.ts.map +1 -0
  33. package/dist/schema.js +123 -0
  34. package/dist/services/lookup-service.d.ts +38 -0
  35. package/dist/services/lookup-service.d.ts.map +1 -0
  36. package/dist/services/lookup-service.js +104 -0
  37. package/dist/services/payment-service.d.ts +40 -0
  38. package/dist/services/payment-service.d.ts.map +1 -0
  39. package/dist/services/payment-service.js +99 -0
  40. package/dist/services/receipt-service.d.ts +45 -0
  41. package/dist/services/receipt-service.d.ts.map +1 -0
  42. package/dist/services/receipt-service.js +119 -0
  43. package/dist/services/return-service.d.ts +27 -0
  44. package/dist/services/return-service.d.ts.map +1 -0
  45. package/dist/services/return-service.js +51 -0
  46. package/dist/services/shift-service.d.ts +36 -0
  47. package/dist/services/shift-service.d.ts.map +1 -0
  48. package/dist/services/shift-service.js +198 -0
  49. package/dist/services/terminal-service.d.ts +21 -0
  50. package/dist/services/terminal-service.d.ts.map +1 -0
  51. package/dist/services/terminal-service.js +59 -0
  52. package/dist/services/transaction-service.d.ts +30 -0
  53. package/dist/services/transaction-service.d.ts.map +1 -0
  54. package/dist/services/transaction-service.js +202 -0
  55. package/dist/types.d.ts +30 -0
  56. package/dist/types.d.ts.map +1 -0
  57. package/dist/types.js +5 -0
  58. package/package.json +40 -0
  59. package/src/hooks/checkout-pos.ts +93 -0
  60. package/src/index.ts +131 -0
  61. package/src/payment-adapter.ts +53 -0
  62. package/src/routes/lookup.ts +44 -0
  63. package/src/routes/payments.ts +82 -0
  64. package/src/routes/receipts.ts +35 -0
  65. package/src/routes/returns.ts +116 -0
  66. package/src/routes/shifts.ts +100 -0
  67. package/src/routes/terminals.ts +62 -0
  68. package/src/routes/transactions.ts +192 -0
  69. package/src/schema.ts +136 -0
  70. package/src/services/lookup-service.ts +136 -0
  71. package/src/services/payment-service.ts +133 -0
  72. package/src/services/receipt-service.ts +169 -0
  73. package/src/services/return-service.ts +65 -0
  74. package/src/services/shift-service.ts +260 -0
  75. package/src/services/terminal-service.ts +76 -0
  76. package/src/services/transaction-service.ts +248 -0
  77. package/src/types.ts +49 -0
@@ -0,0 +1,29 @@
1
+ /**
2
+ * POS-specific checkout hooks.
3
+ *
4
+ * checkout.beforePayment: Sets shippingTotal = 0 for POS transactions (no shipping).
5
+ * checkout.afterCreate: Updates POS transaction with orderId, increments shift counters.
6
+ */
7
+ import type { Db } from "../types";
8
+ interface CheckoutData {
9
+ metadata?: Record<string, unknown> | null;
10
+ shippingTotal: number;
11
+ shippingAddress?: unknown;
12
+ [key: string]: unknown;
13
+ }
14
+ /**
15
+ * Before payment hook: zero out shipping for POS transactions.
16
+ */
17
+ export declare function buildPOSShippingHook(): {
18
+ key: string;
19
+ handler: (...args: unknown[]) => Promise<CheckoutData>;
20
+ };
21
+ /**
22
+ * After create hook: finalize POS transaction with order details.
23
+ */
24
+ export declare function buildPOSFinalizationHook(getDb: () => Db): {
25
+ key: string;
26
+ handler: (...args: unknown[]) => Promise<void>;
27
+ };
28
+ export {};
29
+ //# sourceMappingURL=checkout-pos.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checkout-pos.d.ts","sourceRoot":"","sources":["../../src/hooks/checkout-pos.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,UAAU,CAAC;AAEnC,UAAU,YAAY;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC1C,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAaD;;GAEG;AACH,wBAAgB,oBAAoB;;uBAGP,OAAO,EAAE;EAWrC;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,EAAE;;uBAG3B,OAAO,EAAE;EAsCrC"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * POS-specific checkout hooks.
3
+ *
4
+ * checkout.beforePayment: Sets shippingTotal = 0 for POS transactions (no shipping).
5
+ * checkout.afterCreate: Updates POS transaction with orderId, increments shift counters.
6
+ */
7
+ import { eq, sql } from "drizzle-orm";
8
+ import { posTransactions, posShifts } from "../schema";
9
+ /**
10
+ * Before payment hook: zero out shipping for POS transactions.
11
+ */
12
+ export function buildPOSShippingHook() {
13
+ return {
14
+ key: "checkout.beforePayment",
15
+ handler: async (...args) => {
16
+ const hook = args[0];
17
+ const posTransactionId = hook.data.metadata?.posTransactionId;
18
+ if (!posTransactionId)
19
+ return hook.data;
20
+ // POS transactions have no shipping
21
+ hook.data.shippingTotal = 0;
22
+ hook.data.shippingAddress = undefined;
23
+ return hook.data;
24
+ },
25
+ };
26
+ }
27
+ /**
28
+ * After create hook: finalize POS transaction with order details.
29
+ */
30
+ export function buildPOSFinalizationHook(getDb) {
31
+ return {
32
+ key: "checkout.afterCreate",
33
+ handler: async (...args) => {
34
+ const hook = args[0];
35
+ const result = hook.result;
36
+ if (!result)
37
+ return;
38
+ // Check if this checkout was initiated by a POS transaction
39
+ // The metadata is on the order, not directly on the hook result
40
+ const metadata = result.metadata;
41
+ const posTransactionId = metadata?.posTransactionId;
42
+ if (!posTransactionId)
43
+ return;
44
+ const db = getDb();
45
+ // Update transaction with orderId and status
46
+ await db
47
+ .update(posTransactions)
48
+ .set({
49
+ orderId: result.id,
50
+ status: "completed",
51
+ completedAt: new Date(),
52
+ updatedAt: new Date(),
53
+ })
54
+ .where(eq(posTransactions.id, posTransactionId));
55
+ // Increment shift sales counters
56
+ const posShiftId = metadata?.posShiftId;
57
+ if (posShiftId) {
58
+ await db
59
+ .update(posShifts)
60
+ .set({
61
+ salesCount: sql `${posShifts.salesCount} + 1`,
62
+ salesTotal: sql `${posShifts.salesTotal} + ${result.grandTotal ?? 0}`,
63
+ updatedAt: new Date(),
64
+ })
65
+ .where(eq(posShifts.id, posShiftId));
66
+ }
67
+ },
68
+ };
69
+ }
@@ -0,0 +1,26 @@
1
+ import type { POSPluginOptions } from "./types";
2
+ export type { POSPluginOptions } from "./types";
3
+ export { TerminalService } from "./services/terminal-service";
4
+ export { ShiftService } from "./services/shift-service";
5
+ export { TransactionService } from "./services/transaction-service";
6
+ export { PaymentService } from "./services/payment-service";
7
+ export { ReturnService } from "./services/return-service";
8
+ export { LookupService } from "./services/lookup-service";
9
+ export { ReceiptService } from "./services/receipt-service";
10
+ export { createPOSPaymentAdapter } from "./payment-adapter";
11
+ /**
12
+ * POS Plugin — Tier 0 Core Primitives (RFC-023)
13
+ *
14
+ * Provides:
15
+ * - Terminal management (register, tablet, mobile, kiosk)
16
+ * - Shift management (open/close with cash tracking, Z-report)
17
+ * - Transaction lifecycle (create, hold/recall, void, complete)
18
+ * - Split payment support (cash, card, gift card, store credit)
19
+ * - Returns with original order linkage
20
+ * - Barcode/SKU lookup via indexed queries
21
+ * - Receipt data assembly + email
22
+ * - POS payment adapter for checkout pipeline
23
+ * - Checkout hooks (zero shipping, transaction finalization)
24
+ */
25
+ export declare function posPlugin(userOptions?: POSPluginOptions): import("@unifiedcommerce/core").CommercePlugin;
26
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,gBAAgB,EAAM,MAAM,SAAS,CAAC;AAGpD,YAAY,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAE5D;;;;;;;;;;;;;GAaG;AACH,wBAAgB,SAAS,CAAC,WAAW,GAAE,gBAAqB,kDA+E3D"}
package/dist/index.js ADDED
@@ -0,0 +1,109 @@
1
+ import { defineCommercePlugin } from "@unifiedcommerce/core";
2
+ import { posTerminals, posShifts, posCashEvents, posTransactions, posPayments, posReturnItems, } from "./schema";
3
+ import { TerminalService } from "./services/terminal-service";
4
+ import { ShiftService } from "./services/shift-service";
5
+ import { TransactionService } from "./services/transaction-service";
6
+ import { PaymentService } from "./services/payment-service";
7
+ import { ReturnService } from "./services/return-service";
8
+ import { LookupService } from "./services/lookup-service";
9
+ import { ReceiptService } from "./services/receipt-service";
10
+ import { buildTerminalRoutes } from "./routes/terminals";
11
+ import { buildShiftRoutes } from "./routes/shifts";
12
+ import { buildTransactionRoutes } from "./routes/transactions";
13
+ import { buildPaymentRoutes } from "./routes/payments";
14
+ import { buildReturnRoutes } from "./routes/returns";
15
+ import { buildLookupRoutes } from "./routes/lookup";
16
+ import { buildReceiptRoutes } from "./routes/receipts";
17
+ import { buildPOSShippingHook, buildPOSFinalizationHook } from "./hooks/checkout-pos";
18
+ import { DEFAULT_POS_OPTIONS } from "./types";
19
+ export { TerminalService } from "./services/terminal-service";
20
+ export { ShiftService } from "./services/shift-service";
21
+ export { TransactionService } from "./services/transaction-service";
22
+ export { PaymentService } from "./services/payment-service";
23
+ export { ReturnService } from "./services/return-service";
24
+ export { LookupService } from "./services/lookup-service";
25
+ export { ReceiptService } from "./services/receipt-service";
26
+ export { createPOSPaymentAdapter } from "./payment-adapter";
27
+ /**
28
+ * POS Plugin — Tier 0 Core Primitives (RFC-023)
29
+ *
30
+ * Provides:
31
+ * - Terminal management (register, tablet, mobile, kiosk)
32
+ * - Shift management (open/close with cash tracking, Z-report)
33
+ * - Transaction lifecycle (create, hold/recall, void, complete)
34
+ * - Split payment support (cash, card, gift card, store credit)
35
+ * - Returns with original order linkage
36
+ * - Barcode/SKU lookup via indexed queries
37
+ * - Receipt data assembly + email
38
+ * - POS payment adapter for checkout pipeline
39
+ * - Checkout hooks (zero shipping, transaction finalization)
40
+ */
41
+ export function posPlugin(userOptions = {}) {
42
+ const options = {
43
+ ...DEFAULT_POS_OPTIONS,
44
+ ...userOptions,
45
+ };
46
+ // Shared DB reference for hooks (populated in routes())
47
+ const dbRef = { current: null };
48
+ return defineCommercePlugin({
49
+ id: "pos",
50
+ version: "1.0.0",
51
+ permissions: [
52
+ {
53
+ scope: "pos:admin",
54
+ description: "Register terminals, view all shifts, Z-reports, configure POS settings.",
55
+ },
56
+ {
57
+ scope: "pos:manage",
58
+ description: "Void transactions, apply discounts, process returns, override price.",
59
+ },
60
+ {
61
+ scope: "pos:operate",
62
+ description: "Open/close shifts, ring up sales, accept payment, hold/recall, reprint receipts.",
63
+ },
64
+ ],
65
+ schema: () => ({
66
+ posTerminals,
67
+ posShifts,
68
+ posCashEvents,
69
+ posTransactions,
70
+ posPayments,
71
+ posReturnItems,
72
+ }),
73
+ hooks: () => [
74
+ buildPOSShippingHook(),
75
+ buildPOSFinalizationHook(() => {
76
+ if (!dbRef.current)
77
+ throw new Error("POS plugin DB not initialized — hooks ran before routes()");
78
+ return dbRef.current;
79
+ }),
80
+ ],
81
+ routes: (ctx) => {
82
+ const db = ctx.database.db;
83
+ if (!db)
84
+ return [];
85
+ // Populate the shared DB reference for hooks
86
+ dbRef.current = db;
87
+ const transactionFn = ctx.database.transaction;
88
+ // Initialize services
89
+ const terminalService = new TerminalService(db);
90
+ const shiftService = new ShiftService(db, transactionFn);
91
+ const transactionService = new TransactionService(db, transactionFn);
92
+ const paymentService = new PaymentService(db, transactionFn);
93
+ const returnService = new ReturnService(db);
94
+ const lookupService = new LookupService(db, ctx.services);
95
+ const receiptService = new ReceiptService(db, ctx.services);
96
+ // Cart service from core (for creating POS transaction carts)
97
+ const cartService = ctx.services.cart;
98
+ return [
99
+ ...buildTerminalRoutes(terminalService, ctx),
100
+ ...buildShiftRoutes(shiftService, ctx),
101
+ ...buildTransactionRoutes(transactionService, cartService, ctx),
102
+ ...buildPaymentRoutes(paymentService, transactionService, ctx),
103
+ ...buildReturnRoutes(returnService, transactionService, paymentService, cartService, ctx),
104
+ ...buildLookupRoutes(lookupService, ctx),
105
+ ...buildReceiptRoutes(receiptService, ctx),
106
+ ];
107
+ },
108
+ });
109
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * POS Payment Adapter for the checkout pipeline.
3
+ *
4
+ * POS payments are collected at the terminal before checkout is called.
5
+ * The adapter acts as a pass-through: payment has already been tendered,
6
+ * so authorize/capture are no-ops.
7
+ */
8
+ export interface PaymentAdapter {
9
+ providerId: string;
10
+ createPaymentIntent(params: {
11
+ amount: number;
12
+ currency: string;
13
+ orderId?: string;
14
+ metadata?: Record<string, unknown>;
15
+ }): Promise<{
16
+ id: string;
17
+ status: string;
18
+ amount: number;
19
+ clientSecret?: string;
20
+ }>;
21
+ capturePayment(intentId: string, amount: number): Promise<{
22
+ id: string;
23
+ status: string;
24
+ amountCaptured: number;
25
+ }>;
26
+ refundPayment(paymentId: string, amount: number): Promise<{
27
+ id: string;
28
+ status: string;
29
+ amountRefunded: number;
30
+ }>;
31
+ }
32
+ export declare function createPOSPaymentAdapter(): PaymentAdapter;
33
+ //# sourceMappingURL=payment-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"payment-adapter.d.ts","sourceRoot":"","sources":["../src/payment-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,mBAAmB,CAAC,MAAM,EAAE;QAC1B,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;QACjB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACpC,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACnF,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAClH,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACnH;AAED,wBAAgB,uBAAuB,IAAI,cAAc,CAgCxD"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * POS Payment Adapter for the checkout pipeline.
3
+ *
4
+ * POS payments are collected at the terminal before checkout is called.
5
+ * The adapter acts as a pass-through: payment has already been tendered,
6
+ * so authorize/capture are no-ops.
7
+ */
8
+ export function createPOSPaymentAdapter() {
9
+ return {
10
+ providerId: "pos",
11
+ async createPaymentIntent(params) {
12
+ // POS payments are already collected at the terminal.
13
+ // The "intent" represents the sum of pos_payments rows.
14
+ return {
15
+ id: `pos_${params.orderId ?? crypto.randomUUID()}`,
16
+ status: "requires_capture",
17
+ amount: params.amount,
18
+ };
19
+ },
20
+ async capturePayment(intentId, amount) {
21
+ // POS payments are already collected. Capture is a no-op.
22
+ return {
23
+ id: intentId,
24
+ status: "succeeded",
25
+ amountCaptured: amount,
26
+ };
27
+ },
28
+ async refundPayment(paymentId, amount) {
29
+ // POS refunds are handled by the return transaction flow.
30
+ return {
31
+ id: `ref_${paymentId}`,
32
+ status: "succeeded",
33
+ amountRefunded: amount,
34
+ };
35
+ },
36
+ };
37
+ }
@@ -0,0 +1,9 @@
1
+ import type { LookupService } from "../services/lookup-service";
2
+ import type { PluginRouteRegistration } from "@unifiedcommerce/core";
3
+ export declare function buildLookupRoutes(service: LookupService, ctx: {
4
+ services?: Record<string, unknown>;
5
+ database?: {
6
+ db: unknown;
7
+ };
8
+ }): PluginRouteRegistration[];
9
+ //# sourceMappingURL=lookup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lookup.d.ts","sourceRoot":"","sources":["../../src/routes/lookup.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAErE,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,aAAa,EACtB,GAAG,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,QAAQ,CAAC,EAAE;QAAE,EAAE,EAAE,OAAO,CAAA;KAAE,CAAA;CAAE,GACtE,uBAAuB,EAAE,CAmC3B"}
@@ -0,0 +1,37 @@
1
+ import { router } from "@unifiedcommerce/core";
2
+ import { z } from "@hono/zod-openapi";
3
+ export function buildLookupRoutes(service, ctx) {
4
+ const r = router("POS Lookup", "/pos/lookup", ctx);
5
+ r.get("/barcode/{code}")
6
+ .summary("Lookup by barcode")
7
+ .permission("pos:operate")
8
+ .handler(async ({ params, orgId }) => {
9
+ const result = await service.byBarcode(orgId, params.code);
10
+ if (!result.ok)
11
+ throw new Error(result.error);
12
+ return result.value;
13
+ });
14
+ r.get("/sku/{sku}")
15
+ .summary("Lookup by SKU")
16
+ .permission("pos:operate")
17
+ .handler(async ({ params, orgId }) => {
18
+ const result = await service.bySku(orgId, params.sku);
19
+ if (!result.ok)
20
+ throw new Error(result.error);
21
+ return result.value;
22
+ });
23
+ r.get("/search")
24
+ .summary("Search items")
25
+ .permission("pos:operate")
26
+ .query(z.object({
27
+ q: z.string().min(1).max(200),
28
+ }))
29
+ .handler(async ({ query, orgId }) => {
30
+ const q = query;
31
+ const result = await service.search(orgId, q.q);
32
+ if (!result.ok)
33
+ throw new Error(result.error);
34
+ return result.value;
35
+ });
36
+ return r.routes();
37
+ }
@@ -0,0 +1,10 @@
1
+ import type { PaymentService } from "../services/payment-service";
2
+ import type { TransactionService } from "../services/transaction-service";
3
+ import type { PluginRouteRegistration } from "@unifiedcommerce/core";
4
+ export declare function buildPaymentRoutes(paymentService: PaymentService, transactionService: TransactionService, ctx: {
5
+ services?: Record<string, unknown>;
6
+ database?: {
7
+ db: unknown;
8
+ };
9
+ }): PluginRouteRegistration[];
10
+ //# sourceMappingURL=payments.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"payments.d.ts","sourceRoot":"","sources":["../../src/routes/payments.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AAC1E,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAErE,wBAAgB,kBAAkB,CAChC,cAAc,EAAE,cAAc,EAC9B,kBAAkB,EAAE,kBAAkB,EACtC,GAAG,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,QAAQ,CAAC,EAAE;QAAE,EAAE,EAAE,OAAO,CAAA;KAAE,CAAA;CAAE,GACtE,uBAAuB,EAAE,CAuE3B"}
@@ -0,0 +1,62 @@
1
+ import { router } from "@unifiedcommerce/core";
2
+ import { z } from "@hono/zod-openapi";
3
+ export function buildPaymentRoutes(paymentService, transactionService, ctx) {
4
+ const r = router("POS Payments", "/pos/transactions", ctx);
5
+ r.post("/{id}/payments")
6
+ .summary("Add payment")
7
+ .permission("pos:operate")
8
+ .input(z.object({
9
+ method: z.enum(["cash", "card", "gift_card", "store_credit", "other"]),
10
+ amount: z.number().int().positive(),
11
+ changeGiven: z.number().int().min(0).optional(),
12
+ reference: z.string().max(200).optional(),
13
+ metadata: z.record(z.string(), z.unknown()).optional(),
14
+ }))
15
+ .handler(async ({ params, input, orgId }) => {
16
+ const body = input;
17
+ const result = await paymentService.addPayment(orgId, params.id, body);
18
+ if (!result.ok)
19
+ throw new Error(result.error);
20
+ return result.value;
21
+ });
22
+ r.post("/{id}/complete")
23
+ .summary("Complete transaction")
24
+ .description("Validates total payments >= total, then calls checkout pipeline.")
25
+ .permission("pos:operate")
26
+ .handler(async ({ params, services, orgId }) => {
27
+ // Validate payments cover the total
28
+ const validation = await paymentService.validateForCompletion(orgId, params.id);
29
+ if (!validation.ok)
30
+ throw new Error(validation.error);
31
+ const { transaction } = validation.value;
32
+ // Call checkout pipeline via the checkout service
33
+ // The POS payment adapter handles the payment side
34
+ const checkout = services;
35
+ // Build checkout request — POS goes through the same pipeline as online
36
+ const checkoutBody = {
37
+ cartId: transaction.cartId,
38
+ currency: "USD",
39
+ paymentMethodId: "pos",
40
+ metadata: {
41
+ posTransactionId: transaction.id,
42
+ posShiftId: transaction.shiftId,
43
+ posTerminalId: transaction.terminalId,
44
+ },
45
+ ...(transaction.customerId != null ? { customerId: transaction.customerId } : {}),
46
+ };
47
+ // We need to make an internal call to the checkout pipeline
48
+ // This is handled by POSCheckoutAdapter in hooks/checkout-pos.ts
49
+ // For now, return the transaction with payment status
50
+ // The plugin entry point wires the checkout hook
51
+ // Mark transaction as completed (the afterCreate hook will set orderId)
52
+ const result = await transactionService.complete(params.id, null);
53
+ if (!result.ok)
54
+ throw new Error(result.error);
55
+ return {
56
+ transaction: result.value,
57
+ checkoutRequest: checkoutBody,
58
+ message: "Transaction completed. Use POST /api/checkout with the checkoutRequest body to finalize.",
59
+ };
60
+ });
61
+ return r.routes();
62
+ }
@@ -0,0 +1,9 @@
1
+ import type { ReceiptService } from "../services/receipt-service";
2
+ import type { PluginRouteRegistration } from "@unifiedcommerce/core";
3
+ export declare function buildReceiptRoutes(service: ReceiptService, ctx: {
4
+ services?: Record<string, unknown>;
5
+ database?: {
6
+ db: unknown;
7
+ };
8
+ }): PluginRouteRegistration[];
9
+ //# sourceMappingURL=receipts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"receipts.d.ts","sourceRoot":"","sources":["../../src/routes/receipts.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAErE,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,cAAc,EACvB,GAAG,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,QAAQ,CAAC,EAAE;QAAE,EAAE,EAAE,OAAO,CAAA;KAAE,CAAA;CAAE,GACtE,uBAAuB,EAAE,CA0B3B"}
@@ -0,0 +1,28 @@
1
+ import { router } from "@unifiedcommerce/core";
2
+ import { z } from "@hono/zod-openapi";
3
+ export function buildReceiptRoutes(service, ctx) {
4
+ const r = router("POS Receipts", "/pos/transactions", ctx);
5
+ r.get("/{id}/receipt")
6
+ .summary("Get receipt")
7
+ .permission("pos:operate")
8
+ .handler(async ({ params, orgId }) => {
9
+ const result = await service.getReceipt(orgId, params.id);
10
+ if (!result.ok)
11
+ throw new Error(result.error);
12
+ return result.value;
13
+ });
14
+ r.post("/{id}/receipt/email")
15
+ .summary("Email receipt")
16
+ .permission("pos:operate")
17
+ .input(z.object({
18
+ email: z.string().email(),
19
+ }))
20
+ .handler(async ({ params, input, orgId }) => {
21
+ const body = input;
22
+ const result = await service.emailReceipt(orgId, params.id, body.email);
23
+ if (!result.ok)
24
+ throw new Error(result.error);
25
+ return result.value;
26
+ });
27
+ return r.routes();
28
+ }
@@ -0,0 +1,21 @@
1
+ import type { ReturnService } from "../services/return-service";
2
+ import type { TransactionService } from "../services/transaction-service";
3
+ import type { PaymentService } from "../services/payment-service";
4
+ import type { PluginRouteRegistration } from "@unifiedcommerce/core";
5
+ export declare function buildReturnRoutes(returnService: ReturnService, transactionService: TransactionService, paymentService: PaymentService, cartService: {
6
+ create: (input: {
7
+ currency?: string;
8
+ metadata?: Record<string, unknown>;
9
+ }, actor: unknown) => Promise<{
10
+ ok: boolean;
11
+ value?: {
12
+ id: string;
13
+ };
14
+ }>;
15
+ }, ctx: {
16
+ services?: Record<string, unknown>;
17
+ database?: {
18
+ db: unknown;
19
+ };
20
+ }): PluginRouteRegistration[];
21
+ //# sourceMappingURL=returns.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"returns.d.ts","sourceRoot":"","sources":["../../src/routes/returns.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AAC1E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAErE,wBAAgB,iBAAiB,CAC/B,aAAa,EAAE,aAAa,EAC5B,kBAAkB,EAAE,kBAAkB,EACtC,cAAc,EAAE,cAAc,EAC9B,WAAW,EAAE;IAAE,MAAM,EAAE,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,EAAE,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE;YAAE,EAAE,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC,CAAA;CAAE,EAC/J,GAAG,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,QAAQ,CAAC,EAAE;QAAE,EAAE,EAAE,OAAO,CAAA;KAAE,CAAA;CAAE,GACtE,uBAAuB,EAAE,CAsG3B"}
@@ -0,0 +1,83 @@
1
+ import { router } from "@unifiedcommerce/core";
2
+ import { z } from "@hono/zod-openapi";
3
+ export function buildReturnRoutes(returnService, transactionService, paymentService, cartService, ctx) {
4
+ const r = router("POS Returns", "/pos/returns", ctx);
5
+ r.post("/")
6
+ .summary("Create return")
7
+ .permission("pos:manage")
8
+ .input(z.object({
9
+ shiftId: z.string().uuid(),
10
+ terminalId: z.string().uuid(),
11
+ originalOrderId: z.string().uuid(),
12
+ items: z.array(z.object({
13
+ originalLineItemId: z.string().uuid(),
14
+ quantity: z.number().int().positive(),
15
+ reason: z.enum(["defective", "wrong_item", "changed_mind", "other"]),
16
+ restockingFee: z.number().int().min(0).optional(),
17
+ refundAmount: z.number().int().positive(),
18
+ })).min(1),
19
+ }))
20
+ .handler(async ({ input, actor, orgId }) => {
21
+ const body = input;
22
+ // Create a cart for the return transaction
23
+ const cartResult = await cartService.create({ currency: "USD", metadata: { posReturn: true } }, actor);
24
+ if (!cartResult.ok || !cartResult.value) {
25
+ throw new Error("Failed to create cart for return");
26
+ }
27
+ // Create return transaction
28
+ const txnResult = await transactionService.create(orgId, {
29
+ shiftId: body.shiftId,
30
+ terminalId: body.terminalId,
31
+ operatorId: actor.userId,
32
+ cartId: cartResult.value.id,
33
+ type: "return",
34
+ });
35
+ if (!txnResult.ok)
36
+ throw new Error(txnResult.error);
37
+ // Record return items
38
+ const itemsResult = await returnService.addReturnItems(txnResult.value.id, body.items.map((item) => ({
39
+ ...item,
40
+ originalOrderId: body.originalOrderId,
41
+ })));
42
+ if (!itemsResult.ok)
43
+ throw new Error(itemsResult.error);
44
+ // Update transaction totals
45
+ const refundTotal = body.items.reduce((sum, i) => sum + i.refundAmount, 0);
46
+ await transactionService.updateTotals(txnResult.value.id, {
47
+ subtotal: refundTotal,
48
+ taxTotal: 0,
49
+ total: refundTotal,
50
+ discountTotal: 0,
51
+ });
52
+ return {
53
+ transaction: txnResult.value,
54
+ returnItems: itemsResult.value,
55
+ refundTotal,
56
+ };
57
+ });
58
+ r.post("/{id}/payments")
59
+ .summary("Add refund payment")
60
+ .permission("pos:operate")
61
+ .input(z.object({
62
+ method: z.enum(["cash", "card", "gift_card", "store_credit", "other"]),
63
+ amount: z.number().int().positive(),
64
+ reference: z.string().max(200).optional(),
65
+ }))
66
+ .handler(async ({ params, input, orgId }) => {
67
+ const body = input;
68
+ const result = await paymentService.addPayment(orgId, params.id, body);
69
+ if (!result.ok)
70
+ throw new Error(result.error);
71
+ return result.value;
72
+ });
73
+ r.post("/{id}/complete")
74
+ .summary("Complete return")
75
+ .permission("pos:operate")
76
+ .handler(async ({ params, actor }) => {
77
+ const result = await transactionService.complete(params.id, null);
78
+ if (!result.ok)
79
+ throw new Error(result.error);
80
+ return result.value;
81
+ });
82
+ return r.routes();
83
+ }
@@ -0,0 +1,9 @@
1
+ import type { ShiftService } from "../services/shift-service";
2
+ import type { PluginRouteRegistration } from "@unifiedcommerce/core";
3
+ export declare function buildShiftRoutes(service: ShiftService, ctx: {
4
+ services?: Record<string, unknown>;
5
+ database?: {
6
+ db: unknown;
7
+ };
8
+ }): PluginRouteRegistration[];
9
+ //# sourceMappingURL=shifts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shifts.d.ts","sourceRoot":"","sources":["../../src/routes/shifts.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAErE,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,YAAY,EACrB,GAAG,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,QAAQ,CAAC,EAAE;QAAE,EAAE,EAAE,OAAO,CAAA;KAAE,CAAA;CAAE,GACtE,uBAAuB,EAAE,CA2F3B"}