@hasna/invoices 0.1.4 → 0.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/dist/cli/index.js +52 -8
- package/dist/db/invoices.d.ts.map +1 -1
- package/dist/index.js +61 -8
- package/dist/lib/version.d.ts +1 -1
- package/dist/mcp/index.js +50 -6
- package/dist/server/index.js +50 -6
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -2093,6 +2093,16 @@ function assertInvoiceStatus(status) {
|
|
|
2093
2093
|
throw new RangeError(`Invalid invoice status: ${String(status)}`);
|
|
2094
2094
|
}
|
|
2095
2095
|
}
|
|
2096
|
+
function assertPartyKind(kind) {
|
|
2097
|
+
if (!PARTY_KINDS.has(kind)) {
|
|
2098
|
+
throw new RangeError(`Invalid party kind: ${String(kind)}`);
|
|
2099
|
+
}
|
|
2100
|
+
}
|
|
2101
|
+
function assertNonBlankString(value, field) {
|
|
2102
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
2103
|
+
throw new TypeError(`${field} must not be blank`);
|
|
2104
|
+
}
|
|
2105
|
+
}
|
|
2096
2106
|
function assertSafeCents(value, field) {
|
|
2097
2107
|
if (!Number.isSafeInteger(value) || value < 0) {
|
|
2098
2108
|
throw new RangeError(`${field} must be a safe nonnegative integer`);
|
|
@@ -2210,14 +2220,27 @@ function mapInvoiceLineRow(row) {
|
|
|
2210
2220
|
};
|
|
2211
2221
|
}
|
|
2212
2222
|
function createParty(db, input) {
|
|
2213
|
-
const id = input.id
|
|
2223
|
+
const id = input.id;
|
|
2224
|
+
const kind = input.kind;
|
|
2225
|
+
const legalName = input.legalName;
|
|
2226
|
+
const email = input.email;
|
|
2227
|
+
const taxId = input.taxId;
|
|
2228
|
+
const country = input.country;
|
|
2229
|
+
const address = input.address;
|
|
2230
|
+
if (id !== undefined) {
|
|
2231
|
+
assertNonBlankString(id, "id");
|
|
2232
|
+
}
|
|
2233
|
+
assertPartyKind(kind);
|
|
2234
|
+
assertNonBlankString(legalName, "legalName");
|
|
2235
|
+
const partyId = id ?? randomUUID();
|
|
2214
2236
|
db.query(`
|
|
2215
2237
|
INSERT INTO parties (id, kind, legal_name, email, tax_id, country, address)
|
|
2216
2238
|
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)
|
|
2217
|
-
`).run(
|
|
2218
|
-
return getPartyById(db,
|
|
2239
|
+
`).run(partyId, kind, legalName, email ?? null, taxId ?? null, country ?? null, address ?? null);
|
|
2240
|
+
return getPartyById(db, partyId);
|
|
2219
2241
|
}
|
|
2220
2242
|
function getPartyById(db, id) {
|
|
2243
|
+
assertNonBlankString(id, "id");
|
|
2221
2244
|
const row = db.query("SELECT * FROM parties WHERE id = ?1").get(id);
|
|
2222
2245
|
return row ? mapPartyRow(row) : null;
|
|
2223
2246
|
}
|
|
@@ -2228,8 +2251,28 @@ function listParties(db, kind) {
|
|
|
2228
2251
|
return db.query("SELECT * FROM parties ORDER BY legal_name ASC").all().map(mapPartyRow);
|
|
2229
2252
|
}
|
|
2230
2253
|
function createInvoice(db, input) {
|
|
2231
|
-
const
|
|
2232
|
-
const
|
|
2254
|
+
const id = input.id;
|
|
2255
|
+
const number = input.number;
|
|
2256
|
+
const issuerId = input.issuerId;
|
|
2257
|
+
const customerId = input.customerId;
|
|
2258
|
+
const currency = input.currency;
|
|
2259
|
+
const notes = input.notes;
|
|
2260
|
+
const issuedAt = input.issuedAt;
|
|
2261
|
+
const dueAt = input.dueAt;
|
|
2262
|
+
const lines = input.lines;
|
|
2263
|
+
if (id !== undefined) {
|
|
2264
|
+
assertNonBlankString(id, "id");
|
|
2265
|
+
}
|
|
2266
|
+
assertNonBlankString(number, "number");
|
|
2267
|
+
assertNonBlankString(issuerId, "issuerId");
|
|
2268
|
+
assertNonBlankString(customerId, "customerId");
|
|
2269
|
+
assertNonBlankString(currency, "currency");
|
|
2270
|
+
assertNonBlankString(issuedAt, "issuedAt");
|
|
2271
|
+
if (dueAt !== undefined) {
|
|
2272
|
+
assertNonBlankString(dueAt, "dueAt");
|
|
2273
|
+
}
|
|
2274
|
+
const preparedLines = prepareInvoiceLines(lines);
|
|
2275
|
+
const invoiceId = id ?? randomUUID();
|
|
2233
2276
|
let subtotalCents = 0;
|
|
2234
2277
|
let taxCents = 0;
|
|
2235
2278
|
for (const line of preparedLines) {
|
|
@@ -2246,7 +2289,7 @@ INSERT INTO invoices (
|
|
|
2246
2289
|
id, number, issuer_id, customer_id, status, currency, notes, issued_at, due_at, subtotal_cents, tax_cents, total_cents
|
|
2247
2290
|
)
|
|
2248
2291
|
VALUES (?1, ?2, ?3, ?4, 'draft', ?5, ?6, ?7, ?8, ?9, ?10, ?11)
|
|
2249
|
-
`).run(invoiceId,
|
|
2292
|
+
`).run(invoiceId, number, issuerId, customerId, currency, notes ?? null, issuedAt, dueAt ?? null, subtotalCents, taxCents, totalCents);
|
|
2250
2293
|
const insertLine = db.query(`
|
|
2251
2294
|
INSERT INTO invoice_lines (
|
|
2252
2295
|
id, invoice_id, position, description, quantity, unit_price_cents, tax_rate_basis_points, line_total_cents
|
|
@@ -2310,9 +2353,10 @@ LIMIT ?2
|
|
|
2310
2353
|
OFFSET ?3
|
|
2311
2354
|
`).all(escapedPhrase, limit, offset).map(mapInvoiceRow);
|
|
2312
2355
|
}
|
|
2313
|
-
var INVOICE_STATUSES;
|
|
2356
|
+
var INVOICE_STATUSES, PARTY_KINDS;
|
|
2314
2357
|
var init_invoices = __esm(() => {
|
|
2315
2358
|
INVOICE_STATUSES = new Set(["draft", "sent", "partially_paid", "paid", "void", "overdue"]);
|
|
2359
|
+
PARTY_KINDS = new Set(["issuer", "customer"]);
|
|
2316
2360
|
});
|
|
2317
2361
|
|
|
2318
2362
|
// src/db/database.ts
|
|
@@ -2482,7 +2526,7 @@ function listAgents(db) {
|
|
|
2482
2526
|
}
|
|
2483
2527
|
|
|
2484
2528
|
// src/lib/version.ts
|
|
2485
|
-
var VERSION = "0.1.
|
|
2529
|
+
var VERSION = "0.1.5";
|
|
2486
2530
|
|
|
2487
2531
|
// src/cli/index.ts
|
|
2488
2532
|
init_database();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"invoices.d.ts","sourceRoot":"","sources":["../../src/db/invoices.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAG3C,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,QAAQ,GAAG,UAAU,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,QAAQ,GAAG,UAAU,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,OAAO,GAAG,MAAM,GAAG,gBAAgB,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IAC1E,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,gBAAiB,SAAQ,aAAa;IACrD,KAAK,EAAE,iBAAiB,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,mBAAmB,EAAE,CAAC;CAC9B;
|
|
1
|
+
{"version":3,"file":"invoices.d.ts","sourceRoot":"","sources":["../../src/db/invoices.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// src/lib/version.ts
|
|
3
|
-
var VERSION = "0.1.
|
|
3
|
+
var VERSION = "0.1.5";
|
|
4
4
|
// src/db/database.ts
|
|
5
5
|
import { mkdirSync } from "fs";
|
|
6
6
|
import { dirname, join } from "path";
|
|
@@ -206,6 +206,7 @@ function migrateDatabase(options = {}) {
|
|
|
206
206
|
// src/db/invoices.ts
|
|
207
207
|
import { randomUUID } from "crypto";
|
|
208
208
|
var INVOICE_STATUSES = new Set(["draft", "sent", "partially_paid", "paid", "void", "overdue"]);
|
|
209
|
+
var PARTY_KINDS = new Set(["issuer", "customer"]);
|
|
209
210
|
function normalizePagination(options, defaults) {
|
|
210
211
|
const limit = Number.isFinite(options.limit) ? Math.max(Math.trunc(options.limit), 0) : defaults.limit;
|
|
211
212
|
const offset = Number.isFinite(options.offset) ? Math.max(Math.trunc(options.offset), 0) : 0;
|
|
@@ -216,6 +217,16 @@ function assertInvoiceStatus(status) {
|
|
|
216
217
|
throw new RangeError(`Invalid invoice status: ${String(status)}`);
|
|
217
218
|
}
|
|
218
219
|
}
|
|
220
|
+
function assertPartyKind(kind) {
|
|
221
|
+
if (!PARTY_KINDS.has(kind)) {
|
|
222
|
+
throw new RangeError(`Invalid party kind: ${String(kind)}`);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
function assertNonBlankString(value, field) {
|
|
226
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
227
|
+
throw new TypeError(`${field} must not be blank`);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
219
230
|
function assertSafeCents(value, field) {
|
|
220
231
|
if (!Number.isSafeInteger(value) || value < 0) {
|
|
221
232
|
throw new RangeError(`${field} must be a safe nonnegative integer`);
|
|
@@ -333,14 +344,35 @@ function mapInvoiceLineRow(row) {
|
|
|
333
344
|
};
|
|
334
345
|
}
|
|
335
346
|
function createParty(db, input) {
|
|
336
|
-
const id = input.id
|
|
347
|
+
const id = input.id;
|
|
348
|
+
const kind = input.kind;
|
|
349
|
+
const legalName = input.legalName;
|
|
350
|
+
const email = input.email;
|
|
351
|
+
const taxId = input.taxId;
|
|
352
|
+
const country = input.country;
|
|
353
|
+
const address = input.address;
|
|
354
|
+
if (id !== undefined) {
|
|
355
|
+
assertNonBlankString(id, "id");
|
|
356
|
+
}
|
|
357
|
+
assertPartyKind(kind);
|
|
358
|
+
assertNonBlankString(legalName, "legalName");
|
|
359
|
+
const partyId = id ?? randomUUID();
|
|
337
360
|
db.query(`
|
|
338
361
|
INSERT INTO parties (id, kind, legal_name, email, tax_id, country, address)
|
|
339
362
|
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)
|
|
340
|
-
`).run(
|
|
341
|
-
return getPartyById(db,
|
|
363
|
+
`).run(partyId, kind, legalName, email ?? null, taxId ?? null, country ?? null, address ?? null);
|
|
364
|
+
return getPartyById(db, partyId);
|
|
342
365
|
}
|
|
343
366
|
function updateParty(db, id, updates) {
|
|
367
|
+
const legalName = updates.legalName;
|
|
368
|
+
const email = updates.email;
|
|
369
|
+
const taxId = updates.taxId;
|
|
370
|
+
const country = updates.country;
|
|
371
|
+
const address = updates.address;
|
|
372
|
+
assertNonBlankString(id, "id");
|
|
373
|
+
if (legalName !== undefined) {
|
|
374
|
+
assertNonBlankString(legalName, "legalName");
|
|
375
|
+
}
|
|
344
376
|
db.query(`
|
|
345
377
|
UPDATE parties
|
|
346
378
|
SET legal_name = COALESCE(?2, legal_name),
|
|
@@ -350,10 +382,11 @@ SET legal_name = COALESCE(?2, legal_name),
|
|
|
350
382
|
address = COALESCE(?6, address),
|
|
351
383
|
updated_at = datetime('now')
|
|
352
384
|
WHERE id = ?1
|
|
353
|
-
`).run(id,
|
|
385
|
+
`).run(id, legalName ?? null, email ?? null, taxId ?? null, country ?? null, address ?? null);
|
|
354
386
|
return getPartyById(db, id);
|
|
355
387
|
}
|
|
356
388
|
function getPartyById(db, id) {
|
|
389
|
+
assertNonBlankString(id, "id");
|
|
357
390
|
const row = db.query("SELECT * FROM parties WHERE id = ?1").get(id);
|
|
358
391
|
return row ? mapPartyRow(row) : null;
|
|
359
392
|
}
|
|
@@ -364,8 +397,28 @@ function listParties(db, kind) {
|
|
|
364
397
|
return db.query("SELECT * FROM parties ORDER BY legal_name ASC").all().map(mapPartyRow);
|
|
365
398
|
}
|
|
366
399
|
function createInvoice(db, input) {
|
|
367
|
-
const
|
|
368
|
-
const
|
|
400
|
+
const id = input.id;
|
|
401
|
+
const number = input.number;
|
|
402
|
+
const issuerId = input.issuerId;
|
|
403
|
+
const customerId = input.customerId;
|
|
404
|
+
const currency = input.currency;
|
|
405
|
+
const notes = input.notes;
|
|
406
|
+
const issuedAt = input.issuedAt;
|
|
407
|
+
const dueAt = input.dueAt;
|
|
408
|
+
const lines = input.lines;
|
|
409
|
+
if (id !== undefined) {
|
|
410
|
+
assertNonBlankString(id, "id");
|
|
411
|
+
}
|
|
412
|
+
assertNonBlankString(number, "number");
|
|
413
|
+
assertNonBlankString(issuerId, "issuerId");
|
|
414
|
+
assertNonBlankString(customerId, "customerId");
|
|
415
|
+
assertNonBlankString(currency, "currency");
|
|
416
|
+
assertNonBlankString(issuedAt, "issuedAt");
|
|
417
|
+
if (dueAt !== undefined) {
|
|
418
|
+
assertNonBlankString(dueAt, "dueAt");
|
|
419
|
+
}
|
|
420
|
+
const preparedLines = prepareInvoiceLines(lines);
|
|
421
|
+
const invoiceId = id ?? randomUUID();
|
|
369
422
|
let subtotalCents = 0;
|
|
370
423
|
let taxCents = 0;
|
|
371
424
|
for (const line of preparedLines) {
|
|
@@ -382,7 +435,7 @@ INSERT INTO invoices (
|
|
|
382
435
|
id, number, issuer_id, customer_id, status, currency, notes, issued_at, due_at, subtotal_cents, tax_cents, total_cents
|
|
383
436
|
)
|
|
384
437
|
VALUES (?1, ?2, ?3, ?4, 'draft', ?5, ?6, ?7, ?8, ?9, ?10, ?11)
|
|
385
|
-
`).run(invoiceId,
|
|
438
|
+
`).run(invoiceId, number, issuerId, customerId, currency, notes ?? null, issuedAt, dueAt ?? null, subtotalCents, taxCents, totalCents);
|
|
386
439
|
const insertLine = db.query(`
|
|
387
440
|
INSERT INTO invoice_lines (
|
|
388
441
|
id, invoice_id, position, description, quantity, unit_price_cents, tax_rate_basis_points, line_total_cents
|
package/dist/lib/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const VERSION = "0.1.
|
|
1
|
+
export declare const VERSION = "0.1.5";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/dist/mcp/index.js
CHANGED
|
@@ -4202,6 +4202,7 @@ function migrateDatabase(options = {}) {
|
|
|
4202
4202
|
// src/db/invoices.ts
|
|
4203
4203
|
import { randomUUID } from "crypto";
|
|
4204
4204
|
var INVOICE_STATUSES = new Set(["draft", "sent", "partially_paid", "paid", "void", "overdue"]);
|
|
4205
|
+
var PARTY_KINDS = new Set(["issuer", "customer"]);
|
|
4205
4206
|
function normalizePagination(options, defaults) {
|
|
4206
4207
|
const limit = Number.isFinite(options.limit) ? Math.max(Math.trunc(options.limit), 0) : defaults.limit;
|
|
4207
4208
|
const offset = Number.isFinite(options.offset) ? Math.max(Math.trunc(options.offset), 0) : 0;
|
|
@@ -4212,6 +4213,16 @@ function assertInvoiceStatus(status) {
|
|
|
4212
4213
|
throw new RangeError(`Invalid invoice status: ${String(status)}`);
|
|
4213
4214
|
}
|
|
4214
4215
|
}
|
|
4216
|
+
function assertPartyKind(kind) {
|
|
4217
|
+
if (!PARTY_KINDS.has(kind)) {
|
|
4218
|
+
throw new RangeError(`Invalid party kind: ${String(kind)}`);
|
|
4219
|
+
}
|
|
4220
|
+
}
|
|
4221
|
+
function assertNonBlankString(value, field) {
|
|
4222
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
4223
|
+
throw new TypeError(`${field} must not be blank`);
|
|
4224
|
+
}
|
|
4225
|
+
}
|
|
4215
4226
|
function assertSafeCents(value, field) {
|
|
4216
4227
|
if (!Number.isSafeInteger(value) || value < 0) {
|
|
4217
4228
|
throw new RangeError(`${field} must be a safe nonnegative integer`);
|
|
@@ -4329,14 +4340,27 @@ function mapInvoiceLineRow(row) {
|
|
|
4329
4340
|
};
|
|
4330
4341
|
}
|
|
4331
4342
|
function createParty(db, input) {
|
|
4332
|
-
const id = input.id
|
|
4343
|
+
const id = input.id;
|
|
4344
|
+
const kind = input.kind;
|
|
4345
|
+
const legalName = input.legalName;
|
|
4346
|
+
const email = input.email;
|
|
4347
|
+
const taxId = input.taxId;
|
|
4348
|
+
const country = input.country;
|
|
4349
|
+
const address = input.address;
|
|
4350
|
+
if (id !== undefined) {
|
|
4351
|
+
assertNonBlankString(id, "id");
|
|
4352
|
+
}
|
|
4353
|
+
assertPartyKind(kind);
|
|
4354
|
+
assertNonBlankString(legalName, "legalName");
|
|
4355
|
+
const partyId = id ?? randomUUID();
|
|
4333
4356
|
db.query(`
|
|
4334
4357
|
INSERT INTO parties (id, kind, legal_name, email, tax_id, country, address)
|
|
4335
4358
|
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)
|
|
4336
|
-
`).run(
|
|
4337
|
-
return getPartyById(db,
|
|
4359
|
+
`).run(partyId, kind, legalName, email ?? null, taxId ?? null, country ?? null, address ?? null);
|
|
4360
|
+
return getPartyById(db, partyId);
|
|
4338
4361
|
}
|
|
4339
4362
|
function getPartyById(db, id) {
|
|
4363
|
+
assertNonBlankString(id, "id");
|
|
4340
4364
|
const row = db.query("SELECT * FROM parties WHERE id = ?1").get(id);
|
|
4341
4365
|
return row ? mapPartyRow(row) : null;
|
|
4342
4366
|
}
|
|
@@ -4347,8 +4371,28 @@ function listParties(db, kind) {
|
|
|
4347
4371
|
return db.query("SELECT * FROM parties ORDER BY legal_name ASC").all().map(mapPartyRow);
|
|
4348
4372
|
}
|
|
4349
4373
|
function createInvoice(db, input) {
|
|
4350
|
-
const
|
|
4351
|
-
const
|
|
4374
|
+
const id = input.id;
|
|
4375
|
+
const number = input.number;
|
|
4376
|
+
const issuerId = input.issuerId;
|
|
4377
|
+
const customerId = input.customerId;
|
|
4378
|
+
const currency = input.currency;
|
|
4379
|
+
const notes = input.notes;
|
|
4380
|
+
const issuedAt = input.issuedAt;
|
|
4381
|
+
const dueAt = input.dueAt;
|
|
4382
|
+
const lines = input.lines;
|
|
4383
|
+
if (id !== undefined) {
|
|
4384
|
+
assertNonBlankString(id, "id");
|
|
4385
|
+
}
|
|
4386
|
+
assertNonBlankString(number, "number");
|
|
4387
|
+
assertNonBlankString(issuerId, "issuerId");
|
|
4388
|
+
assertNonBlankString(customerId, "customerId");
|
|
4389
|
+
assertNonBlankString(currency, "currency");
|
|
4390
|
+
assertNonBlankString(issuedAt, "issuedAt");
|
|
4391
|
+
if (dueAt !== undefined) {
|
|
4392
|
+
assertNonBlankString(dueAt, "dueAt");
|
|
4393
|
+
}
|
|
4394
|
+
const preparedLines = prepareInvoiceLines(lines);
|
|
4395
|
+
const invoiceId = id ?? randomUUID();
|
|
4352
4396
|
let subtotalCents = 0;
|
|
4353
4397
|
let taxCents = 0;
|
|
4354
4398
|
for (const line of preparedLines) {
|
|
@@ -4365,7 +4409,7 @@ INSERT INTO invoices (
|
|
|
4365
4409
|
id, number, issuer_id, customer_id, status, currency, notes, issued_at, due_at, subtotal_cents, tax_cents, total_cents
|
|
4366
4410
|
)
|
|
4367
4411
|
VALUES (?1, ?2, ?3, ?4, 'draft', ?5, ?6, ?7, ?8, ?9, ?10, ?11)
|
|
4368
|
-
`).run(invoiceId,
|
|
4412
|
+
`).run(invoiceId, number, issuerId, customerId, currency, notes ?? null, issuedAt, dueAt ?? null, subtotalCents, taxCents, totalCents);
|
|
4369
4413
|
const insertLine = db.query(`
|
|
4370
4414
|
INSERT INTO invoice_lines (
|
|
4371
4415
|
id, invoice_id, position, description, quantity, unit_price_cents, tax_rate_basis_points, line_total_cents
|
package/dist/server/index.js
CHANGED
|
@@ -4010,6 +4010,7 @@ function openInvoiceDatabase(options = {}) {
|
|
|
4010
4010
|
// src/db/invoices.ts
|
|
4011
4011
|
import { randomUUID } from "crypto";
|
|
4012
4012
|
var INVOICE_STATUSES = new Set(["draft", "sent", "partially_paid", "paid", "void", "overdue"]);
|
|
4013
|
+
var PARTY_KINDS = new Set(["issuer", "customer"]);
|
|
4013
4014
|
function normalizePagination(options, defaults) {
|
|
4014
4015
|
const limit = Number.isFinite(options.limit) ? Math.max(Math.trunc(options.limit), 0) : defaults.limit;
|
|
4015
4016
|
const offset = Number.isFinite(options.offset) ? Math.max(Math.trunc(options.offset), 0) : 0;
|
|
@@ -4020,6 +4021,16 @@ function assertInvoiceStatus(status) {
|
|
|
4020
4021
|
throw new RangeError(`Invalid invoice status: ${String(status)}`);
|
|
4021
4022
|
}
|
|
4022
4023
|
}
|
|
4024
|
+
function assertPartyKind(kind) {
|
|
4025
|
+
if (!PARTY_KINDS.has(kind)) {
|
|
4026
|
+
throw new RangeError(`Invalid party kind: ${String(kind)}`);
|
|
4027
|
+
}
|
|
4028
|
+
}
|
|
4029
|
+
function assertNonBlankString(value, field) {
|
|
4030
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
4031
|
+
throw new TypeError(`${field} must not be blank`);
|
|
4032
|
+
}
|
|
4033
|
+
}
|
|
4023
4034
|
function assertSafeCents(value, field) {
|
|
4024
4035
|
if (!Number.isSafeInteger(value) || value < 0) {
|
|
4025
4036
|
throw new RangeError(`${field} must be a safe nonnegative integer`);
|
|
@@ -4137,14 +4148,27 @@ function mapInvoiceLineRow(row) {
|
|
|
4137
4148
|
};
|
|
4138
4149
|
}
|
|
4139
4150
|
function createParty(db, input) {
|
|
4140
|
-
const id = input.id
|
|
4151
|
+
const id = input.id;
|
|
4152
|
+
const kind = input.kind;
|
|
4153
|
+
const legalName = input.legalName;
|
|
4154
|
+
const email = input.email;
|
|
4155
|
+
const taxId = input.taxId;
|
|
4156
|
+
const country = input.country;
|
|
4157
|
+
const address = input.address;
|
|
4158
|
+
if (id !== undefined) {
|
|
4159
|
+
assertNonBlankString(id, "id");
|
|
4160
|
+
}
|
|
4161
|
+
assertPartyKind(kind);
|
|
4162
|
+
assertNonBlankString(legalName, "legalName");
|
|
4163
|
+
const partyId = id ?? randomUUID();
|
|
4141
4164
|
db.query(`
|
|
4142
4165
|
INSERT INTO parties (id, kind, legal_name, email, tax_id, country, address)
|
|
4143
4166
|
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)
|
|
4144
|
-
`).run(
|
|
4145
|
-
return getPartyById(db,
|
|
4167
|
+
`).run(partyId, kind, legalName, email ?? null, taxId ?? null, country ?? null, address ?? null);
|
|
4168
|
+
return getPartyById(db, partyId);
|
|
4146
4169
|
}
|
|
4147
4170
|
function getPartyById(db, id) {
|
|
4171
|
+
assertNonBlankString(id, "id");
|
|
4148
4172
|
const row = db.query("SELECT * FROM parties WHERE id = ?1").get(id);
|
|
4149
4173
|
return row ? mapPartyRow(row) : null;
|
|
4150
4174
|
}
|
|
@@ -4155,8 +4179,28 @@ function listParties(db, kind) {
|
|
|
4155
4179
|
return db.query("SELECT * FROM parties ORDER BY legal_name ASC").all().map(mapPartyRow);
|
|
4156
4180
|
}
|
|
4157
4181
|
function createInvoice(db, input) {
|
|
4158
|
-
const
|
|
4159
|
-
const
|
|
4182
|
+
const id = input.id;
|
|
4183
|
+
const number = input.number;
|
|
4184
|
+
const issuerId = input.issuerId;
|
|
4185
|
+
const customerId = input.customerId;
|
|
4186
|
+
const currency = input.currency;
|
|
4187
|
+
const notes = input.notes;
|
|
4188
|
+
const issuedAt = input.issuedAt;
|
|
4189
|
+
const dueAt = input.dueAt;
|
|
4190
|
+
const lines = input.lines;
|
|
4191
|
+
if (id !== undefined) {
|
|
4192
|
+
assertNonBlankString(id, "id");
|
|
4193
|
+
}
|
|
4194
|
+
assertNonBlankString(number, "number");
|
|
4195
|
+
assertNonBlankString(issuerId, "issuerId");
|
|
4196
|
+
assertNonBlankString(customerId, "customerId");
|
|
4197
|
+
assertNonBlankString(currency, "currency");
|
|
4198
|
+
assertNonBlankString(issuedAt, "issuedAt");
|
|
4199
|
+
if (dueAt !== undefined) {
|
|
4200
|
+
assertNonBlankString(dueAt, "dueAt");
|
|
4201
|
+
}
|
|
4202
|
+
const preparedLines = prepareInvoiceLines(lines);
|
|
4203
|
+
const invoiceId = id ?? randomUUID();
|
|
4160
4204
|
let subtotalCents = 0;
|
|
4161
4205
|
let taxCents = 0;
|
|
4162
4206
|
for (const line of preparedLines) {
|
|
@@ -4173,7 +4217,7 @@ INSERT INTO invoices (
|
|
|
4173
4217
|
id, number, issuer_id, customer_id, status, currency, notes, issued_at, due_at, subtotal_cents, tax_cents, total_cents
|
|
4174
4218
|
)
|
|
4175
4219
|
VALUES (?1, ?2, ?3, ?4, 'draft', ?5, ?6, ?7, ?8, ?9, ?10, ?11)
|
|
4176
|
-
`).run(invoiceId,
|
|
4220
|
+
`).run(invoiceId, number, issuerId, customerId, currency, notes ?? null, issuedAt, dueAt ?? null, subtotalCents, taxCents, totalCents);
|
|
4177
4221
|
const insertLine = db.query(`
|
|
4178
4222
|
INSERT INTO invoice_lines (
|
|
4179
4223
|
id, invoice_id, position, description, quantity, unit_price_cents, tax_rate_basis_points, line_total_cents
|