@blob-solutions/vcr-am-sdk 0.17.0 → 0.18.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/CHANGELOG.md +24 -0
- package/README.md +5 -2
- package/lib/index.d.cts +18 -1
- package/lib/index.d.ts +18 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,30 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `@blob-solutions/vcr-am-sdk`. The format is loosely based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project follows [Semantic Versioning](https://semver.org/).
|
|
4
4
|
|
|
5
|
+
## [0.18.0] — 2026-08-28
|
|
6
|
+
|
|
7
|
+
Stops making integrators guess a department id.
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- **`SaleItem.department` is now optional.** Omit it and the line inherits the department of the offer it references — for an inline new offer, the `defaultDepartment` you declared on it. Passing one explicitly still works and still wins, which is what you want when you deliberately sell the same SKU out of a second department.
|
|
12
|
+
|
|
13
|
+
The field was required, so every integration had to name a department per line, and the natural thing to write is the first id. That is not a harmless default: departments carry the tax regime, every register is created with one department per regime in a fixed order, and `{ id: 1 }` is the VAT one on every register whether or not the merchant owes VAT. Nothing rejects the mismatch — the receipt simply prints a VAT line the merchant does not owe, and a fiscal receipt can only be refunded and reissued, never corrected. We found this in the field.
|
|
14
|
+
|
|
15
|
+
```diff
|
|
16
|
+
items: [
|
|
17
|
+
{
|
|
18
|
+
offer: { externalId: "sku-coffee" },
|
|
19
|
+
- department: { id: 1 },
|
|
20
|
+
quantity: "1",
|
|
21
|
+
price: "1500",
|
|
22
|
+
unit: "pc",
|
|
23
|
+
},
|
|
24
|
+
],
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Requires the server-side change shipped alongside it; against an older deployment an omitted `department` is a `422`.
|
|
28
|
+
|
|
5
29
|
## [0.17.0] — 2026-08-28
|
|
6
30
|
|
|
7
31
|
Makes a `502` from an unreachable tax service recoverable. Until now the SDK told you the call failed but gave you no way to learn whether the document survived, and the only obvious response — retry — was the one that creates a duplicate fiscal receipt.
|
package/README.md
CHANGED
|
@@ -57,7 +57,6 @@ const { crn, srcReceiptId, fiscal } = await vcr.registerSale({
|
|
|
57
57
|
items: [
|
|
58
58
|
{
|
|
59
59
|
offer: { externalId: "sku-coffee" },
|
|
60
|
-
department: { id: 1 },
|
|
61
60
|
quantity: "1",
|
|
62
61
|
price: "1500",
|
|
63
62
|
unit: "pc",
|
|
@@ -142,7 +141,7 @@ await vcr.registerSale({
|
|
|
142
141
|
cashier: { id: 1 },
|
|
143
142
|
items: [
|
|
144
143
|
// price is in USD; VCR converts to AMD.
|
|
145
|
-
{ offer: { id: 5 },
|
|
144
|
+
{ offer: { id: 5 }, quantity: "1", price: "10", currency: "USD", unit: "pc" },
|
|
146
145
|
],
|
|
147
146
|
autoSettle: { tender: "cash" }, // AMD total is server-derived
|
|
148
147
|
buyer: { type: "individual" },
|
|
@@ -191,6 +190,10 @@ const cashier = await vcr.createCashier({
|
|
|
191
190
|
|
|
192
191
|
`listOffers({ externalId?, type?, includeArchived? })` is handy for checking whether an offer already exists (by `externalId`) before creating it. `updateOffer` renames an offer's title going forward — already-issued receipts are unchanged. Offer titles use the canonical `OfferTitle` shape (`{ type: "localized" | "universal", ... }`); `createOffer` also still accepts the deprecated legacy `{ value, localizationStrategy }` shape.
|
|
193
192
|
|
|
193
|
+
**Departments decide the tax regime**, so `defaultDepartment` is the one field on `createOffer` worth stopping over. Every register is created with one department per regime — VAT, VAT-exempt, turnover tax, micro-enterprise — and they are numbered in that order, which makes `{ id: 1 }` the VAT one on every register whether or not the merchant owes VAT. Call `listDepartments()` once, read `taxRegime`, and use the id that matches how the business is actually registered. Booking a sale under the wrong regime is not rejected by anything, and a fiscal receipt can only be refunded and reissued, never corrected.
|
|
194
|
+
|
|
195
|
+
Sale items then leave `department` out and inherit the offer's, so the decision is made once per offer instead of once per line.
|
|
196
|
+
|
|
194
197
|
```typescript
|
|
195
198
|
const [existing] = await vcr.listOffers({ externalId: "sku-coffee" });
|
|
196
199
|
if (existing === undefined) {
|
package/lib/index.d.cts
CHANGED
|
@@ -584,7 +584,24 @@ type NewOffer = {
|
|
|
584
584
|
type Offer = NewOffer | ExistingOfferByExternalId | ExistingOfferById;
|
|
585
585
|
type SaleItem = {
|
|
586
586
|
offer: Offer;
|
|
587
|
-
|
|
587
|
+
/**
|
|
588
|
+
* Department to book this line under. **Omit it** unless you have a reason
|
|
589
|
+
* not to: the line then inherits the department of the offer it references
|
|
590
|
+
* (`defaultDepartment`), which for an inline new offer is the one you just
|
|
591
|
+
* declared on it.
|
|
592
|
+
*
|
|
593
|
+
* The department — not the offer — decides the tax regime printed on the
|
|
594
|
+
* receipt, and every register is created with one department per regime.
|
|
595
|
+
* So a hard-coded `{ id: 1 }` copied from an example is not a harmless
|
|
596
|
+
* default: on a register that owes no VAT it books the sale under the VAT
|
|
597
|
+
* department anyway, and the receipt shows a VAT line the merchant does not
|
|
598
|
+
* owe. Nothing rejects it, and a fiscal receipt can only be refunded and
|
|
599
|
+
* reissued, never corrected.
|
|
600
|
+
*
|
|
601
|
+
* Set it explicitly only to override the offer — selling the same SKU out
|
|
602
|
+
* of a second department (a VAT payer booking an exempt transaction, say).
|
|
603
|
+
*/
|
|
604
|
+
department?: DepartmentInput;
|
|
588
605
|
quantity: string;
|
|
589
606
|
/**
|
|
590
607
|
* Unit price. AMD by default. When {@link SaleItem.currency} is set to a
|
package/lib/index.d.ts
CHANGED
|
@@ -584,7 +584,24 @@ type NewOffer = {
|
|
|
584
584
|
type Offer = NewOffer | ExistingOfferByExternalId | ExistingOfferById;
|
|
585
585
|
type SaleItem = {
|
|
586
586
|
offer: Offer;
|
|
587
|
-
|
|
587
|
+
/**
|
|
588
|
+
* Department to book this line under. **Omit it** unless you have a reason
|
|
589
|
+
* not to: the line then inherits the department of the offer it references
|
|
590
|
+
* (`defaultDepartment`), which for an inline new offer is the one you just
|
|
591
|
+
* declared on it.
|
|
592
|
+
*
|
|
593
|
+
* The department — not the offer — decides the tax regime printed on the
|
|
594
|
+
* receipt, and every register is created with one department per regime.
|
|
595
|
+
* So a hard-coded `{ id: 1 }` copied from an example is not a harmless
|
|
596
|
+
* default: on a register that owes no VAT it books the sale under the VAT
|
|
597
|
+
* department anyway, and the receipt shows a VAT line the merchant does not
|
|
598
|
+
* owe. Nothing rejects it, and a fiscal receipt can only be refunded and
|
|
599
|
+
* reissued, never corrected.
|
|
600
|
+
*
|
|
601
|
+
* Set it explicitly only to override the offer — selling the same SKU out
|
|
602
|
+
* of a second department (a VAT payer booking an exempt transaction, say).
|
|
603
|
+
*/
|
|
604
|
+
department?: DepartmentInput;
|
|
588
605
|
quantity: string;
|
|
589
606
|
/**
|
|
590
607
|
* Unit price. AMD by default. When {@link SaleItem.currency} is set to a
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blob-solutions/vcr-am-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"description": "Official TypeScript/JavaScript SDK for the VCR.AM Virtual Cash Register API — fiscalize sales, refunds, and prepayments through Armenia's State Revenue Committee.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"vcr",
|