@stacksjs/defaults 0.75.169 → 0.75.170
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.
|
@@ -264,6 +264,28 @@ tests rather than extrapolating a generic CRUD interface. Native models cover
|
|
|
264
264
|
more domain features than the short table here lists. Feature-specific routes
|
|
265
265
|
and jobs also need their enabled feature, tables and worker prerequisites.
|
|
266
266
|
|
|
267
|
+
## German tills: TSE signing and the DSFinV-K export
|
|
268
|
+
|
|
269
|
+
Three pure modules for a till in Germany (KassenSichV, § 146a AO). They hold the rules, not a certification: whether a till is compliant depends on the whole system and its operator.
|
|
270
|
+
|
|
271
|
+
- `@stacksjs/commerce/fiskaly`: a client for fiskaly SIGN DE v2, a cloud TSE. `fiskalySignDe({ apiKey, apiSecret, baseUrl?, fetch? })` caches and refreshes its token; `provisionTss(api, { tssId, clientId, clientSerialNumber, adminPin, adminPuk? })` takes a TSS from nothing (or from where an earlier attempt stopped; keep the PUK it answers) to INITIALIZED with a client; `startTransaction` / `finishTransaction` sign a sale (revisions 1 and 2). `FiskalyError.outage` says when a sale should go on unsigned and be marked.
|
|
272
|
+
- `@stacksjs/commerce/kassensichv`: the VAT keys (`DE_VAT_KEYS`: 1 = 19%, 2 = 7%, 5/6/7 = 0%), `processData` (`Beleg^75.33_7.99_0.00_0.00_0.00^10.00:Bar_64.30:Unbar`), `fiskalyReceiptFor` (amounts per VAT rate and payment type), `receiptQrCode` (the twelve-field `V0;…` QR content of DSFinV-K Anhang I), `receiptVatLines` and `TSE_FAILURE_NOTICE`.
|
|
273
|
+
- `@stacksjs/commerce/dsfinvk`: the export. `DSFINVK_TABLES` are the twenty tables of the official index.xml (DSFinV-K 2.4: files, columns, order, types, lengths, decimals); `dsfinvkExport(closings)` builds every CSV plus `index.xml` and `gdpdu-01-09-2004.dtd` from a till's cash point closings, totals per business case and payment type included. Rows are validated (mandatory columns, lengths, enumerations, time formats); a broken export throws `DsfinvkError` instead of being written. Zip the files yourself (`zipEntries` in `@stacksjs/storage`).
|
|
274
|
+
|
|
275
|
+
```typescript
|
|
276
|
+
import { fiskalyReceiptFor, processData, receiptQrCode } from '@stacksjs/commerce/kassensichv'
|
|
277
|
+
import { fiskalySignDe } from '@stacksjs/commerce/fiskaly'
|
|
278
|
+
|
|
279
|
+
const vat = [{ key: 1, grossCents: 1500 }, { key: 2, grossCents: 500 }]
|
|
280
|
+
const payments = [{ kind: 'Unbar', cents: 2000 }]
|
|
281
|
+
const api = fiskalySignDe({ apiKey, apiSecret })
|
|
282
|
+
await api.startTransaction(tssId, txId, clientId)
|
|
283
|
+
const tx = await api.finishTransaction(tssId, txId, clientId, fiskalyReceiptFor({ vat, payments }))
|
|
284
|
+
const qr = receiptQrCode({ clientSerialNumber, processType: 'Kassenbeleg-V1', processData: processData({ vat, payments }), transactionNumber: tx.number, signatureCounter: Number(tx.signature!.counter), start: tx.time_start, end: tx.time_end!, signatureAlgorithm: tx.signature!.algorithm, logTimeFormat: tx.log!.timestamp_format, signature: tx.signature!.value, publicKey: tx.signature!.public_key })
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
Traps: amounts are gross cents (German prices include VAT). A refund is a new receipt with negative amounts, referenced to the sale (`references`, REF_TYP `Transaktion`); AVBelegstorno is not for TSE tills. A transaction the TSE could not sign still goes into the export, with `tse.error` (TSE_TA_FEHLER) and no signature. fiskaly client serials (and KASSE_SERIENNR) may not contain `_` or `/` (`isClientSerialNumber`).
|
|
288
|
+
|
|
267
289
|
## Gotchas
|
|
268
290
|
|
|
269
291
|
### Writing raw SQL here
|
|
@@ -68,7 +68,7 @@ Browser runtime bindings are documented separately in `stacks-auto-imports`.
|
|
|
68
68
|
| `@stacksjs/orm` | [`stacks-orm`](../stacks-orm/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/index.ts) | 60 |
|
|
69
69
|
| `@stacksjs/pagination` | [`stacks-pagination`](../stacks-pagination/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/pagination/src/index.ts) | 0 |
|
|
70
70
|
| `@stacksjs/path` | [`stacks-path`](../stacks-path/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/path/src/index.ts) | 10 |
|
|
71
|
-
| `@stacksjs/payments` | [`stacks-payments`](../stacks-payments/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/index.ts) |
|
|
71
|
+
| `@stacksjs/payments` | [`stacks-payments`](../stacks-payments/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/index.ts) | 23 |
|
|
72
72
|
| `@stacksjs/push` | [`stacks-push`](../stacks-push/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/push/src/index.ts) | 6 |
|
|
73
73
|
| `@stacksjs/query-builder` | [`stacks-query-builder`](../stacks-query-builder/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/query-builder/src/index.ts) | 6 |
|
|
74
74
|
| `@stacksjs/queue` | [`stacks-queue`](../stacks-queue/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/queue/src/index.ts) | 48 |
|
|
@@ -655,9 +655,9 @@ Guidance: [`stacks-payments`](../stacks-payments/SKILL.md). Source: [storage/fra
|
|
|
655
655
|
|
|
656
656
|
Declared runtime exports: `Payment`, `freshIdempotencyKey`, `stacksIdempotencyKey`, `subscriptionGrantsAccess`, `subscriptionPeriod`.
|
|
657
657
|
|
|
658
|
-
Local source modules: [src/billable/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/billable/index.ts), [src/connect/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/connect/index.ts), [src/direct-debit.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/direct-debit.ts), [src/driver/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/driver/index.ts), [src/drivers/stripe.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/drivers/stripe.ts), [src/idempotency.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/idempotency.ts), [src/payment.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/payment.ts), [src/subscription-state.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/subscription-state.ts).
|
|
658
|
+
Local source modules: [src/billable/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/billable/index.ts), [src/connect/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/connect/index.ts), [src/direct-debit.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/direct-debit.ts), [src/driver/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/driver/index.ts), [src/drivers/stripe.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/drivers/stripe.ts), [src/idempotency.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/idempotency.ts), [src/payment.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/payment.ts), [src/subscription-state.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/subscription-state.ts), [src/terminal.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/terminal.ts).
|
|
659
659
|
|
|
660
|
-
Evidence directory: [
|
|
660
|
+
Evidence directory: [23 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
|
|
661
661
|
|
|
662
662
|
### @stacksjs/push
|
|
663
663
|
|
|
@@ -176,6 +176,30 @@ const mandate = await retrieveDebitMandate(stripe, debit.mandateId!) // { refere
|
|
|
176
176
|
- `CheckoutRequest.paymentMethods` (Stripe's names) limits a neutral checkout's methods: Stripe's `allowed_payment_method_types` (Stripe API 2026-01-28.clover has no `payment_method_types`, and only offers methods enabled in the Dashboard); Adyen maps `card` and `sepa_debit` to `allowedPaymentMethods`; Paddle and Lemon Squeezy refuse it.
|
|
177
177
|
- Connect: a destination charge without `on_behalf_of` debits under the platform's creditor ID and mandate, so enable SEPA on the platform account.
|
|
178
178
|
|
|
179
|
+
### Card-present payments (Stripe Terminal)
|
|
180
|
+
|
|
181
|
+
`src/terminal.ts` (also `@stacksjs/payments/terminal`) is the server-driven Terminal flow: a smart reader (WisePOS E, S700, simulated) collects the card while the server holds the PaymentIntent.
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
import { stripeTerminal, terminalChargeState, cardPresentDetails, latestChargeId } from '@stacksjs/payments/terminal'
|
|
185
|
+
|
|
186
|
+
const terminal = stripeTerminal({ secretKey: env.STRIPE_SECRET_KEY, apiBase: env.STRIPE_API_BASE }) // apiBase: an HTTP double in tests
|
|
187
|
+
const place = await terminal.createLocation({ displayName: 'Studio Mitte', address: { line1: 'Torstraße 1', city: 'Berlin', postal_code: '10119', country: 'DE' } }, 'location:12')
|
|
188
|
+
const reader = await terminal.registerReader({ registrationCode: 'simulated-wpe', label: 'Front desk', location: place.id })
|
|
189
|
+
const intent = await terminal.createPaymentIntent({ amount: 2000, currency: 'eur', onBehalfOf: acct, transferDestination: acct }, 'sale:91')
|
|
190
|
+
await terminal.processPaymentIntent(reader.id, intent.id)
|
|
191
|
+
// poll (or take terminal.reader.action_succeeded / action_failed):
|
|
192
|
+
const outcome = terminalChargeState(await terminal.retrievePaymentIntent(intent.id), await terminal.retrieveReader(reader.id))
|
|
193
|
+
// outcome.state: 'waiting' | 'succeeded' | 'failed' (retry on the same PaymentIntent) | 'canceled'
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
- A REST client (form encoding, `Idempotency-Key`, Stripe's error object as `StripeApiError`) rather than the `stripe` SDK: no optional dependency, and `apiBase` lets tests use an HTTP fake.
|
|
197
|
+
- It pins `Stripe-Version` to `STRIPE_TERMINAL_API_VERSION` (`2026-09-30.endive`), where a PaymentIntent names its method with `allowed_payment_method_types` (`payment_method_types` is refused). Pass `apiVersion: null` for the account default.
|
|
198
|
+
- A declined card leaves the PaymentIntent `requires_payment_method`; process it on the reader again. `cancelReaderAction` takes it off the screen; cancel the PaymentIntent too when the sale is abandoned.
|
|
199
|
+
- Refunds of card-present charges are ordinary refunds (`terminal.refund`), except Interac, which needs the card at the reader.
|
|
200
|
+
- `cardPresentDetails` reads what a card receipt prints (brand, last four, AID, application name, authorisation code); `latestChargeId` the charge behind a PaymentIntent.
|
|
201
|
+
- Simulated readers (`SIMULATED_READER_CODES`, test keys only: `isTestKey`) and `presentPaymentMethod` with a test card number exercise declines.
|
|
202
|
+
|
|
179
203
|
### Customers
|
|
180
204
|
|
|
181
205
|
```typescript
|
package/ide/vscode/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"publisher": "Stacks",
|
|
3
3
|
"name": "vscode-stacks",
|
|
4
4
|
"displayName": "Stacks",
|
|
5
|
-
"version": "0.75.
|
|
5
|
+
"version": "0.75.170",
|
|
6
6
|
"description": "Stacks, built into VS Code: stx templates, pickier linting and formatting, encrypted env files, the dev server preview and every buddy command. No other extensions required.",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"funding": "https://github.com/sponsors/chrisbbreuer",
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@stacksjs/defaults",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"sideEffects": false,
|
|
5
|
-
"version": "0.75.
|
|
5
|
+
"version": "0.75.170",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
8
|
"url": "git+https://github.com/stacksjs/stacks.git",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"dependencies": {
|
|
56
56
|
"@iconify-json/f7": "^1.2.2",
|
|
57
57
|
"@iconify-json/hugeicons": "^1.2.35",
|
|
58
|
-
"@stacksjs/mobile": "0.75.
|
|
58
|
+
"@stacksjs/mobile": "0.75.170",
|
|
59
59
|
"@stacksjs/sanitizer": "^0.2.483",
|
|
60
60
|
"@xterm/addon-fit": "^0.11.0",
|
|
61
61
|
"@xterm/xterm": "^6.0.0",
|