@porulle/plugin-pos 0.63.0 → 0.65.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/README.md +1 -1
- package/dist/index.d.ts +0 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -2
- package/dist/services/payment-service.d.ts +0 -8
- package/dist/services/payment-service.d.ts.map +1 -1
- package/dist/services/payment-service.js +0 -20
- package/dist/services/receipt-service.d.ts +1 -0
- package/dist/services/receipt-service.d.ts.map +1 -1
- package/dist/services/receipt-service.js +24 -18
- package/dist/services/return-service.d.ts +0 -8
- package/dist/services/return-service.d.ts.map +1 -1
- package/dist/services/return-service.js +0 -21
- package/dist/types.d.ts +0 -6
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +0 -3
- package/package.json +2 -3
- package/src/index.ts +0 -3
- package/src/services/payment-service.ts +0 -23
- package/src/services/receipt-service.ts +26 -19
- package/src/services/return-service.ts +0 -23
- package/src/types.ts +0 -9
- package/dist/payment-adapter.d.ts +0 -33
- package/dist/payment-adapter.d.ts.map +0 -1
- package/dist/payment-adapter.js +0 -37
- package/src/payment-adapter.ts +0 -53
package/README.md
CHANGED
|
@@ -52,7 +52,7 @@ Registers POS tables for terminals, shifts, transactions, payments, and return l
|
|
|
52
52
|
|
|
53
53
|
## Configuration options
|
|
54
54
|
|
|
55
|
-
`POSPluginOptions`: `
|
|
55
|
+
`POSPluginOptions`: `pinAuth` (API key scope, credential TTL, PIN lockout thresholds).
|
|
56
56
|
|
|
57
57
|
## License
|
|
58
58
|
|
package/dist/index.d.ts
CHANGED
|
@@ -9,7 +9,6 @@ export { LookupService } from "./services/lookup-service.js";
|
|
|
9
9
|
export { ReceiptService } from "./services/receipt-service.js";
|
|
10
10
|
export { PinService, hashPin, verifyPinHash } from "./services/pin-service.js";
|
|
11
11
|
export { ExchangeService } from "./services/exchange-service.js";
|
|
12
|
-
export { createPOSPaymentAdapter } from "./payment-adapter.js";
|
|
13
12
|
/**
|
|
14
13
|
* POS Plugin — Tier 0 Core Primitives
|
|
15
14
|
*
|
|
@@ -21,7 +20,6 @@ export { createPOSPaymentAdapter } from "./payment-adapter.js";
|
|
|
21
20
|
* - Returns with original order linkage
|
|
22
21
|
* - Barcode/SKU lookup via indexed queries
|
|
23
22
|
* - Receipt data assembly + email
|
|
24
|
-
* - POS payment adapter for checkout pipeline
|
|
25
23
|
* - Checkout hooks (zero shipping, transaction finalization)
|
|
26
24
|
*/
|
|
27
25
|
export declare function posPlugin(userOptions?: POSPluginOptions): import("@porulle/core").CommercePlugin;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AA8BA,OAAO,KAAK,EAAE,gBAAgB,EAAM,MAAM,YAAY,CAAC;AAGvD,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AACvE,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC/E,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACjE
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AA8BA,OAAO,KAAK,EAAE,gBAAgB,EAAM,MAAM,YAAY,CAAC;AAGvD,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AACvE,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC/E,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACjE;;;;;;;;;;;;GAYG;AACH,wBAAgB,SAAS,CAAC,WAAW,GAAE,gBAAqB,0CAwG3D"}
|
package/dist/index.js
CHANGED
|
@@ -29,7 +29,6 @@ export { LookupService } from "./services/lookup-service.js";
|
|
|
29
29
|
export { ReceiptService } from "./services/receipt-service.js";
|
|
30
30
|
export { PinService, hashPin, verifyPinHash } from "./services/pin-service.js";
|
|
31
31
|
export { ExchangeService } from "./services/exchange-service.js";
|
|
32
|
-
export { createPOSPaymentAdapter } from "./payment-adapter.js";
|
|
33
32
|
/**
|
|
34
33
|
* POS Plugin — Tier 0 Core Primitives
|
|
35
34
|
*
|
|
@@ -41,7 +40,6 @@ export { createPOSPaymentAdapter } from "./payment-adapter.js";
|
|
|
41
40
|
* - Returns with original order linkage
|
|
42
41
|
* - Barcode/SKU lookup via indexed queries
|
|
43
42
|
* - Receipt data assembly + email
|
|
44
|
-
* - POS payment adapter for checkout pipeline
|
|
45
43
|
* - Checkout hooks (zero shipping, transaction finalization)
|
|
46
44
|
*/
|
|
47
45
|
export function posPlugin(userOptions = {}) {
|
|
@@ -19,10 +19,6 @@ export declare class PaymentService {
|
|
|
19
19
|
* Get total payments collected for a transaction.
|
|
20
20
|
*/
|
|
21
21
|
getPaymentTotal(transactionId: string, tx?: Db): Promise<number>;
|
|
22
|
-
/**
|
|
23
|
-
* List all payments for a transaction.
|
|
24
|
-
*/
|
|
25
|
-
listPayments(transactionId: string): Promise<PluginResult<Payment[]>>;
|
|
26
22
|
/**
|
|
27
23
|
* Validate that total payments cover the transaction total, then return
|
|
28
24
|
* the transaction details needed for checkout.
|
|
@@ -32,9 +28,5 @@ export declare class PaymentService {
|
|
|
32
28
|
payments: Payment[];
|
|
33
29
|
totalPaid: number;
|
|
34
30
|
}>>;
|
|
35
|
-
/**
|
|
36
|
-
* Mark payments as refunded for a transaction.
|
|
37
|
-
*/
|
|
38
|
-
refundPayments(transactionId: string, tx?: Db): Promise<void>;
|
|
39
31
|
}
|
|
40
32
|
//# sourceMappingURL=payment-service.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"payment-service.d.ts","sourceRoot":"","sources":["../../src/services/payment-service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,OAAO,KAAK,EAAE,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE5D,qBAAa,cAAc;IAEvB,OAAO,CAAC,EAAE;IACV,OAAO,CAAC,WAAW;gBADX,EAAE,EAAE,EAAE,EACN,WAAW,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,OAAO,CAAC,OAAO,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC;IAG7E;;;OAGG;IACG,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,KAAK,EAAE;QAC5D,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,WAAW,GAAG,cAAc,GAAG,OAAO,CAAC;QACjE,MAAM,EAAE,MAAM,CAAC;QACf,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACpC,EAAE,EAAE,CAAC,EAAE,EAAE,GAAG,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;IA0C3C;;OAEG;IACG,eAAe,CAAC,aAAa,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IAetE
|
|
1
|
+
{"version":3,"file":"payment-service.d.ts","sourceRoot":"","sources":["../../src/services/payment-service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,OAAO,KAAK,EAAE,EAAE,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE5D,qBAAa,cAAc;IAEvB,OAAO,CAAC,EAAE;IACV,OAAO,CAAC,WAAW;gBADX,EAAE,EAAE,EAAE,EACN,WAAW,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,OAAO,CAAC,OAAO,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC;IAG7E;;;OAGG;IACG,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,KAAK,EAAE;QAC5D,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,WAAW,GAAG,cAAc,GAAG,OAAO,CAAC;QACjE,MAAM,EAAE,MAAM,CAAC;QACf,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACpC,EAAE,EAAE,CAAC,EAAE,EAAE,GAAG,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;IA0C3C;;OAEG;IACG,eAAe,CAAC,aAAa,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IAetE;;;OAGG;IACG,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;QACtF,WAAW,EAAE,WAAW,CAAC;QACzB,QAAQ,EAAE,OAAO,EAAE,CAAC;QACpB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC,CAAC;CA6BJ"}
|
|
@@ -60,16 +60,6 @@ export class PaymentService {
|
|
|
60
60
|
.where(and(eq(posPayments.transactionId, transactionId), eq(posPayments.status, "collected")));
|
|
61
61
|
return Number(rows[0]?.total ?? 0);
|
|
62
62
|
}
|
|
63
|
-
/**
|
|
64
|
-
* List all payments for a transaction.
|
|
65
|
-
*/
|
|
66
|
-
async listPayments(transactionId) {
|
|
67
|
-
const rows = await this.db
|
|
68
|
-
.select()
|
|
69
|
-
.from(posPayments)
|
|
70
|
-
.where(eq(posPayments.transactionId, transactionId));
|
|
71
|
-
return Ok(rows);
|
|
72
|
-
}
|
|
73
63
|
/**
|
|
74
64
|
* Validate that total payments cover the transaction total, then return
|
|
75
65
|
* the transaction details needed for checkout.
|
|
@@ -94,14 +84,4 @@ export class PaymentService {
|
|
|
94
84
|
}
|
|
95
85
|
return Ok({ transaction: txn, payments, totalPaid });
|
|
96
86
|
}
|
|
97
|
-
/**
|
|
98
|
-
* Mark payments as refunded for a transaction.
|
|
99
|
-
*/
|
|
100
|
-
async refundPayments(transactionId, tx) {
|
|
101
|
-
const db = tx ?? this.db;
|
|
102
|
-
await db
|
|
103
|
-
.update(posPayments)
|
|
104
|
-
.set({ status: "refunded" })
|
|
105
|
-
.where(eq(posPayments.transactionId, transactionId));
|
|
106
|
-
}
|
|
107
87
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"receipt-service.d.ts","sourceRoot":"","sources":["../../src/services/receipt-service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,OAAO,KAAK,EAAE,EAAE,EAAwB,MAAM,aAAa,CAAC;AAE5D,MAAM,WAAW,WAAW;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,KAAK,CAAC;QACf,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE,MAAM,CAAC;QACnB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KACvB,CAAC,CAAC;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,KAAK,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,CAAC;QACf,WAAW,EAAE,MAAM,CAAC;QACpB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KAC3B,CAAC,CAAC;IACH,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"receipt-service.d.ts","sourceRoot":"","sources":["../../src/services/receipt-service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,OAAO,KAAK,EAAE,EAAE,EAAwB,MAAM,aAAa,CAAC;AAE5D,MAAM,WAAW,WAAW;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,KAAK,CAAC;QACf,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE,MAAM,CAAC;QACnB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KACvB,CAAC,CAAC;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,KAAK,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,CAAC;QACf,WAAW,EAAE,MAAM,CAAC;QACpB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KAC3B,CAAC,CAAC;IACH,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,cAAc;IAEvB,OAAO,CAAC,EAAE;IACV,OAAO,CAAC,QAAQ;gBADR,EAAE,EAAE,EAAE,EACN,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAG3C;;OAEG;IACG,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC;IAuF1F;;OAEG;IACG,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;QAAE,IAAI,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAqBjH,OAAO,CAAC,iBAAiB;CAqB1B"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { eq, and } from "@porulle/core/drizzle";
|
|
2
|
-
import { Ok, Err } from "@porulle/core";
|
|
2
|
+
import { Ok, Err, escapeHtml, formatAmount } from "@porulle/core";
|
|
3
3
|
import { posTransactions, posPayments } from "../schema.js";
|
|
4
4
|
export class ReceiptService {
|
|
5
5
|
db;
|
|
@@ -37,17 +37,21 @@ export class ReceiptService {
|
|
|
37
37
|
.where(eq(posPayments.transactionId, transactionId));
|
|
38
38
|
// Get order line items from core
|
|
39
39
|
let lineItems = [];
|
|
40
|
+
let currency = "USD";
|
|
40
41
|
if (txn.orderId) {
|
|
41
42
|
const orders = this.services.orders;
|
|
42
43
|
if (orders) {
|
|
43
44
|
const orderResult = await orders.getById(txn.orderId, null);
|
|
44
|
-
if (orderResult.ok && orderResult.value
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
45
|
+
if (orderResult.ok && orderResult.value) {
|
|
46
|
+
currency = orderResult.value.currency ?? currency;
|
|
47
|
+
if (orderResult.value.lineItems) {
|
|
48
|
+
lineItems = orderResult.value.lineItems.map((li) => ({
|
|
49
|
+
title: li.title ?? "Item",
|
|
50
|
+
quantity: li.quantity,
|
|
51
|
+
unitPrice: li.unitPrice ?? 0,
|
|
52
|
+
totalPrice: li.totalPrice ?? 0,
|
|
53
|
+
}));
|
|
54
|
+
}
|
|
51
55
|
}
|
|
52
56
|
}
|
|
53
57
|
}
|
|
@@ -77,6 +81,7 @@ export class ReceiptService {
|
|
|
77
81
|
})),
|
|
78
82
|
changeDue,
|
|
79
83
|
customerId: txn.customerId,
|
|
84
|
+
currency,
|
|
80
85
|
});
|
|
81
86
|
}
|
|
82
87
|
/**
|
|
@@ -93,27 +98,28 @@ export class ReceiptService {
|
|
|
93
98
|
await emailService.send({
|
|
94
99
|
to: email,
|
|
95
100
|
subject: `Receipt ${receiptResult.value.receiptNumber}`,
|
|
96
|
-
html: this.formatReceiptHtml(receiptResult.value),
|
|
101
|
+
html: this.formatReceiptHtml(receiptResult.value, receiptResult.value.currency),
|
|
97
102
|
});
|
|
98
103
|
return Ok({ sent: true });
|
|
99
104
|
}
|
|
100
|
-
formatReceiptHtml(receipt) {
|
|
105
|
+
formatReceiptHtml(receipt, currency = "USD") {
|
|
106
|
+
const fmt = (minor) => formatAmount(minor, currency);
|
|
101
107
|
const lines = receipt.lineItems
|
|
102
|
-
.map((li) => `<tr><td>${li.title}</td><td>${li.quantity}</td><td>${(li.unitPrice
|
|
108
|
+
.map((li) => `<tr><td>${escapeHtml(li.title)}</td><td>${li.quantity}</td><td>${fmt(li.unitPrice)}</td><td>${fmt(li.totalPrice)}</td></tr>`)
|
|
103
109
|
.join("");
|
|
104
110
|
return `
|
|
105
|
-
<h2>Receipt ${receipt.receiptNumber}</h2>
|
|
111
|
+
<h2>Receipt ${escapeHtml(receipt.receiptNumber)}</h2>
|
|
106
112
|
<p>Date: ${receipt.timestamp.toISOString()}</p>
|
|
107
113
|
<table>
|
|
108
114
|
<tr><th>Item</th><th>Qty</th><th>Price</th><th>Total</th></tr>
|
|
109
115
|
${lines}
|
|
110
116
|
</table>
|
|
111
|
-
<p>Subtotal: ${(receipt.subtotal
|
|
112
|
-
${receipt.discountTotal > 0 ? `<p>Discount: -${(receipt.discountTotal
|
|
113
|
-
<p>Tax: ${(receipt.taxTotal
|
|
114
|
-
<p><strong>Total: ${(receipt.total
|
|
115
|
-
${receipt.payments.map((p) => `<p>${p.method}: ${(p.amount
|
|
116
|
-
${receipt.changeDue > 0 ? `<p>Change: ${(receipt.changeDue
|
|
117
|
+
<p>Subtotal: ${fmt(receipt.subtotal)}</p>
|
|
118
|
+
${receipt.discountTotal > 0 ? `<p>Discount: -${fmt(receipt.discountTotal)}</p>` : ""}
|
|
119
|
+
<p>Tax: ${fmt(receipt.taxTotal)}</p>
|
|
120
|
+
<p><strong>Total: ${fmt(receipt.total)}</strong></p>
|
|
121
|
+
${receipt.payments.map((p) => `<p>${escapeHtml(p.method)}: ${fmt(p.amount)}</p>`).join("")}
|
|
122
|
+
${receipt.changeDue > 0 ? `<p>Change: ${fmt(receipt.changeDue)}</p>` : ""}
|
|
117
123
|
`;
|
|
118
124
|
}
|
|
119
125
|
}
|
|
@@ -15,13 +15,5 @@ export declare class ReturnService {
|
|
|
15
15
|
restockingFee?: number;
|
|
16
16
|
refundAmount: number;
|
|
17
17
|
}>, tx?: Db): Promise<PluginResult<ReturnItem[]>>;
|
|
18
|
-
/**
|
|
19
|
-
* Get all return items for a return transaction.
|
|
20
|
-
*/
|
|
21
|
-
getReturnItems(transactionId: string): Promise<PluginResult<ReturnItem[]>>;
|
|
22
|
-
/**
|
|
23
|
-
* Calculate total refund amount for a return transaction.
|
|
24
|
-
*/
|
|
25
|
-
calculateRefundTotal(transactionId: string): Promise<number>;
|
|
26
18
|
}
|
|
27
19
|
//# sourceMappingURL=return-service.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"return-service.d.ts","sourceRoot":"","sources":["../../src/services/return-service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,OAAO,KAAK,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAElD,qBAAa,aAAa;IACZ,OAAO,CAAC,EAAE;gBAAF,EAAE,EAAE,EAAE;IAE1B;;;OAGG;IACG,cAAc,CAAC,aAAa,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC;QACvD,eAAe,EAAE,MAAM,CAAC;QACxB,kBAAkB,EAAE,MAAM,CAAC;QAC3B,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,WAAW,GAAG,YAAY,GAAG,cAAc,GAAG,OAAO,CAAC;QAC9D,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,GAAG,OAAO,CAAC,YAAY,CAAC,UAAU,EAAE,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"return-service.d.ts","sourceRoot":"","sources":["../../src/services/return-service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,OAAO,KAAK,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAElD,qBAAa,aAAa;IACZ,OAAO,CAAC,EAAE;gBAAF,EAAE,EAAE,EAAE;IAE1B;;;OAGG;IACG,cAAc,CAAC,aAAa,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC;QACvD,eAAe,EAAE,MAAM,CAAC;QACxB,kBAAkB,EAAE,MAAM,CAAC;QAC3B,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,WAAW,GAAG,YAAY,GAAG,cAAc,GAAG,OAAO,CAAC;QAC9D,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,GAAG,OAAO,CAAC,YAAY,CAAC,UAAU,EAAE,CAAC,CAAC;CAsBlD"}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { eq } from "@porulle/core/drizzle";
|
|
2
1
|
import { Ok, Err } from "@porulle/core";
|
|
3
2
|
import { posReturnItems } from "../schema.js";
|
|
4
3
|
export class ReturnService {
|
|
@@ -29,24 +28,4 @@ export class ReturnService {
|
|
|
29
28
|
.returning();
|
|
30
29
|
return Ok(rows);
|
|
31
30
|
}
|
|
32
|
-
/**
|
|
33
|
-
* Get all return items for a return transaction.
|
|
34
|
-
*/
|
|
35
|
-
async getReturnItems(transactionId) {
|
|
36
|
-
const rows = await this.db
|
|
37
|
-
.select()
|
|
38
|
-
.from(posReturnItems)
|
|
39
|
-
.where(eq(posReturnItems.transactionId, transactionId));
|
|
40
|
-
return Ok(rows);
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* Calculate total refund amount for a return transaction.
|
|
44
|
-
*/
|
|
45
|
-
async calculateRefundTotal(transactionId) {
|
|
46
|
-
const items = await this.db
|
|
47
|
-
.select()
|
|
48
|
-
.from(posReturnItems)
|
|
49
|
-
.where(eq(posReturnItems.transactionId, transactionId));
|
|
50
|
-
return items.reduce((sum, item) => sum + item.refundAmount, 0);
|
|
51
|
-
}
|
|
52
31
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -23,12 +23,6 @@ export type CashEventType = "float" | "drop" | "pickup" | "paid_in" | "paid_out"
|
|
|
23
23
|
export type ShiftStatus = "open" | "closed";
|
|
24
24
|
export type TerminalType = "register" | "tablet" | "mobile" | "kiosk";
|
|
25
25
|
export interface POSPluginOptions {
|
|
26
|
-
/** Default currency for new transactions. Default: "USD" */
|
|
27
|
-
defaultCurrency?: string;
|
|
28
|
-
/** Maximum hold duration in hours before auto-void. Default: 24 */
|
|
29
|
-
maxHoldHours?: number;
|
|
30
|
-
/** Require manager override for discounts above this percentage. Default: 20 */
|
|
31
|
-
discountOverrideThreshold?: number;
|
|
32
26
|
/** PIN auth runtime (issue #51). */
|
|
33
27
|
pinAuth?: {
|
|
34
28
|
/** Named auth.apiKeyScopes config used to mint per-shift keys. */
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,KAAK,EACV,YAAY,EACZ,SAAS,EACT,aAAa,EACb,eAAe,EACf,WAAW,EACX,cAAc,EACd,eAAe,EACf,cAAc,EACf,MAAM,aAAa,CAAC;AAErB,MAAM,MAAM,QAAQ,GAAG,OAAO,YAAY,CAAC,YAAY,CAAC;AACxD,MAAM,MAAM,cAAc,GAAG,OAAO,YAAY,CAAC,YAAY,CAAC;AAE9D,MAAM,MAAM,KAAK,GAAG,OAAO,SAAS,CAAC,YAAY,CAAC;AAClD,MAAM,MAAM,WAAW,GAAG,OAAO,SAAS,CAAC,YAAY,CAAC;AAExD,MAAM,MAAM,SAAS,GAAG,OAAO,aAAa,CAAC,YAAY,CAAC;AAC1D,MAAM,MAAM,eAAe,GAAG,OAAO,aAAa,CAAC,YAAY,CAAC;AAEhE,MAAM,MAAM,WAAW,GAAG,OAAO,eAAe,CAAC,YAAY,CAAC;AAC9D,MAAM,MAAM,iBAAiB,GAAG,OAAO,eAAe,CAAC,YAAY,CAAC;AAEpE,MAAM,MAAM,OAAO,GAAG,OAAO,WAAW,CAAC,YAAY,CAAC;AACtD,MAAM,MAAM,aAAa,GAAG,OAAO,WAAW,CAAC,YAAY,CAAC;AAE5D,MAAM,MAAM,UAAU,GAAG,OAAO,cAAc,CAAC,YAAY,CAAC;AAC5D,MAAM,MAAM,gBAAgB,GAAG,OAAO,cAAc,CAAC,YAAY,CAAC;AAElE,MAAM,MAAM,WAAW,GAAG,OAAO,eAAe,CAAC,YAAY,CAAC;AAC9D,MAAM,MAAM,iBAAiB,GAAG,OAAO,eAAe,CAAC,YAAY,CAAC;AAEpE,MAAM,MAAM,UAAU,GAAG,OAAO,cAAc,CAAC,YAAY,CAAC;AAC5D,MAAM,MAAM,gBAAgB,GAAG,OAAO,cAAc,CAAC,YAAY,CAAC;AAElE,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,MAAM,GAAG,WAAW,GAAG,QAAQ,CAAC;AACzE,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,QAAQ,GAAG,UAAU,CAAC;AAC7D,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,MAAM,GAAG,WAAW,GAAG,cAAc,GAAG,OAAO,CAAC;AACrF,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,GAAG,SAAS,GAAG,UAAU,CAAC;AACjF,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,QAAQ,CAAC;AAC5C,MAAM,MAAM,YAAY,GAAG,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEtE,MAAM,WAAW,gBAAgB;IAC/B,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,KAAK,EACV,YAAY,EACZ,SAAS,EACT,aAAa,EACb,eAAe,EACf,WAAW,EACX,cAAc,EACd,eAAe,EACf,cAAc,EACf,MAAM,aAAa,CAAC;AAErB,MAAM,MAAM,QAAQ,GAAG,OAAO,YAAY,CAAC,YAAY,CAAC;AACxD,MAAM,MAAM,cAAc,GAAG,OAAO,YAAY,CAAC,YAAY,CAAC;AAE9D,MAAM,MAAM,KAAK,GAAG,OAAO,SAAS,CAAC,YAAY,CAAC;AAClD,MAAM,MAAM,WAAW,GAAG,OAAO,SAAS,CAAC,YAAY,CAAC;AAExD,MAAM,MAAM,SAAS,GAAG,OAAO,aAAa,CAAC,YAAY,CAAC;AAC1D,MAAM,MAAM,eAAe,GAAG,OAAO,aAAa,CAAC,YAAY,CAAC;AAEhE,MAAM,MAAM,WAAW,GAAG,OAAO,eAAe,CAAC,YAAY,CAAC;AAC9D,MAAM,MAAM,iBAAiB,GAAG,OAAO,eAAe,CAAC,YAAY,CAAC;AAEpE,MAAM,MAAM,OAAO,GAAG,OAAO,WAAW,CAAC,YAAY,CAAC;AACtD,MAAM,MAAM,aAAa,GAAG,OAAO,WAAW,CAAC,YAAY,CAAC;AAE5D,MAAM,MAAM,UAAU,GAAG,OAAO,cAAc,CAAC,YAAY,CAAC;AAC5D,MAAM,MAAM,gBAAgB,GAAG,OAAO,cAAc,CAAC,YAAY,CAAC;AAElE,MAAM,MAAM,WAAW,GAAG,OAAO,eAAe,CAAC,YAAY,CAAC;AAC9D,MAAM,MAAM,iBAAiB,GAAG,OAAO,eAAe,CAAC,YAAY,CAAC;AAEpE,MAAM,MAAM,UAAU,GAAG,OAAO,cAAc,CAAC,YAAY,CAAC;AAC5D,MAAM,MAAM,gBAAgB,GAAG,OAAO,cAAc,CAAC,YAAY,CAAC;AAElE,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,MAAM,GAAG,WAAW,GAAG,QAAQ,CAAC;AACzE,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,QAAQ,GAAG,UAAU,CAAC;AAC7D,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,MAAM,GAAG,WAAW,GAAG,cAAc,GAAG,OAAO,CAAC;AACrF,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,GAAG,SAAS,GAAG,UAAU,CAAC;AACjF,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,QAAQ,CAAC;AAC5C,MAAM,MAAM,YAAY,GAAG,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEtE,MAAM,WAAW,gBAAgB;IAC/B,oCAAoC;IACpC,OAAO,CAAC,EAAE;QACR,kEAAkE;QAClE,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,kEAAkE;QAClE,oBAAoB,CAAC,EAAE,MAAM,CAAC;QAC9B,+DAA+D;QAC/D,kBAAkB,CAAC,EAAE,MAAM,CAAC;QAC5B,qFAAqF;QACrF,oBAAoB,CAAC,EAAE,MAAM,CAAC;KAC/B,CAAC;CACH;AAED,eAAO,MAAM,mBAAmB,EAAE,QAAQ,CAAC,gBAAgB,CAE1D,CAAC"}
|
package/dist/types.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@porulle/plugin-pos",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.65.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -19,8 +19,7 @@
|
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"@hono/zod-openapi": "^1.2.2",
|
|
21
21
|
"hono": "^4.12.5",
|
|
22
|
-
"@porulle/core": "0.
|
|
23
|
-
"@porulle/db": "0.63.0"
|
|
22
|
+
"@porulle/core": "0.65.0"
|
|
24
23
|
},
|
|
25
24
|
"devDependencies": {
|
|
26
25
|
"@types/node": "^24.5.2",
|
package/src/index.ts
CHANGED
|
@@ -41,8 +41,6 @@ export { LookupService } from "./services/lookup-service.js";
|
|
|
41
41
|
export { ReceiptService } from "./services/receipt-service.js";
|
|
42
42
|
export { PinService, hashPin, verifyPinHash } from "./services/pin-service.js";
|
|
43
43
|
export { ExchangeService } from "./services/exchange-service.js";
|
|
44
|
-
export { createPOSPaymentAdapter } from "./payment-adapter.js";
|
|
45
|
-
|
|
46
44
|
/**
|
|
47
45
|
* POS Plugin — Tier 0 Core Primitives
|
|
48
46
|
*
|
|
@@ -54,7 +52,6 @@ export { createPOSPaymentAdapter } from "./payment-adapter.js";
|
|
|
54
52
|
* - Returns with original order linkage
|
|
55
53
|
* - Barcode/SKU lookup via indexed queries
|
|
56
54
|
* - Receipt data assembly + email
|
|
57
|
-
* - POS payment adapter for checkout pipeline
|
|
58
55
|
* - Checkout hooks (zero shipping, transaction finalization)
|
|
59
56
|
*/
|
|
60
57
|
export function posPlugin(userOptions: POSPluginOptions = {}) {
|
|
@@ -80,18 +80,6 @@ export class PaymentService {
|
|
|
80
80
|
return Number(rows[0]?.total ?? 0);
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
/**
|
|
84
|
-
* List all payments for a transaction.
|
|
85
|
-
*/
|
|
86
|
-
async listPayments(transactionId: string): Promise<PluginResult<Payment[]>> {
|
|
87
|
-
const rows = await this.db
|
|
88
|
-
.select()
|
|
89
|
-
.from(posPayments)
|
|
90
|
-
.where(eq(posPayments.transactionId, transactionId));
|
|
91
|
-
|
|
92
|
-
return Ok(rows);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
83
|
/**
|
|
96
84
|
* Validate that total payments cover the transaction total, then return
|
|
97
85
|
* the transaction details needed for checkout.
|
|
@@ -129,15 +117,4 @@ export class PaymentService {
|
|
|
129
117
|
|
|
130
118
|
return Ok({ transaction: txn, payments, totalPaid });
|
|
131
119
|
}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Mark payments as refunded for a transaction.
|
|
135
|
-
*/
|
|
136
|
-
async refundPayments(transactionId: string, tx?: Db): Promise<void> {
|
|
137
|
-
const db = tx ?? this.db;
|
|
138
|
-
await db
|
|
139
|
-
.update(posPayments)
|
|
140
|
-
.set({ status: "refunded" })
|
|
141
|
-
.where(eq(posPayments.transactionId, transactionId));
|
|
142
|
-
}
|
|
143
120
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { eq, and } from "@porulle/core/drizzle";
|
|
2
|
-
import { Ok, Err } from "@porulle/core";
|
|
2
|
+
import { Ok, Err, escapeHtml, formatAmount } from "@porulle/core";
|
|
3
3
|
import type { PluginResult } from "@porulle/core";
|
|
4
4
|
import { posTransactions, posPayments } from "../schema.js";
|
|
5
5
|
import type { Db, Transaction, Payment } from "../types.js";
|
|
@@ -29,6 +29,7 @@ export interface ReceiptData {
|
|
|
29
29
|
}>;
|
|
30
30
|
changeDue: number;
|
|
31
31
|
customerId?: string | null;
|
|
32
|
+
currency: string;
|
|
32
33
|
}
|
|
33
34
|
|
|
34
35
|
export class ReceiptService {
|
|
@@ -74,20 +75,24 @@ export class ReceiptService {
|
|
|
74
75
|
|
|
75
76
|
// Get order line items from core
|
|
76
77
|
let lineItems: ReceiptData["lineItems"] = [];
|
|
78
|
+
let currency = "USD";
|
|
77
79
|
if (txn.orderId) {
|
|
78
80
|
const orders = this.services.orders as {
|
|
79
|
-
getById: (id: string, actor: unknown) => Promise<{ ok: boolean; value?: { lineItems?: Array<{ title?: string; quantity: number; unitPrice?: number; totalPrice?: number }> } }>;
|
|
81
|
+
getById: (id: string, actor: unknown) => Promise<{ ok: boolean; value?: { currency?: string; lineItems?: Array<{ title?: string; quantity: number; unitPrice?: number; totalPrice?: number }> } }>;
|
|
80
82
|
} | undefined;
|
|
81
83
|
|
|
82
84
|
if (orders) {
|
|
83
85
|
const orderResult = await orders.getById(txn.orderId, null);
|
|
84
|
-
if (orderResult.ok && orderResult.value
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
86
|
+
if (orderResult.ok && orderResult.value) {
|
|
87
|
+
currency = orderResult.value.currency ?? currency;
|
|
88
|
+
if (orderResult.value.lineItems) {
|
|
89
|
+
lineItems = orderResult.value.lineItems.map((li) => ({
|
|
90
|
+
title: li.title ?? "Item",
|
|
91
|
+
quantity: li.quantity,
|
|
92
|
+
unitPrice: li.unitPrice ?? 0,
|
|
93
|
+
totalPrice: li.totalPrice ?? 0,
|
|
94
|
+
}));
|
|
95
|
+
}
|
|
91
96
|
}
|
|
92
97
|
}
|
|
93
98
|
}
|
|
@@ -119,6 +124,7 @@ export class ReceiptService {
|
|
|
119
124
|
})),
|
|
120
125
|
changeDue,
|
|
121
126
|
customerId: txn.customerId,
|
|
127
|
+
currency,
|
|
122
128
|
});
|
|
123
129
|
}
|
|
124
130
|
|
|
@@ -140,30 +146,31 @@ export class ReceiptService {
|
|
|
140
146
|
await emailService.send({
|
|
141
147
|
to: email,
|
|
142
148
|
subject: `Receipt ${receiptResult.value.receiptNumber}`,
|
|
143
|
-
html: this.formatReceiptHtml(receiptResult.value),
|
|
149
|
+
html: this.formatReceiptHtml(receiptResult.value, receiptResult.value.currency),
|
|
144
150
|
});
|
|
145
151
|
|
|
146
152
|
return Ok({ sent: true });
|
|
147
153
|
}
|
|
148
154
|
|
|
149
|
-
private formatReceiptHtml(receipt: ReceiptData): string {
|
|
155
|
+
private formatReceiptHtml(receipt: ReceiptData, currency = "USD"): string {
|
|
156
|
+
const fmt = (minor: number) => formatAmount(minor, currency);
|
|
150
157
|
const lines = receipt.lineItems
|
|
151
|
-
.map((li) => `<tr><td>${li.title}</td><td>${li.quantity}</td><td>${(li.unitPrice
|
|
158
|
+
.map((li) => `<tr><td>${escapeHtml(li.title)}</td><td>${li.quantity}</td><td>${fmt(li.unitPrice)}</td><td>${fmt(li.totalPrice)}</td></tr>`)
|
|
152
159
|
.join("");
|
|
153
160
|
|
|
154
161
|
return `
|
|
155
|
-
<h2>Receipt ${receipt.receiptNumber}</h2>
|
|
162
|
+
<h2>Receipt ${escapeHtml(receipt.receiptNumber)}</h2>
|
|
156
163
|
<p>Date: ${receipt.timestamp.toISOString()}</p>
|
|
157
164
|
<table>
|
|
158
165
|
<tr><th>Item</th><th>Qty</th><th>Price</th><th>Total</th></tr>
|
|
159
166
|
${lines}
|
|
160
167
|
</table>
|
|
161
|
-
<p>Subtotal: ${(receipt.subtotal
|
|
162
|
-
${receipt.discountTotal > 0 ? `<p>Discount: -${(receipt.discountTotal
|
|
163
|
-
<p>Tax: ${(receipt.taxTotal
|
|
164
|
-
<p><strong>Total: ${(receipt.total
|
|
165
|
-
${receipt.payments.map((p) => `<p>${p.method}: ${(p.amount
|
|
166
|
-
${receipt.changeDue > 0 ? `<p>Change: ${(receipt.changeDue
|
|
168
|
+
<p>Subtotal: ${fmt(receipt.subtotal)}</p>
|
|
169
|
+
${receipt.discountTotal > 0 ? `<p>Discount: -${fmt(receipt.discountTotal)}</p>` : ""}
|
|
170
|
+
<p>Tax: ${fmt(receipt.taxTotal)}</p>
|
|
171
|
+
<p><strong>Total: ${fmt(receipt.total)}</strong></p>
|
|
172
|
+
${receipt.payments.map((p) => `<p>${escapeHtml(p.method)}: ${fmt(p.amount)}</p>`).join("")}
|
|
173
|
+
${receipt.changeDue > 0 ? `<p>Change: ${fmt(receipt.changeDue)}</p>` : ""}
|
|
167
174
|
`;
|
|
168
175
|
}
|
|
169
176
|
}
|
|
@@ -40,27 +40,4 @@ export class ReturnService {
|
|
|
40
40
|
return Ok(rows);
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
/**
|
|
44
|
-
* Get all return items for a return transaction.
|
|
45
|
-
*/
|
|
46
|
-
async getReturnItems(transactionId: string): Promise<PluginResult<ReturnItem[]>> {
|
|
47
|
-
const rows = await this.db
|
|
48
|
-
.select()
|
|
49
|
-
.from(posReturnItems)
|
|
50
|
-
.where(eq(posReturnItems.transactionId, transactionId));
|
|
51
|
-
|
|
52
|
-
return Ok(rows);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Calculate total refund amount for a return transaction.
|
|
57
|
-
*/
|
|
58
|
-
async calculateRefundTotal(transactionId: string): Promise<number> {
|
|
59
|
-
const items = await this.db
|
|
60
|
-
.select()
|
|
61
|
-
.from(posReturnItems)
|
|
62
|
-
.where(eq(posReturnItems.transactionId, transactionId));
|
|
63
|
-
|
|
64
|
-
return items.reduce((sum, item) => sum + item.refundAmount, 0);
|
|
65
|
-
}
|
|
66
43
|
}
|
package/src/types.ts
CHANGED
|
@@ -42,12 +42,6 @@ export type ShiftStatus = "open" | "closed";
|
|
|
42
42
|
export type TerminalType = "register" | "tablet" | "mobile" | "kiosk";
|
|
43
43
|
|
|
44
44
|
export interface POSPluginOptions {
|
|
45
|
-
/** Default currency for new transactions. Default: "USD" */
|
|
46
|
-
defaultCurrency?: string;
|
|
47
|
-
/** Maximum hold duration in hours before auto-void. Default: 24 */
|
|
48
|
-
maxHoldHours?: number;
|
|
49
|
-
/** Require manager override for discounts above this percentage. Default: 20 */
|
|
50
|
-
discountOverrideThreshold?: number;
|
|
51
45
|
/** PIN auth runtime (issue #51). */
|
|
52
46
|
pinAuth?: {
|
|
53
47
|
/** Named auth.apiKeyScopes config used to mint per-shift keys. */
|
|
@@ -62,8 +56,5 @@ export interface POSPluginOptions {
|
|
|
62
56
|
}
|
|
63
57
|
|
|
64
58
|
export const DEFAULT_POS_OPTIONS: Required<POSPluginOptions> = {
|
|
65
|
-
defaultCurrency: "USD",
|
|
66
|
-
maxHoldHours: 24,
|
|
67
|
-
discountOverrideThreshold: 20,
|
|
68
59
|
pinAuth: {},
|
|
69
60
|
};
|
|
@@ -1,33 +0,0 @@
|
|
|
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
|
|
@@ -1 +0,0 @@
|
|
|
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"}
|
package/dist/payment-adapter.js
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
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
|
-
}
|
package/src/payment-adapter.ts
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
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
|
-
|
|
9
|
-
export interface PaymentAdapter {
|
|
10
|
-
providerId: string;
|
|
11
|
-
createPaymentIntent(params: {
|
|
12
|
-
amount: number;
|
|
13
|
-
currency: string;
|
|
14
|
-
orderId?: string;
|
|
15
|
-
metadata?: Record<string, unknown>;
|
|
16
|
-
}): Promise<{ id: string; status: string; amount: number; clientSecret?: string }>;
|
|
17
|
-
capturePayment(intentId: string, amount: number): Promise<{ id: string; status: string; amountCaptured: number }>;
|
|
18
|
-
refundPayment(paymentId: string, amount: number): Promise<{ id: string; status: string; amountRefunded: number }>;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export function createPOSPaymentAdapter(): PaymentAdapter {
|
|
22
|
-
return {
|
|
23
|
-
providerId: "pos",
|
|
24
|
-
|
|
25
|
-
async createPaymentIntent(params) {
|
|
26
|
-
// POS payments are already collected at the terminal.
|
|
27
|
-
// The "intent" represents the sum of pos_payments rows.
|
|
28
|
-
return {
|
|
29
|
-
id: `pos_${params.orderId ?? crypto.randomUUID()}`,
|
|
30
|
-
status: "requires_capture",
|
|
31
|
-
amount: params.amount,
|
|
32
|
-
};
|
|
33
|
-
},
|
|
34
|
-
|
|
35
|
-
async capturePayment(intentId, amount) {
|
|
36
|
-
// POS payments are already collected. Capture is a no-op.
|
|
37
|
-
return {
|
|
38
|
-
id: intentId,
|
|
39
|
-
status: "succeeded",
|
|
40
|
-
amountCaptured: amount,
|
|
41
|
-
};
|
|
42
|
-
},
|
|
43
|
-
|
|
44
|
-
async refundPayment(paymentId, amount) {
|
|
45
|
-
// POS refunds are handled by the return transaction flow.
|
|
46
|
-
return {
|
|
47
|
-
id: `ref_${paymentId}`,
|
|
48
|
-
status: "succeeded",
|
|
49
|
-
amountRefunded: amount,
|
|
50
|
-
};
|
|
51
|
-
},
|
|
52
|
-
};
|
|
53
|
-
}
|