@fayz-ai/core 0.31.0 → 0.33.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/dist/app/app-config.d.ts +10 -0
- package/dist/app/app-config.d.ts.map +1 -1
- package/dist/{chunk-HVWFFFKN.js → chunk-MFFT663T.js} +25 -6
- package/dist/chunk-MFFT663T.js.map +1 -0
- package/dist/{chunk-XJGV7TWQ.js → chunk-OI5K5E33.js} +177 -15
- package/dist/chunk-OI5K5E33.js.map +1 -0
- package/dist/{chunk-7M4NWLIT.js → chunk-QZ22VPRZ.js} +3 -3
- package/dist/{chunk-7M4NWLIT.js.map → chunk-QZ22VPRZ.js.map} +1 -1
- package/dist/{chunk-ZGAGCTQM.js → chunk-X3GYBLGO.js} +3 -3
- package/dist/{chunk-ZGAGCTQM.js.map → chunk-X3GYBLGO.js.map} +1 -1
- package/dist/{chunk-ZNTO44TD.js → chunk-XCSAWLFX.js} +71 -6
- package/dist/chunk-XCSAWLFX.js.map +1 -0
- package/dist/data/archetype.d.ts.map +1 -1
- package/dist/data/attached-row.d.ts +26 -0
- package/dist/data/attached-row.d.ts.map +1 -0
- package/dist/data/index.js +2 -2
- package/dist/data/resolve.d.ts.map +1 -1
- package/dist/data/supabase.d.ts +1 -1
- package/dist/data/supabase.d.ts.map +1 -1
- package/dist/data/write-refused.d.ts +16 -0
- package/dist/data/write-refused.d.ts.map +1 -0
- package/dist/entity/payee-account-fields.d.ts +11 -0
- package/dist/entity/payee-account-fields.d.ts.map +1 -0
- package/dist/entity/record-rail.d.ts +61 -0
- package/dist/entity/record-rail.d.ts.map +1 -0
- package/dist/i18n/index.js +1 -1
- package/dist/i18n/shell-translations.en.d.ts.map +1 -1
- package/dist/i18n/shell-translations.pt-br.d.ts.map +1 -1
- package/dist/index.d.ts +17 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +277 -9
- package/dist/index.js.map +1 -1
- package/dist/integrations/index.js +2 -2
- package/dist/lib/cancel-replay.d.ts +25 -0
- package/dist/lib/cancel-replay.d.ts.map +1 -0
- package/dist/lib/channel-kind.d.ts +30 -0
- package/dist/lib/channel-kind.d.ts.map +1 -0
- package/dist/lib/discount-share.d.ts +23 -0
- package/dist/lib/discount-share.d.ts.map +1 -0
- package/dist/lib/document-br.d.ts +22 -0
- package/dist/lib/document-br.d.ts.map +1 -0
- package/dist/manifest/index.d.ts +1 -1
- package/dist/manifest/index.d.ts.map +1 -1
- package/dist/orders/index.d.ts +39 -0
- package/dist/orders/index.d.ts.map +1 -1
- package/dist/orders/index.js +41 -4
- package/dist/orders/index.js.map +1 -1
- package/dist/orders/openingServiceCharge.d.ts +16 -0
- package/dist/orders/openingServiceCharge.d.ts.map +1 -0
- package/dist/orders/paymentKey.d.ts +22 -0
- package/dist/orders/paymentKey.d.ts.map +1 -0
- package/dist/{shell-translations.pt-br-J5Y5TAJ4.js → shell-translations.pt-br-HZ2EK5ZG.js} +70 -5
- package/dist/shell-translations.pt-br-HZ2EK5ZG.js.map +1 -0
- package/dist/testing/index.js +3 -3
- package/dist/types/crud.d.ts +217 -2
- package/dist/types/crud.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-HVWFFFKN.js.map +0 -1
- package/dist/chunk-XJGV7TWQ.js.map +0 -1
- package/dist/chunk-ZNTO44TD.js.map +0 -1
- package/dist/shell-translations.pt-br-J5Y5TAJ4.js.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { CONNECTIONS_TABLE, CONNECTOR_CATEGORIES, ConnectionSettingsError, ConnectorRuntimeTokenUnavailableError, RequestBlockedError, RequestPlaneError, SYNC_RUNS_TABLE, assertSettingsAllowed, buyerIdempotencyKey, connectionKey, connectionRuns, connectionSettings, connectionStatus, connectorDirection, connectorEntities, connectorGrantScopes, connectorPermissions, connectorPlanes, connectorRuntimeToken, connectorSettings, connectorSubscribes, connectorSubscribesTo, createConnectionStore, createRpcEffectLedger, eventKeyMatches, getConnectorRuntimeTokenSource, grants, groupedPermissions, hasRequestPlane, hasSensitivePermission, invocationPlane, isConnectorCategory, isDataPermission, isEventPermission, isSettingSet, listConnections, missingRequiredSettings, permissionActions, permissionsWrite, preferredPlane, requestPlaneSpec, runEffect, runRequest, setConnectorRuntimeTokenSource, settingsStatus, setupStatusDetail, sortedPermissions, withAfterHooks } from '../chunk-
|
|
1
|
+
export { CONNECTIONS_TABLE, CONNECTOR_CATEGORIES, ConnectionSettingsError, ConnectorRuntimeTokenUnavailableError, RequestBlockedError, RequestPlaneError, SYNC_RUNS_TABLE, assertSettingsAllowed, buyerIdempotencyKey, connectionKey, connectionRuns, connectionSettings, connectionStatus, connectorDirection, connectorEntities, connectorGrantScopes, connectorPermissions, connectorPlanes, connectorRuntimeToken, connectorSettings, connectorSubscribes, connectorSubscribesTo, createConnectionStore, createRpcEffectLedger, eventKeyMatches, getConnectorRuntimeTokenSource, grants, groupedPermissions, hasRequestPlane, hasSensitivePermission, invocationPlane, isConnectorCategory, isDataPermission, isEventPermission, isSettingSet, listConnections, missingRequiredSettings, permissionActions, permissionsWrite, preferredPlane, requestPlaneSpec, runEffect, runRequest, setConnectorRuntimeTokenSource, settingsStatus, setupStatusDetail, sortedPermissions, withAfterHooks } from '../chunk-QZ22VPRZ.js';
|
|
2
2
|
export { CONNECTOR_RUNTIME_TOKEN_HEADER, ConnectorHttpError, RateLimitExceededError, advanceWindow, backoffDelay, classify, createRateLimiter, cursorCompleteness, fetchWithRetry, isExpiring, paginate, parseRetryAfter, reconcileMirror, serializeCursor, sliceWindow, statusNeedsBody } from '../chunk-3TRR2YLM.js';
|
|
3
|
-
import '../chunk-
|
|
3
|
+
import '../chunk-MFFT663T.js';
|
|
4
4
|
import '../chunk-6TVRNKWW.js';
|
|
5
5
|
//# sourceMappingURL=index.js.map
|
|
6
6
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** Uma linha cancelada, como o banco a devolve. */
|
|
2
|
+
export interface CancelledRow {
|
|
3
|
+
id: string;
|
|
4
|
+
quantity: number | string;
|
|
5
|
+
metadata?: Record<string, unknown> | null;
|
|
6
|
+
}
|
|
7
|
+
export interface CancelReplayResult {
|
|
8
|
+
lineId: string;
|
|
9
|
+
cancelledQuantity: number;
|
|
10
|
+
fullyCancelled: boolean;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* O resultado de uma operação que JÁ aconteceu, reconstruído das linhas.
|
|
14
|
+
*
|
|
15
|
+
* A parte que erra fácil é qual id reportar. No parcial, a linha cancelada é
|
|
16
|
+
* NOVA — e o resultado tem de falar do id da ORIGINAL, porque é esse que a tela
|
|
17
|
+
* compara item a item (`assertCancellation`). Sem isso, a repetição devolveria
|
|
18
|
+
* ids que o pedido não mencionou, e a conferência acusaria divergência onde não
|
|
19
|
+
* há.
|
|
20
|
+
*
|
|
21
|
+
* `cancelled_from` no metadata é o que carrega essa origem. Ausente = a linha
|
|
22
|
+
* cancelada É a original, e o cancelamento foi total.
|
|
23
|
+
*/
|
|
24
|
+
export declare function cancelReplayResults(rows: CancelledRow[], operationKey: string): CancelReplayResult[];
|
|
25
|
+
//# sourceMappingURL=cancel-replay.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cancel-replay.d.ts","sourceRoot":"","sources":["../../src/lib/cancel-replay.ts"],"names":[],"mappings":"AAgBA,mDAAmD;AACnD,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAA;IACV,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAA;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAA;CAC1C;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAA;IACd,iBAAiB,EAAE,MAAM,CAAA;IACzB,cAAc,EAAE,OAAO,CAAA;CACxB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,YAAY,EAAE,EACpB,YAAY,EAAE,MAAM,GACnB,kBAAkB,EAAE,CAUtB"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Os três canais que o V2 nomeia — o valor de `orders.channel`.
|
|
3
|
+
*
|
|
4
|
+
* Chamava-se `OrderChannel` e colidia com o `OrderChannel` do `@fayz-ai/shop`,
|
|
5
|
+
* que é OUTRA coisa: lá é a entidade «canal de venda» da loja, aqui é a união
|
|
6
|
+
* de strings que a comanda carrega. O `@fayz-ai/app-runtime` re-exporta os dois
|
|
7
|
+
* pacotes com `export *` e o TypeScript recusou a ambiguidade — mas o build
|
|
8
|
+
* quebrado foi a parte barata: dois tipos diferentes com um nome só fariam um
|
|
9
|
+
* app gerado importar `OrderChannel` e receber o do outro domínio, em silêncio.
|
|
10
|
+
*
|
|
11
|
+
* O nome novo é o da coluna que ele descreve, que é o que ele sempre foi.
|
|
12
|
+
*/
|
|
13
|
+
export type OrderChannel = 'balcao' | 'retirada' | 'delivery';
|
|
14
|
+
/**
|
|
15
|
+
* A espécie do V1 equivalente a este canal, ou `null` quando o canal não é um
|
|
16
|
+
* dos três (um nome novo não ganha equivalência por engano).
|
|
17
|
+
*/
|
|
18
|
+
export declare function legacyKindOfChannel(channel: string): string | null;
|
|
19
|
+
/**
|
|
20
|
+
* O canal a que uma linha pertence, olhando os DOIS campos.
|
|
21
|
+
*
|
|
22
|
+
* `channel` manda quando existe — é o que o V2 escreve de propósito. Sem ele,
|
|
23
|
+
* a espécie responde, e só para as três que têm equivalência: `dine_in` é
|
|
24
|
+
* mesa, não canal, e devolver 'balcao' para ela poria a Mesa 11 no balcão.
|
|
25
|
+
*/
|
|
26
|
+
export declare function channelOfOrder(row: {
|
|
27
|
+
channel?: string | null;
|
|
28
|
+
kind?: string | null;
|
|
29
|
+
}): OrderChannel | null;
|
|
30
|
+
//# sourceMappingURL=channel-kind.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channel-kind.d.ts","sourceRoot":"","sources":["../../src/lib/channel-kind.ts"],"names":[],"mappings":"AAqBA;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,UAAU,GAAG,UAAU,CAAA;AAS7D;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAElE;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GACrD,YAAY,GAAG,IAAI,CASrB"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** Centavos, para o dinheiro não passar por float no caminho. */
|
|
2
|
+
export interface ShareInput {
|
|
3
|
+
/** As linhas escolhidas, com o valor cheio de cada uma em centavos. */
|
|
4
|
+
lines: Array<{
|
|
5
|
+
id: string;
|
|
6
|
+
grossCents: number;
|
|
7
|
+
}>;
|
|
8
|
+
/** O desconto pedido, em centavos. */
|
|
9
|
+
amountCents: number;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* O desconto de cada linha, somando EXATAMENTE o pedido.
|
|
13
|
+
*
|
|
14
|
+
* A proporção é a do V1; o fechamento da soma é acréscimo nosso e necessário: em
|
|
15
|
+
* centavos, três quintos de R$ 50 não são inteiros, e três arredondamentos
|
|
16
|
+
* independentes somam 49,99 ou 50,01. O resto vai para a MAIOR linha, que é onde
|
|
17
|
+
* um centavo pesa menos e onde ele sempre cabe.
|
|
18
|
+
*
|
|
19
|
+
* Nunca passa do valor da linha, e nunca é negativo — as duas bordas que o
|
|
20
|
+
* `Math.min/Math.max` do V2 já protegia, e que continuam protegidas.
|
|
21
|
+
*/
|
|
22
|
+
export declare function fixedDiscountShares(input: ShareInput): Map<string, number>;
|
|
23
|
+
//# sourceMappingURL=discount-share.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discount-share.d.ts","sourceRoot":"","sources":["../../src/lib/discount-share.ts"],"names":[],"mappings":"AAwBA,iEAAiE;AACjE,MAAM,WAAW,UAAU;IACzB,uEAAuE;IACvE,KAAK,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAChD,sCAAsC;IACtC,WAAW,EAAE,MAAM,CAAA;CACpB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,UAAU,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CA6B1E"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export declare const onlyDigits: (s: string) => string;
|
|
2
|
+
export declare function isValidCPF(value: string): boolean;
|
|
3
|
+
export declare function isValidCNPJ(value: string): boolean;
|
|
4
|
+
export declare const isValidCpfOrCnpj: (value: string) => boolean;
|
|
5
|
+
export declare function formatCPF(value: string): string;
|
|
6
|
+
export declare function formatCNPJ(value: string): string;
|
|
7
|
+
/**
|
|
8
|
+
* A máscara que decide sozinha pelo COMPRIMENTO.
|
|
9
|
+
*
|
|
10
|
+
* Até onze dígitos desenha CPF; do décimo segundo em diante vira CNPJ. É o que
|
|
11
|
+
* permite um campo só para os dois — e um campo só é o certo, porque quem está
|
|
12
|
+
* no caixa não sabe de antemão o que o cliente vai ditar.
|
|
13
|
+
*/
|
|
14
|
+
export declare function maskCpfCnpj(value: string): string;
|
|
15
|
+
/** O que este texto É: cpf, cnpj, inválido — ou vazio, que não é erro. */
|
|
16
|
+
export declare function docKind(value: string): 'cpf' | 'cnpj' | 'invalid' | 'empty';
|
|
17
|
+
/** A recusa do V1, literal. `null` quando pode seguir — inclusive vazio. */
|
|
18
|
+
export declare function documentRefusal(value: string): {
|
|
19
|
+
title: string;
|
|
20
|
+
description: string;
|
|
21
|
+
} | null;
|
|
22
|
+
//# sourceMappingURL=document-br.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document-br.d.ts","sourceRoot":"","sources":["../../src/lib/document-br.ts"],"names":[],"mappings":"AAsBA,eAAO,MAAM,UAAU,GAAI,GAAG,MAAM,KAAG,MAAsC,CAAA;AAE7E,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAejD;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAclD;AAED,eAAO,MAAM,gBAAgB,GAAI,OAAO,MAAM,KAAG,OACR,CAAA;AAEzC,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAK/C;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMhD;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGjD;AAED,0EAA0E;AAC1E,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,CAM3E;AAED,4EAA4E;AAC5E,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAI5F"}
|
package/dist/manifest/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/manifest/index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/manifest/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAChD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AAC9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,KAAK,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAA;AACjF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AACrD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAC7D,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AAC9F,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAgBnD,eAAO,MAAM,wBAAwB,IAAI,CAAA;AAEzC,MAAM,MAAM,eAAe,GAAG,UAAU,GAAG,UAAU,GAAG,WAAW,GAAG,MAAM,GAAG,QAAQ,CAAA;AAEvF,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,eAAe,CAAA;IACzB,wEAAwE;IACxE,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,uDAAuD;IACvD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,oEAAoE;IACpE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAClC;AAED,sFAAsF;AACtF,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,UAAU,CAAA;IAC3C,gCAAgC;IAChC,MAAM,CAAC,EAAE,SAAS,EAAE,CAAA;IACpB,+DAA+D;IAC/D,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,kEAAkE;IAClE,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,kDAAkD;IAClD,UAAU,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;CACjD;AAED,MAAM,WAAW,SAAS;IACxB,2EAA2E;IAC3E,EAAE,EAAE,MAAM,CAAA;IACV,4EAA4E;IAC5E,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAChC,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,0EAA0E;IAC1E,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,SAAS,EAAE,CAAA;IACrB,KAAK,CAAC,EAAE,YAAY,EAAE,CAAA;IACtB;;qDAEiD;IACjD,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAClC;AAYD;;8EAE8E;AAC9E,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,uEAAuE;IACvE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,iFAAiF;IACjF,UAAU,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;IAChD,IAAI,EAAE;QACJ,KAAK,EAAE,MAAM,CAAA;QACb,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,YAAY,CAAC,EAAE,OAAO,CAAA;QACtB,cAAc,CAAC,EAAE,MAAM,CAAA;QACvB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;QACxB,aAAa,CAAC,EAAE,MAAM,CAAA;QACtB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;QAClC,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,aAAa,CAAC,EAAE,MAAM,CAAA;QACtB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAA;KAC5C,CAAA;IACD,MAAM,EAAE,KAAK,CAAC;QACZ,GAAG,EAAE,MAAM,CAAA;QACX,KAAK,EAAE,MAAM,CAAA;QACb,IAAI,EAAE,MAAM,CAAA;QACZ,QAAQ,CAAC,EAAE,OAAO,CAAA;QAClB,UAAU,CAAC,EAAE,OAAO,CAAA;QACpB;;2EAEmE;QACnE,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,6CAA6C;QAC7C,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;QAClB,gEAAgE;QAChE,aAAa,CAAC,EAAE,MAAM,CAAA;KACvB,CAAC,CAAA;CACH;AAED,kEAAkE;AAClE,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,IAAI,EAAE,MAAM,GAAG,SAAS,CAAA;IACxB,UAAU,CAAC,EAAE,gBAAgB,CAAA;IAC7B,UAAU,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;IAChD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,SAAS,CAAC,EAAE,eAAe,CAAA;IAC3B,oBAAoB,CAAC,EAAE,OAAO,CAAA;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;8CAC0C;IAC1C,IAAI,CAAC,EAAE,SAAS,CAAA;CACjB;AAED;qCACqC;AACrC,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,SAAS,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,iFAAiF;IACjF,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED;sEACsE;AACtE,YAAY,EAAE,mBAAmB,IAAI,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAE1E;kFACkF;AAClF,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,aAAa,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC,CAAA;IACxF,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC1C,aAAa,CAAC,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAC3D;AAED,MAAM,WAAW,aAAa;IAC5B;gFAC4E;IAC5E,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IACjE,iFAAiF;IACjF,KAAK,CAAC,EAAE,kBAAkB,EAAE,CAAA;IAC5B;;qEAEiE;IACjE,cAAc,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAA;IACpC,QAAQ,CAAC,EAAE,cAAc,EAAE,CAAA;IAC3B,KAAK,CAAC,EAAE,cAAc,EAAE,CAAA;IACxB,UAAU,CAAC,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC,CAAA;IAC5F,gBAAgB,CAAC,EAAE,kBAAkB,EAAE,CAAA;IACvC,IAAI,CAAC,EAAE,mBAAmB,EAAE,CAAA;IAC5B,eAAe,CAAC,EAAE,oBAAoB,CAAA;CACvC;AAaD,gFAAgF;AAChF,MAAM,WAAW,uBAAuB;IACtC,0EAA0E;IAC1E,MAAM,EAAE,MAAM,CAAA;IACd,kFAAkF;IAClF,UAAU,EAAE,KAAK,CAAC,MAAM,GAAG,QAAQ,GAAG,QAAQ,CAAC,CAAA;IAC/C,4EAA4E;IAC5E,MAAM,EAAE,MAAM,CAAA;CACf;AAED;2DAC2D;AAC3D,MAAM,WAAW,YAAa,SAAQ,uBAAuB;IAC3D,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,YAAY,EAAE,CAAA;CACzB;AAED,MAAM,WAAW,WAAW;IAC1B,eAAe,EAAE,MAAM,CAAA;IACvB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,CAAC,EAAE,UAAU,CAAA;IACpB,MAAM,CAAC,EAAE,YAAY,CAAA;IACrB;8EAC0E;IAC1E,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC/B,+EAA+E;IAC/E,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAA;IACzC,uEAAuE;IACvE,QAAQ,CAAC,EAAE,SAAS,EAAE,CAAA;IACtB,WAAW,CAAC,EAAE,iBAAiB,CAAA;IAC/B,OAAO,CAAC,EAAE,aAAa,CAAA;IACvB;oFACgF;IAChF,iBAAiB,CAAC,EAAE,gBAAgB,EAAE,CAAA;IACtC,8DAA8D;IAC9D,KAAK,CAAC,EAAE,aAAa,CAAA;IACrB,qEAAqE;IACrE,kBAAkB,CAAC,EAAE,kBAAkB,CAAA;IACvC,oEAAoE;IACpE,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAQD,KAAK,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;AACtC,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,EAAE,WAAW,KAAK,WAAW,CAAA;AAgC/D,yFAAyF;AACzF,wBAAgB,yBAAyB,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,iBAAiB,GAAG,IAAI,CAE1F;AAQD;qDACqD;AACrD,wBAAgB,eAAe,CAAC,KAAK,EAAE,WAAW,GAAG,WAAW,CAkB/D;AAED;iEACiE;AACjE,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,WAAW,GAAG,MAAM,EAAE,CA2EzD"}
|
package/dist/orders/index.d.ts
CHANGED
|
@@ -88,6 +88,14 @@ export interface PaymentResult {
|
|
|
88
88
|
paid: boolean;
|
|
89
89
|
/** Set when the invoice stands but the money could not be booked. */
|
|
90
90
|
warning?: string;
|
|
91
|
+
/**
|
|
92
|
+
* O banco reconheceu a chave e NÃO gravou de novo.
|
|
93
|
+
*
|
|
94
|
+
* É o duplo clique protegido — e era o segundo pagamento de uma conta
|
|
95
|
+
* dividida sumindo em silêncio, enquanto a chave era fixa por parcela.
|
|
96
|
+
* Quem chama precisa distinguir «recebi» de «isso eu já tinha».
|
|
97
|
+
*/
|
|
98
|
+
replayed?: boolean;
|
|
91
99
|
}
|
|
92
100
|
export interface ReceivePaymentInput {
|
|
93
101
|
invoice: Invoice;
|
|
@@ -100,6 +108,37 @@ export interface ReceivePaymentInput {
|
|
|
100
108
|
* surface has a real shift-opening screen, and it is visible in the ledger.
|
|
101
109
|
*/
|
|
102
110
|
openCashSession?: boolean;
|
|
111
|
+
/**
|
|
112
|
+
* A conta que RECEBE, quando quem vende já perguntou.
|
|
113
|
+
*
|
|
114
|
+
* O PDV pergunta — «Conta de recebimento» — e a resposta mandava nada: este
|
|
115
|
+
* módulo achava uma conta pelo `code`, e numa casa com duas maquininhas
|
|
116
|
+
* (Cielo e Stone, dois `card_receivable_credit`) o dinheiro caía na que o
|
|
117
|
+
* código encontrasse primeiro, não na que passou o cartão. A conciliação
|
|
118
|
+
* fecha por maquininha.
|
|
119
|
+
*
|
|
120
|
+
* Ignorada para `cash`: dinheiro liquida no caixa aberto do operador, que é
|
|
121
|
+
* uma sessão e não uma conta.
|
|
122
|
+
*/
|
|
123
|
+
accountId?: string;
|
|
124
|
+
/**
|
|
125
|
+
* A chave de idempotência, quando quem chama já tem uma.
|
|
126
|
+
*
|
|
127
|
+
* Omitida, ela nasce da impressão digital do pagamento — que é o que
|
|
128
|
+
* distingue «o mesmo botão apertado duas vezes» de «a segunda metade da
|
|
129
|
+
* conta».
|
|
130
|
+
*/
|
|
131
|
+
idempotencyKey?: string;
|
|
132
|
+
/**
|
|
133
|
+
* A bandeira, quando a forma tem uma — «Visa», «Alelo».
|
|
134
|
+
*
|
|
135
|
+
* `financial_receive_payment` já a aceita; faltava alguém passar. Sem ela a
|
|
136
|
+
* conciliação do mês não separa Visa de Mastercard, e o extrato da
|
|
137
|
+
* adquirente deixa de bater linha a linha com o razão.
|
|
138
|
+
*/
|
|
139
|
+
cardBrand?: string;
|
|
140
|
+
/** Em quantas vezes. `1` é à vista, e é o que o débito sempre é. */
|
|
141
|
+
cardInstallments?: number;
|
|
103
142
|
}
|
|
104
143
|
export declare function receivePayment(ctx: OrderContext, input: ReceivePaymentInput): Promise<PaymentResult>;
|
|
105
144
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/orders/index.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/orders/index.ts"],"names":[],"mappings":"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"}
|
package/dist/orders/index.js
CHANGED
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
// src/orders/paymentKey.ts
|
|
2
|
+
var emVoo = /* @__PURE__ */ new Map();
|
|
3
|
+
function digital(f) {
|
|
4
|
+
return [f.instalmentId, f.method, f.amountCents, f.accountId ?? "", f.cardBrand ?? ""].join("|");
|
|
5
|
+
}
|
|
6
|
+
function paymentOperationKey(f, newId = () => crypto.randomUUID()) {
|
|
7
|
+
const d = digital(f);
|
|
8
|
+
const atual = emVoo.get(d);
|
|
9
|
+
if (atual) return atual;
|
|
10
|
+
const nova = newId();
|
|
11
|
+
emVoo.set(d, nova);
|
|
12
|
+
return nova;
|
|
13
|
+
}
|
|
14
|
+
function releasePaymentKey(f) {
|
|
15
|
+
emVoo.delete(digital(f));
|
|
16
|
+
}
|
|
17
|
+
|
|
1
18
|
// src/orders/index.ts
|
|
2
19
|
var OrderError = class extends Error {
|
|
3
20
|
constructor(message, cause) {
|
|
@@ -114,12 +131,20 @@ async function receivePayment(ctx, input) {
|
|
|
114
131
|
let accountId = null;
|
|
115
132
|
let cashSessionId = null;
|
|
116
133
|
const code = ACCOUNT_CODE[input.method];
|
|
117
|
-
|
|
134
|
+
const liquidaNoCaixa = input.method === "cash";
|
|
135
|
+
if (input.accountId && !liquidaNoCaixa) {
|
|
136
|
+
accountId = input.accountId;
|
|
137
|
+
} else if (code) {
|
|
118
138
|
const account = await ctx.db.from("plg_financial_accounts").select("id").eq("code", code).eq("is_active", true).limit(1).maybeSingle();
|
|
119
139
|
if (!account.data) {
|
|
120
140
|
return { paid: false, warning: `Fatura ${input.invoice.number} emitida; falta a conta "${code}" no Financeiro.` };
|
|
121
141
|
}
|
|
122
142
|
accountId = account.data.id;
|
|
143
|
+
} else if (!liquidaNoCaixa) {
|
|
144
|
+
return {
|
|
145
|
+
paid: false,
|
|
146
|
+
warning: `Fatura ${input.invoice.number} emitida; escolha a conta que recebe este pagamento.`
|
|
147
|
+
};
|
|
123
148
|
} else {
|
|
124
149
|
const open = await ctx.db.from("plg_financial_cash_register_sessions").select("id").eq("status", "open").limit(1).maybeSingle();
|
|
125
150
|
cashSessionId = open.data?.id ?? null;
|
|
@@ -142,20 +167,32 @@ async function receivePayment(ctx, input) {
|
|
|
142
167
|
}
|
|
143
168
|
}
|
|
144
169
|
const amount = money(input.amountCents ?? instalment.amountCents);
|
|
145
|
-
const
|
|
170
|
+
const digital2 = {
|
|
171
|
+
instalmentId: instalment.id,
|
|
172
|
+
method: input.method,
|
|
173
|
+
amountCents: input.amountCents ?? instalment.amountCents,
|
|
174
|
+
accountId,
|
|
175
|
+
cardBrand: input.cardBrand ?? null
|
|
176
|
+
};
|
|
177
|
+
const chave = input.idempotencyKey ?? paymentOperationKey(digital2);
|
|
178
|
+
const { data, error } = await ctx.db.rpc("financial_receive_payment", {
|
|
146
179
|
p_installment_id: instalment.id,
|
|
147
180
|
p_amount: amount,
|
|
148
181
|
p_account_id: accountId,
|
|
149
182
|
p_method: input.method,
|
|
150
183
|
p_cash_session_id: cashSessionId,
|
|
151
184
|
// The same bill confirmed twice must not take the money twice.
|
|
152
|
-
|
|
185
|
+
p_card_brand: input.cardBrand || null,
|
|
186
|
+
p_card_installments: input.cardInstallments && input.cardInstallments > 1 ? input.cardInstallments : null,
|
|
187
|
+
p_idempotency_key: chave,
|
|
153
188
|
p_metadata: { source: ctx.source }
|
|
154
189
|
});
|
|
155
190
|
if (error) {
|
|
156
191
|
return { paid: false, warning: `Fatura ${input.invoice.number} emitida; o pagamento n\xE3o foi baixado (${error.message}).` };
|
|
157
192
|
}
|
|
158
|
-
|
|
193
|
+
const replayed = data?.replayed === true;
|
|
194
|
+
if (!replayed) releasePaymentKey(digital2);
|
|
195
|
+
return { paid: true, replayed };
|
|
159
196
|
}
|
|
160
197
|
async function settle(ctx, orderId, payment) {
|
|
161
198
|
const invoice = await completeOrder(ctx, orderId);
|
package/dist/orders/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/orders/index.ts"],"names":[],"mappings":";AAyDO,IAAM,UAAA,GAAN,cAAyB,KAAA,CAAM;AAAA,EACpC,WAAA,CAAY,SAA0B,KAAA,EAAiB;AACrD,IAAA,KAAA,CAAM,OAAO,CAAA;AADuB,IAAA,IAAA,CAAA,KAAA,GAAA,KAAA;AAEpC,IAAA,IAAA,CAAK,IAAA,GAAO,YAAA;AAAA,EACd;AACF;AAEA,SAAS,MAAA,CAAO,OAAkD,IAAA,EAAqB;AACrF,EAAA,IAAI,KAAA,EAAO,SAAS,OAAA,EAAS,MAAM,IAAI,UAAA,CAAW,CAAA,EAAG,IAAI,CAAA,6BAAA,CAA4B,CAAA;AACrF,EAAA,MAAM,IAAI,WAAW,CAAA,EAAG,IAAI,KAAK,KAAA,EAAO,OAAA,IAAW,qBAAqB,CAAA,CAAA,EAAI,KAAK,CAAA;AACnF;AAEA,IAAM,QAAQ,CAAC,KAAA,KAAkB,IAAA,CAAK,KAAA,CAAM,KAAK,CAAA,GAAI,GAAA;AAoBrD,eAAsB,SAAA,CAAU,KAAmB,KAAA,EAAwC;AACzF,EAAA,MAAM,EAAE,MAAM,KAAA,EAAM,GAAI,MAAM,GAAA,CAAI,EAAA,CAAG,IAAI,cAAA,EAAgB;AAAA,IACvD,QAAQ,KAAA,CAAM,IAAA;AAAA,IACd,UAAU,KAAA,CAAM,KAAA,IAAS,EAAC,EAAG,IAAI,SAAS,CAAA;AAAA,IAC1C,UAAA,EAAY,MAAM,OAAA,IAAW,IAAA;AAAA,IAC7B,SAAA,EAAW,IAAI,MAAA,IAAU,IAAA;AAAA,IACzB,QAAA,EAAU,MAAM,MAAA,IAAU,IAAA;AAAA,IAC1B,SAAA,EAAW,MAAM,OAAA,IAAW,IAAA;AAAA,IAC5B,OAAA,EAAS,MAAM,KAAA,IAAS,IAAA;AAAA,IACxB,UAAA,EAAY,EAAE,GAAI,KAAA,CAAM,YAAY,EAAC,EAAI,MAAA,EAAQ,GAAA,CAAI,MAAA,EAAO;AAAA,IAC5D,iBAAA,EAAmB,MAAM,cAAA,IAAkB;AAAA,GAC5C,CAAA;AACD,EAAA,IAAI,KAAA,IAAS,CAAC,IAAA,EAAM,MAAA,CAAO,OAAO,4BAAyB,CAAA;AAC3D,EAAA,OAAO,IAAA;AACT;AAEA,IAAM,SAAA,GAAY,CAAC,CAAA,EAAc,KAAA,MAAmB;AAAA,EAClD,UAAA,EAAY,EAAE,SAAA,IAAa,IAAA;AAAA,EAC3B,MAAM,CAAA,CAAE,IAAA;AAAA,EACR,WAAA,EAAa,EAAE,WAAA,IAAe,IAAA;AAAA,EAC9B,UAAU,CAAA,CAAE,QAAA;AAAA,EACZ,UAAA,EAAY,KAAA,CAAM,CAAA,CAAE,cAAc,CAAA;AAAA,EAClC,UAAA,EAAY,KAAA;AAAA,EACZ,UAAU,EAAE,GAAI,EAAE,QAAA,IAAY,IAAK,MAAA,EAAQ,CAAA,CAAE,IAAI,GAAI,CAAA,CAAE,OAAO,EAAE,IAAA,EAAM,EAAE,IAAA,EAAK,GAAI,EAAC;AACpF,CAAA,CAAA;AAYA,eAAsB,QAAA,CACpB,GAAA,EAAmB,OAAA,EAAiB,KAAA,EACnB;AACjB,EAAA,IAAI,KAAA,CAAM,SAAS,CAAA,EAAG;AACpB,IAAA,MAAM,EAAE,KAAA,EAAM,GAAI,MAAM,IAAI,EAAA,CAAG,IAAA,CAAK,OAAO,CAAA,CAAE,MAAA,CAAO,KAAA,CAAM,GAAA,CAAI,CAAC,GAAG,KAAA,MAAW;AAAA,MAC3E,WAAW,GAAA,CAAI,QAAA;AAAA,MACf,OAAA,EAAS,IAAI,MAAA,IAAU,IAAA;AAAA,MACvB,QAAA,EAAU,OAAA;AAAA,MACV,UAAA,EAAY,EAAE,SAAA,IAAa,IAAA;AAAA,MAC3B,MAAM,CAAA,CAAE,IAAA;AAAA,MACR,WAAA,EAAa,EAAE,WAAA,IAAe,IAAA;AAAA,MAC9B,UAAU,CAAA,CAAE,QAAA;AAAA,MACZ,UAAA,EAAY,KAAA,CAAM,CAAA,CAAE,cAAc,CAAA;AAAA,MAClC,KAAA,EAAO,KAAA,CAAM,CAAA,CAAE,cAAA,GAAiB,EAAE,QAAQ,CAAA;AAAA,MAC1C,UAAA,EAAY,KAAA;AAAA,MACZ,QAAA,EAAU,EAAE,GAAI,CAAA,CAAE,YAAY,EAAC,EAAI,MAAA,EAAQ,CAAA,CAAE,EAAA,EAAI,MAAA,EAAQ,IAAI,MAAA,EAAQ,GAAI,EAAE,IAAA,GAAO,EAAE,MAAM,CAAA,CAAE,IAAA,EAAK,GAAI,EAAC;AAAG,MACzG,CAAC,CAAA;AACH,IAAA,IAAI,KAAA,EAAO,MAAA,CAAO,KAAA,EAAO,gCAA6B,CAAA;AAAA,EACxD;AACA,EAAA,OAAO,SAAA,CAAU,KAAK,OAAO,CAAA;AAC/B;AAGA,eAAsB,SAAA,CAAU,KAAmB,OAAA,EAAkC;AACnF,EAAA,MAAM,OAAO,MAAM,GAAA,CAAI,EAAA,CAAG,IAAA,CAAK,OAAO,CAAA,CAAE,MAAA,CAAO,OAAO,CAAA,CACnD,GAAG,UAAA,EAAY,OAAO,CAAA,CAAE,EAAA,CAAG,gBAAgB,IAAI,CAAA;AAClD,EAAA,IAAI,IAAA,CAAK,KAAA,EAAO,MAAA,CAAO,IAAA,CAAK,OAAO,sCAAmC,CAAA;AACtE,EAAA,MAAM,KAAA,GAAQ,KAAK,KAAA,CAAA,CAAO,IAAA,CAAK,QAAQ,EAAC,EAAG,OAAO,CAAC,GAAA,EAAK,MAAM,GAAA,GAAM,MAAA,CAAO,EAAE,KAAA,IAAS,CAAC,GAAG,CAAC,CAAA,GAAI,GAAG,CAAA,GAAI,GAAA;AACtG,EAAA,MAAM,QAAQ,MAAM,GAAA,CAAI,EAAA,CAAG,IAAA,CAAK,QAAQ,CAAA,CAAE,MAAA,CAAO,EAAE,QAAA,EAAU,OAAO,KAAA,EAAO,CAAA,CAAE,EAAA,CAAG,MAAM,OAAO,CAAA;AAC7F,EAAA,IAAI,KAAA,CAAM,KAAA,EAAO,MAAA,CAAO,KAAA,CAAM,OAAO,sCAAmC,CAAA;AACxE,EAAA,OAAO,IAAA,CAAK,KAAA,CAAM,KAAA,GAAQ,GAAG,CAAA;AAC/B;AAGA,eAAsB,SAAA,CAAU,GAAA,EAAmB,OAAA,EAAiB,MAAA,EAA+B;AACjG,EAAA,MAAM,EAAE,KAAA,EAAM,GAAI,MAAM,GAAA,CAAI,GAAG,IAAA,CAAK,QAAQ,CAAA,CAAE,MAAA,CAAO,EAAE,MAAA,EAAQ,CAAA,CAAE,EAAA,CAAG,MAAM,OAAO,CAAA;AACjF,EAAA,IAAI,KAAA,EAAO,MAAA,CAAO,KAAA,EAAO,CAAA,6BAAA,EAA6B,MAAM,CAAA,CAAA,CAAG,CAAA;AACjE;AAYA,eAAsB,SAAA,CAAU,KAAmB,OAAA,EAA0C;AAC3F,EAAA,MAAM,EAAE,IAAA,EAAM,KAAA,EAAM,GAAI,MAAM,IAAI,EAAA,CAAG,IAAA,CAAK,wBAAwB,CAAA,CAC/D,MAAA,CAAO,mEAAmE,EAC1E,EAAA,CAAG,UAAA,EAAY,OAAO,CAAA,CAAE,EAAA,CAAG,cAAA,EAAgB,IAAI,CAAA,CAAE,KAAA,CAAM,CAAC,CAAA,CAAE,WAAA,EAAY;AACzE,EAAA,IAAI,KAAA,EAAO,MAAA,CAAO,KAAA,EAAO,gCAA6B,CAAA;AACtD,EAAA,IAAI,CAAC,MAAM,OAAO,IAAA;AAClB,EAAA,OAAO;AAAA,IACL,IAAI,IAAA,CAAK,EAAA;AAAA,IACT,QAAQ,IAAA,CAAK,MAAA;AAAA,IACb,UAAA,EAAY,KAAK,KAAA,CAAM,MAAA,CAAO,KAAK,KAAA,IAAS,CAAC,IAAI,GAAG,CAAA;AAAA,IACpD,WAAA,EAAA,CAAc,IAAA,CAAK,kCAAA,IAAsC,EAAC,EAAG,GAAA;AAAA,MAC3D,CAAC,CAAA,MAAgD,EAAE,EAAA,EAAI,EAAE,EAAA,EAAI,WAAA,EAAa,IAAA,CAAK,KAAA,CAAM,MAAA,CAAO,CAAA,CAAE,MAAM,CAAA,GAAI,GAAG,CAAA,EAAE;AAAA;AAC/G,GACF;AACF;AAOA,eAAsB,aAAA,CAAc,KAAmB,OAAA,EAAmC;AACxF,EAAA,MAAM,SAAA,CAAU,KAAK,OAAO,CAAA;AAC5B,EAAA,MAAM,SAAA,CAAU,GAAA,EAAK,OAAA,EAAS,WAAW,CAAA;AACzC,EAAA,MAAM,OAAA,GAAU,MAAM,SAAA,CAAU,GAAA,EAAK,OAAO,CAAA;AAC5C,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,MAAM,IAAI,WAAW,0EAAkE,CAAA;AAAA,EACzF;AACA,EAAA,OAAO,OAAA;AACT;AAOA,IAAM,YAAA,GAAuD;AAAA,EAC3D,GAAA,EAAK,KAAA;AAAA,EAAO,WAAA,EAAa,SAAA;AAAA,EAAW,UAAA,EAAY,QAAA;AAAA,EAAU,QAAA,EAAU;AACtE,CAAA;AAGO,IAAM,eAAA,GAAiD;AAAA,EAC5D,IAAA,EAAM,MAAA;AAAA,EAAQ,QAAA,EAAU,MAAA;AAAA,EACxB,GAAA,EAAK,KAAA;AAAA,EACL,IAAA,EAAM,aAAA;AAAA,EAAe,MAAA,EAAQ,aAAA;AAAA,EAAe,WAAA,EAAU,aAAA;AAAA,EAAe,MAAA,EAAQ,aAAA;AAAA,EAC7E,KAAA,EAAO,YAAA;AAAA,EAAc,MAAA,EAAQ,YAAA;AAAA,EAAc,WAAA,EAAU;AACvD;AAqBA,eAAsB,cAAA,CACpB,KAAmB,KAAA,EACK;AACxB,EAAA,MAAM,UAAA,GAAa,KAAA,CAAM,OAAA,CAAQ,WAAA,CAAY,CAAC,CAAA;AAC9C,EAAA,IAAI,CAAC,UAAA,EAAY;AACf,IAAA,OAAO,EAAE,MAAM,KAAA,EAAO,OAAA,EAAS,UAAU,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA,yBAAA,CAAA,EAA4B;AAAA,EAC3F;AAEA,EAAA,IAAI,SAAA,GAA2B,IAAA;AAC/B,EAAA,IAAI,aAAA,GAA+B,IAAA;AACnC,EAAA,MAAM,IAAA,GAAO,YAAA,CAAa,KAAA,CAAM,MAAM,CAAA;AAEtC,EAAA,IAAI,IAAA,EAAM;AACR,IAAA,MAAM,OAAA,GAAU,MAAM,GAAA,CAAI,EAAA,CAAG,KAAK,wBAAwB,CAAA,CAAE,OAAO,IAAI,CAAA,CACpE,GAAG,MAAA,EAAQ,IAAI,EAAE,EAAA,CAAG,WAAA,EAAa,IAAI,CAAA,CAAE,KAAA,CAAM,CAAC,CAAA,CAAE,WAAA,EAAY;AAC/D,IAAA,IAAI,CAAC,QAAQ,IAAA,EAAM;AACjB,MAAA,OAAO,EAAE,IAAA,EAAM,KAAA,EAAO,OAAA,EAAS,CAAA,OAAA,EAAU,MAAM,OAAA,CAAQ,MAAM,CAAA,yBAAA,EAA4B,IAAI,CAAA,gBAAA,CAAA,EAAmB;AAAA,IAClH;AACA,IAAA,SAAA,GAAY,QAAQ,IAAA,CAAK,EAAA;AAAA,EAC3B,CAAA,MAAO;AACL,IAAA,MAAM,OAAO,MAAM,GAAA,CAAI,EAAA,CAAG,IAAA,CAAK,sCAAsC,CAAA,CAClE,MAAA,CAAO,IAAI,CAAA,CAAE,GAAG,QAAA,EAAU,MAAM,EAAE,KAAA,CAAM,CAAC,EAAE,WAAA,EAAY;AAC1D,IAAA,aAAA,GAAgB,IAAA,CAAK,MAAM,EAAA,IAAM,IAAA;AACjC,IAAA,IAAI,CAAC,aAAA,EAAe;AAClB,MAAA,IAAI,CAAC,MAAM,eAAA,EAAiB;AAC1B,QAAA,OAAO,EAAE,MAAM,KAAA,EAAO,OAAA,EAAS,UAAU,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA,gDAAA,CAAA,EAAmD;AAAA,MAClH;AACA,MAAA,MAAM,KAAA,GAAQ,MAAM,GAAA,CAAI,EAAA,CAAG,KAAK,wBAAwB,CAAA,CAAE,OAAO,IAAI,CAAA,CAClE,GAAG,MAAA,EAAQ,eAAe,EAAE,EAAA,CAAG,WAAA,EAAa,IAAI,CAAA,CAAE,KAAA,CAAM,CAAC,CAAA,CAAE,WAAA,EAAY;AAC1E,MAAA,IAAI,CAAC,MAAM,IAAA,EAAM;AACf,QAAA,OAAO,EAAE,MAAM,KAAA,EAAO,OAAA,EAAS,UAAU,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA,uCAAA,CAAA,EAA0C;AAAA,MACzG;AACA,MAAA,MAAM,MAAA,GAAS,MAAM,GAAA,CAAI,EAAA,CAAG,IAAI,6BAAA,EAA+B;AAAA,QAC7D,kBAAA,EAAoB,MAAM,IAAA,CAAK,EAAA;AAAA,QAAI,gBAAA,EAAkB;AAAA,OACtD,CAAA;AACD,MAAA,IAAI,OAAO,KAAA,EAAO;AAChB,QAAA,OAAO,EAAE,IAAA,EAAM,KAAA,EAAO,OAAA,EAAS,CAAA,OAAA,EAAU,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA,gCAAA,EAAgC,MAAA,CAAO,KAAA,CAAM,OAAO,CAAA,EAAA,CAAA,EAAK;AAAA,MACxH;AACA,MAAA,aAAA,GAAiB,OAAO,IAAA,CAAgC,UAAA;AAAA,IAC1D;AAAA,EACF;AAEA,EAAA,MAAM,MAAA,GAAS,KAAA,CAAM,KAAA,CAAM,WAAA,IAAe,WAAW,WAAW,CAAA;AAChE,EAAA,MAAM,EAAE,KAAA,EAAM,GAAI,MAAM,GAAA,CAAI,EAAA,CAAG,IAAI,2BAAA,EAA6B;AAAA,IAC9D,kBAAkB,UAAA,CAAW,EAAA;AAAA,IAC7B,QAAA,EAAU,MAAA;AAAA,IACV,YAAA,EAAc,SAAA;AAAA,IACd,UAAU,KAAA,CAAM,MAAA;AAAA,IAChB,iBAAA,EAAmB,aAAA;AAAA;AAAA,IAEnB,iBAAA,EAAmB,CAAA,IAAA,EAAO,UAAA,CAAW,EAAE,CAAA,CAAA;AAAA,IACvC,UAAA,EAAY,EAAE,MAAA,EAAQ,GAAA,CAAI,MAAA;AAAO,GAClC,CAAA;AACD,EAAA,IAAI,KAAA,EAAO;AACT,IAAA,OAAO,EAAE,IAAA,EAAM,KAAA,EAAO,OAAA,EAAS,CAAA,OAAA,EAAU,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA,0CAAA,EAA0C,KAAA,CAAM,OAAO,CAAA,EAAA,CAAA,EAAK;AAAA,EAC3H;AACA,EAAA,OAAO,EAAE,MAAM,IAAA,EAAK;AACtB;AAQA,eAAsB,MAAA,CACpB,GAAA,EACA,OAAA,EACA,OAAA,EAC+C;AAC/C,EAAA,MAAM,OAAA,GAAU,MAAM,aAAA,CAAc,GAAA,EAAK,OAAO,CAAA;AAChD,EAAA,MAAM,MAAA,GAAS,MAAM,cAAA,CAAe,GAAA,EAAK,EAAE,GAAG,OAAA,EAAS,SAAS,CAAA;AAChE,EAAA,OAAO,EAAE,OAAA,EAAS,GAAG,MAAA,EAAO;AAC9B","file":"index.js","sourcesContent":["// ---------------------------------------------------------------------------\n// Order to cash, once.\n//\n// The PDV, the totem and anything else that sells write the SAME order: open\n// it, add lines, complete it, take the money. Three surfaces with three copies\n// of that sequence is three subtly different orders in one restaurant's books\n// — a totem sale that never raises a receivable, a till that writes its own\n// invoice rows beside the ones the cluster already numbers.\n//\n// So this module is a thin, shared vocabulary over what the cluster ALREADY\n// defines, and deliberately invents nothing:\n//\n// order_create(kind, …) opens the document\n// public.items the lines\n// orders.status = 'completed' raises the receivable, by trigger\n// financial_receive_payment(instalment, …) books the money\n//\n// It does not own the session: the caller passes a signed-in client, because\n// who a surface authenticates as (device user, kiosk user, real person) is a\n// decision each surface has to make for itself.\n// ---------------------------------------------------------------------------\n\nimport type { SupabaseClient } from '@supabase/supabase-js'\n\n/** Who is writing, and on whose behalf. */\nexport interface OrderContext {\n db: SupabaseClient\n tenantId: string\n unitId?: string\n /**\n * The writing surface, e.g. `chef-pos:caixa-01`. Stamped into metadata on\n * everything this module writes, because \"which machine did this\" is the\n * first question support asks and the last thing anyone can reconstruct.\n */\n source: string\n}\n\n/** A line as a selling surface holds it: cents, never a float. */\nexport interface OrderLine {\n /** The surface's own id for the line, kept so a reload returns the same line. */\n id: string\n /** public.products.id when the line is a catalogue item. */\n productId?: string\n name: string\n quantity: number\n unitPriceCents: number\n note?: string\n /**\n * What was done to the dish, in one line. Modifiers also ride in `metadata`,\n * but a printed kitchen ticket reads columns, not JSON — so the thing the\n * cook has to do differently belongs in one the ticket already shows.\n */\n description?: string\n /** Anything the surface needs back on reload: modifiers, state, timestamps. */\n metadata?: Record<string, unknown>\n}\n\nexport class OrderError extends Error {\n constructor(message: string, readonly cause?: unknown) {\n super(message)\n this.name = 'OrderError'\n }\n}\n\nfunction refuse(error: { message: string; code?: string } | null, what: string): never {\n if (error?.code === '42501') throw new OrderError(`${what}: sem permissão para isto.`)\n throw new OrderError(`${what}: ${error?.message ?? 'motivo desconhecido'}`, error)\n}\n\nconst money = (cents: number) => Math.round(cents) / 100\n\n// --- opening ----------------------------------------------------------------\n\nexport interface OpenOrderInput {\n /** A species registered in public.order_kinds: dine_in, takeout, delivery, sale. */\n kind: string\n /** Must be in that kind's status list. Defaults to the registry's own default. */\n status?: string\n /** Where the sale came from: 'pos', 'totem', 'whatsapp'. */\n channel?: string\n lines?: OrderLine[]\n partyId?: string\n notes?: string\n metadata?: Record<string, unknown>\n /** Replaying the same tap returns the same order instead of a second one. */\n idempotencyKey?: string\n}\n\n/** Opens the document. Returns the order id — from here on that IS the sale. */\nexport async function openOrder(ctx: OrderContext, input: OpenOrderInput): Promise<string> {\n const { data, error } = await ctx.db.rpc('order_create', {\n p_kind: input.kind,\n p_lines: (input.lines ?? []).map(toRpcLine),\n p_party_id: input.partyId ?? null,\n p_unit_id: ctx.unitId ?? null,\n p_status: input.status ?? null,\n p_channel: input.channel ?? null,\n p_notes: input.notes ?? null,\n p_metadata: { ...(input.metadata ?? {}), source: ctx.source },\n p_idempotency_key: input.idempotencyKey ?? null,\n })\n if (error || !data) refuse(error, 'O pedido não foi aberto')\n return data as string\n}\n\nconst toRpcLine = (l: OrderLine, index: number) => ({\n product_id: l.productId ?? null,\n name: l.name,\n description: l.description ?? null,\n quantity: l.quantity,\n unit_price: money(l.unitPriceCents),\n sort_order: index,\n metadata: { ...(l.metadata ?? {}), lineId: l.id, ...(l.note ? { note: l.note } : {}) },\n})\n\n// --- lines ------------------------------------------------------------------\n\n/**\n * Appends lines and leaves the header agreeing with them.\n *\n * The total is read back from the order rather than added up on the client:\n * another terminal may have written to the same comanda a second ago, and a\n * header computed from one screen's idea of the ticket is how a bill starts\n * disagreeing with its own lines.\n */\nexport async function addLines(\n ctx: OrderContext, orderId: string, lines: OrderLine[],\n): Promise<number> {\n if (lines.length > 0) {\n const { error } = await ctx.db.from('items').insert(lines.map((l, index) => ({\n tenant_id: ctx.tenantId,\n unit_id: ctx.unitId ?? null,\n order_id: orderId,\n product_id: l.productId ?? null,\n name: l.name,\n description: l.description ?? null,\n quantity: l.quantity,\n unit_price: money(l.unitPriceCents),\n total: money(l.unitPriceCents * l.quantity),\n sort_order: index,\n metadata: { ...(l.metadata ?? {}), lineId: l.id, source: ctx.source, ...(l.note ? { note: l.note } : {}) },\n })))\n if (error) refuse(error, 'Os itens não foram gravados')\n }\n return syncTotal(ctx, orderId)\n}\n\n/** Recomputes subtotal/total from the lines the order actually holds. */\nexport async function syncTotal(ctx: OrderContext, orderId: string): Promise<number> {\n const read = await ctx.db.from('items').select('total')\n .eq('order_id', orderId).is('cancelled_at', null)\n if (read.error) refuse(read.error, 'O total do pedido não foi apurado')\n const total = Math.round((read.data ?? []).reduce((sum, r) => sum + Number(r.total ?? 0), 0) * 100) / 100\n const write = await ctx.db.from('orders').update({ subtotal: total, total }).eq('id', orderId)\n if (write.error) refuse(write.error, 'O total do pedido não foi gravado')\n return Math.round(total * 100)\n}\n\n/** Moves the order along its own machine. The cluster refuses an illegal hop. */\nexport async function setStatus(ctx: OrderContext, orderId: string, status: string): Promise<void> {\n const { error } = await ctx.db.from('orders').update({ status }).eq('id', orderId)\n if (error) refuse(error, `O pedido não passou para \"${status}\"`)\n}\n\n// --- money ------------------------------------------------------------------\n\nexport interface Invoice {\n id: string\n number: string\n totalCents: number\n instalments: { id: string; amountCents: number }[]\n}\n\n/** The receivable behind an order, once there is one. */\nexport async function invoiceOf(ctx: OrderContext, orderId: string): Promise<Invoice | null> {\n const { data, error } = await ctx.db.from('plg_financial_invoices')\n .select('id, number, total, plg_financial_invoice_installments(id, amount)')\n .eq('order_id', orderId).is('cancelled_at', null).limit(1).maybeSingle()\n if (error) refuse(error, 'A fatura não foi encontrada')\n if (!data) return null\n return {\n id: data.id,\n number: data.number,\n totalCents: Math.round(Number(data.total ?? 0) * 100),\n instalments: (data.plg_financial_invoice_installments ?? []).map(\n (i: { id: string; amount: number | string }) => ({ id: i.id, amountCents: Math.round(Number(i.amount) * 100) }),\n ),\n }\n}\n\n/**\n * Completes the order, which is what RAISES the receivable — the cluster's\n * trigger does it in the same transaction, so a closed sale can never be\n * missing its invoice. No surface writes an invoice row of its own.\n */\nexport async function completeOrder(ctx: OrderContext, orderId: string): Promise<Invoice> {\n await syncTotal(ctx, orderId)\n await setStatus(ctx, orderId, 'completed')\n const invoice = await invoiceOf(ctx, orderId)\n if (!invoice) {\n throw new OrderError('O pedido fechou sem gerar fatura — não libere antes de conferir.')\n }\n return invoice\n}\n\n/** What a surface's payment button means to the ledger. */\nexport type PaymentMethod = 'cash' | 'pix' | 'credit_card' | 'debit_card' | 'transfer' | 'other'\n\n/** Which `plg_financial_accounts.code` settles each method. Cash has none: it\n * settles into the operator's open caixinha, which is a session, not a code. */\nconst ACCOUNT_CODE: Partial<Record<PaymentMethod, string>> = {\n pix: 'pix', credit_card: 'credito', debit_card: 'debito', transfer: 'pix',\n}\n\n/** The buttons a surface shows, in the words the ledger uses. */\nexport const PAYMENT_METHODS: Record<string, PaymentMethod> = {\n cash: 'cash', dinheiro: 'cash',\n pix: 'pix',\n card: 'credit_card', cartao: 'credit_card', 'cartão': 'credit_card', credit: 'credit_card',\n debit: 'debit_card', debito: 'debit_card', 'débito': 'debit_card',\n}\n\nexport interface PaymentResult {\n paid: boolean\n /** Set when the invoice stands but the money could not be booked. */\n warning?: string\n}\n\nexport interface ReceivePaymentInput {\n invoice: Invoice\n method: PaymentMethod\n /** Defaults to the instalment's full amount. */\n amountCents?: number\n /**\n * Cash needs an open caixinha. `true` lets this open one with a counted\n * opening of zero rather than refuse the banknote — a stand-in until the\n * surface has a real shift-opening screen, and it is visible in the ledger.\n */\n openCashSession?: boolean\n}\n\nexport async function receivePayment(\n ctx: OrderContext, input: ReceivePaymentInput,\n): Promise<PaymentResult> {\n const instalment = input.invoice.instalments[0]\n if (!instalment) {\n return { paid: false, warning: `Fatura ${input.invoice.number} sem parcela para baixar.` }\n }\n\n let accountId: string | null = null\n let cashSessionId: string | null = null\n const code = ACCOUNT_CODE[input.method]\n\n if (code) {\n const account = await ctx.db.from('plg_financial_accounts').select('id')\n .eq('code', code).eq('is_active', true).limit(1).maybeSingle()\n if (!account.data) {\n return { paid: false, warning: `Fatura ${input.invoice.number} emitida; falta a conta \"${code}\" no Financeiro.` }\n }\n accountId = account.data.id\n } else {\n const open = await ctx.db.from('plg_financial_cash_register_sessions')\n .select('id').eq('status', 'open').limit(1).maybeSingle()\n cashSessionId = open.data?.id ?? null\n if (!cashSessionId) {\n if (!input.openCashSession) {\n return { paid: false, warning: `Fatura ${input.invoice.number} emitida; abra o caixa para receber em dinheiro.` }\n }\n const cofre = await ctx.db.from('plg_financial_accounts').select('id')\n .eq('kind', 'cash_physical').eq('is_active', true).limit(1).maybeSingle()\n if (!cofre.data) {\n return { paid: false, warning: `Fatura ${input.invoice.number} emitida; sem cofre para abrir o caixa.` }\n }\n const opened = await ctx.db.rpc('financial_cash_session_open', {\n p_cofre_account_id: cofre.data.id, p_opening_amount: 0,\n })\n if (opened.error) {\n return { paid: false, warning: `Fatura ${input.invoice.number} emitida; o caixa não abriu (${opened.error.message}).` }\n }\n cashSessionId = (opened.data as { session_id: string }).session_id\n }\n }\n\n const amount = money(input.amountCents ?? instalment.amountCents)\n const { error } = await ctx.db.rpc('financial_receive_payment', {\n p_installment_id: instalment.id,\n p_amount: amount,\n p_account_id: accountId,\n p_method: input.method,\n p_cash_session_id: cashSessionId,\n // The same bill confirmed twice must not take the money twice.\n p_idempotency_key: `pay:${instalment.id}`,\n p_metadata: { source: ctx.source },\n })\n if (error) {\n return { paid: false, warning: `Fatura ${input.invoice.number} emitida; o pagamento não foi baixado (${error.message}).` }\n }\n return { paid: true }\n}\n\n/**\n * The whole tail of a sale: complete, get the invoice, book the money. The\n * invoice is returned even when the payment leg fails, because the receivable\n * is real either way and the surface has to say so rather than pretend the\n * close did not happen.\n */\nexport async function settle(\n ctx: OrderContext,\n orderId: string,\n payment: Omit<ReceivePaymentInput, 'invoice'>,\n): Promise<{ invoice: Invoice } & PaymentResult> {\n const invoice = await completeOrder(ctx, orderId)\n const result = await receivePayment(ctx, { ...payment, invoice })\n return { invoice, ...result }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/orders/paymentKey.ts","../../src/orders/index.ts"],"names":["digital"],"mappings":"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","file":"index.js","sourcesContent":["// ---------------------------------------------------------------------------\n// A chave de idempotência de um pagamento.\n//\n// `financial_receive_payment` guarda a chave e, se ela repetir, devolve o\n// movimento anterior com `replayed: true` **sem gravar nada**. É o que protege\n// o duplo clique — e é o que engolia a segunda metade de uma conta dividida\n// enquanto a chave era `pay:<parcela>`, fixa: pagar R$ 50 no cartão e R$ 50 em\n// dinheiro gravava só o primeiro, e a tela dizia que recebeu os dois.\n//\n// A regra é a do V1 (`registerPaymentOperationKeys` em\n// `lib/checkoutCalculations.ts`), e ela resolve os dois casos de uma vez:\n//\n// - a chave nasce da IMPRESSÃO DIGITAL do pagamento — parcela, método,\n// valor, conta, bandeira — então um pagamento diferente ganha chave\n// diferente;\n// - e é APAGADA no sucesso, então dois pagamentos idênticos (R$ 50 em\n// dinheiro, duas vezes, numa conta dividida ao meio) ganham chaves\n// diferentes, enquanto o mesmo pagamento reenviado antes de terminar\n// reusa a dele.\n//\n// O mapa vive na memória da aba, que é exatamente o escopo do duplo clique.\n// ---------------------------------------------------------------------------\n\n/** O que distingue um pagamento de outro, para efeito de repetição. */\nexport interface PaymentFingerprint {\n instalmentId: string\n method: string\n amountCents: number\n accountId?: string | null\n cardBrand?: string | null\n}\n\nconst emVoo = new Map<string, string>()\n\nfunction digital(f: PaymentFingerprint): string {\n return [f.instalmentId, f.method, f.amountCents, f.accountId ?? '', f.cardBrand ?? ''].join('|')\n}\n\n/**\n * A chave deste pagamento — a mesma enquanto ele não terminar.\n *\n * `newId` existe para o teste: em produção é `crypto.randomUUID`.\n */\nexport function paymentOperationKey(\n f: PaymentFingerprint,\n newId: () => string = () => crypto.randomUUID(),\n): string {\n const d = digital(f)\n const atual = emVoo.get(d)\n if (atual) return atual\n const nova = newId()\n emVoo.set(d, nova)\n return nova\n}\n\n/**\n * Terminou: a próxima vez que este mesmo pagamento aparecer, ele é OUTRO.\n *\n * Chamado só no sucesso. No erro a chave fica, porque o operador vai tentar de\n * novo o mesmo pagamento — e aí repetir a chave é o comportamento certo.\n */\nexport function releasePaymentKey(f: PaymentFingerprint): void {\n emVoo.delete(digital(f))\n}\n","// ---------------------------------------------------------------------------\n// Order to cash, once.\n//\n// The PDV, the totem and anything else that sells write the SAME order: open\n// it, add lines, complete it, take the money. Three surfaces with three copies\n// of that sequence is three subtly different orders in one restaurant's books\n// — a totem sale that never raises a receivable, a till that writes its own\n// invoice rows beside the ones the cluster already numbers.\n//\n// So this module is a thin, shared vocabulary over what the cluster ALREADY\n// defines, and deliberately invents nothing:\n//\n// order_create(kind, …) opens the document\n// public.items the lines\n// orders.status = 'completed' raises the receivable, by trigger\n// financial_receive_payment(instalment, …) books the money\n//\n// It does not own the session: the caller passes a signed-in client, because\n// who a surface authenticates as (device user, kiosk user, real person) is a\n// decision each surface has to make for itself.\n// ---------------------------------------------------------------------------\n\nimport type { SupabaseClient } from '@supabase/supabase-js'\nimport { paymentOperationKey, releasePaymentKey } from './paymentKey'\n\n/** Who is writing, and on whose behalf. */\nexport interface OrderContext {\n db: SupabaseClient\n tenantId: string\n unitId?: string\n /**\n * The writing surface, e.g. `chef-pos:caixa-01`. Stamped into metadata on\n * everything this module writes, because \"which machine did this\" is the\n * first question support asks and the last thing anyone can reconstruct.\n */\n source: string\n}\n\n/** A line as a selling surface holds it: cents, never a float. */\nexport interface OrderLine {\n /** The surface's own id for the line, kept so a reload returns the same line. */\n id: string\n /** public.products.id when the line is a catalogue item. */\n productId?: string\n name: string\n quantity: number\n unitPriceCents: number\n note?: string\n /**\n * What was done to the dish, in one line. Modifiers also ride in `metadata`,\n * but a printed kitchen ticket reads columns, not JSON — so the thing the\n * cook has to do differently belongs in one the ticket already shows.\n */\n description?: string\n /** Anything the surface needs back on reload: modifiers, state, timestamps. */\n metadata?: Record<string, unknown>\n}\n\nexport class OrderError extends Error {\n constructor(message: string, readonly cause?: unknown) {\n super(message)\n this.name = 'OrderError'\n }\n}\n\nfunction refuse(error: { message: string; code?: string } | null, what: string): never {\n if (error?.code === '42501') throw new OrderError(`${what}: sem permissão para isto.`)\n throw new OrderError(`${what}: ${error?.message ?? 'motivo desconhecido'}`, error)\n}\n\nconst money = (cents: number) => Math.round(cents) / 100\n\n// --- opening ----------------------------------------------------------------\n\nexport interface OpenOrderInput {\n /** A species registered in public.order_kinds: dine_in, takeout, delivery, sale. */\n kind: string\n /** Must be in that kind's status list. Defaults to the registry's own default. */\n status?: string\n /** Where the sale came from: 'pos', 'totem', 'whatsapp'. */\n channel?: string\n lines?: OrderLine[]\n partyId?: string\n notes?: string\n metadata?: Record<string, unknown>\n /** Replaying the same tap returns the same order instead of a second one. */\n idempotencyKey?: string\n}\n\n/** Opens the document. Returns the order id — from here on that IS the sale. */\nexport async function openOrder(ctx: OrderContext, input: OpenOrderInput): Promise<string> {\n const { data, error } = await ctx.db.rpc('order_create', {\n p_kind: input.kind,\n p_lines: (input.lines ?? []).map(toRpcLine),\n p_party_id: input.partyId ?? null,\n p_unit_id: ctx.unitId ?? null,\n p_status: input.status ?? null,\n p_channel: input.channel ?? null,\n p_notes: input.notes ?? null,\n p_metadata: { ...(input.metadata ?? {}), source: ctx.source },\n p_idempotency_key: input.idempotencyKey ?? null,\n })\n if (error || !data) refuse(error, 'O pedido não foi aberto')\n return data as string\n}\n\nconst toRpcLine = (l: OrderLine, index: number) => ({\n product_id: l.productId ?? null,\n name: l.name,\n description: l.description ?? null,\n quantity: l.quantity,\n unit_price: money(l.unitPriceCents),\n sort_order: index,\n metadata: { ...(l.metadata ?? {}), lineId: l.id, ...(l.note ? { note: l.note } : {}) },\n})\n\n// --- lines ------------------------------------------------------------------\n\n/**\n * Appends lines and leaves the header agreeing with them.\n *\n * The total is read back from the order rather than added up on the client:\n * another terminal may have written to the same comanda a second ago, and a\n * header computed from one screen's idea of the ticket is how a bill starts\n * disagreeing with its own lines.\n */\nexport async function addLines(\n ctx: OrderContext, orderId: string, lines: OrderLine[],\n): Promise<number> {\n if (lines.length > 0) {\n const { error } = await ctx.db.from('items').insert(lines.map((l, index) => ({\n tenant_id: ctx.tenantId,\n unit_id: ctx.unitId ?? null,\n order_id: orderId,\n product_id: l.productId ?? null,\n name: l.name,\n description: l.description ?? null,\n quantity: l.quantity,\n unit_price: money(l.unitPriceCents),\n total: money(l.unitPriceCents * l.quantity),\n sort_order: index,\n metadata: { ...(l.metadata ?? {}), lineId: l.id, source: ctx.source, ...(l.note ? { note: l.note } : {}) },\n })))\n if (error) refuse(error, 'Os itens não foram gravados')\n }\n return syncTotal(ctx, orderId)\n}\n\n/** Recomputes subtotal/total from the lines the order actually holds. */\nexport async function syncTotal(ctx: OrderContext, orderId: string): Promise<number> {\n const read = await ctx.db.from('items').select('total')\n .eq('order_id', orderId).is('cancelled_at', null)\n if (read.error) refuse(read.error, 'O total do pedido não foi apurado')\n const total = Math.round((read.data ?? []).reduce((sum, r) => sum + Number(r.total ?? 0), 0) * 100) / 100\n const write = await ctx.db.from('orders').update({ subtotal: total, total }).eq('id', orderId)\n if (write.error) refuse(write.error, 'O total do pedido não foi gravado')\n return Math.round(total * 100)\n}\n\n/** Moves the order along its own machine. The cluster refuses an illegal hop. */\nexport async function setStatus(ctx: OrderContext, orderId: string, status: string): Promise<void> {\n const { error } = await ctx.db.from('orders').update({ status }).eq('id', orderId)\n if (error) refuse(error, `O pedido não passou para \"${status}\"`)\n}\n\n// --- money ------------------------------------------------------------------\n\nexport interface Invoice {\n id: string\n number: string\n totalCents: number\n instalments: { id: string; amountCents: number }[]\n}\n\n/** The receivable behind an order, once there is one. */\nexport async function invoiceOf(ctx: OrderContext, orderId: string): Promise<Invoice | null> {\n const { data, error } = await ctx.db.from('plg_financial_invoices')\n .select('id, number, total, plg_financial_invoice_installments(id, amount)')\n .eq('order_id', orderId).is('cancelled_at', null).limit(1).maybeSingle()\n if (error) refuse(error, 'A fatura não foi encontrada')\n if (!data) return null\n return {\n id: data.id,\n number: data.number,\n totalCents: Math.round(Number(data.total ?? 0) * 100),\n instalments: (data.plg_financial_invoice_installments ?? []).map(\n (i: { id: string; amount: number | string }) => ({ id: i.id, amountCents: Math.round(Number(i.amount) * 100) }),\n ),\n }\n}\n\n/**\n * Completes the order, which is what RAISES the receivable — the cluster's\n * trigger does it in the same transaction, so a closed sale can never be\n * missing its invoice. No surface writes an invoice row of its own.\n */\nexport async function completeOrder(ctx: OrderContext, orderId: string): Promise<Invoice> {\n await syncTotal(ctx, orderId)\n await setStatus(ctx, orderId, 'completed')\n const invoice = await invoiceOf(ctx, orderId)\n if (!invoice) {\n throw new OrderError('O pedido fechou sem gerar fatura — não libere antes de conferir.')\n }\n return invoice\n}\n\n/** What a surface's payment button means to the ledger. */\nexport type PaymentMethod = 'cash' | 'pix' | 'credit_card' | 'debit_card' | 'transfer' | 'other'\n\n/** Which `plg_financial_accounts.code` settles each method. Cash has none: it\n * settles into the operator's open caixinha, which is a session, not a code. */\nconst ACCOUNT_CODE: Partial<Record<PaymentMethod, string>> = {\n pix: 'pix', credit_card: 'credito', debit_card: 'debito', transfer: 'pix',\n}\n\n/** The buttons a surface shows, in the words the ledger uses. */\nexport const PAYMENT_METHODS: Record<string, PaymentMethod> = {\n cash: 'cash', dinheiro: 'cash',\n pix: 'pix',\n card: 'credit_card', cartao: 'credit_card', 'cartão': 'credit_card', credit: 'credit_card',\n debit: 'debit_card', debito: 'debit_card', 'débito': 'debit_card',\n}\n\nexport interface PaymentResult {\n paid: boolean\n /** Set when the invoice stands but the money could not be booked. */\n warning?: string\n /**\n * O banco reconheceu a chave e NÃO gravou de novo.\n *\n * É o duplo clique protegido — e era o segundo pagamento de uma conta\n * dividida sumindo em silêncio, enquanto a chave era fixa por parcela.\n * Quem chama precisa distinguir «recebi» de «isso eu já tinha».\n */\n replayed?: boolean\n}\n\nexport interface ReceivePaymentInput {\n invoice: Invoice\n method: PaymentMethod\n /** Defaults to the instalment's full amount. */\n amountCents?: number\n /**\n * Cash needs an open caixinha. `true` lets this open one with a counted\n * opening of zero rather than refuse the banknote — a stand-in until the\n * surface has a real shift-opening screen, and it is visible in the ledger.\n */\n openCashSession?: boolean\n /**\n * A conta que RECEBE, quando quem vende já perguntou.\n *\n * O PDV pergunta — «Conta de recebimento» — e a resposta mandava nada: este\n * módulo achava uma conta pelo `code`, e numa casa com duas maquininhas\n * (Cielo e Stone, dois `card_receivable_credit`) o dinheiro caía na que o\n * código encontrasse primeiro, não na que passou o cartão. A conciliação\n * fecha por maquininha.\n *\n * Ignorada para `cash`: dinheiro liquida no caixa aberto do operador, que é\n * uma sessão e não uma conta.\n */\n accountId?: string\n /**\n * A chave de idempotência, quando quem chama já tem uma.\n *\n * Omitida, ela nasce da impressão digital do pagamento — que é o que\n * distingue «o mesmo botão apertado duas vezes» de «a segunda metade da\n * conta».\n */\n idempotencyKey?: string\n /**\n * A bandeira, quando a forma tem uma — «Visa», «Alelo».\n *\n * `financial_receive_payment` já a aceita; faltava alguém passar. Sem ela a\n * conciliação do mês não separa Visa de Mastercard, e o extrato da\n * adquirente deixa de bater linha a linha com o razão.\n */\n cardBrand?: string\n /** Em quantas vezes. `1` é à vista, e é o que o débito sempre é. */\n cardInstallments?: number\n}\n\nexport async function receivePayment(\n ctx: OrderContext, input: ReceivePaymentInput,\n): Promise<PaymentResult> {\n const instalment = input.invoice.instalments[0]\n if (!instalment) {\n return { paid: false, warning: `Fatura ${input.invoice.number} sem parcela para baixar.` }\n }\n\n let accountId: string | null = null\n let cashSessionId: string | null = null\n const code = ACCOUNT_CODE[input.method]\n // SÓ o dinheiro liquida no caixa. Todo o resto — inclusive `other`, que é\n // onde caem vale e cheque — precisa de uma conta, e `financial_receive_payment`\n // recusa sem ela: *«an account is required for method %»*. Antes `other`\n // caía no ramo do caixa, abria uma sessão à toa e estourava depois.\n const liquidaNoCaixa = input.method === 'cash'\n\n if (input.accountId && !liquidaNoCaixa) {\n // A ESCOLHA DO OPERADOR GANHA de qualquer busca por código.\n accountId = input.accountId\n } else if (code) {\n const account = await ctx.db.from('plg_financial_accounts').select('id')\n .eq('code', code).eq('is_active', true).limit(1).maybeSingle()\n if (!account.data) {\n return { paid: false, warning: `Fatura ${input.invoice.number} emitida; falta a conta \"${code}\" no Financeiro.` }\n }\n accountId = account.data.id\n } else if (!liquidaNoCaixa) {\n return {\n paid: false,\n warning: `Fatura ${input.invoice.number} emitida; escolha a conta que recebe este pagamento.`,\n }\n } else {\n const open = await ctx.db.from('plg_financial_cash_register_sessions')\n .select('id').eq('status', 'open').limit(1).maybeSingle()\n cashSessionId = open.data?.id ?? null\n if (!cashSessionId) {\n if (!input.openCashSession) {\n return { paid: false, warning: `Fatura ${input.invoice.number} emitida; abra o caixa para receber em dinheiro.` }\n }\n const cofre = await ctx.db.from('plg_financial_accounts').select('id')\n .eq('kind', 'cash_physical').eq('is_active', true).limit(1).maybeSingle()\n if (!cofre.data) {\n return { paid: false, warning: `Fatura ${input.invoice.number} emitida; sem cofre para abrir o caixa.` }\n }\n const opened = await ctx.db.rpc('financial_cash_session_open', {\n p_cofre_account_id: cofre.data.id, p_opening_amount: 0,\n })\n if (opened.error) {\n return { paid: false, warning: `Fatura ${input.invoice.number} emitida; o caixa não abriu (${opened.error.message}).` }\n }\n cashSessionId = (opened.data as { session_id: string }).session_id\n }\n }\n\n const amount = money(input.amountCents ?? instalment.amountCents)\n // A chave nasce do CONTEÚDO do pagamento, não só da parcela — ver\n // `paymentKey.ts`. Com `pay:<parcela>` fixa, a segunda metade de uma conta\n // dividida voltava `replayed: true` e não gravava nada.\n const digital = {\n instalmentId: instalment.id,\n method: input.method,\n amountCents: input.amountCents ?? instalment.amountCents,\n accountId,\n cardBrand: input.cardBrand ?? null,\n }\n const chave = input.idempotencyKey ?? paymentOperationKey(digital)\n const { data, error } = await ctx.db.rpc('financial_receive_payment', {\n p_installment_id: instalment.id,\n p_amount: amount,\n p_account_id: accountId,\n p_method: input.method,\n p_cash_session_id: cashSessionId,\n // The same bill confirmed twice must not take the money twice.\n p_card_brand: input.cardBrand || null,\n p_card_installments: input.cardInstallments && input.cardInstallments > 1\n ? input.cardInstallments\n : null,\n p_idempotency_key: chave,\n p_metadata: { source: ctx.source },\n })\n if (error) {\n // A chave FICA: o operador vai tentar o mesmo pagamento de novo, e aí\n // repeti-la é o comportamento certo.\n return { paid: false, warning: `Fatura ${input.invoice.number} emitida; o pagamento não foi baixado (${error.message}).` }\n }\n const replayed = (data as { replayed?: boolean } | null)?.replayed === true\n if (!replayed) releasePaymentKey(digital)\n return { paid: true, replayed }\n}\n\n/**\n * The whole tail of a sale: complete, get the invoice, book the money. The\n * invoice is returned even when the payment leg fails, because the receivable\n * is real either way and the surface has to say so rather than pretend the\n * close did not happen.\n */\nexport async function settle(\n ctx: OrderContext,\n orderId: string,\n payment: Omit<ReceivePaymentInput, 'invoice'>,\n): Promise<{ invoice: Invoice } & PaymentResult> {\n const invoice = await completeOrder(ctx, orderId)\n const result = await receivePayment(ctx, { ...payment, invoice })\n return { invoice, ...result }\n}\n"]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface ServiceChargePreset {
|
|
2
|
+
percent: number;
|
|
3
|
+
isActive?: boolean;
|
|
4
|
+
isDefault?: boolean;
|
|
5
|
+
/** A ordem do cadastro — o `display_order` do V1. */
|
|
6
|
+
position?: number;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* A taxa com que a comanda nasce, na escada do V1.
|
|
10
|
+
*
|
|
11
|
+
* `housePercent` é o último recurso e é do V2, não do V1: lá a escada para no
|
|
12
|
+
* catálogo. Fica porque a casa que configurou o número e não cadastrou preset
|
|
13
|
+
* nenhum ainda tem uma intenção escrita, e ignorá-la seria perder informação.
|
|
14
|
+
*/
|
|
15
|
+
export declare function openingServiceCharge(presets: ReadonlyArray<ServiceChargePreset>, housePercent?: number | null): number;
|
|
16
|
+
//# sourceMappingURL=openingServiceCharge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openingServiceCharge.d.ts","sourceRoot":"","sources":["../../src/orders/openingServiceCharge.ts"],"names":[],"mappings":"AA8BA,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,qDAAqD;IACrD,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,aAAa,CAAC,mBAAmB,CAAC,EAC3C,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,GAC3B,MAAM,CAeR"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/** O que distingue um pagamento de outro, para efeito de repetição. */
|
|
2
|
+
export interface PaymentFingerprint {
|
|
3
|
+
instalmentId: string;
|
|
4
|
+
method: string;
|
|
5
|
+
amountCents: number;
|
|
6
|
+
accountId?: string | null;
|
|
7
|
+
cardBrand?: string | null;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* A chave deste pagamento — a mesma enquanto ele não terminar.
|
|
11
|
+
*
|
|
12
|
+
* `newId` existe para o teste: em produção é `crypto.randomUUID`.
|
|
13
|
+
*/
|
|
14
|
+
export declare function paymentOperationKey(f: PaymentFingerprint, newId?: () => string): string;
|
|
15
|
+
/**
|
|
16
|
+
* Terminou: a próxima vez que este mesmo pagamento aparecer, ele é OUTRO.
|
|
17
|
+
*
|
|
18
|
+
* Chamado só no sucesso. No erro a chave fica, porque o operador vai tentar de
|
|
19
|
+
* novo o mesmo pagamento — e aí repetir a chave é o comportamento certo.
|
|
20
|
+
*/
|
|
21
|
+
export declare function releasePaymentKey(f: PaymentFingerprint): void;
|
|
22
|
+
//# sourceMappingURL=paymentKey.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paymentKey.d.ts","sourceRoot":"","sources":["../../src/orders/paymentKey.ts"],"names":[],"mappings":"AAuBA,uEAAuE;AACvE,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,MAAM,CAAA;IACpB,MAAM,EAAE,MAAM,CAAA;IACd,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAC1B;AAQD;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,CAAC,EAAE,kBAAkB,EACrB,KAAK,GAAE,MAAM,MAAkC,GAC9C,MAAM,CAOR;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,kBAAkB,GAAG,IAAI,CAE7D"}
|