keez-invoicing 1.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +28 -0
- package/README.md +366 -0
- package/dist/coverage/lcov-report/block-navigation.js +71 -0
- package/dist/coverage/lcov-report/prettify.js +478 -0
- package/dist/coverage/lcov-report/sorter.js +177 -0
- package/dist/eslint.config.js +56 -0
- package/dist/jest.config.cjs +13 -0
- package/dist/jest.config.js +13 -0
- package/dist/src/api/__tests__/index.test.js +52 -0
- package/dist/src/api/authorise.js +48 -0
- package/dist/src/api/invoices/cancel.js +33 -0
- package/dist/src/api/invoices/create.js +97 -0
- package/dist/src/api/invoices/delete.js +33 -0
- package/dist/src/api/invoices/downloadPdf.js +31 -0
- package/dist/src/api/invoices/getAll.js +84 -0
- package/dist/src/api/invoices/sendMail.js +59 -0
- package/dist/src/api/invoices/submitEfactura.js +34 -0
- package/dist/src/api/invoices/update.js +61 -0
- package/dist/src/api/invoices/validate.js +39 -0
- package/dist/src/api/invoices/view.js +93 -0
- package/dist/src/api/items/create.js +42 -0
- package/dist/src/api/items/getAll.js +74 -0
- package/dist/src/api/items/getById.js +46 -0
- package/dist/src/api/items/index.js +14 -0
- package/dist/src/api/items/patch.js +49 -0
- package/dist/src/api/items/update.js +41 -0
- package/dist/src/config/constants.js +23 -0
- package/dist/src/config/constructorParam.js +3 -0
- package/dist/src/config/measureUnit.js +22 -0
- package/dist/src/config/paymentType.js +17 -0
- package/dist/src/config/paymentType.js.js +16 -0
- package/dist/src/dto/allInvoicesResponse.js +3 -0
- package/dist/src/dto/authResponse.js +3 -0
- package/dist/src/dto/common/index.js +3 -0
- package/dist/src/dto/common/paginationParams.js +3 -0
- package/dist/src/dto/createInvoiceRequest.js +3 -0
- package/dist/src/dto/invoiceResponse.js +3 -0
- package/dist/src/dto/invoices/index.js +3 -0
- package/dist/src/dto/invoices/invoiceFilterParams.js +3 -0
- package/dist/src/dto/invoices/invoiceRequestV2.js +3 -0
- package/dist/src/dto/invoices/sendInvoiceParams.js +3 -0
- package/dist/src/dto/items/allItemsResponse.js +3 -0
- package/dist/src/dto/items/index.js +3 -0
- package/dist/src/dto/items/itemRequest.js +3 -0
- package/dist/src/dto/items/itemResponse.js +3 -0
- package/dist/src/errors/KeezError.js +27 -0
- package/dist/src/helpers/logger.js +15 -0
- package/dist/src/index.js +15 -0
- package/dist/src/keezApi.js +283 -0
- package/dist/tests/additional-coverage.test.js +351 -0
- package/dist/tests/edge-cases.test.js +353 -0
- package/dist/tests/error-handling.test.js +224 -0
- package/dist/tests/filter-params.test.js +267 -0
- package/dist/tests/index.test.js +493 -0
- package/dist/tests/invoices-extended.test.js +168 -0
- package/dist/tests/items.test.js +142 -0
- package/dist/types/coverage/lcov-report/block-navigation.d.ts +1 -0
- package/dist/types/coverage/lcov-report/prettify.d.ts +0 -0
- package/dist/types/coverage/lcov-report/sorter.d.ts +1 -0
- package/dist/types/eslint.config.d.ts +2 -0
- package/dist/types/jest.config.d.cts +9 -0
- package/dist/types/jest.config.d.ts +9 -0
- package/dist/types/src/api/__tests__/index.test.d.ts +1 -0
- package/dist/types/src/api/authorise.d.ts +18 -0
- package/dist/types/src/api/invoices/cancel.d.ts +9 -0
- package/dist/types/src/api/invoices/create.d.ts +22 -0
- package/dist/types/src/api/invoices/delete.d.ts +9 -0
- package/dist/types/src/api/invoices/downloadPdf.d.ts +8 -0
- package/dist/types/src/api/invoices/getAll.d.ts +22 -0
- package/dist/types/src/api/invoices/sendMail.d.ts +24 -0
- package/dist/types/src/api/invoices/submitEfactura.d.ts +9 -0
- package/dist/types/src/api/invoices/update.d.ts +11 -0
- package/dist/types/src/api/invoices/validate.d.ts +21 -0
- package/dist/types/src/api/invoices/view.d.ts +22 -0
- package/dist/types/src/api/items/create.d.ts +10 -0
- package/dist/types/src/api/items/getAll.d.ts +10 -0
- package/dist/types/src/api/items/getById.d.ts +10 -0
- package/dist/types/src/api/items/index.d.ts +5 -0
- package/dist/types/src/api/items/patch.d.ts +11 -0
- package/dist/types/src/api/items/update.d.ts +11 -0
- package/dist/types/src/config/constants.d.ts +13 -0
- package/dist/types/src/config/constructorParam.d.ts +6 -0
- package/dist/types/src/config/measureUnit.d.ts +17 -0
- package/dist/types/src/config/paymentType.d.ts +12 -0
- package/dist/types/src/config/paymentType.js.d.ts +11 -0
- package/dist/types/src/dto/allInvoicesResponse.d.ts +21 -0
- package/dist/types/src/dto/authResponse.d.ts +7 -0
- package/dist/types/src/dto/common/index.d.ts +1 -0
- package/dist/types/src/dto/common/paginationParams.d.ts +4 -0
- package/dist/types/src/dto/createInvoiceRequest.d.ts +34 -0
- package/dist/types/src/dto/invoiceResponse.d.ts +48 -0
- package/dist/types/src/dto/invoices/index.d.ts +3 -0
- package/dist/types/src/dto/invoices/invoiceFilterParams.d.ts +8 -0
- package/dist/types/src/dto/invoices/invoiceRequestV2.d.ts +23 -0
- package/dist/types/src/dto/invoices/sendInvoiceParams.d.ts +5 -0
- package/dist/types/src/dto/items/allItemsResponse.d.ts +13 -0
- package/dist/types/src/dto/items/index.d.ts +3 -0
- package/dist/types/src/dto/items/itemRequest.d.ts +34 -0
- package/dist/types/src/dto/items/itemResponse.d.ts +15 -0
- package/dist/types/src/errors/KeezError.d.ts +11 -0
- package/dist/types/src/helpers/logger.d.ts +2 -0
- package/dist/types/src/index.d.ts +11 -0
- package/dist/types/src/keezApi.d.ts +114 -0
- package/dist/types/tests/additional-coverage.test.d.ts +1 -0
- package/dist/types/tests/edge-cases.test.d.ts +1 -0
- package/dist/types/tests/error-handling.test.d.ts +1 -0
- package/dist/types/tests/filter-params.test.d.ts +1 -0
- package/dist/types/tests/index.test.d.ts +1 -0
- package/dist/types/tests/invoices-extended.test.d.ts +1 -0
- package/dist/types/tests/items.test.d.ts +1 -0
- package/package.json +66 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026, TPN LABS
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
16
|
+
contributors may be used to endorse or promote products derived from
|
|
17
|
+
this software without specific prior written permission.
|
|
18
|
+
|
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
23
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
24
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
25
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
26
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
27
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
28
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
package/README.md
ADDED
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img width="100px" src="https://raw.githubusercontent.com/TPN-Labs/keez-node/main/.github/images/favicon512x512-npm.png" align="center" alt=":package: keez-node" />
|
|
3
|
+
<h2 align="center">keez-invoicing</h2>
|
|
4
|
+
<p align="center">A simple npm package for invoicing that wraps around Keez API.</p>
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
# Keez wrapper using Node
|
|
8
|
+
|
|
9
|
+
[](https://www.npmjs.com/package/keez-invoicing)
|
|
10
|
+
[](https://www.npmjs.com/package/keez-invoicing)
|
|
11
|
+
|
|
12
|
+
## Getting started
|
|
13
|
+
|
|
14
|
+
Please consult [Keez API documentation](https://app.keez.ro/help/api/content.html) for more information on how to use the API.
|
|
15
|
+
|
|
16
|
+
### Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install keez-invoicing
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Configuration
|
|
23
|
+
|
|
24
|
+
### Constructor Options
|
|
25
|
+
|
|
26
|
+
| Option | Type | Required | Description |
|
|
27
|
+
|--------|------|----------|-------------|
|
|
28
|
+
| `application_id` | `string` | Yes | Application ID from Keez |
|
|
29
|
+
| `client_eid` | `string` | Yes | Client entity ID |
|
|
30
|
+
| `secret` | `string` | Yes | API secret |
|
|
31
|
+
| `live` | `boolean` | Yes | `true` for production (`app.keez.ro`), `false` for staging (`staging.keez.ro`) |
|
|
32
|
+
|
|
33
|
+
### Initialization
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
import { KeezApi } from 'keez-invoicing';
|
|
37
|
+
|
|
38
|
+
const keezApi = new KeezApi({
|
|
39
|
+
application_id: 'KEEZ_APPLICATION_ID',
|
|
40
|
+
client_eid: 'KEEZ_CLIENT_ID',
|
|
41
|
+
secret: 'KEEZ_SECRET',
|
|
42
|
+
live: true, // false for staging environment
|
|
43
|
+
});
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## API Reference
|
|
47
|
+
|
|
48
|
+
### Invoice Methods
|
|
49
|
+
|
|
50
|
+
| Method | Parameters | Returns | Description |
|
|
51
|
+
|--------|------------|---------|-------------|
|
|
52
|
+
| `getAllInvoices(params?)` | `InvoiceFilterParams?` | `Promise<AllInvoicesResponse>` | Get all invoices with optional filtering |
|
|
53
|
+
| `getInvoiceByExternalId(id)` | `string` | `Promise<InvoiceResponse>` | Get invoice by external ID |
|
|
54
|
+
| `createInvoice(params)` | `InvoiceRequest` | `Promise<string>` | Create invoice, returns external ID |
|
|
55
|
+
| `updateInvoice(id, params)` | `string, InvoiceRequestV2` | `Promise<void>` | Update an existing invoice |
|
|
56
|
+
| `deleteInvoice(id)` | `string` | `Promise<void>` | Delete an invoice |
|
|
57
|
+
| `sendInvoice(email, id)` | `string, string` | `Promise<string>` | Send invoice via email |
|
|
58
|
+
| `sendInvoice(emailParams, id)` | `SendInvoiceEmailParams, string` | `Promise<string>` | Send invoice with CC/BCC |
|
|
59
|
+
| `validateInvoice(id)` | `string` | `Promise<string>` | Validate an invoice |
|
|
60
|
+
| `cancelInvoice(id)` | `string` | `Promise<void>` | Cancel an invoice |
|
|
61
|
+
| `submitInvoiceToEfactura(id)` | `string` | `Promise<string>` | Submit invoice to eFactura |
|
|
62
|
+
| `downloadInvoicePdf(id)` | `string` | `Promise<Buffer>` | Download invoice as PDF |
|
|
63
|
+
|
|
64
|
+
### Item Methods
|
|
65
|
+
|
|
66
|
+
| Method | Parameters | Returns | Description |
|
|
67
|
+
|--------|------------|---------|-------------|
|
|
68
|
+
| `getAllItems(params?)` | `ItemFilterParams?` | `Promise<AllItemsResponse>` | Get all items with optional filtering |
|
|
69
|
+
| `getItemByExternalId(id)` | `string` | `Promise<ItemResponse>` | Get item by external ID |
|
|
70
|
+
| `createItem(item)` | `CreateItemRequest` | `Promise<string>` | Create item, returns external ID |
|
|
71
|
+
| `updateItem(id, item)` | `string, UpdateItemRequest` | `Promise<void>` | Update an existing item |
|
|
72
|
+
| `patchItem(id, item)` | `string, PatchItemRequest` | `Promise<void>` | Partially update an item |
|
|
73
|
+
|
|
74
|
+
### PaymentType Enum
|
|
75
|
+
|
|
76
|
+
| Value | Name | Description |
|
|
77
|
+
|-------|------|-------------|
|
|
78
|
+
| `1` | `CASH` | Cash payment with fiscal receipt |
|
|
79
|
+
| `2` | `CARD` | Card payment with fiscal receipt |
|
|
80
|
+
| `3` | `BANK_TRANSFER` | Invoice paid via bank transfer |
|
|
81
|
+
| `4` | `CASH_RECEIPT` | Cash payment with receipt |
|
|
82
|
+
| `5` | `CASH_ON_DELIVERY` | Cash on delivery |
|
|
83
|
+
| `6` | `CARD_ONLINE` | Online card payment |
|
|
84
|
+
| `7` | `CARD_PLATFORMS` | Payment via distribution platforms (e.g., Emag) |
|
|
85
|
+
| `8` | `HOLIDAY_VOUCHER_CARD` | Holiday voucher payment (card) |
|
|
86
|
+
| `9` | `HOLIDAY_VOUCHER_TICKET` | Holiday voucher payment (ticket) |
|
|
87
|
+
|
|
88
|
+
### MeasureUnit Enum
|
|
89
|
+
|
|
90
|
+
| Value | Name | Description |
|
|
91
|
+
|-------|------|-------------|
|
|
92
|
+
| `1` | `PIECE` | Piece (Bucata) |
|
|
93
|
+
| `2` | `KILOGRAM` | Kilogram |
|
|
94
|
+
| `3` | `GRAM` | Gram |
|
|
95
|
+
| `4` | `LITER` | Liter |
|
|
96
|
+
| `5` | `METER` | Meter |
|
|
97
|
+
| `6` | `SQUARE_METER` | Square meter |
|
|
98
|
+
| `7` | `CUBIC_METER` | Cubic meter |
|
|
99
|
+
| `8` | `HOUR` | Hour |
|
|
100
|
+
| `9` | `DAY` | Day |
|
|
101
|
+
| `10` | `MONTH` | Month |
|
|
102
|
+
| `11` | `YEAR` | Year |
|
|
103
|
+
| `12` | `SET` | Set |
|
|
104
|
+
| `13` | `PACK` | Pack |
|
|
105
|
+
| `14` | `BOX` | Box |
|
|
106
|
+
| `15` | `SERVICE` | Service |
|
|
107
|
+
|
|
108
|
+
## TypeScript Types
|
|
109
|
+
|
|
110
|
+
All types are exported from the main package:
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
import {
|
|
114
|
+
KeezApi,
|
|
115
|
+
PaymentType,
|
|
116
|
+
MeasureUnit,
|
|
117
|
+
// Request types
|
|
118
|
+
InvoiceRequest,
|
|
119
|
+
InvoiceRequestV2,
|
|
120
|
+
InvoiceLineItem,
|
|
121
|
+
Partner,
|
|
122
|
+
CreateItemRequest,
|
|
123
|
+
UpdateItemRequest,
|
|
124
|
+
PatchItemRequest,
|
|
125
|
+
// Response types
|
|
126
|
+
InvoiceResponse,
|
|
127
|
+
Item,
|
|
128
|
+
AllInvoicesResponse,
|
|
129
|
+
ShortInvoiceResponse,
|
|
130
|
+
ItemResponse,
|
|
131
|
+
AllItemsResponse,
|
|
132
|
+
AuthResponse,
|
|
133
|
+
// Filter types
|
|
134
|
+
InvoiceFilterParams,
|
|
135
|
+
ItemFilterParams,
|
|
136
|
+
PaginationParams,
|
|
137
|
+
SendInvoiceEmailParams,
|
|
138
|
+
// Error classes
|
|
139
|
+
KeezError,
|
|
140
|
+
KeezAuthError,
|
|
141
|
+
KeezApiError,
|
|
142
|
+
} from 'keez-invoicing';
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### InvoiceFilterParams
|
|
146
|
+
|
|
147
|
+
| Property | Type | Description |
|
|
148
|
+
|----------|------|-------------|
|
|
149
|
+
| `offset` | `number?` | Pagination offset |
|
|
150
|
+
| `count` | `number?` | Number of records to return |
|
|
151
|
+
| `status` | `string?` | Filter by invoice status |
|
|
152
|
+
| `fromDate` | `number?` | Filter by start date |
|
|
153
|
+
| `toDate` | `number?` | Filter by end date |
|
|
154
|
+
| `series` | `string?` | Filter by invoice series |
|
|
155
|
+
| `partnerName` | `string?` | Filter by partner name |
|
|
156
|
+
|
|
157
|
+
### ItemFilterParams
|
|
158
|
+
|
|
159
|
+
| Property | Type | Description |
|
|
160
|
+
|----------|------|-------------|
|
|
161
|
+
| `offset` | `number?` | Pagination offset |
|
|
162
|
+
| `count` | `number?` | Number of records to return |
|
|
163
|
+
| `itemName` | `string?` | Filter by item name |
|
|
164
|
+
| `itemCode` | `string?` | Filter by item code |
|
|
165
|
+
| `isActive` | `boolean?` | Filter by active status |
|
|
166
|
+
|
|
167
|
+
### SendInvoiceEmailParams
|
|
168
|
+
|
|
169
|
+
| Property | Type | Description |
|
|
170
|
+
|----------|------|-------------|
|
|
171
|
+
| `to` | `string` | Primary recipient email |
|
|
172
|
+
| `cc` | `string[]?` | CC recipients |
|
|
173
|
+
| `bcc` | `string[]?` | BCC recipients |
|
|
174
|
+
|
|
175
|
+
### CreateItemRequest
|
|
176
|
+
|
|
177
|
+
| Property | Type | Required | Description |
|
|
178
|
+
|----------|------|----------|-------------|
|
|
179
|
+
| `itemName` | `string` | Yes | Item name |
|
|
180
|
+
| `measureUnitId` | `MeasureUnit` | Yes | Measure unit |
|
|
181
|
+
| `unitPrice` | `number` | Yes | Unit price |
|
|
182
|
+
| `vatPercent` | `number` | Yes | VAT percentage |
|
|
183
|
+
| `itemCode` | `string` | No | Item code |
|
|
184
|
+
| `itemDescription` | `string` | No | Description |
|
|
185
|
+
| `vatCategoryCode` | `string` | No | VAT category code |
|
|
186
|
+
| `vatExemptionReason` | `string` | No | VAT exemption reason |
|
|
187
|
+
| `isActive` | `boolean` | No | Is active (default: true) |
|
|
188
|
+
|
|
189
|
+
### InvoiceRequest
|
|
190
|
+
|
|
191
|
+
| Property | Type | Required | Description |
|
|
192
|
+
|----------|------|----------|-------------|
|
|
193
|
+
| `series` | `string` | Yes | Invoice series |
|
|
194
|
+
| `currencyCode` | `string` | Yes | Currency code (e.g., 'RON') |
|
|
195
|
+
| `amount` | `number` | Yes | Invoice amount |
|
|
196
|
+
| `paymentType` | `PaymentType` | Yes | Payment type |
|
|
197
|
+
| `partner` | `Partner` | Yes | Partner/client details |
|
|
198
|
+
| `itemId` | `string` | Yes | Item external ID |
|
|
199
|
+
| `documentDate` | `number` | No | Document date (timestamp) |
|
|
200
|
+
| `dueDate` | `number` | No | Due date (timestamp) |
|
|
201
|
+
| `measureUnitId` | `number` | No | Measure unit ID |
|
|
202
|
+
| `quantity` | `number` | No | Quantity |
|
|
203
|
+
| `vatOnCollection` | `boolean` | No | VAT on collection |
|
|
204
|
+
|
|
205
|
+
### Partner
|
|
206
|
+
|
|
207
|
+
| Property | Type | Description |
|
|
208
|
+
|----------|------|-------------|
|
|
209
|
+
| `partnerName` | `string` | Partner/client name |
|
|
210
|
+
| `isLegalPerson` | `boolean` | Is legal entity |
|
|
211
|
+
| `identificationNumber` | `string` | ID number (CNP/CUI) |
|
|
212
|
+
| `countryCode` | `string` | Country code (e.g., 'RO') |
|
|
213
|
+
| `countryName` | `string` | Country name |
|
|
214
|
+
| `countyCode` | `string` | County code (e.g., 'RO.B') |
|
|
215
|
+
| `countyName` | `string` | County name |
|
|
216
|
+
| `cityName` | `string` | City name |
|
|
217
|
+
| `addressDetails` | `string` | Full address |
|
|
218
|
+
|
|
219
|
+
### Error Classes
|
|
220
|
+
|
|
221
|
+
| Class | Description |
|
|
222
|
+
|-------|-------------|
|
|
223
|
+
| `KeezError` | Base error class with `statusCode` and `originalError` properties |
|
|
224
|
+
| `KeezAuthError` | Authentication errors (extends `KeezError`) |
|
|
225
|
+
| `KeezApiError` | API request errors (extends `KeezError`) |
|
|
226
|
+
|
|
227
|
+
## Examples
|
|
228
|
+
|
|
229
|
+
### Getting all invoices with filtering
|
|
230
|
+
|
|
231
|
+
```ts
|
|
232
|
+
// Get all invoices
|
|
233
|
+
const invoices = await keezApi.getAllInvoices();
|
|
234
|
+
console.log(`Total invoices: ${invoices.recordsCount}`);
|
|
235
|
+
|
|
236
|
+
// Get invoices with filters
|
|
237
|
+
const filteredInvoices = await keezApi.getAllInvoices({
|
|
238
|
+
status: 'VALIDATED',
|
|
239
|
+
fromDate: 20240101,
|
|
240
|
+
toDate: 20241231,
|
|
241
|
+
offset: 0,
|
|
242
|
+
count: 50,
|
|
243
|
+
});
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Getting invoice by ID
|
|
247
|
+
|
|
248
|
+
```ts
|
|
249
|
+
const invoice = await keezApi.getInvoiceByExternalId('invoice-external-id');
|
|
250
|
+
console.log(`Invoice: ${invoice.series}-${invoice.number}`);
|
|
251
|
+
console.log(`Status: ${invoice.status}`);
|
|
252
|
+
console.log(`Amount: ${invoice.grossAmount} ${invoice.currencyCode}`);
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### Creating an invoice
|
|
256
|
+
|
|
257
|
+
```ts
|
|
258
|
+
import { KeezApi, PaymentType } from 'keez-invoicing';
|
|
259
|
+
|
|
260
|
+
const result = await keezApi.createInvoice({
|
|
261
|
+
amount: 400,
|
|
262
|
+
currencyCode: 'RON',
|
|
263
|
+
itemId: 'KEEZ_ITEM_ID',
|
|
264
|
+
partner: {
|
|
265
|
+
isLegalPerson: false,
|
|
266
|
+
partnerName: 'John Doe',
|
|
267
|
+
countryName: 'Romania',
|
|
268
|
+
countryCode: 'RO',
|
|
269
|
+
countyCode: 'RO.B',
|
|
270
|
+
countyName: 'Bucuresti',
|
|
271
|
+
addressDetails: 'Str. Comerciala nr. 4',
|
|
272
|
+
cityName: 'Bucharest',
|
|
273
|
+
identificationNumber: '1234',
|
|
274
|
+
},
|
|
275
|
+
paymentType: PaymentType.BANK_TRANSFER,
|
|
276
|
+
series: 'INV',
|
|
277
|
+
});
|
|
278
|
+
console.log(`Created invoice with external ID: ${result}`);
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### Sending invoice via email with CC/BCC
|
|
282
|
+
|
|
283
|
+
```ts
|
|
284
|
+
// Simple email
|
|
285
|
+
const result = await keezApi.sendInvoice('client@example.com', 'invoice-external-id');
|
|
286
|
+
|
|
287
|
+
// With CC and BCC
|
|
288
|
+
const resultWithCc = await keezApi.sendInvoice(
|
|
289
|
+
{
|
|
290
|
+
to: 'client@example.com',
|
|
291
|
+
cc: ['accounting@example.com'],
|
|
292
|
+
bcc: ['archive@example.com'],
|
|
293
|
+
},
|
|
294
|
+
'invoice-external-id'
|
|
295
|
+
);
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### Working with items
|
|
299
|
+
|
|
300
|
+
```ts
|
|
301
|
+
import { KeezApi, MeasureUnit } from 'keez-invoicing';
|
|
302
|
+
|
|
303
|
+
// Create an item
|
|
304
|
+
const itemId = await keezApi.createItem({
|
|
305
|
+
itemName: 'Consulting Service',
|
|
306
|
+
measureUnitId: MeasureUnit.HOUR,
|
|
307
|
+
unitPrice: 150,
|
|
308
|
+
vatPercent: 19,
|
|
309
|
+
itemDescription: 'Professional consulting service',
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
// Get all items
|
|
313
|
+
const items = await keezApi.getAllItems({ isActive: true });
|
|
314
|
+
|
|
315
|
+
// Get item by ID
|
|
316
|
+
const item = await keezApi.getItemByExternalId(itemId);
|
|
317
|
+
|
|
318
|
+
// Partially update an item
|
|
319
|
+
await keezApi.patchItem(itemId, { unitPrice: 175 });
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### Invoice lifecycle operations
|
|
323
|
+
|
|
324
|
+
```ts
|
|
325
|
+
// Validate an invoice
|
|
326
|
+
await keezApi.validateInvoice('invoice-external-id');
|
|
327
|
+
|
|
328
|
+
// Submit to eFactura (Romanian electronic invoicing)
|
|
329
|
+
const uploadIndex = await keezApi.submitInvoiceToEfactura('invoice-external-id');
|
|
330
|
+
|
|
331
|
+
// Download invoice PDF
|
|
332
|
+
const pdfBuffer = await keezApi.downloadInvoicePdf('invoice-external-id');
|
|
333
|
+
fs.writeFileSync('invoice.pdf', pdfBuffer);
|
|
334
|
+
|
|
335
|
+
// Cancel an invoice
|
|
336
|
+
await keezApi.cancelInvoice('invoice-external-id');
|
|
337
|
+
|
|
338
|
+
// Delete an invoice
|
|
339
|
+
await keezApi.deleteInvoice('invoice-external-id');
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### Error handling
|
|
343
|
+
|
|
344
|
+
```ts
|
|
345
|
+
import { KeezApi, KeezAuthError, KeezApiError } from 'keez-invoicing';
|
|
346
|
+
|
|
347
|
+
try {
|
|
348
|
+
const invoices = await keezApi.getAllInvoices();
|
|
349
|
+
} catch (error) {
|
|
350
|
+
if (error instanceof KeezAuthError) {
|
|
351
|
+
console.error('Authentication failed:', error.message);
|
|
352
|
+
} else if (error instanceof KeezApiError) {
|
|
353
|
+
console.error('API error:', error.message, 'Status:', error.statusCode);
|
|
354
|
+
} else {
|
|
355
|
+
throw error;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
## Contributing
|
|
361
|
+
|
|
362
|
+
Contributions, issues and feature requests are welcome!
|
|
363
|
+
|
|
364
|
+
## License
|
|
365
|
+
|
|
366
|
+
Copyright © 2023 - 2026 [TPN LABS](https://tpn-labs.com) - All rights reserved. This project is [MIT](LICENSE) licensed.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
var jumpToCode = (function init() {
|
|
4
|
+
// Classes of code we would like to highlight in the file view
|
|
5
|
+
var missingCoverageClasses = ['.cbranch-no', '.cstat-no', '.fstat-no'];
|
|
6
|
+
// Elements to highlight in the file listing view
|
|
7
|
+
var fileListingElements = ['td.pct.low'];
|
|
8
|
+
// We don't want to select elements that are direct descendants of another match
|
|
9
|
+
var notSelector = ':not(' + missingCoverageClasses.join('):not(') + ') > '; // becomes `:not(a):not(b) > `
|
|
10
|
+
// Selector that finds elements on the page to which we can jump
|
|
11
|
+
var selector = fileListingElements.join(', ') +
|
|
12
|
+
', ' +
|
|
13
|
+
notSelector +
|
|
14
|
+
missingCoverageClasses.join(', ' + notSelector); // becomes `:not(a):not(b) > a, :not(a):not(b) > b`
|
|
15
|
+
// The NodeList of matching elements
|
|
16
|
+
var missingCoverageElements = document.querySelectorAll(selector);
|
|
17
|
+
var currentIndex;
|
|
18
|
+
function toggleClass(index) {
|
|
19
|
+
missingCoverageElements
|
|
20
|
+
.item(currentIndex)
|
|
21
|
+
.classList.remove('highlighted');
|
|
22
|
+
missingCoverageElements.item(index).classList.add('highlighted');
|
|
23
|
+
}
|
|
24
|
+
function makeCurrent(index) {
|
|
25
|
+
toggleClass(index);
|
|
26
|
+
currentIndex = index;
|
|
27
|
+
missingCoverageElements.item(index).scrollIntoView({
|
|
28
|
+
behavior: 'smooth',
|
|
29
|
+
block: 'center',
|
|
30
|
+
inline: 'center'
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
function goToPrevious() {
|
|
34
|
+
var nextIndex = 0;
|
|
35
|
+
if (typeof currentIndex !== 'number' || currentIndex === 0) {
|
|
36
|
+
nextIndex = missingCoverageElements.length - 1;
|
|
37
|
+
}
|
|
38
|
+
else if (missingCoverageElements.length > 1) {
|
|
39
|
+
nextIndex = currentIndex - 1;
|
|
40
|
+
}
|
|
41
|
+
makeCurrent(nextIndex);
|
|
42
|
+
}
|
|
43
|
+
function goToNext() {
|
|
44
|
+
var nextIndex = 0;
|
|
45
|
+
if (typeof currentIndex === 'number' &&
|
|
46
|
+
currentIndex < missingCoverageElements.length - 1) {
|
|
47
|
+
nextIndex = currentIndex + 1;
|
|
48
|
+
}
|
|
49
|
+
makeCurrent(nextIndex);
|
|
50
|
+
}
|
|
51
|
+
return function jump(event) {
|
|
52
|
+
if (document.getElementById('fileSearch') === document.activeElement &&
|
|
53
|
+
document.activeElement != null) {
|
|
54
|
+
// if we're currently focused on the search input, we don't want to navigate
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
switch (event.which) {
|
|
58
|
+
case 78: // n
|
|
59
|
+
case 74: // j
|
|
60
|
+
goToNext();
|
|
61
|
+
break;
|
|
62
|
+
case 66: // b
|
|
63
|
+
case 75: // k
|
|
64
|
+
case 80: // p
|
|
65
|
+
goToPrevious();
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
})();
|
|
70
|
+
window.addEventListener('keydown', jumpToCode);
|
|
71
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmxvY2stbmF2aWdhdGlvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL2NvdmVyYWdlL2xjb3YtcmVwb3J0L2Jsb2NrLW5hdmlnYXRpb24uanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLG9CQUFvQjtBQUNwQixJQUFJLFVBQVUsR0FBRyxDQUFDLFNBQVMsSUFBSTtJQUMzQiw4REFBOEQ7SUFDOUQsSUFBSSxzQkFBc0IsR0FBRyxDQUFDLGFBQWEsRUFBRSxXQUFXLEVBQUUsV0FBVyxDQUFDLENBQUM7SUFFdkUsaURBQWlEO0lBQ2pELElBQUksbUJBQW1CLEdBQUcsQ0FBQyxZQUFZLENBQUMsQ0FBQztJQUV6QyxnRkFBZ0Y7SUFDaEYsSUFBSSxXQUFXLEdBQUcsT0FBTyxHQUFHLHNCQUFzQixDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsR0FBRyxNQUFNLENBQUMsQ0FBQyw4QkFBOEI7SUFFMUcsZ0VBQWdFO0lBQ2hFLElBQUksUUFBUSxHQUNSLG1CQUFtQixDQUFDLElBQUksQ0FBQyxJQUFJLENBQUM7UUFDOUIsSUFBSTtRQUNKLFdBQVc7UUFDWCxzQkFBc0IsQ0FBQyxJQUFJLENBQUMsSUFBSSxHQUFHLFdBQVcsQ0FBQyxDQUFDLENBQUMsbURBQW1EO0lBRXhHLG9DQUFvQztJQUNwQyxJQUFJLHVCQUF1QixHQUFHLFFBQVEsQ0FBQyxnQkFBZ0IsQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUVsRSxJQUFJLFlBQVksQ0FBQztJQUVqQixTQUFTLFdBQVcsQ0FBQyxLQUFLO1FBQ3RCLHVCQUF1QjthQUNsQixJQUFJLENBQUMsWUFBWSxDQUFDO2FBQ2xCLFNBQVMsQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFDLENBQUM7UUFDckMsdUJBQXVCLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsYUFBYSxDQUFDLENBQUM7SUFDckUsQ0FBQztJQUVELFNBQVMsV0FBVyxDQUFDLEtBQUs7UUFDdEIsV0FBVyxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ25CLFlBQVksR0FBRyxLQUFLLENBQUM7UUFDckIsdUJBQXVCLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLGNBQWMsQ0FBQztZQUMvQyxRQUFRLEVBQUUsUUFBUTtZQUNsQixLQUFLLEVBQUUsUUFBUTtZQUNmLE1BQU0sRUFBRSxRQUFRO1NBQ25CLENBQUMsQ0FBQztJQUNQLENBQUM7SUFFRCxTQUFTLFlBQVk7UUFDakIsSUFBSSxTQUFTLEdBQUcsQ0FBQyxDQUFDO1FBQ2xCLElBQUksT0FBTyxZQUFZLEtBQUssUUFBUSxJQUFJLFlBQVksS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUN6RCxTQUFTLEdBQUcsdUJBQXVCLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQztRQUNuRCxDQUFDO2FBQU0sSUFBSSx1QkFBdUIsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDNUMsU0FBUyxHQUFHLFlBQVksR0FBRyxDQUFDLENBQUM7UUFDakMsQ0FBQztRQUVELFdBQVcsQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUMzQixDQUFDO0lBRUQsU0FBUyxRQUFRO1FBQ2IsSUFBSSxTQUFTLEdBQUcsQ0FBQyxDQUFDO1FBRWxCLElBQ0ksT0FBTyxZQUFZLEtBQUssUUFBUTtZQUNoQyxZQUFZLEdBQUcsdUJBQXVCLENBQUMsTUFBTSxHQUFHLENBQUMsRUFDbkQsQ0FBQztZQUNDLFNBQVMsR0FBRyxZQUFZLEdBQUcsQ0FBQyxDQUFDO1FBQ2pDLENBQUM7UUFFRCxXQUFXLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDM0IsQ0FBQztJQUVELE9BQU8sU0FBUyxJQUFJLENBQUMsS0FBSztRQUN0QixJQUNJLFFBQVEsQ0FBQyxjQUFjLENBQUMsWUFBWSxDQUFDLEtBQUssUUFBUSxDQUFDLGFBQWE7WUFDaEUsUUFBUSxDQUFDLGFBQWEsSUFBSSxJQUFJLEVBQ2hDLENBQUM7WUFDQyw0RUFBNEU7WUFDNUUsT0FBTztRQUNYLENBQUM7UUFFRCxRQUFRLEtBQUssQ0FBQyxLQUFLLEVBQUUsQ0FBQztZQUNsQixLQUFLLEVBQUUsQ0FBQyxDQUFDLElBQUk7WUFDYixLQUFLLEVBQUUsRUFBRSxJQUFJO2dCQUNULFFBQVEsRUFBRSxDQUFDO2dCQUNYLE1BQU07WUFDVixLQUFLLEVBQUUsQ0FBQyxDQUFDLElBQUk7WUFDYixLQUFLLEVBQUUsQ0FBQyxDQUFDLElBQUk7WUFDYixLQUFLLEVBQUUsRUFBRSxJQUFJO2dCQUNULFlBQVksRUFBRSxDQUFDO2dCQUNmLE1BQU07UUFDZCxDQUFDO0lBQ0wsQ0FBQyxDQUFDO0FBQ04sQ0FBQyxDQUFDLEVBQUUsQ0FBQztBQUNMLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxTQUFTLEVBQUUsVUFBVSxDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKiBlc2xpbnQtZGlzYWJsZSAqL1xudmFyIGp1bXBUb0NvZGUgPSAoZnVuY3Rpb24gaW5pdCgpIHtcbiAgICAvLyBDbGFzc2VzIG9mIGNvZGUgd2Ugd291bGQgbGlrZSB0byBoaWdobGlnaHQgaW4gdGhlIGZpbGUgdmlld1xuICAgIHZhciBtaXNzaW5nQ292ZXJhZ2VDbGFzc2VzID0gWycuY2JyYW5jaC1ubycsICcuY3N0YXQtbm8nLCAnLmZzdGF0LW5vJ107XG5cbiAgICAvLyBFbGVtZW50cyB0byBoaWdobGlnaHQgaW4gdGhlIGZpbGUgbGlzdGluZyB2aWV3XG4gICAgdmFyIGZpbGVMaXN0aW5nRWxlbWVudHMgPSBbJ3RkLnBjdC5sb3cnXTtcblxuICAgIC8vIFdlIGRvbid0IHdhbnQgdG8gc2VsZWN0IGVsZW1lbnRzIHRoYXQgYXJlIGRpcmVjdCBkZXNjZW5kYW50cyBvZiBhbm90aGVyIG1hdGNoXG4gICAgdmFyIG5vdFNlbGVjdG9yID0gJzpub3QoJyArIG1pc3NpbmdDb3ZlcmFnZUNsYXNzZXMuam9pbignKTpub3QoJykgKyAnKSA+ICc7IC8vIGJlY29tZXMgYDpub3QoYSk6bm90KGIpID4gYFxuXG4gICAgLy8gU2VsZWN0b3IgdGhhdCBmaW5kcyBlbGVtZW50cyBvbiB0aGUgcGFnZSB0byB3aGljaCB3ZSBjYW4ganVtcFxuICAgIHZhciBzZWxlY3RvciA9XG4gICAgICAgIGZpbGVMaXN0aW5nRWxlbWVudHMuam9pbignLCAnKSArXG4gICAgICAgICcsICcgK1xuICAgICAgICBub3RTZWxlY3RvciArXG4gICAgICAgIG1pc3NpbmdDb3ZlcmFnZUNsYXNzZXMuam9pbignLCAnICsgbm90U2VsZWN0b3IpOyAvLyBiZWNvbWVzIGA6bm90KGEpOm5vdChiKSA+IGEsIDpub3QoYSk6bm90KGIpID4gYmBcblxuICAgIC8vIFRoZSBOb2RlTGlzdCBvZiBtYXRjaGluZyBlbGVtZW50c1xuICAgIHZhciBtaXNzaW5nQ292ZXJhZ2VFbGVtZW50cyA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoc2VsZWN0b3IpO1xuXG4gICAgdmFyIGN1cnJlbnRJbmRleDtcblxuICAgIGZ1bmN0aW9uIHRvZ2dsZUNsYXNzKGluZGV4KSB7XG4gICAgICAgIG1pc3NpbmdDb3ZlcmFnZUVsZW1lbnRzXG4gICAgICAgICAgICAuaXRlbShjdXJyZW50SW5kZXgpXG4gICAgICAgICAgICAuY2xhc3NMaXN0LnJlbW92ZSgnaGlnaGxpZ2h0ZWQnKTtcbiAgICAgICAgbWlzc2luZ0NvdmVyYWdlRWxlbWVudHMuaXRlbShpbmRleCkuY2xhc3NMaXN0LmFkZCgnaGlnaGxpZ2h0ZWQnKTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBtYWtlQ3VycmVudChpbmRleCkge1xuICAgICAgICB0b2dnbGVDbGFzcyhpbmRleCk7XG4gICAgICAgIGN1cnJlbnRJbmRleCA9IGluZGV4O1xuICAgICAgICBtaXNzaW5nQ292ZXJhZ2VFbGVtZW50cy5pdGVtKGluZGV4KS5zY3JvbGxJbnRvVmlldyh7XG4gICAgICAgICAgICBiZWhhdmlvcjogJ3Ntb290aCcsXG4gICAgICAgICAgICBibG9jazogJ2NlbnRlcicsXG4gICAgICAgICAgICBpbmxpbmU6ICdjZW50ZXInXG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGdvVG9QcmV2aW91cygpIHtcbiAgICAgICAgdmFyIG5leHRJbmRleCA9IDA7XG4gICAgICAgIGlmICh0eXBlb2YgY3VycmVudEluZGV4ICE9PSAnbnVtYmVyJyB8fCBjdXJyZW50SW5kZXggPT09IDApIHtcbiAgICAgICAgICAgIG5leHRJbmRleCA9IG1pc3NpbmdDb3ZlcmFnZUVsZW1lbnRzLmxlbmd0aCAtIDE7XG4gICAgICAgIH0gZWxzZSBpZiAobWlzc2luZ0NvdmVyYWdlRWxlbWVudHMubGVuZ3RoID4gMSkge1xuICAgICAgICAgICAgbmV4dEluZGV4ID0gY3VycmVudEluZGV4IC0gMTtcbiAgICAgICAgfVxuXG4gICAgICAgIG1ha2VDdXJyZW50KG5leHRJbmRleCk7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gZ29Ub05leHQoKSB7XG4gICAgICAgIHZhciBuZXh0SW5kZXggPSAwO1xuXG4gICAgICAgIGlmIChcbiAgICAgICAgICAgIHR5cGVvZiBjdXJyZW50SW5kZXggPT09ICdudW1iZXInICYmXG4gICAgICAgICAgICBjdXJyZW50SW5kZXggPCBtaXNzaW5nQ292ZXJhZ2VFbGVtZW50cy5sZW5ndGggLSAxXG4gICAgICAgICkge1xuICAgICAgICAgICAgbmV4dEluZGV4ID0gY3VycmVudEluZGV4ICsgMTtcbiAgICAgICAgfVxuXG4gICAgICAgIG1ha2VDdXJyZW50KG5leHRJbmRleCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGZ1bmN0aW9uIGp1bXAoZXZlbnQpIHtcbiAgICAgICAgaWYgKFxuICAgICAgICAgICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2ZpbGVTZWFyY2gnKSA9PT0gZG9jdW1lbnQuYWN0aXZlRWxlbWVudCAmJlxuICAgICAgICAgICAgZG9jdW1lbnQuYWN0aXZlRWxlbWVudCAhPSBudWxsXG4gICAgICAgICkge1xuICAgICAgICAgICAgLy8gaWYgd2UncmUgY3VycmVudGx5IGZvY3VzZWQgb24gdGhlIHNlYXJjaCBpbnB1dCwgd2UgZG9uJ3Qgd2FudCB0byBuYXZpZ2F0ZVxuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgc3dpdGNoIChldmVudC53aGljaCkge1xuICAgICAgICAgICAgY2FzZSA3ODogLy8gblxuICAgICAgICAgICAgY2FzZSA3NDogLy8galxuICAgICAgICAgICAgICAgIGdvVG9OZXh0KCk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIDY2OiAvLyBiXG4gICAgICAgICAgICBjYXNlIDc1OiAvLyBrXG4gICAgICAgICAgICBjYXNlIDgwOiAvLyBwXG4gICAgICAgICAgICAgICAgZ29Ub1ByZXZpb3VzKCk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICB9O1xufSkoKTtcbndpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdrZXlkb3duJywganVtcFRvQ29kZSk7XG4iXX0=
|