@tallyui/pos 3.0.4 → 3.1.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.
- package/dist/index.d.ts +19 -1
- package/dist/index.js +91 -41
- package/package.json +6 -6
- package/src/index.ts +1 -0
- package/src/order/index.ts +1 -0
- package/src/order/use-parked-sales.ts +24 -0
- package/src/pos-order/finalize.ts +1 -1
- package/src/pos-order/schema.ts +5 -2
- package/src/pos-order/types.ts +2 -0
- package/src/sale/use-sale.ts +43 -15
package/dist/index.d.ts
CHANGED
|
@@ -465,6 +465,12 @@ interface OrderManager {
|
|
|
465
465
|
}
|
|
466
466
|
declare function createOrderManager(options: OrderManagerOptions): OrderManager;
|
|
467
467
|
|
|
468
|
+
/** The parked sales in `drafts`, newest first, live; and a discard that removes one. */
|
|
469
|
+
declare function useParkedSales(drafts: RxCollection | undefined): {
|
|
470
|
+
parked: ParkedOrderSummary[];
|
|
471
|
+
discard: (id: string) => Promise<void>;
|
|
472
|
+
};
|
|
473
|
+
|
|
468
474
|
interface ReceiptLineItem {
|
|
469
475
|
name: string;
|
|
470
476
|
sku: string;
|
|
@@ -596,6 +602,8 @@ interface PosOrderPayment {
|
|
|
596
602
|
}
|
|
597
603
|
interface PosOrder {
|
|
598
604
|
id: string;
|
|
605
|
+
/** The sale order's id (the builder's), set by finalizeOrder (pos_orders v7, ADR-072): support traceability from a draft or preview to this stored order. Never sent, never printed. */
|
|
606
|
+
saleId?: string;
|
|
599
607
|
createdAt: string;
|
|
600
608
|
currency: string;
|
|
601
609
|
pricesIncludeTax: boolean;
|
|
@@ -711,6 +719,8 @@ declare function toOrderCreateEnvelope(order: PosOrder, deviceId: string, attemp
|
|
|
711
719
|
* Like version 4 (ADR-069), it is one-way: an older build shows no orders.
|
|
712
720
|
* Version 6 adds `taxRounding`, the strategy the sale's figures were computed with (#287; never sent), and changes
|
|
713
721
|
* nothing else. Its migration sets it on every older row. It is one-way like version 5.
|
|
722
|
+
* Version 7 adds `saleId`, the sale order's id (ADR-072; never sent), and changes nothing else. Its migration is the
|
|
723
|
+
* identity: older orders have no `saleId`. It is one-way like version 6.
|
|
714
724
|
*/
|
|
715
725
|
declare const posOrderSchema: RxJsonSchema<PosOrder>;
|
|
716
726
|
/**
|
|
@@ -1895,6 +1905,14 @@ declare function useSale(settings: Pick<StoreSettings, 'currency'>, opts: {
|
|
|
1895
1905
|
amountMinor: number;
|
|
1896
1906
|
reference?: string;
|
|
1897
1907
|
} | null) => void;
|
|
1908
|
+
/** ADR-072: external is capped at the balance due; change comes only from cash. */
|
|
1909
|
+
addTender(tender: {
|
|
1910
|
+
method: "cash" | "external";
|
|
1911
|
+
amountMinor: number;
|
|
1912
|
+
reference?: string;
|
|
1913
|
+
}): string | null;
|
|
1914
|
+
/** ADR-072: remove one tender and its dropped-reference warning. An id not among the payments changes nothing. */
|
|
1915
|
+
removeTender(paymentId: string): void;
|
|
1898
1916
|
cancelTender(): void;
|
|
1899
1917
|
/**
|
|
1900
1918
|
* Finalizes the tender, stamps the session (see `session`), hands the order to `onSaleCompleted`,
|
|
@@ -2304,4 +2322,4 @@ declare function planLegs(plan: TenderPlan, rowsSinceFrom: {
|
|
|
2304
2322
|
};
|
|
2305
2323
|
};
|
|
2306
2324
|
|
|
2307
|
-
export { type Actor, type AddLineInput, type AppliedDiscount, type BackendNotFound, type BasketLine, CartError, type CashMovement, type CashMovementCollection, type CatalogueEntry, type Closure, type ClosureCollection, type ClosureContext, type ClosureScope, type CommandTransport, type Correction, CurrencyProvider, type CurrencyProviderProps, type CustomerSummary, DISCOUNTS_UNSUPPORTED, type Discount, type DisplayLine, type DisplayTotals, type FinalizeOptions, type HttpTransportOptions, type LedgerRow, type LineItem, type LineTaxLine, type LogEntry, type LogLevel, type LogSink, type Logger, MAX_TENDER_MINOR, MICROS_PER_MINOR, type Movement$1 as Movement, type MovementType, type Order, type OrderBuilder, type OrderBuilderOptions, OrderContentMismatchError, type OrderManager, type OrderManagerOptions, type OrderOutbox, type OrderOutboxOptions, type OrderTaxTotals, type OutboxState, type ParkedOrderSummary, type Payment, type PaymentMethod, type PaymentTransport, type PlanLeg, type PosOrder, type PosOrderLine, type PosOrderLocalWarning, PosOrderOpenClosedError, type PosOrderPayment, type PosOrderServerFailures, type PosOrderSyncStatus, type RateTaxLine, type ReceiptConfig, type ReceiptData, type ReceiptLineItem, type RecordedFigures, RegisterApprovalRequiredError, type RegisterBucket, RegisterCloseIncompleteError, type RegisterCommand, type RegisterCommandCollection, type RegisterCounters, type RegisterDocument, type RegisterFact, type RegisterHost, RegisterIdInvalidError, RegisterMovementAmountError, RegisterMovementReasonError, RegisterMovementStrandedError, type RegisterOutbox, type RegisterOutboxOptions, type RegisterSession, RegisterSessionAlreadyOpenError, RegisterSessionClosedError, type RegisterSessionCollection, RegisterSessionRequiredError, type RegisterStore, RegisterTenderInProgressError, type Repository, type ResolveStoreSettingsOptions, SALE_SAVING, type SaleStage, type SentOrder, type SplitTab, type StoreSettingsResolution, type StoreSettingsState, TAX_ROUNDING_MIXED_NOTE, type TaxContext, type TaxLineInput, TaxProvider, type TaxProviderProps, type TaxRateMap, type TenderAction, type TenderKey, type TenderLineId, type TenderPlan, type TenderState, type TenderView, type TransportOutcome, UnsupportedOrderVersionError, type UseOrderOutboxOptions, type UseOrderOutboxResult, type UseRegisterOutboxOptions, type UseRegisterOutboxResult, type UseRegisterSessionOptions, activePlan, addEntryToCart, addPosOrderCollection, advancePerpetual, allocateOrderDiscount, appliedMinor, backToSelling, bindRegister, buildClosureDocument, buildReceiptData, buildXReportDocument, callbackSink, cashMovementSchema, catalogueEntries, changeMinor, clampClosureScope, closeNeedsApproval, closeSession, closureCommand, closureSchema, computeOrderTax, consoleSink, countVariance, createBackendNotFound, createHttpCommandTransport, createLogger, createOrderBuilder, createOrderManager, createOrderOutbox, createRegisterOutbox, createRepository, denominationTotal, denominations, deriveExpected, deriveSettled, ensureRegister, evenSplitShareMinor, exportCsv, finalizeOrder, findEntryByCode, formatClosureDate, getBoundRegisterId, getDeviceId, initTenderState, initialTenderState, isServerDecimal, labelKeys, minorToDecimal, mintClosureNumber, mintUuid, movementCommand, movementFieldError, needsAttention, nextSaleCounter, normalizeAmount, observeRegister$, openSession, openSessionSelector, orderDraftSchema, outboxLogger, overThreshold, parkedOrderSummaries$, parseMinor, planLegs, posOrderCollection, posOrderSchema, posOrdersLogger, quickTenderedAmounts, ratePpmFromPercent, readBoundRegister, readRegister, reconcileRegisterCommands, recordMovement, recordRegisterFact, registerCommandCollection, registerCommandSchema, registerCommandsLogger, registerFactsLogger, registerSessionCollection, registerSessionSchema, requireOpenSession, resolveStoreSettings, restoreOrderDraft, roundMicrosToMinor, saleLogger, sameSale, searchProducts, selectClosureRows, sessionOpenCommand, sessionTransitionCommand, stampSession, startCounting, stockOverlay$, stockOverlayAsOf$, taxFiguresForBasket, taxLinesByRate, taxLogger, taxMicros, taxProviderProps, tenderReducer, toOrderCreateEnvelope, unbindRegister, useCurrencyCode, useCurrencyFormatter, useOrderOutbox, useRegisterOutbox, useRegisterSession, useSale, useStoreSettings, useTax, uuidv7, validAmount, varianceText, variantPriceLabel, voidMovement, withPricingContext, writeClosure, writeOrderDraft };
|
|
2325
|
+
export { type Actor, type AddLineInput, type AppliedDiscount, type BackendNotFound, type BasketLine, CartError, type CashMovement, type CashMovementCollection, type CatalogueEntry, type Closure, type ClosureCollection, type ClosureContext, type ClosureScope, type CommandTransport, type Correction, CurrencyProvider, type CurrencyProviderProps, type CustomerSummary, DISCOUNTS_UNSUPPORTED, type Discount, type DisplayLine, type DisplayTotals, type FinalizeOptions, type HttpTransportOptions, type LedgerRow, type LineItem, type LineTaxLine, type LogEntry, type LogLevel, type LogSink, type Logger, MAX_TENDER_MINOR, MICROS_PER_MINOR, type Movement$1 as Movement, type MovementType, type Order, type OrderBuilder, type OrderBuilderOptions, OrderContentMismatchError, type OrderManager, type OrderManagerOptions, type OrderOutbox, type OrderOutboxOptions, type OrderTaxTotals, type OutboxState, type ParkedOrderSummary, type Payment, type PaymentMethod, type PaymentTransport, type PlanLeg, type PosOrder, type PosOrderLine, type PosOrderLocalWarning, PosOrderOpenClosedError, type PosOrderPayment, type PosOrderServerFailures, type PosOrderSyncStatus, type RateTaxLine, type ReceiptConfig, type ReceiptData, type ReceiptLineItem, type RecordedFigures, RegisterApprovalRequiredError, type RegisterBucket, RegisterCloseIncompleteError, type RegisterCommand, type RegisterCommandCollection, type RegisterCounters, type RegisterDocument, type RegisterFact, type RegisterHost, RegisterIdInvalidError, RegisterMovementAmountError, RegisterMovementReasonError, RegisterMovementStrandedError, type RegisterOutbox, type RegisterOutboxOptions, type RegisterSession, RegisterSessionAlreadyOpenError, RegisterSessionClosedError, type RegisterSessionCollection, RegisterSessionRequiredError, type RegisterStore, RegisterTenderInProgressError, type Repository, type ResolveStoreSettingsOptions, SALE_SAVING, type SaleStage, type SentOrder, type SplitTab, type StoreSettingsResolution, type StoreSettingsState, TAX_ROUNDING_MIXED_NOTE, type TaxContext, type TaxLineInput, TaxProvider, type TaxProviderProps, type TaxRateMap, type TenderAction, type TenderKey, type TenderLineId, type TenderPlan, type TenderState, type TenderView, type TransportOutcome, UnsupportedOrderVersionError, type UseOrderOutboxOptions, type UseOrderOutboxResult, type UseRegisterOutboxOptions, type UseRegisterOutboxResult, type UseRegisterSessionOptions, activePlan, addEntryToCart, addPosOrderCollection, advancePerpetual, allocateOrderDiscount, appliedMinor, backToSelling, bindRegister, buildClosureDocument, buildReceiptData, buildXReportDocument, callbackSink, cashMovementSchema, catalogueEntries, changeMinor, clampClosureScope, closeNeedsApproval, closeSession, closureCommand, closureSchema, computeOrderTax, consoleSink, countVariance, createBackendNotFound, createHttpCommandTransport, createLogger, createOrderBuilder, createOrderManager, createOrderOutbox, createRegisterOutbox, createRepository, denominationTotal, denominations, deriveExpected, deriveSettled, ensureRegister, evenSplitShareMinor, exportCsv, finalizeOrder, findEntryByCode, formatClosureDate, getBoundRegisterId, getDeviceId, initTenderState, initialTenderState, isServerDecimal, labelKeys, minorToDecimal, mintClosureNumber, mintUuid, movementCommand, movementFieldError, needsAttention, nextSaleCounter, normalizeAmount, observeRegister$, openSession, openSessionSelector, orderDraftSchema, outboxLogger, overThreshold, parkedOrderSummaries$, parseMinor, planLegs, posOrderCollection, posOrderSchema, posOrdersLogger, quickTenderedAmounts, ratePpmFromPercent, readBoundRegister, readRegister, reconcileRegisterCommands, recordMovement, recordRegisterFact, registerCommandCollection, registerCommandSchema, registerCommandsLogger, registerFactsLogger, registerSessionCollection, registerSessionSchema, requireOpenSession, resolveStoreSettings, restoreOrderDraft, roundMicrosToMinor, saleLogger, sameSale, searchProducts, selectClosureRows, sessionOpenCommand, sessionTransitionCommand, stampSession, startCounting, stockOverlay$, stockOverlayAsOf$, taxFiguresForBasket, taxLinesByRate, taxLogger, taxMicros, taxProviderProps, tenderReducer, toOrderCreateEnvelope, unbindRegister, useCurrencyCode, useCurrencyFormatter, useOrderOutbox, useParkedSales, useRegisterOutbox, useRegisterSession, useSale, useStoreSettings, useTax, uuidv7, validAmount, varianceText, variantPriceLabel, voidMovement, withPricingContext, writeClosure, writeOrderDraft };
|
package/dist/index.js
CHANGED
|
@@ -1082,6 +1082,27 @@ function createOrderManager(options) {
|
|
|
1082
1082
|
};
|
|
1083
1083
|
}
|
|
1084
1084
|
|
|
1085
|
+
// src/order/use-parked-sales.ts
|
|
1086
|
+
import { useEffect as useEffect2, useState as useState2 } from "react";
|
|
1087
|
+
function useParkedSales(drafts) {
|
|
1088
|
+
const [parked, setParked] = useState2([]);
|
|
1089
|
+
useEffect2(() => {
|
|
1090
|
+
if (!drafts) {
|
|
1091
|
+
setParked([]);
|
|
1092
|
+
return;
|
|
1093
|
+
}
|
|
1094
|
+
const subscription = parkedOrderSummaries$(drafts).subscribe((summaries) => {
|
|
1095
|
+
setParked([...summaries].sort((a, b) => b.parkedAt.localeCompare(a.parkedAt)));
|
|
1096
|
+
});
|
|
1097
|
+
return () => subscription.unsubscribe();
|
|
1098
|
+
}, [drafts]);
|
|
1099
|
+
const discard = async (id2) => {
|
|
1100
|
+
if (!drafts) throw new Error("useParkedSales: discard() needs the drafts collection");
|
|
1101
|
+
await (await drafts.findOne(id2).exec())?.remove();
|
|
1102
|
+
};
|
|
1103
|
+
return { parked, discard };
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1085
1106
|
// src/receipt/build-receipt-data.ts
|
|
1086
1107
|
function buildReceiptData(order, config) {
|
|
1087
1108
|
const taxLines = taxLinesByRate(order.lineItems, order.taxMinor, config.taxLabels, order.taxRounding).map(
|
|
@@ -1181,7 +1202,7 @@ function stockOverlayAsOf$(collection) {
|
|
|
1181
1202
|
}
|
|
1182
1203
|
|
|
1183
1204
|
// src/sale/use-sale.ts
|
|
1184
|
-
import { useEffect as
|
|
1205
|
+
import { useEffect as useEffect4, useLayoutEffect, useRef as useRef3, useState as useState4 } from "react";
|
|
1185
1206
|
|
|
1186
1207
|
// src/pos-order/uuidv7.ts
|
|
1187
1208
|
function format(ms, bytes) {
|
|
@@ -1418,6 +1439,7 @@ function finalizeOrder(order, options = {}) {
|
|
|
1418
1439
|
const now = (options.now ?? /* @__PURE__ */ new Date()).toISOString();
|
|
1419
1440
|
return freezeSentForm({
|
|
1420
1441
|
id: id2,
|
|
1442
|
+
saleId: order.id,
|
|
1421
1443
|
createdAt: now,
|
|
1422
1444
|
updatedAt: now,
|
|
1423
1445
|
commandId: newId(),
|
|
@@ -1448,12 +1470,13 @@ function finalizeOrder(order, options = {}) {
|
|
|
1448
1470
|
import { addRxPlugin } from "rxdb";
|
|
1449
1471
|
import { RxDBMigrationSchemaPlugin } from "rxdb/plugins/migration-schema";
|
|
1450
1472
|
var posOrderSchema = {
|
|
1451
|
-
version:
|
|
1473
|
+
version: 7,
|
|
1452
1474
|
primaryKey: "id",
|
|
1453
1475
|
type: "object",
|
|
1454
1476
|
additionalProperties: false,
|
|
1455
1477
|
properties: {
|
|
1456
1478
|
id: { type: "string", maxLength: 36 },
|
|
1479
|
+
saleId: { type: "string", maxLength: 36 },
|
|
1457
1480
|
commandId: { type: "string", maxLength: 36 },
|
|
1458
1481
|
createdAt: { type: "string", maxLength: 40 },
|
|
1459
1482
|
updatedAt: { type: "string" },
|
|
@@ -1602,7 +1625,7 @@ function posOrderCollection() {
|
|
|
1602
1625
|
};
|
|
1603
1626
|
return {
|
|
1604
1627
|
schema: posOrderSchema,
|
|
1605
|
-
migrationStrategies: { 1: identity2, 2: identity2, 3: identity2, 4: identity2, 5: recordSent, 6: recordRounding }
|
|
1628
|
+
migrationStrategies: { 1: identity2, 2: identity2, 3: identity2, 4: identity2, 5: recordSent, 6: recordRounding, 7: identity2 }
|
|
1606
1629
|
};
|
|
1607
1630
|
}
|
|
1608
1631
|
|
|
@@ -2994,7 +3017,7 @@ function buildXReportDocument(session, context) {
|
|
|
2994
3017
|
}
|
|
2995
3018
|
|
|
2996
3019
|
// src/register/use-register-session.ts
|
|
2997
|
-
import { useEffect as
|
|
3020
|
+
import { useEffect as useEffect3, useMemo as useMemo3, useRef as useRef2, useState as useState3, useSyncExternalStore } from "react";
|
|
2998
3021
|
import { combineLatest, map as map5, of, switchMap } from "rxjs";
|
|
2999
3022
|
|
|
3000
3023
|
// src/register/register-commands.ts
|
|
@@ -3214,7 +3237,7 @@ function useRegisterSession(options) {
|
|
|
3214
3237
|
}
|
|
3215
3238
|
});
|
|
3216
3239
|
};
|
|
3217
|
-
|
|
3240
|
+
useEffect3(reconcile, [commandTarget]);
|
|
3218
3241
|
const source = useMemo3(() => {
|
|
3219
3242
|
if (!enabled || !sessions || !movements || !closures || !orders || !registerId || !register) return null;
|
|
3220
3243
|
return combineLatest([
|
|
@@ -3233,14 +3256,14 @@ function useRegisterSession(options) {
|
|
|
3233
3256
|
const tender = useRef2(tenderInProgress);
|
|
3234
3257
|
tender.current = tenderInProgress;
|
|
3235
3258
|
const closing = useSyncExternalStore(subscribeClosing, () => closingByRegister.has(registerId ?? ""));
|
|
3236
|
-
const [observed, setObserved] =
|
|
3237
|
-
|
|
3259
|
+
const [observed, setObserved] = useState3(null);
|
|
3260
|
+
useEffect3(() => {
|
|
3238
3261
|
if (!source) return;
|
|
3239
3262
|
const subscription = source.subscribe((snapshot) => setObserved({ source, snapshot }));
|
|
3240
3263
|
return () => subscription.unsubscribe();
|
|
3241
3264
|
}, [source]);
|
|
3242
|
-
const [, setMinute] =
|
|
3243
|
-
|
|
3265
|
+
const [, setMinute] = useState3(0);
|
|
3266
|
+
useEffect3(() => {
|
|
3244
3267
|
if (!enabled || !expectedCloseTime) return;
|
|
3245
3268
|
const timer = setInterval(() => setMinute((value) => value + 1), 6e4);
|
|
3246
3269
|
return () => clearInterval(timer);
|
|
@@ -3272,7 +3295,7 @@ function useRegisterSession(options) {
|
|
|
3272
3295
|
return state.running = run;
|
|
3273
3296
|
};
|
|
3274
3297
|
const seen = useRef2(null);
|
|
3275
|
-
|
|
3298
|
+
useEffect3(() => {
|
|
3276
3299
|
if (!data) return;
|
|
3277
3300
|
const ids = data.closureRows.map((row) => row.id);
|
|
3278
3301
|
if (seen.current?.source !== source) {
|
|
@@ -3545,19 +3568,19 @@ var HUNG_SAVE_CHECK_MS = 5e3;
|
|
|
3545
3568
|
function useSale(settings, opts) {
|
|
3546
3569
|
const taxContext = useTax();
|
|
3547
3570
|
const madeWith = useRef3({ taxContext, currency: settings.currency });
|
|
3548
|
-
const [rendered, setBuilder] =
|
|
3571
|
+
const [rendered, setBuilder] = useState4(() => createOrderBuilder({ currency: settings.currency, taxContext }));
|
|
3549
3572
|
const builderNow = useRef3(rendered);
|
|
3550
|
-
const [order, setOrder] =
|
|
3551
|
-
const [stage, setStage] =
|
|
3552
|
-
const [saleError, setError] =
|
|
3573
|
+
const [order, setOrder] = useState4(() => rendered.getSnapshot());
|
|
3574
|
+
const [stage, setStage] = useState4({ kind: "cart" });
|
|
3575
|
+
const [saleError, setError] = useState4(null);
|
|
3553
3576
|
const configError = referenceError("cashierRef", opts.cashierRef) ?? referenceError("registerId", opts.registerId);
|
|
3554
3577
|
const pending = useRef3(null);
|
|
3555
|
-
const [saving, setSaving] =
|
|
3578
|
+
const [saving, setSaving] = useState4(false);
|
|
3556
3579
|
const error = saving && saleError ? saleError : configError ?? saleError;
|
|
3557
3580
|
const tenderSession = useRef3(null);
|
|
3558
|
-
const
|
|
3581
|
+
const droppedReferences = useRef3(/* @__PURE__ */ new Set());
|
|
3559
3582
|
const confirmed = useRef3(null);
|
|
3560
|
-
const [canContinue, setCanContinue] =
|
|
3583
|
+
const [canContinue, setCanContinue] = useState4(false);
|
|
3561
3584
|
const attempts = useRef3(0);
|
|
3562
3585
|
const hungSaveTimer = useRef3(null);
|
|
3563
3586
|
const checking = useRef3(null);
|
|
@@ -3590,7 +3613,7 @@ function useSale(settings, opts) {
|
|
|
3590
3613
|
pending.current = null;
|
|
3591
3614
|
inFlight.current = null;
|
|
3592
3615
|
tenderSession.current = null;
|
|
3593
|
-
|
|
3616
|
+
droppedReferences.current.clear();
|
|
3594
3617
|
setSaving(false);
|
|
3595
3618
|
madeWith.current = { taxContext, currency: settings.currency };
|
|
3596
3619
|
const next = restored ?? createOrderBuilder({ currency: settings.currency, taxContext });
|
|
@@ -3601,7 +3624,7 @@ function useSale(settings, opts) {
|
|
|
3601
3624
|
setStage({ kind: "cart" });
|
|
3602
3625
|
setError(null);
|
|
3603
3626
|
}
|
|
3604
|
-
|
|
3627
|
+
useEffect4(() => {
|
|
3605
3628
|
const subscription = rendered.order$.subscribe(setOrder);
|
|
3606
3629
|
return () => subscription.unsubscribe();
|
|
3607
3630
|
}, [rendered]);
|
|
@@ -3611,7 +3634,7 @@ function useSale(settings, opts) {
|
|
|
3611
3634
|
const liveIdle = stageNow.current.kind === "cart" && !live.lineItems.length && !inFlight.current && !pending.current;
|
|
3612
3635
|
if (liveIdle && (madeWith.current.taxContext !== taxContext || madeWith.current.currency !== settings.currency)) resetSale(live.customer ?? null);
|
|
3613
3636
|
});
|
|
3614
|
-
|
|
3637
|
+
useEffect4(() => () => {
|
|
3615
3638
|
clearHungSaveTimer();
|
|
3616
3639
|
if (pending.current || inFlight.current) {
|
|
3617
3640
|
saleLogger.error(
|
|
@@ -3620,21 +3643,29 @@ function useSale(settings, opts) {
|
|
|
3620
3643
|
);
|
|
3621
3644
|
}
|
|
3622
3645
|
}, []);
|
|
3623
|
-
function
|
|
3624
|
-
|
|
3625
|
-
const reason = referenceReason(tender?.reference);
|
|
3646
|
+
function addOne(tender) {
|
|
3647
|
+
const reason = referenceReason(tender.reference);
|
|
3626
3648
|
const dropped = reason && (reason === "nul" ? "it contains a NUL character" : `it is over ${PAYLOAD_STRING_MAX} characters`);
|
|
3627
|
-
const kept =
|
|
3649
|
+
const kept = dropped ? { method: tender.method, amountMinor: tender.amountMinor } : tender;
|
|
3628
3650
|
const builder = builderNow.current;
|
|
3629
|
-
const
|
|
3630
|
-
if (
|
|
3631
|
-
|
|
3632
|
-
|
|
3633
|
-
|
|
3651
|
+
const paymentId = builder.addPayment(kept);
|
|
3652
|
+
if (dropped) {
|
|
3653
|
+
droppedReferences.current.add(paymentId);
|
|
3654
|
+
setError(`The terminal's payment reference couldn't be kept (${dropped}); the payment is recorded without it.`);
|
|
3655
|
+
}
|
|
3634
3656
|
try {
|
|
3635
3657
|
if (dropped) saleLogger.warn("the terminal's payment reference was dropped", { reason: dropped, method: tender.method });
|
|
3636
3658
|
} catch {
|
|
3637
3659
|
}
|
|
3660
|
+
return paymentId;
|
|
3661
|
+
}
|
|
3662
|
+
function setTender(tender) {
|
|
3663
|
+
if (locked()) return;
|
|
3664
|
+
const builder = builderNow.current;
|
|
3665
|
+
for (const payment of builder.getSnapshot().payments) builder.removePayment(payment.id);
|
|
3666
|
+
droppedReferences.current.clear();
|
|
3667
|
+
setError(null);
|
|
3668
|
+
if (tender) addOne(tender);
|
|
3638
3669
|
}
|
|
3639
3670
|
function checkStored(completion) {
|
|
3640
3671
|
const attempt2 = attempts.current;
|
|
@@ -3672,7 +3703,7 @@ function useSale(settings, opts) {
|
|
|
3672
3703
|
if (hungSaveTimer.current === timer) clearHungSaveTimer();
|
|
3673
3704
|
if (pending.current !== completion) return;
|
|
3674
3705
|
pending.current = null;
|
|
3675
|
-
|
|
3706
|
+
droppedReferences.current.clear();
|
|
3676
3707
|
confirm(null);
|
|
3677
3708
|
setSaving(false);
|
|
3678
3709
|
setError(null);
|
|
@@ -3778,6 +3809,23 @@ function useSale(settings, opts) {
|
|
|
3778
3809
|
setStage({ kind: "tender", method });
|
|
3779
3810
|
},
|
|
3780
3811
|
setTender,
|
|
3812
|
+
/** ADR-072: external is capped at the balance due; change comes only from cash. */
|
|
3813
|
+
addTender(tender) {
|
|
3814
|
+
if (locked() || !Number.isInteger(tender.amountMinor) || tender.amountMinor <= 0) return null;
|
|
3815
|
+
if (tender.method === "external") {
|
|
3816
|
+
const due = builderNow.current.getSnapshot().balanceDueMinor;
|
|
3817
|
+
if (due <= 0) return null;
|
|
3818
|
+
return addOne({ ...tender, amountMinor: Math.min(tender.amountMinor, due) });
|
|
3819
|
+
}
|
|
3820
|
+
return addOne(tender);
|
|
3821
|
+
},
|
|
3822
|
+
/** ADR-072: remove one tender and its dropped-reference warning. An id not among the payments changes nothing. */
|
|
3823
|
+
removeTender(paymentId) {
|
|
3824
|
+
if (locked()) return;
|
|
3825
|
+
if (!builderNow.current.getSnapshot().payments.some((payment) => payment.id === paymentId)) return;
|
|
3826
|
+
builderNow.current.removePayment(paymentId);
|
|
3827
|
+
droppedReferences.current.delete(paymentId);
|
|
3828
|
+
},
|
|
3781
3829
|
cancelTender() {
|
|
3782
3830
|
if (locked()) return;
|
|
3783
3831
|
setTender(null);
|
|
@@ -3805,13 +3853,14 @@ function useSale(settings, opts) {
|
|
|
3805
3853
|
if (pending.current) return deliver(pending.current);
|
|
3806
3854
|
setSaving(true);
|
|
3807
3855
|
const current = builderNow.current.getSnapshot();
|
|
3856
|
+
const localWarnings = current.payments.filter((payment) => droppedReferences.current.has(payment.id)).map((payment) => ({ code: "payment_reference_dropped", paymentId: payment.id }));
|
|
3808
3857
|
let posOrder;
|
|
3809
3858
|
try {
|
|
3810
3859
|
posOrder = finalizeOrder(current, {
|
|
3811
3860
|
registerId: opts.registerId,
|
|
3812
3861
|
cashierRef: opts.cashierRef,
|
|
3813
3862
|
capabilities: opts.capabilities,
|
|
3814
|
-
...
|
|
3863
|
+
...localWarnings.length ? { localWarnings } : {}
|
|
3815
3864
|
});
|
|
3816
3865
|
} catch (error2) {
|
|
3817
3866
|
setSaving(false);
|
|
@@ -4735,15 +4784,15 @@ function createRegisterOutbox(options) {
|
|
|
4735
4784
|
}
|
|
4736
4785
|
|
|
4737
4786
|
// src/outbox/use-register-outbox.ts
|
|
4738
|
-
import { useEffect as
|
|
4787
|
+
import { useEffect as useEffect5, useRef as useRef4, useState as useState5 } from "react";
|
|
4739
4788
|
var idle = { pending: 0, sending: false };
|
|
4740
4789
|
function useRegisterOutbox(options) {
|
|
4741
4790
|
const { commands, deviceId } = options;
|
|
4742
4791
|
const latest = useRef4(options);
|
|
4743
4792
|
latest.current = options;
|
|
4744
4793
|
const current = useRef4(null);
|
|
4745
|
-
const [state, setState] =
|
|
4746
|
-
|
|
4794
|
+
const [state, setState] = useState5(idle);
|
|
4795
|
+
useEffect5(() => {
|
|
4747
4796
|
setState(idle);
|
|
4748
4797
|
if (!commands) return;
|
|
4749
4798
|
const outbox = createRegisterOutbox({
|
|
@@ -4777,7 +4826,7 @@ function useRegisterOutbox(options) {
|
|
|
4777
4826
|
}
|
|
4778
4827
|
|
|
4779
4828
|
// src/outbox/use-order-outbox.ts
|
|
4780
|
-
import { useEffect as
|
|
4829
|
+
import { useEffect as useEffect6, useMemo as useMemo4, useRef as useRef5, useState as useState6 } from "react";
|
|
4781
4830
|
var idle2 = { pending: 0, sending: false };
|
|
4782
4831
|
var noneStuck = [];
|
|
4783
4832
|
function useOrderOutbox(options) {
|
|
@@ -4787,12 +4836,12 @@ function useOrderOutbox(options) {
|
|
|
4787
4836
|
const current = useRef5(null);
|
|
4788
4837
|
const openingError = useRef5(null);
|
|
4789
4838
|
const loggedMismatches = useRef5(/* @__PURE__ */ new Set());
|
|
4790
|
-
const [orders, setOrders] =
|
|
4791
|
-
const [state, setState] =
|
|
4792
|
-
const [recent, setRecent] =
|
|
4839
|
+
const [orders, setOrders] = useState6(null);
|
|
4840
|
+
const [state, setState] = useState6(idle2);
|
|
4841
|
+
const [recent, setRecent] = useState6([]);
|
|
4793
4842
|
const savesInFlight = useRef5(0);
|
|
4794
|
-
const [savesInFlightCount, setSavesInFlightCount] =
|
|
4795
|
-
|
|
4843
|
+
const [savesInFlightCount, setSavesInFlightCount] = useState6(0);
|
|
4844
|
+
useEffect6(() => {
|
|
4796
4845
|
let active = true;
|
|
4797
4846
|
let dispose;
|
|
4798
4847
|
openingError.current = null;
|
|
@@ -4835,7 +4884,7 @@ function useOrderOutbox(options) {
|
|
|
4835
4884
|
dispose?.();
|
|
4836
4885
|
};
|
|
4837
4886
|
}, [storeKey, deviceId]);
|
|
4838
|
-
|
|
4887
|
+
useEffect6(() => {
|
|
4839
4888
|
latest.current.onBusy?.(state.sending);
|
|
4840
4889
|
return () => latest.current.onBusy?.(false);
|
|
4841
4890
|
}, [state.sending]);
|
|
@@ -5218,6 +5267,7 @@ export {
|
|
|
5218
5267
|
useCurrencyCode,
|
|
5219
5268
|
useCurrencyFormatter,
|
|
5220
5269
|
useOrderOutbox,
|
|
5270
|
+
useParkedSales,
|
|
5221
5271
|
useRegisterOutbox,
|
|
5222
5272
|
useRegisterSession,
|
|
5223
5273
|
useSale,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tallyui/pos",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.1.1",
|
|
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",
|
|
@@ -27,20 +27,20 @@
|
|
|
27
27
|
"directory": "packages/pos"
|
|
28
28
|
},
|
|
29
29
|
"peerDependencies": {
|
|
30
|
-
"@tallyui/core": "^3.
|
|
30
|
+
"@tallyui/core": "^3.1.1",
|
|
31
31
|
"react": ">=18",
|
|
32
32
|
"rxdb": "~17.5.0",
|
|
33
33
|
"rxjs": ">=7"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
|
-
"@tallyui/core": "3.
|
|
36
|
+
"@tallyui/core": "3.1.1",
|
|
37
37
|
"@types/react": ">=18",
|
|
38
38
|
"react": "^19.2.4",
|
|
39
39
|
"rxdb": "17.5.0",
|
|
40
40
|
"rxjs": "7.8.2",
|
|
41
|
-
"@tallyui/connector-medusa": "3.
|
|
42
|
-
"@tallyui/connector-woocommerce": "3.
|
|
43
|
-
"@tallyui/database": "3.
|
|
41
|
+
"@tallyui/connector-medusa": "3.1.1",
|
|
42
|
+
"@tallyui/connector-woocommerce": "3.1.1",
|
|
43
|
+
"@tallyui/database": "3.1.1"
|
|
44
44
|
},
|
|
45
45
|
"scripts": {
|
|
46
46
|
"build": "tsup",
|
package/src/index.ts
CHANGED
|
@@ -27,6 +27,7 @@ export type { Repository } from './repository';
|
|
|
27
27
|
// Order
|
|
28
28
|
export { createOrderBuilder, createOrderManager, allocateOrderDiscount, taxFiguresForBasket } from './order';
|
|
29
29
|
export { orderDraftSchema, writeOrderDraft, restoreOrderDraft, parkedOrderSummaries$ } from './order';
|
|
30
|
+
export { useParkedSales } from './order';
|
|
30
31
|
export type { BasketLine } from './order';
|
|
31
32
|
export type { OrderBuilder, OrderBuilderOptions } from './order';
|
|
32
33
|
export type { OrderManager, OrderManagerOptions, ParkedOrderSummary } from './order';
|
package/src/order/index.ts
CHANGED
|
@@ -5,6 +5,7 @@ export { allocateOrderDiscount } from './allocate-order-discount';
|
|
|
5
5
|
export type { OrderBuilder, OrderBuilderOptions } from './order-builder';
|
|
6
6
|
export { createOrderManager } from './order-manager';
|
|
7
7
|
export { orderDraftSchema, writeOrderDraft, restoreOrderDraft, parkedOrderSummaries$ } from './order-drafts';
|
|
8
|
+
export { useParkedSales } from './use-parked-sales';
|
|
8
9
|
export type { OrderManager, OrderManagerOptions, ParkedOrderSummary } from './order-manager';
|
|
9
10
|
export type {
|
|
10
11
|
Order,
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
import type { RxCollection } from 'rxdb';
|
|
3
|
+
import { parkedOrderSummaries$, type ParkedOrderSummary } from './order-drafts';
|
|
4
|
+
|
|
5
|
+
/** The parked sales in `drafts`, newest first, live; and a discard that removes one. */
|
|
6
|
+
export function useParkedSales(drafts: RxCollection | undefined): {
|
|
7
|
+
parked: ParkedOrderSummary[];
|
|
8
|
+
discard: (id: string) => Promise<void>;
|
|
9
|
+
} {
|
|
10
|
+
const [parked, setParked] = useState<ParkedOrderSummary[]>([]);
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
if (!drafts) { setParked([]); return; }
|
|
13
|
+
const subscription = parkedOrderSummaries$(drafts).subscribe((summaries) => {
|
|
14
|
+
setParked([...summaries].sort((a, b) => b.parkedAt.localeCompare(a.parkedAt)));
|
|
15
|
+
});
|
|
16
|
+
return () => subscription.unsubscribe();
|
|
17
|
+
}, [drafts]);
|
|
18
|
+
|
|
19
|
+
const discard = async (id: string): Promise<void> => {
|
|
20
|
+
if (!drafts) throw new Error('useParkedSales: discard() needs the drafts collection');
|
|
21
|
+
await (await drafts.findOne(id).exec())?.remove();
|
|
22
|
+
};
|
|
23
|
+
return { parked, discard };
|
|
24
|
+
}
|
|
@@ -204,7 +204,7 @@ export function finalizeOrder(order: Order, options: FinalizeOptions = {}): PosO
|
|
|
204
204
|
: { granularity: rounding.granularity, mode: rounding.mode };
|
|
205
205
|
const now = (options.now ?? new Date()).toISOString();
|
|
206
206
|
return freezeSentForm({
|
|
207
|
-
id, createdAt: now, updatedAt: now, commandId: newId(), syncStatus: 'pending',
|
|
207
|
+
id, saleId: order.id, createdAt: now, updatedAt: now, commandId: newId(), syncStatus: 'pending',
|
|
208
208
|
currency: order.currency, pricesIncludeTax: order.pricesIncludeTax, lines, payments,
|
|
209
209
|
subtotalMinor: order.subtotalMinor, discountMinor: order.discountMinor,
|
|
210
210
|
taxMinor: order.taxMinor, totalMinor: order.totalMinor, taxRounding,
|
package/src/pos-order/schema.ts
CHANGED
|
@@ -18,11 +18,14 @@ import type { PosOrder } from './types';
|
|
|
18
18
|
* Like version 4 (ADR-069), it is one-way: an older build shows no orders.
|
|
19
19
|
* Version 6 adds `taxRounding`, the strategy the sale's figures were computed with (#287; never sent), and changes
|
|
20
20
|
* nothing else. Its migration sets it on every older row. It is one-way like version 5.
|
|
21
|
+
* Version 7 adds `saleId`, the sale order's id (ADR-072; never sent), and changes nothing else. Its migration is the
|
|
22
|
+
* identity: older orders have no `saleId`. It is one-way like version 6.
|
|
21
23
|
*/
|
|
22
24
|
export const posOrderSchema: RxJsonSchema<PosOrder> = {
|
|
23
|
-
version:
|
|
25
|
+
version: 7, primaryKey: 'id', type: 'object', additionalProperties: false,
|
|
24
26
|
properties: {
|
|
25
27
|
id: { type: 'string', maxLength: 36 },
|
|
28
|
+
saleId: { type: 'string', maxLength: 36 },
|
|
26
29
|
commandId: { type: 'string', maxLength: 36 },
|
|
27
30
|
createdAt: { type: 'string', maxLength: 40 },
|
|
28
31
|
updatedAt: { type: 'string' },
|
|
@@ -126,5 +129,5 @@ export function posOrderCollection(): { schema: RxJsonSchema<PosOrder>; migratio
|
|
|
126
129
|
// it means no older sale is ever re-rounded (#287).
|
|
127
130
|
const recordRounding = (doc: PosOrder) => { doc.taxRounding ??= { ...DEFAULT_TAX_ROUNDING }; return doc; };
|
|
128
131
|
return { schema: posOrderSchema,
|
|
129
|
-
migrationStrategies: { 1: identity, 2: identity, 3: identity, 4: identity, 5: recordSent, 6: recordRounding } };
|
|
132
|
+
migrationStrategies: { 1: identity, 2: identity, 3: identity, 4: identity, 5: recordSent, 6: recordRounding, 7: identity } };
|
|
130
133
|
}
|
package/src/pos-order/types.ts
CHANGED
|
@@ -42,6 +42,8 @@ export interface PosOrderPayment {
|
|
|
42
42
|
|
|
43
43
|
export interface PosOrder {
|
|
44
44
|
id: string;
|
|
45
|
+
/** The sale order's id (the builder's), set by finalizeOrder (pos_orders v7, ADR-072): support traceability from a draft or preview to this stored order. Never sent, never printed. */
|
|
46
|
+
saleId?: string;
|
|
45
47
|
createdAt: string;
|
|
46
48
|
currency: string;
|
|
47
49
|
pricesIncludeTax: boolean;
|
package/src/sale/use-sale.ts
CHANGED
|
@@ -72,8 +72,8 @@ export function useSale(settings: Pick<StoreSettings, 'currency'>, opts: {
|
|
|
72
72
|
const error = saving && saleError ? saleError : configError ?? saleError;
|
|
73
73
|
// The session pinned by startTender for this tender (`undefined` inside: none); null until a tender starts.
|
|
74
74
|
const tenderSession = useRef<{ session: typeof opts.session } | null>(null);
|
|
75
|
-
// The
|
|
76
|
-
const
|
|
75
|
+
// The ids, at the tender, of payments whose terminal references were dropped.
|
|
76
|
+
const droppedReferences = useRef<Set<string>>(new Set());
|
|
77
77
|
// The pending completion isStored confirmed stored after its save failed; `canContinue` mirrors it for
|
|
78
78
|
// rendering. `attempts` counts complete() attempts, so a confirmation that lands after a new one is dropped.
|
|
79
79
|
const confirmed = useRef<{ order: Order; posOrder: PosOrder } | null>(null);
|
|
@@ -115,7 +115,7 @@ export function useSale(settings: Pick<StoreSettings, 'currency'>, opts: {
|
|
|
115
115
|
confirm(null); pending.current = null;
|
|
116
116
|
inFlight.current = null;
|
|
117
117
|
tenderSession.current = null;
|
|
118
|
-
|
|
118
|
+
droppedReferences.current.clear();
|
|
119
119
|
setSaving(false);
|
|
120
120
|
madeWith.current = { taxContext, currency: settings.currency };
|
|
121
121
|
const next = restored ?? createOrderBuilder({ currency: settings.currency, taxContext });
|
|
@@ -149,23 +149,32 @@ export function useSale(settings: Pick<StoreSettings, 'currency'>, opts: {
|
|
|
149
149
|
}
|
|
150
150
|
}, []);
|
|
151
151
|
|
|
152
|
-
function
|
|
153
|
-
if (locked()) return;
|
|
152
|
+
function addOne(tender: { method: 'cash' | 'external'; amountMinor: number; reference?: string }): string {
|
|
154
153
|
// A terminal reference finalize would refuse is dropped as it's entered, never the payment (the money is
|
|
155
154
|
// taken): the tender applies without it, with a message that doesn't block complete() and a
|
|
156
155
|
// localWarnings entry on the stored order naming the payment whose reference was dropped.
|
|
157
|
-
const reason = referenceReason(tender
|
|
156
|
+
const reason = referenceReason(tender.reference);
|
|
158
157
|
const dropped = reason && (reason === 'nul' ? 'it contains a NUL character' : `it is over ${PAYLOAD_STRING_MAX} characters`);
|
|
159
|
-
const kept =
|
|
158
|
+
const kept = dropped ? { method: tender.method, amountMinor: tender.amountMinor } : tender;
|
|
160
159
|
const builder = builderNow.current;
|
|
161
|
-
const
|
|
162
|
-
if (
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
160
|
+
const paymentId = builder.addPayment(kept);
|
|
161
|
+
if (dropped) {
|
|
162
|
+
droppedReferences.current.add(paymentId);
|
|
163
|
+
setError(`The terminal's payment reference couldn't be kept (${dropped}); the payment is recorded without it.`);
|
|
164
|
+
}
|
|
166
165
|
try {
|
|
167
|
-
if (dropped) saleLogger.warn("the terminal's payment reference was dropped", { reason: dropped, method: tender
|
|
166
|
+
if (dropped) saleLogger.warn("the terminal's payment reference was dropped", { reason: dropped, method: tender.method });
|
|
168
167
|
} catch { /* a failing sink must never lose the tender */ }
|
|
168
|
+
return paymentId;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function setTender(tender: { method: 'cash' | 'external'; amountMinor: number; reference?: string } | null) {
|
|
172
|
+
if (locked()) return;
|
|
173
|
+
const builder = builderNow.current;
|
|
174
|
+
for (const payment of builder.getSnapshot().payments) builder.removePayment(payment.id);
|
|
175
|
+
droppedReferences.current.clear();
|
|
176
|
+
setError(null);
|
|
177
|
+
if (tender) addOne(tender);
|
|
169
178
|
}
|
|
170
179
|
|
|
171
180
|
/** Asks `isStored`; Continue is offered only once it confirms, for this attempt, with the completion still pending. */
|
|
@@ -212,7 +221,7 @@ export function useSale(settings: Pick<StoreSettings, 'currency'>, opts: {
|
|
|
212
221
|
if (hungSaveTimer.current === timer) clearHungSaveTimer();
|
|
213
222
|
if (pending.current !== completion) return;
|
|
214
223
|
pending.current = null;
|
|
215
|
-
|
|
224
|
+
droppedReferences.current.clear();
|
|
216
225
|
confirm(null);
|
|
217
226
|
setSaving(false);
|
|
218
227
|
setError(null);
|
|
@@ -315,6 +324,23 @@ export function useSale(settings: Pick<StoreSettings, 'currency'>, opts: {
|
|
|
315
324
|
setStage({ kind: 'tender', method });
|
|
316
325
|
},
|
|
317
326
|
setTender,
|
|
327
|
+
/** ADR-072: external is capped at the balance due; change comes only from cash. */
|
|
328
|
+
addTender(tender: { method: 'cash' | 'external'; amountMinor: number; reference?: string }): string | null {
|
|
329
|
+
if (locked() || !Number.isInteger(tender.amountMinor) || tender.amountMinor <= 0) return null;
|
|
330
|
+
if (tender.method === 'external') {
|
|
331
|
+
const due = builderNow.current.getSnapshot().balanceDueMinor;
|
|
332
|
+
if (due <= 0) return null;
|
|
333
|
+
return addOne({ ...tender, amountMinor: Math.min(tender.amountMinor, due) });
|
|
334
|
+
}
|
|
335
|
+
return addOne(tender);
|
|
336
|
+
},
|
|
337
|
+
/** ADR-072: remove one tender and its dropped-reference warning. An id not among the payments changes nothing. */
|
|
338
|
+
removeTender(paymentId: string): void {
|
|
339
|
+
if (locked()) return;
|
|
340
|
+
if (!builderNow.current.getSnapshot().payments.some((payment) => payment.id === paymentId)) return;
|
|
341
|
+
builderNow.current.removePayment(paymentId);
|
|
342
|
+
droppedReferences.current.delete(paymentId);
|
|
343
|
+
},
|
|
318
344
|
cancelTender() {
|
|
319
345
|
if (locked()) return;
|
|
320
346
|
setTender(null);
|
|
@@ -342,10 +368,12 @@ export function useSale(settings: Pick<StoreSettings, 'currency'>, opts: {
|
|
|
342
368
|
if (pending.current) return deliver(pending.current);
|
|
343
369
|
setSaving(true);
|
|
344
370
|
const current = builderNow.current.getSnapshot();
|
|
371
|
+
const localWarnings = current.payments.filter((payment) => droppedReferences.current.has(payment.id))
|
|
372
|
+
.map((payment) => ({ code: 'payment_reference_dropped' as const, paymentId: payment.id }));
|
|
345
373
|
let posOrder: PosOrder;
|
|
346
374
|
try {
|
|
347
375
|
posOrder = finalizeOrder(current, { registerId: opts.registerId, cashierRef: opts.cashierRef, capabilities: opts.capabilities,
|
|
348
|
-
...(
|
|
376
|
+
...(localWarnings.length ? { localWarnings } : {}) });
|
|
349
377
|
} catch (error) {
|
|
350
378
|
setSaving(false);
|
|
351
379
|
setError((error as Error).message);
|