@tallyui/pos 0.1.0 → 3.0.0-next.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/dist/index.d.ts +2031 -43
- package/dist/index.js +4629 -205
- package/package.json +23 -12
- package/src/currency/currency-provider.tsx +12 -4
- package/src/currency/index.ts +1 -2
- package/src/index.ts +53 -4
- package/src/order/allocate-order-discount.ts +34 -0
- package/src/order/index.ts +8 -0
- package/src/order/order-builder.ts +256 -95
- package/src/order/order-manager.ts +26 -43
- package/src/order/tax-figures.ts +23 -0
- package/src/order/types.ts +73 -15
- package/src/outbox/backend-not-found.ts +27 -0
- package/src/outbox/http-transport.ts +67 -0
- package/src/outbox/index.ts +9 -0
- package/src/outbox/logger.ts +3 -0
- package/src/outbox/order-outbox.ts +502 -0
- package/src/outbox/register-outbox.ts +250 -0
- package/src/outbox/types.test-d.ts +22 -0
- package/src/outbox/types.ts +36 -0
- package/src/outbox/use-order-outbox.ts +175 -0
- package/src/pos-order/__fixtures__/order-create-v3.json +97 -0
- package/src/pos-order/command.ts +123 -0
- package/src/pos-order/device-id.ts +23 -0
- package/src/pos-order/finalize.ts +219 -0
- package/src/pos-order/index.ts +10 -0
- package/src/pos-order/needs-attention.ts +16 -0
- package/src/pos-order/open.ts +269 -0
- package/src/pos-order/same-sale.ts +26 -0
- package/src/pos-order/schema.ts +130 -0
- package/src/pos-order/types.ts +93 -0
- package/src/pos-order/uuidv7.ts +54 -0
- package/src/product/index.ts +2 -0
- package/src/product/search-products.ts +32 -0
- package/src/product/stock.ts +25 -0
- package/src/receipt/build-receipt-data.ts +39 -23
- package/src/receipt/types.ts +17 -10
- package/src/register/__fixtures__/closure-local-row.json +61 -0
- package/src/register/__fixtures__/closure.json +197 -0
- package/src/register/__fixtures__/corrections-dst.json +63 -0
- package/src/register/closure-document.ts +277 -0
- package/src/register/closure-rows.ts +65 -0
- package/src/register/document-labels.ts +46 -0
- package/src/register/expected.ts +66 -0
- package/src/register/export-csv.ts +74 -0
- package/src/register/facts.ts +109 -0
- package/src/register/index.ts +32 -0
- package/src/register/money.ts +18 -0
- package/src/register/movement-input.ts +59 -0
- package/src/register/register-commands.ts +147 -0
- package/src/register/register-count.denominations.ts +11 -0
- package/src/register/register-count.helpers.ts +64 -0
- package/src/register/register-document.ts +268 -0
- package/src/register/schemas.ts +175 -0
- package/src/register/session-store.ts +570 -0
- package/src/register/settled-figures.ts +98 -0
- package/src/register/use-register-session.ts +469 -0
- package/src/rxdb/index.ts +2 -0
- package/src/sale/cart.ts +23 -0
- package/src/sale/catalogue.ts +21 -0
- package/src/sale/index.ts +5 -0
- package/src/sale/use-sale.ts +394 -0
- package/src/store-settings/index.ts +5 -0
- package/src/store-settings/map-store-settings.ts +18 -0
- package/src/store-settings/resolve-store-settings.ts +65 -0
- package/src/store-settings/use-store-settings.ts +84 -0
- package/src/tax/exact.ts +218 -0
- package/src/tax/index.ts +4 -3
- package/src/tax/tax-provider.tsx +35 -12
- package/src/tax/types.ts +8 -6
- package/src/tender/index.ts +2 -0
- package/src/tender/tender-state.ts +326 -0
- package/src/currency/currency-provider.test.tsx +0 -36
- package/src/currency/format-currency.test.ts +0 -36
- package/src/currency/format-currency.ts +0 -18
- package/src/logging/logger.test.ts +0 -154
- package/src/logging/sinks.test.ts +0 -60
- package/src/order/discount-engine.test.ts +0 -152
- package/src/order/order-builder.test.ts +0 -246
- package/src/order/order-manager.test.ts +0 -209
- package/src/order/payment.test.ts +0 -91
- package/src/receipt/build-receipt-data.test.ts +0 -166
- package/src/repository/create-repository.test.ts +0 -166
- package/src/tax/calculate.test.ts +0 -59
- package/src/tax/calculate.ts +0 -32
- package/src/tax/tax-provider.test.tsx +0 -51
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tallyui/pos",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "3.0.0-next.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Shared POS business logic for Tally UI — tax, orders, payments, discounts, receipts",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -15,25 +15,36 @@
|
|
|
15
15
|
},
|
|
16
16
|
"files": [
|
|
17
17
|
"dist",
|
|
18
|
-
"src"
|
|
18
|
+
"src",
|
|
19
|
+
"!src/**/*.test.ts",
|
|
20
|
+
"!src/**/*.test.tsx",
|
|
21
|
+
"!src/**/*.test-helper.ts"
|
|
19
22
|
],
|
|
20
23
|
"license": "MIT",
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "git+https://github.com/TallyUI/tallyui.git",
|
|
27
|
+
"directory": "packages/pos"
|
|
25
28
|
},
|
|
26
29
|
"peerDependencies": {
|
|
27
|
-
"@tallyui/core": "
|
|
30
|
+
"@tallyui/core": "^3.0.0-next.0",
|
|
28
31
|
"react": ">=18",
|
|
29
|
-
"rxdb": "
|
|
32
|
+
"rxdb": "~17.5.0",
|
|
30
33
|
"rxjs": ">=7"
|
|
31
34
|
},
|
|
32
35
|
"devDependencies": {
|
|
33
|
-
"@tallyui/core": "
|
|
36
|
+
"@tallyui/core": "3.0.0-next.0",
|
|
34
37
|
"@types/react": ">=18",
|
|
35
38
|
"react": "^19.2.4",
|
|
36
|
-
"rxdb": "
|
|
37
|
-
"rxjs": "7.8.2"
|
|
39
|
+
"rxdb": "17.5.0",
|
|
40
|
+
"rxjs": "7.8.2",
|
|
41
|
+
"@tallyui/connector-medusa": "3.0.0-next.0",
|
|
42
|
+
"@tallyui/connector-woocommerce": "3.0.0-next.0",
|
|
43
|
+
"@tallyui/database": "3.0.0-next.0"
|
|
44
|
+
},
|
|
45
|
+
"scripts": {
|
|
46
|
+
"build": "tsup",
|
|
47
|
+
"typecheck": "tsc --noEmit",
|
|
48
|
+
"test": "vitest run"
|
|
38
49
|
}
|
|
39
|
-
}
|
|
50
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createContext, useContext, useMemo, useCallback } from 'react';
|
|
2
2
|
import type { ReactNode } from 'react';
|
|
3
|
-
import {
|
|
3
|
+
import { formatMoney, type Money } from '@tallyui/core';
|
|
4
4
|
|
|
5
5
|
interface CurrencyContext {
|
|
6
6
|
currencyCode: string;
|
|
@@ -20,13 +20,21 @@ export function CurrencyProvider({ currencyCode, locale, children }: CurrencyPro
|
|
|
20
20
|
return <CurrencyCtx.Provider value={value}>{children}</CurrencyCtx.Provider>;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
export function useCurrencyFormatter(): (
|
|
23
|
+
export function useCurrencyFormatter(): (money: Money) => string {
|
|
24
24
|
const ctx = useContext(CurrencyCtx);
|
|
25
25
|
if (!ctx) {
|
|
26
26
|
throw new Error('useCurrencyFormatter() must be used within a <CurrencyProvider>');
|
|
27
27
|
}
|
|
28
28
|
return useCallback(
|
|
29
|
-
(
|
|
30
|
-
[ctx.
|
|
29
|
+
(money: Money) => formatMoney(money, ctx.locale) ?? `${money.amount} ${money.currency}`,
|
|
30
|
+
[ctx.locale],
|
|
31
31
|
);
|
|
32
32
|
}
|
|
33
|
+
|
|
34
|
+
export function useCurrencyCode(): string {
|
|
35
|
+
const ctx = useContext(CurrencyCtx);
|
|
36
|
+
if (!ctx) {
|
|
37
|
+
throw new Error('useCurrencyCode() must be used within a <CurrencyProvider>');
|
|
38
|
+
}
|
|
39
|
+
return ctx.currencyCode;
|
|
40
|
+
}
|
package/src/currency/index.ts
CHANGED
|
@@ -1,3 +1,2 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export { CurrencyProvider, useCurrencyFormatter } from './currency-provider';
|
|
1
|
+
export { CurrencyProvider, useCurrencyFormatter, useCurrencyCode } from './currency-provider';
|
|
3
2
|
export type { CurrencyProviderProps } from './currency-provider';
|
package/src/index.ts
CHANGED
|
@@ -3,27 +3,42 @@ export { createLogger, consoleSink, callbackSink } from './logging';
|
|
|
3
3
|
export type { Logger, LogSink, LogEntry, LogLevel } from './logging';
|
|
4
4
|
|
|
5
5
|
// Currency
|
|
6
|
-
export {
|
|
6
|
+
export { CurrencyProvider, useCurrencyFormatter, useCurrencyCode } from './currency';
|
|
7
7
|
export type { CurrencyProviderProps } from './currency';
|
|
8
8
|
|
|
9
9
|
// Tax
|
|
10
|
-
export {
|
|
10
|
+
export { TaxProvider, useTax, taxLogger } from './tax';
|
|
11
|
+
export { MICROS_PER_MINOR, ratePpmFromPercent, taxMicros, roundMicrosToMinor, computeOrderTax, taxLinesByRate } from './tax';
|
|
12
|
+
export type { TaxLineInput, OrderTaxTotals, RateTaxLine } from './tax';
|
|
11
13
|
export type { TaxProviderProps } from './tax';
|
|
12
|
-
export type {
|
|
14
|
+
export type { TaxRateMap, TaxContext } from './tax';
|
|
15
|
+
|
|
16
|
+
// Store settings
|
|
17
|
+
export { resolveStoreSettings, useStoreSettings, withPricingContext, taxProviderProps } from './store-settings';
|
|
18
|
+
export type { StoreSettingsResolution, ResolveStoreSettingsOptions, StoreSettingsState } from './store-settings';
|
|
19
|
+
|
|
20
|
+
// RxDB reads past the query cache, and live lists that can't leave it stale (RxDB 16.21.1 bug 4)
|
|
21
|
+
export { readFresh, countFresh, watchFresh } from './rxdb';
|
|
13
22
|
|
|
14
23
|
// Repository
|
|
15
24
|
export { createRepository } from './repository';
|
|
16
25
|
export type { Repository } from './repository';
|
|
17
26
|
|
|
18
27
|
// Order
|
|
19
|
-
export { createOrderBuilder, createOrderManager } from './order';
|
|
28
|
+
export { createOrderBuilder, createOrderManager, allocateOrderDiscount, taxFiguresForBasket } from './order';
|
|
29
|
+
export type { BasketLine } from './order';
|
|
20
30
|
export type { OrderBuilder, OrderBuilderOptions } from './order';
|
|
21
31
|
export type { OrderManager, OrderManagerOptions, ParkedOrderSummary } from './order';
|
|
22
32
|
export type {
|
|
23
33
|
Order,
|
|
34
|
+
SentOrder,
|
|
24
35
|
LineItem,
|
|
36
|
+
LineTaxLine,
|
|
37
|
+
AddLineInput,
|
|
25
38
|
Discount,
|
|
26
39
|
AppliedDiscount,
|
|
40
|
+
DisplayTotals,
|
|
41
|
+
DisplayLine,
|
|
27
42
|
Payment,
|
|
28
43
|
CustomerSummary,
|
|
29
44
|
PaymentMethod,
|
|
@@ -32,3 +47,37 @@ export type {
|
|
|
32
47
|
// Receipt
|
|
33
48
|
export { buildReceiptData } from './receipt';
|
|
34
49
|
export type { ReceiptData, ReceiptLineItem, ReceiptConfig } from './receipt';
|
|
50
|
+
|
|
51
|
+
// Product
|
|
52
|
+
export { searchProducts, withStockOverlay, getProductStock, stockOverlay$, stockOverlayAsOf$ } from './product';
|
|
53
|
+
|
|
54
|
+
// Sale
|
|
55
|
+
export { useSale, DISCOUNTS_UNSUPPORTED, SALE_SAVING, saleLogger, addEntryToCart, CartError, catalogueEntries, findEntryByCode, variantPriceLabel } from './sale';
|
|
56
|
+
export type { SaleStage, CatalogueEntry } from './sale';
|
|
57
|
+
|
|
58
|
+
export { uuidv7, finalizeOrder, toOrderCreateEnvelope, UnsupportedOrderVersionError, posOrderSchema, posOrderCollection, addPosOrderCollection, PosOrderOpenClosedError, posOrdersLogger, getDeviceId, needsAttention, sameSale, OrderContentMismatchError } from './pos-order';
|
|
59
|
+
export type { PosOrderSyncStatus, PosOrderLine, PosOrderPayment, PosOrderLocalWarning, PosOrderServerFailures, PosOrder, FinalizeOptions } from './pos-order';
|
|
60
|
+
export { createHttpCommandTransport, createOrderOutbox, useOrderOutbox, outboxLogger } from './outbox';
|
|
61
|
+
export { createRegisterOutbox } from './outbox';
|
|
62
|
+
export type { RegisterOutboxOptions, RegisterOutbox } from './outbox';
|
|
63
|
+
export { createBackendNotFound } from './outbox/backend-not-found';
|
|
64
|
+
export type { BackendNotFound } from './outbox/backend-not-found';
|
|
65
|
+
export type { HttpTransportOptions, OrderOutboxOptions, OrderOutbox, TransportOutcome, CommandTransport, OutboxState, UseOrderOutboxOptions, UseOrderOutboxResult } from './outbox';
|
|
66
|
+
export { tenderReducer, initTenderState, initialTenderState, appliedMinor, changeMinor, quickTenderedAmounts, evenSplitShareMinor, activePlan, planLegs, MAX_TENDER_MINOR } from './tender';
|
|
67
|
+
export type { PaymentTransport, TenderView, TenderLineId, TenderPlan, SplitTab, TenderState, TenderKey, TenderAction, PlanLeg } from './tender';
|
|
68
|
+
|
|
69
|
+
// Register
|
|
70
|
+
export { normalizeAmount, isServerDecimal, movementFieldError, deriveExpected, parseMinor, validAmount, countVariance, overThreshold, closeNeedsApproval, denominationTotal, varianceText, denominations } from './register';
|
|
71
|
+
export type { MovementType, LedgerRow, Movement } from './register';
|
|
72
|
+
export { registerSessionSchema, registerSessionCollection, cashMovementSchema, closureSchema } from './register';
|
|
73
|
+
export type { RegisterSession, CashMovement, Closure } from './register';
|
|
74
|
+
export { registerCommandSchema, registerCommandCollection, registerCommandsLogger, sessionOpenCommand, sessionTransitionCommand, movementCommand, closureCommand, reconcileRegisterCommands } from './register';
|
|
75
|
+
export type { RegisterCommand, RegisterCommandCollection } from './register';
|
|
76
|
+
export { mintUuid, readRegister, ensureRegister, observeRegister$, getBoundRegisterId, readBoundRegister, bindRegister, unbindRegister, nextSaleCounter, mintClosureNumber, advancePerpetual, RegisterIdInvalidError } from './register';
|
|
77
|
+
export type { RegisterHost, RegisterCounters, RegisterBucket, RegisterStore, RegisterDocument } from './register';
|
|
78
|
+
export { RegisterSessionRequiredError, RegisterSessionClosedError, RegisterMovementAmountError, RegisterMovementReasonError, RegisterMovementStrandedError, openSessionSelector, requireOpenSession, stampSession, openSession, startCounting, backToSelling, closeSession, recordMovement, voidMovement, writeClosure } from './register';
|
|
79
|
+
export type { RegisterSessionCollection, CashMovementCollection, ClosureCollection } from './register';
|
|
80
|
+
export { deriveSettled, exportCsv, labelKeys, clampClosureScope, selectClosureRows } from './register';
|
|
81
|
+
export type { Correction, RecordedFigures, ClosureScope } from './register';
|
|
82
|
+
export { minorToDecimal, formatClosureDate, buildClosureDocument, buildXReportDocument, TAX_ROUNDING_MIXED_NOTE, registerFactsLogger, recordRegisterFact, type ClosureContext, type Actor, type RegisterFact } from './register';
|
|
83
|
+
export { useRegisterSession, RegisterTenderInProgressError, RegisterSessionAlreadyOpenError, RegisterCloseIncompleteError, RegisterApprovalRequiredError, type UseRegisterSessionOptions } from './register';
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Splits an order discount across lines in proportion to each line's pre-order-discount amount,
|
|
3
|
+
* in its own tax mode (ADR-062), with largest-remainder rounding to the minor unit.
|
|
4
|
+
*
|
|
5
|
+
* - The shares sum exactly to `totalMinor`, and no share exceeds its line's amount.
|
|
6
|
+
* - Leftover units go to the largest remainders; ties go to the earlier line, so the result is deterministic.
|
|
7
|
+
* - A line with a zero or negative amount gets 0.
|
|
8
|
+
*
|
|
9
|
+
* Throws RangeError unless every input is a safe integer and 0 ≤ totalMinor ≤ Σ positive amounts.
|
|
10
|
+
*/
|
|
11
|
+
export function allocateOrderDiscount(lineAmountsMinor: readonly number[], totalMinor: number): number[] {
|
|
12
|
+
if (!Number.isSafeInteger(totalMinor) || totalMinor < 0 || !lineAmountsMinor.every(Number.isSafeInteger)) {
|
|
13
|
+
throw new RangeError('Amounts must be safe integers and the discount non-negative');
|
|
14
|
+
}
|
|
15
|
+
const weights = lineAmountsMinor.map((amount) => BigInt(Math.max(0, amount)));
|
|
16
|
+
const weightTotal = weights.reduce((sum, weight) => sum + weight, 0n);
|
|
17
|
+
const total = BigInt(totalMinor);
|
|
18
|
+
if (total > weightTotal) throw new RangeError('Order discount exceeds the lines it applies to');
|
|
19
|
+
if (total === 0n) return weights.map(() => 0);
|
|
20
|
+
|
|
21
|
+
// BigInt keeps total × weight exact however large the order is.
|
|
22
|
+
const shares = weights.map((weight) => (total * weight) / weightTotal);
|
|
23
|
+
const remainders = weights.map((weight) => (total * weight) % weightTotal);
|
|
24
|
+
let leftover = total - shares.reduce((sum, share) => sum + share, 0n);
|
|
25
|
+
const ranked = remainders.map((_, index) => index)
|
|
26
|
+
.sort((a, b) => remainders[a] === remainders[b] ? a - b : remainders[a] > remainders[b] ? -1 : 1);
|
|
27
|
+
// Each leftover unit goes to a line with a non-zero remainder, whose share is still below its amount.
|
|
28
|
+
for (const index of ranked) {
|
|
29
|
+
if (leftover === 0n) break;
|
|
30
|
+
shares[index] += 1n;
|
|
31
|
+
leftover -= 1n;
|
|
32
|
+
}
|
|
33
|
+
return shares.map(Number);
|
|
34
|
+
}
|
package/src/order/index.ts
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
export { createOrderBuilder } from './order-builder';
|
|
2
|
+
export { taxFiguresForBasket } from './tax-figures';
|
|
3
|
+
export type { BasketLine } from './tax-figures';
|
|
4
|
+
export { allocateOrderDiscount } from './allocate-order-discount';
|
|
2
5
|
export type { OrderBuilder, OrderBuilderOptions } from './order-builder';
|
|
3
6
|
export { createOrderManager } from './order-manager';
|
|
4
7
|
export type { OrderManager, OrderManagerOptions, ParkedOrderSummary } from './order-manager';
|
|
5
8
|
export type {
|
|
6
9
|
Order,
|
|
10
|
+
SentOrder,
|
|
7
11
|
LineItem,
|
|
12
|
+
LineTaxLine,
|
|
13
|
+
AddLineInput,
|
|
8
14
|
Discount,
|
|
9
15
|
AppliedDiscount,
|
|
16
|
+
DisplayTotals,
|
|
17
|
+
DisplayLine,
|
|
10
18
|
Payment,
|
|
11
19
|
CustomerSummary,
|
|
12
20
|
PaymentMethod,
|