@voyantjs/finance 0.3.0 → 0.4.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/index.d.ts +18 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +25 -5
- package/dist/routes-documents.d.ts +159 -0
- package/dist/routes-documents.d.ts.map +1 -0
- package/dist/routes-documents.js +35 -0
- package/dist/routes-public.d.ts +517 -0
- package/dist/routes-public.d.ts.map +1 -0
- package/dist/routes-public.js +60 -0
- package/dist/routes-settlement.d.ts +63 -0
- package/dist/routes-settlement.d.ts.map +1 -0
- package/dist/routes-settlement.js +18 -0
- package/dist/routes-shared.d.ts +12 -0
- package/dist/routes-shared.d.ts.map +1 -0
- package/dist/routes-shared.js +3 -0
- package/dist/routes.d.ts +207 -161
- package/dist/routes.d.ts.map +1 -1
- package/dist/routes.js +40 -1
- package/dist/schema.d.ts +17 -17
- package/dist/service-documents.d.ts +67 -0
- package/dist/service-documents.d.ts.map +1 -0
- package/dist/service-documents.js +226 -0
- package/dist/service-public.d.ts +251 -0
- package/dist/service-public.d.ts.map +1 -0
- package/dist/service-public.js +418 -0
- package/dist/service-settlement.d.ts +36 -0
- package/dist/service-settlement.d.ts.map +1 -0
- package/dist/service-settlement.js +172 -0
- package/dist/service.d.ts +175 -181
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +54 -67
- package/dist/validation-billing.d.ts +119 -9
- package/dist/validation-billing.d.ts.map +1 -1
- package/dist/validation-billing.js +54 -1
- package/dist/validation-payments.d.ts +83 -83
- package/dist/validation-public.d.ts +443 -0
- package/dist/validation-public.d.ts.map +1 -0
- package/dist/validation-public.js +183 -0
- package/dist/validation-shared.d.ts +24 -24
- package/dist/validation.d.ts +1 -0
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +1 -0
- package/package.json +15 -5
package/dist/routes.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AAC7D,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAA;AAkE7C,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6CA0/BtB,CAAA;AAEJ,MAAM,MAAM,aAAa,GAAG,OAAO,aAAa,CAAA;AAChD,MAAM,MAAM,mBAAmB,GAAG,OAAO,mBAAmB,CAAA"}
|
package/dist/routes.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Hono } from "hono";
|
|
2
2
|
import { financeService } from "./service.js";
|
|
3
|
-
import { agingReportQuerySchema, applyDefaultBookingPaymentPlanSchema, cancelPaymentSessionSchema, completePaymentSessionSchema, createPaymentSessionFromGuaranteeSchema, createPaymentSessionFromInvoiceSchema, createPaymentSessionFromScheduleSchema, expirePaymentSessionSchema, failPaymentSessionSchema, insertBookingGuaranteeSchema, insertBookingItemCommissionSchema, insertBookingItemTaxLineSchema, insertBookingPaymentScheduleSchema, insertCreditNoteLineItemSchema, insertCreditNoteSchema, insertFinanceNoteSchema, insertInvoiceExternalRefSchema, insertInvoiceLineItemSchema, insertInvoiceNumberSeriesSchema, insertInvoiceSchema, insertInvoiceTemplateSchema, insertPaymentAuthorizationSchema, insertPaymentCaptureSchema, insertPaymentInstrumentSchema, insertPaymentSchema, insertPaymentSessionSchema, insertSupplierPaymentSchema, insertTaxRegimeSchema, invoiceListQuerySchema, invoiceNumberSeriesListQuerySchema, invoiceTemplateListQuerySchema, markPaymentSessionRequiresRedirectSchema, paymentAuthorizationListQuerySchema, paymentCaptureListQuerySchema, paymentInstrumentListQuerySchema, paymentSessionListQuerySchema, profitabilityQuerySchema, renderInvoiceInputSchema, revenueReportQuerySchema, supplierPaymentListQuerySchema, taxRegimeListQuerySchema, updateBookingGuaranteeSchema, updateBookingItemCommissionSchema, updateBookingItemTaxLineSchema, updateBookingPaymentScheduleSchema, updateCreditNoteSchema, updateInvoiceLineItemSchema, updateInvoiceNumberSeriesSchema, updateInvoiceSchema, updateInvoiceTemplateSchema, updatePaymentAuthorizationSchema, updatePaymentCaptureSchema, updatePaymentInstrumentSchema, updatePaymentSessionSchema, updateSupplierPaymentSchema, updateTaxRegimeSchema, } from "./validation.js";
|
|
3
|
+
import { agingReportQuerySchema, applyDefaultBookingPaymentPlanSchema, cancelPaymentSessionSchema, completePaymentSessionSchema, createPaymentSessionFromGuaranteeSchema, createPaymentSessionFromInvoiceSchema, createPaymentSessionFromScheduleSchema, expirePaymentSessionSchema, failPaymentSessionSchema, insertBookingGuaranteeSchema, insertBookingItemCommissionSchema, insertBookingItemTaxLineSchema, insertBookingPaymentScheduleSchema, insertCreditNoteLineItemSchema, insertCreditNoteSchema, insertFinanceNoteSchema, insertInvoiceExternalRefSchema, insertInvoiceLineItemSchema, insertInvoiceNumberSeriesSchema, insertInvoiceSchema, insertInvoiceTemplateSchema, insertPaymentAuthorizationSchema, insertPaymentCaptureSchema, insertPaymentInstrumentSchema, insertPaymentSchema, insertPaymentSessionSchema, insertSupplierPaymentSchema, insertTaxRegimeSchema, invoiceFromBookingSchema, invoiceListQuerySchema, invoiceNumberSeriesListQuerySchema, invoiceTemplateListQuerySchema, markPaymentSessionRequiresRedirectSchema, paymentAuthorizationListQuerySchema, paymentCaptureListQuerySchema, paymentInstrumentListQuerySchema, paymentSessionListQuerySchema, profitabilityQuerySchema, renderInvoiceInputSchema, revenueReportQuerySchema, supplierPaymentListQuerySchema, taxRegimeListQuerySchema, updateBookingGuaranteeSchema, updateBookingItemCommissionSchema, updateBookingItemTaxLineSchema, updateBookingPaymentScheduleSchema, updateCreditNoteSchema, updateInvoiceLineItemSchema, updateInvoiceNumberSeriesSchema, updateInvoiceSchema, updateInvoiceTemplateSchema, updatePaymentAuthorizationSchema, updatePaymentCaptureSchema, updatePaymentInstrumentSchema, updatePaymentSessionSchema, updateSupplierPaymentSchema, updateTaxRegimeSchema, } from "./validation.js";
|
|
4
4
|
// ==========================================================================
|
|
5
5
|
// Finance Routes — method-chained for Hono RPC type inference
|
|
6
6
|
// ==========================================================================
|
|
@@ -351,6 +351,45 @@ export const financeRoutes = new Hono()
|
|
|
351
351
|
return c.json({
|
|
352
352
|
data: await financeService.createInvoice(c.get("db"), insertInvoiceSchema.parse(await c.req.json())),
|
|
353
353
|
}, 201);
|
|
354
|
+
})
|
|
355
|
+
// POST /invoices/from-booking — Create draft invoice from booking + booking items
|
|
356
|
+
.post("/invoices/from-booking", async (c) => {
|
|
357
|
+
const input = invoiceFromBookingSchema.parse(await c.req.json());
|
|
358
|
+
const db = c.get("db");
|
|
359
|
+
const [{ bookingItems, bookings }, { eq }] = await Promise.all([
|
|
360
|
+
import("@voyantjs/bookings/schema"),
|
|
361
|
+
import("drizzle-orm"),
|
|
362
|
+
]);
|
|
363
|
+
const [booking] = await db
|
|
364
|
+
.select()
|
|
365
|
+
.from(bookings)
|
|
366
|
+
.where(eq(bookings.id, input.bookingId))
|
|
367
|
+
.limit(1);
|
|
368
|
+
if (!booking) {
|
|
369
|
+
return c.json({ error: "Booking not found" }, 404);
|
|
370
|
+
}
|
|
371
|
+
const items = await db.select().from(bookingItems).where(eq(bookingItems.bookingId, booking.id));
|
|
372
|
+
const row = await financeService.createInvoiceFromBooking(db, input, {
|
|
373
|
+
booking: {
|
|
374
|
+
id: booking.id,
|
|
375
|
+
bookingNumber: booking.bookingNumber,
|
|
376
|
+
personId: booking.personId,
|
|
377
|
+
organizationId: booking.organizationId,
|
|
378
|
+
sellCurrency: booking.sellCurrency,
|
|
379
|
+
baseCurrency: booking.baseCurrency,
|
|
380
|
+
fxRateSetId: null,
|
|
381
|
+
sellAmountCents: booking.sellAmountCents,
|
|
382
|
+
baseSellAmountCents: booking.baseSellAmountCents,
|
|
383
|
+
},
|
|
384
|
+
items: items.map((item) => ({
|
|
385
|
+
id: item.id,
|
|
386
|
+
title: item.title,
|
|
387
|
+
quantity: item.quantity,
|
|
388
|
+
unitSellAmountCents: item.unitSellAmountCents,
|
|
389
|
+
totalSellAmountCents: item.totalSellAmountCents,
|
|
390
|
+
})),
|
|
391
|
+
});
|
|
392
|
+
return c.json({ data: row }, 201);
|
|
354
393
|
})
|
|
355
394
|
// GET /invoices/:id — Get single invoice
|
|
356
395
|
.get("/invoices/:id", async (c) => {
|
package/dist/schema.d.ts
CHANGED
|
@@ -136,7 +136,7 @@ export declare const paymentInstruments: import("drizzle-orm/pg-core").PgTableWi
|
|
|
136
136
|
tableName: "payment_instruments";
|
|
137
137
|
dataType: "string";
|
|
138
138
|
columnType: "PgEnumColumn";
|
|
139
|
-
data: "
|
|
139
|
+
data: "other" | "voucher" | "wallet" | "credit_card" | "debit_card" | "cash" | "direct_bill" | "bank_account";
|
|
140
140
|
driverParam: string;
|
|
141
141
|
notNull: true;
|
|
142
142
|
hasDefault: false;
|
|
@@ -153,7 +153,7 @@ export declare const paymentInstruments: import("drizzle-orm/pg-core").PgTableWi
|
|
|
153
153
|
tableName: "payment_instruments";
|
|
154
154
|
dataType: "string";
|
|
155
155
|
columnType: "PgEnumColumn";
|
|
156
|
-
data: "expired" | "
|
|
156
|
+
data: "expired" | "revoked" | "active" | "inactive" | "failed_verification";
|
|
157
157
|
driverParam: string;
|
|
158
158
|
notNull: true;
|
|
159
159
|
hasDefault: true;
|
|
@@ -655,7 +655,7 @@ export declare const paymentSessions: import("drizzle-orm/pg-core").PgTableWithC
|
|
|
655
655
|
tableName: "payment_sessions";
|
|
656
656
|
dataType: "string";
|
|
657
657
|
columnType: "PgEnumColumn";
|
|
658
|
-
data: "
|
|
658
|
+
data: "expired" | "cancelled" | "pending" | "failed" | "paid" | "requires_redirect" | "processing" | "authorized";
|
|
659
659
|
driverParam: string;
|
|
660
660
|
notNull: true;
|
|
661
661
|
hasDefault: true;
|
|
@@ -808,7 +808,7 @@ export declare const paymentSessions: import("drizzle-orm/pg-core").PgTableWithC
|
|
|
808
808
|
tableName: "payment_sessions";
|
|
809
809
|
dataType: "string";
|
|
810
810
|
columnType: "PgEnumColumn";
|
|
811
|
-
data: "
|
|
811
|
+
data: "other" | "voucher" | "wallet" | "bank_transfer" | "credit_card" | "debit_card" | "cash" | "cheque" | "direct_bill";
|
|
812
812
|
driverParam: string;
|
|
813
813
|
notNull: false;
|
|
814
814
|
hasDefault: false;
|
|
@@ -1280,7 +1280,7 @@ export declare const paymentAuthorizations: import("drizzle-orm/pg-core").PgTabl
|
|
|
1280
1280
|
tableName: "payment_authorizations";
|
|
1281
1281
|
dataType: "string";
|
|
1282
1282
|
columnType: "PgEnumColumn";
|
|
1283
|
-
data: "
|
|
1283
|
+
data: "expired" | "pending" | "failed" | "authorized" | "partially_captured" | "captured" | "voided";
|
|
1284
1284
|
driverParam: string;
|
|
1285
1285
|
notNull: true;
|
|
1286
1286
|
hasDefault: true;
|
|
@@ -1297,7 +1297,7 @@ export declare const paymentAuthorizations: import("drizzle-orm/pg-core").PgTabl
|
|
|
1297
1297
|
tableName: "payment_authorizations";
|
|
1298
1298
|
dataType: "string";
|
|
1299
1299
|
columnType: "PgEnumColumn";
|
|
1300
|
-
data: "
|
|
1300
|
+
data: "manual" | "automatic";
|
|
1301
1301
|
driverParam: string;
|
|
1302
1302
|
notNull: true;
|
|
1303
1303
|
hasDefault: true;
|
|
@@ -1561,7 +1561,7 @@ export declare const paymentCaptures: import("drizzle-orm/pg-core").PgTableWithC
|
|
|
1561
1561
|
tableName: "payment_captures";
|
|
1562
1562
|
dataType: "string";
|
|
1563
1563
|
columnType: "PgEnumColumn";
|
|
1564
|
-
data: "
|
|
1564
|
+
data: "completed" | "pending" | "failed" | "refunded" | "voided";
|
|
1565
1565
|
driverParam: string;
|
|
1566
1566
|
notNull: true;
|
|
1567
1567
|
hasDefault: true;
|
|
@@ -1808,7 +1808,7 @@ export declare const bookingPaymentSchedules: import("drizzle-orm/pg-core").PgTa
|
|
|
1808
1808
|
tableName: "booking_payment_schedules";
|
|
1809
1809
|
dataType: "string";
|
|
1810
1810
|
columnType: "PgEnumColumn";
|
|
1811
|
-
data: "
|
|
1811
|
+
data: "expired" | "cancelled" | "pending" | "paid" | "due" | "waived";
|
|
1812
1812
|
driverParam: string;
|
|
1813
1813
|
notNull: true;
|
|
1814
1814
|
hasDefault: true;
|
|
@@ -2004,7 +2004,7 @@ export declare const bookingGuarantees: import("drizzle-orm/pg-core").PgTableWit
|
|
|
2004
2004
|
tableName: "booking_guarantees";
|
|
2005
2005
|
dataType: "string";
|
|
2006
2006
|
columnType: "PgEnumColumn";
|
|
2007
|
-
data: "
|
|
2007
|
+
data: "other" | "voucher" | "bank_transfer" | "credit_card" | "deposit" | "preauth" | "card_on_file" | "agency_letter";
|
|
2008
2008
|
driverParam: string;
|
|
2009
2009
|
notNull: true;
|
|
2010
2010
|
hasDefault: false;
|
|
@@ -2021,7 +2021,7 @@ export declare const bookingGuarantees: import("drizzle-orm/pg-core").PgTableWit
|
|
|
2021
2021
|
tableName: "booking_guarantees";
|
|
2022
2022
|
dataType: "string";
|
|
2023
2023
|
columnType: "PgEnumColumn";
|
|
2024
|
-
data: "
|
|
2024
|
+
data: "expired" | "cancelled" | "pending" | "released" | "failed" | "active";
|
|
2025
2025
|
driverParam: string;
|
|
2026
2026
|
notNull: true;
|
|
2027
2027
|
hasDefault: true;
|
|
@@ -2549,7 +2549,7 @@ export declare const bookingItemCommissions: import("drizzle-orm/pg-core").PgTab
|
|
|
2549
2549
|
tableName: "booking_item_commissions";
|
|
2550
2550
|
dataType: "string";
|
|
2551
2551
|
columnType: "PgEnumColumn";
|
|
2552
|
-
data: "internal" | "supplier" | "other" | "
|
|
2552
|
+
data: "internal" | "supplier" | "other" | "affiliate" | "channel" | "agency" | "agent";
|
|
2553
2553
|
driverParam: string;
|
|
2554
2554
|
notNull: true;
|
|
2555
2555
|
hasDefault: false;
|
|
@@ -2634,7 +2634,7 @@ export declare const bookingItemCommissions: import("drizzle-orm/pg-core").PgTab
|
|
|
2634
2634
|
tableName: "booking_item_commissions";
|
|
2635
2635
|
dataType: "string";
|
|
2636
2636
|
columnType: "PgEnumColumn";
|
|
2637
|
-
data: "
|
|
2637
|
+
data: "pending" | "paid" | "void" | "accrued" | "payable";
|
|
2638
2638
|
driverParam: string;
|
|
2639
2639
|
notNull: true;
|
|
2640
2640
|
hasDefault: true;
|
|
@@ -3596,7 +3596,7 @@ export declare const payments: import("drizzle-orm/pg-core").PgTableWithColumns<
|
|
|
3596
3596
|
tableName: "payments";
|
|
3597
3597
|
dataType: "string";
|
|
3598
3598
|
columnType: "PgEnumColumn";
|
|
3599
|
-
data: "
|
|
3599
|
+
data: "other" | "voucher" | "wallet" | "bank_transfer" | "credit_card" | "debit_card" | "cash" | "cheque" | "direct_bill";
|
|
3600
3600
|
driverParam: string;
|
|
3601
3601
|
notNull: true;
|
|
3602
3602
|
hasDefault: false;
|
|
@@ -3664,7 +3664,7 @@ export declare const payments: import("drizzle-orm/pg-core").PgTableWithColumns<
|
|
|
3664
3664
|
tableName: "payments";
|
|
3665
3665
|
dataType: "string";
|
|
3666
3666
|
columnType: "PgEnumColumn";
|
|
3667
|
-
data: "
|
|
3667
|
+
data: "completed" | "pending" | "failed" | "refunded";
|
|
3668
3668
|
driverParam: string;
|
|
3669
3669
|
notNull: true;
|
|
3670
3670
|
hasDefault: true;
|
|
@@ -4303,7 +4303,7 @@ export declare const supplierPayments: import("drizzle-orm/pg-core").PgTableWith
|
|
|
4303
4303
|
tableName: "supplier_payments";
|
|
4304
4304
|
dataType: "string";
|
|
4305
4305
|
columnType: "PgEnumColumn";
|
|
4306
|
-
data: "
|
|
4306
|
+
data: "other" | "voucher" | "wallet" | "bank_transfer" | "credit_card" | "debit_card" | "cash" | "cheque" | "direct_bill";
|
|
4307
4307
|
driverParam: string;
|
|
4308
4308
|
notNull: true;
|
|
4309
4309
|
hasDefault: false;
|
|
@@ -4337,7 +4337,7 @@ export declare const supplierPayments: import("drizzle-orm/pg-core").PgTableWith
|
|
|
4337
4337
|
tableName: "supplier_payments";
|
|
4338
4338
|
dataType: "string";
|
|
4339
4339
|
columnType: "PgEnumColumn";
|
|
4340
|
-
data: "
|
|
4340
|
+
data: "completed" | "pending" | "failed" | "refunded";
|
|
4341
4341
|
driverParam: string;
|
|
4342
4342
|
notNull: true;
|
|
4343
4343
|
hasDefault: true;
|
|
@@ -5053,7 +5053,7 @@ export declare const invoiceRenditions: import("drizzle-orm/pg-core").PgTableWit
|
|
|
5053
5053
|
tableName: "invoice_renditions";
|
|
5054
5054
|
dataType: "string";
|
|
5055
5055
|
columnType: "PgEnumColumn";
|
|
5056
|
-
data: "
|
|
5056
|
+
data: "json" | "pdf" | "html" | "xml";
|
|
5057
5057
|
driverParam: string;
|
|
5058
5058
|
notNull: true;
|
|
5059
5059
|
hasDefault: true;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { StorageProvider, StorageUploadBody } from "@voyantjs/voyant-storage";
|
|
2
|
+
import type { PostgresJsDatabase } from "drizzle-orm/postgres-js";
|
|
3
|
+
import { type invoiceLineItems, type invoiceRenditions, type invoices, invoiceTemplates, type payments } from "./schema.js";
|
|
4
|
+
import type { GenerateInvoiceDocumentInput } from "./validation.js";
|
|
5
|
+
export interface GeneratedInvoiceRenditionArtifact {
|
|
6
|
+
format?: "html" | "pdf" | "xml" | "json";
|
|
7
|
+
storageKey?: string | null;
|
|
8
|
+
fileSize?: number | null;
|
|
9
|
+
checksum?: string | null;
|
|
10
|
+
language?: string | null;
|
|
11
|
+
metadata?: Record<string, unknown> | null;
|
|
12
|
+
}
|
|
13
|
+
export interface InvoiceDocumentGeneratorContext {
|
|
14
|
+
db: PostgresJsDatabase;
|
|
15
|
+
invoice: typeof invoices.$inferSelect;
|
|
16
|
+
template: typeof invoiceTemplates.$inferSelect | null;
|
|
17
|
+
lineItems: Array<typeof invoiceLineItems.$inferSelect>;
|
|
18
|
+
payments: Array<typeof payments.$inferSelect>;
|
|
19
|
+
renderedBody: string;
|
|
20
|
+
renderedBodyFormat: "html" | "markdown" | "lexical_json";
|
|
21
|
+
variables: Record<string, unknown>;
|
|
22
|
+
bindings: Record<string, unknown>;
|
|
23
|
+
targetFormat: "html" | "pdf" | "xml" | "json";
|
|
24
|
+
language: string | null;
|
|
25
|
+
}
|
|
26
|
+
export type InvoiceDocumentGenerator = (context: InvoiceDocumentGeneratorContext) => Promise<GeneratedInvoiceRenditionArtifact>;
|
|
27
|
+
export interface InvoiceDocumentRuntimeOptions {
|
|
28
|
+
bindings?: Record<string, unknown>;
|
|
29
|
+
generator: InvoiceDocumentGenerator;
|
|
30
|
+
}
|
|
31
|
+
export interface StorageBackedInvoiceDocumentUpload {
|
|
32
|
+
body: StorageUploadBody;
|
|
33
|
+
format?: "html" | "pdf" | "xml" | "json";
|
|
34
|
+
key?: string | null;
|
|
35
|
+
metadata?: Record<string, unknown> | null;
|
|
36
|
+
language?: string | null;
|
|
37
|
+
}
|
|
38
|
+
export type StorageBackedInvoiceDocumentSerializer = (context: InvoiceDocumentGeneratorContext) => Promise<StorageBackedInvoiceDocumentUpload> | StorageBackedInvoiceDocumentUpload;
|
|
39
|
+
export interface StorageBackedInvoiceDocumentGeneratorOptions {
|
|
40
|
+
storage: StorageProvider;
|
|
41
|
+
keyPrefix?: string | ((context: InvoiceDocumentGeneratorContext) => Promise<string> | string);
|
|
42
|
+
serializer?: StorageBackedInvoiceDocumentSerializer;
|
|
43
|
+
signedUrlExpiresIn?: number;
|
|
44
|
+
}
|
|
45
|
+
export interface GeneratedInvoiceDocumentRecord {
|
|
46
|
+
invoiceId: string;
|
|
47
|
+
renderedBodyFormat: "html" | "markdown" | "lexical_json";
|
|
48
|
+
renderedBody: string;
|
|
49
|
+
rendition: typeof invoiceRenditions.$inferSelect;
|
|
50
|
+
}
|
|
51
|
+
export declare function defaultStorageBackedInvoiceDocumentSerializer(context: InvoiceDocumentGeneratorContext): Promise<StorageBackedInvoiceDocumentUpload> | StorageBackedInvoiceDocumentUpload;
|
|
52
|
+
export declare function defaultPdfInvoiceDocumentSerializer(context: InvoiceDocumentGeneratorContext): Promise<StorageBackedInvoiceDocumentUpload>;
|
|
53
|
+
export declare function createStorageBackedInvoiceDocumentGenerator(options: StorageBackedInvoiceDocumentGeneratorOptions): InvoiceDocumentGenerator;
|
|
54
|
+
export declare function createPdfInvoiceDocumentGenerator(options: Omit<StorageBackedInvoiceDocumentGeneratorOptions, "serializer">): InvoiceDocumentGenerator;
|
|
55
|
+
export declare const financeDocumentsService: {
|
|
56
|
+
generateInvoiceDocument(db: PostgresJsDatabase, invoiceId: string, input: GenerateInvoiceDocumentInput, runtime: InvoiceDocumentRuntimeOptions): Promise<{
|
|
57
|
+
status: "not_found" | "generator_failed";
|
|
58
|
+
} | ({
|
|
59
|
+
status: "generated";
|
|
60
|
+
} & GeneratedInvoiceDocumentRecord)>;
|
|
61
|
+
regenerateInvoiceDocument(db: PostgresJsDatabase, invoiceId: string, input: GenerateInvoiceDocumentInput, runtime: InvoiceDocumentRuntimeOptions): Promise<{
|
|
62
|
+
status: "not_found" | "generator_failed";
|
|
63
|
+
} | ({
|
|
64
|
+
status: "generated";
|
|
65
|
+
} & GeneratedInvoiceDocumentRecord)>;
|
|
66
|
+
};
|
|
67
|
+
//# sourceMappingURL=service-documents.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service-documents.d.ts","sourceRoot":"","sources":["../src/service-documents.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { renderPdfDocument } from "@voyantjs/utils/pdf-renderer";
|
|
2
|
+
import { and, desc, eq } from "drizzle-orm";
|
|
3
|
+
import { invoiceTemplates, } from "./schema.js";
|
|
4
|
+
import { financeService, renderInvoiceBody } from "./service.js";
|
|
5
|
+
function defaultInvoiceDocumentMimeType(format) {
|
|
6
|
+
switch (format) {
|
|
7
|
+
case "html":
|
|
8
|
+
return "text/html; charset=utf-8";
|
|
9
|
+
case "json":
|
|
10
|
+
return "application/json; charset=utf-8";
|
|
11
|
+
case "xml":
|
|
12
|
+
return "application/xml; charset=utf-8";
|
|
13
|
+
default:
|
|
14
|
+
return "application/pdf";
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
function encodeStringBody(value) {
|
|
18
|
+
return new TextEncoder().encode(value);
|
|
19
|
+
}
|
|
20
|
+
function getBodySize(body) {
|
|
21
|
+
if (body instanceof Uint8Array)
|
|
22
|
+
return body.byteLength;
|
|
23
|
+
if (body instanceof ArrayBuffer)
|
|
24
|
+
return body.byteLength;
|
|
25
|
+
return body.size;
|
|
26
|
+
}
|
|
27
|
+
function toUploadMetadata(metadata) {
|
|
28
|
+
const entries = Object.entries(metadata ?? {}).filter(([, value]) => ["string", "number", "boolean"].includes(typeof value));
|
|
29
|
+
return entries.length > 0
|
|
30
|
+
? Object.fromEntries(entries.map(([key, value]) => [key, String(value)]))
|
|
31
|
+
: undefined;
|
|
32
|
+
}
|
|
33
|
+
export function defaultStorageBackedInvoiceDocumentSerializer(context) {
|
|
34
|
+
switch (context.targetFormat) {
|
|
35
|
+
case "html":
|
|
36
|
+
return {
|
|
37
|
+
body: encodeStringBody(context.renderedBody),
|
|
38
|
+
format: "html",
|
|
39
|
+
language: context.language,
|
|
40
|
+
metadata: { renderedBodyFormat: context.renderedBodyFormat },
|
|
41
|
+
};
|
|
42
|
+
case "json":
|
|
43
|
+
return {
|
|
44
|
+
body: encodeStringBody(JSON.stringify(context.variables, null, 2)),
|
|
45
|
+
format: "json",
|
|
46
|
+
language: context.language,
|
|
47
|
+
metadata: { renderedBodyFormat: context.renderedBodyFormat },
|
|
48
|
+
};
|
|
49
|
+
case "xml":
|
|
50
|
+
return {
|
|
51
|
+
body: encodeStringBody(context.renderedBody),
|
|
52
|
+
format: "xml",
|
|
53
|
+
language: context.language,
|
|
54
|
+
metadata: { renderedBodyFormat: context.renderedBodyFormat },
|
|
55
|
+
};
|
|
56
|
+
default:
|
|
57
|
+
return defaultPdfInvoiceDocumentSerializer(context);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
export async function defaultPdfInvoiceDocumentSerializer(context) {
|
|
61
|
+
const body = await renderPdfDocument({
|
|
62
|
+
title: `Invoice ${context.invoice.id}`,
|
|
63
|
+
content: context.renderedBody,
|
|
64
|
+
format: context.renderedBodyFormat === "lexical_json"
|
|
65
|
+
? "lexical_json"
|
|
66
|
+
: context.renderedBodyFormat === "html"
|
|
67
|
+
? "html"
|
|
68
|
+
: "markdown",
|
|
69
|
+
metadataLines: [
|
|
70
|
+
`Invoice ID: ${context.invoice.id}`,
|
|
71
|
+
...(context.language ? [`Language: ${context.language}`] : []),
|
|
72
|
+
],
|
|
73
|
+
});
|
|
74
|
+
return {
|
|
75
|
+
body,
|
|
76
|
+
format: "pdf",
|
|
77
|
+
language: context.language,
|
|
78
|
+
metadata: {
|
|
79
|
+
renderedBodyFormat: context.renderedBodyFormat,
|
|
80
|
+
renderer: "voyant-basic-pdf",
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
export function createStorageBackedInvoiceDocumentGenerator(options) {
|
|
85
|
+
const serializer = options.serializer ?? defaultStorageBackedInvoiceDocumentSerializer;
|
|
86
|
+
return async (context) => {
|
|
87
|
+
const upload = await serializer(context);
|
|
88
|
+
const format = upload.format ?? context.targetFormat;
|
|
89
|
+
const keyPrefix = typeof options.keyPrefix === "function"
|
|
90
|
+
? await options.keyPrefix(context)
|
|
91
|
+
: (options.keyPrefix ?? `invoices/${context.invoice.id}`);
|
|
92
|
+
const key = upload.key?.trim() || `${keyPrefix.replace(/\/$/, "")}/rendition.${format}`;
|
|
93
|
+
const uploaded = await options.storage.upload(upload.body, {
|
|
94
|
+
key,
|
|
95
|
+
contentType: defaultInvoiceDocumentMimeType(format),
|
|
96
|
+
metadata: toUploadMetadata(upload.metadata),
|
|
97
|
+
});
|
|
98
|
+
const downloadUrl = uploaded.url ||
|
|
99
|
+
(options.signedUrlExpiresIn
|
|
100
|
+
? await options.storage.signedUrl(uploaded.key, options.signedUrlExpiresIn)
|
|
101
|
+
: "");
|
|
102
|
+
return {
|
|
103
|
+
format,
|
|
104
|
+
storageKey: uploaded.key,
|
|
105
|
+
fileSize: getBodySize(upload.body),
|
|
106
|
+
language: upload.language ?? context.language,
|
|
107
|
+
metadata: {
|
|
108
|
+
...(upload.metadata ?? {}),
|
|
109
|
+
storageProvider: options.storage.name,
|
|
110
|
+
...(uploaded.url ? { url: uploaded.url } : {}),
|
|
111
|
+
...(downloadUrl ? { downloadUrl } : {}),
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
export function createPdfInvoiceDocumentGenerator(options) {
|
|
117
|
+
return createStorageBackedInvoiceDocumentGenerator({
|
|
118
|
+
...options,
|
|
119
|
+
serializer: defaultPdfInvoiceDocumentSerializer,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
async function prepareInvoiceDocument(db, invoiceId, input) {
|
|
123
|
+
const invoice = await financeService.getInvoiceById(db, invoiceId);
|
|
124
|
+
if (!invoice) {
|
|
125
|
+
return { status: "not_found" };
|
|
126
|
+
}
|
|
127
|
+
let templateId = input.templateId ?? invoice.templateId ?? null;
|
|
128
|
+
if (!templateId) {
|
|
129
|
+
const [defaultTemplate] = await db
|
|
130
|
+
.select()
|
|
131
|
+
.from(invoiceTemplates)
|
|
132
|
+
.where(and(eq(invoiceTemplates.isDefault, true), eq(invoiceTemplates.active, true)))
|
|
133
|
+
.orderBy(desc(invoiceTemplates.updatedAt))
|
|
134
|
+
.limit(1);
|
|
135
|
+
templateId = defaultTemplate?.id ?? null;
|
|
136
|
+
}
|
|
137
|
+
const [template, lineItems, paymentRows] = await Promise.all([
|
|
138
|
+
templateId ? financeService.getInvoiceTemplateById(db, templateId) : Promise.resolve(null),
|
|
139
|
+
financeService.listInvoiceLineItems(db, invoiceId),
|
|
140
|
+
financeService.listPayments(db, invoiceId),
|
|
141
|
+
]);
|
|
142
|
+
const renderedBodyFormat = template?.bodyFormat ?? "html";
|
|
143
|
+
const variables = {
|
|
144
|
+
invoice,
|
|
145
|
+
lineItems,
|
|
146
|
+
payments: paymentRows,
|
|
147
|
+
};
|
|
148
|
+
const renderedBody = template
|
|
149
|
+
? renderInvoiceBody(template.body, template.bodyFormat, variables)
|
|
150
|
+
: JSON.stringify(variables);
|
|
151
|
+
return {
|
|
152
|
+
status: "ready",
|
|
153
|
+
invoice,
|
|
154
|
+
template,
|
|
155
|
+
lineItems,
|
|
156
|
+
payments: paymentRows,
|
|
157
|
+
renderedBody,
|
|
158
|
+
renderedBodyFormat,
|
|
159
|
+
variables,
|
|
160
|
+
targetFormat: input.format,
|
|
161
|
+
language: input.language ?? invoice.language ?? template?.language ?? null,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
export const financeDocumentsService = {
|
|
165
|
+
async generateInvoiceDocument(db, invoiceId, input, runtime) {
|
|
166
|
+
const prepared = await prepareInvoiceDocument(db, invoiceId, input);
|
|
167
|
+
if (prepared.status === "not_found") {
|
|
168
|
+
return { status: "not_found" };
|
|
169
|
+
}
|
|
170
|
+
let artifact;
|
|
171
|
+
try {
|
|
172
|
+
artifact = await runtime.generator({
|
|
173
|
+
db,
|
|
174
|
+
invoice: prepared.invoice,
|
|
175
|
+
template: prepared.template,
|
|
176
|
+
lineItems: prepared.lineItems,
|
|
177
|
+
payments: prepared.payments,
|
|
178
|
+
renderedBody: prepared.renderedBody,
|
|
179
|
+
renderedBodyFormat: prepared.renderedBodyFormat,
|
|
180
|
+
variables: prepared.variables,
|
|
181
|
+
bindings: runtime.bindings ?? {},
|
|
182
|
+
targetFormat: prepared.targetFormat,
|
|
183
|
+
language: prepared.language,
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
return { status: "generator_failed" };
|
|
188
|
+
}
|
|
189
|
+
if (input.replaceExisting) {
|
|
190
|
+
const existing = await financeService.listInvoiceRenditions(db, invoiceId);
|
|
191
|
+
for (const rendition of existing) {
|
|
192
|
+
if (rendition.format === (artifact.format ?? prepared.targetFormat) &&
|
|
193
|
+
rendition.status !== "stale") {
|
|
194
|
+
await financeService.updateInvoiceRendition(db, rendition.id, { status: "stale" });
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
const rendition = await financeService.createInvoiceRendition(db, invoiceId, {
|
|
199
|
+
templateId: prepared.template?.id ?? null,
|
|
200
|
+
format: artifact.format ?? prepared.targetFormat,
|
|
201
|
+
status: "ready",
|
|
202
|
+
storageKey: artifact.storageKey ?? null,
|
|
203
|
+
fileSize: artifact.fileSize ?? null,
|
|
204
|
+
checksum: artifact.checksum ?? null,
|
|
205
|
+
language: artifact.language ?? prepared.language ?? null,
|
|
206
|
+
generatedAt: new Date().toISOString(),
|
|
207
|
+
metadata: {
|
|
208
|
+
...(artifact.metadata ?? {}),
|
|
209
|
+
renderedBodyFormat: prepared.renderedBodyFormat,
|
|
210
|
+
},
|
|
211
|
+
});
|
|
212
|
+
if (!rendition) {
|
|
213
|
+
return { status: "not_found" };
|
|
214
|
+
}
|
|
215
|
+
return {
|
|
216
|
+
status: "generated",
|
|
217
|
+
invoiceId: prepared.invoice.id,
|
|
218
|
+
renderedBodyFormat: prepared.renderedBodyFormat,
|
|
219
|
+
renderedBody: prepared.renderedBody,
|
|
220
|
+
rendition,
|
|
221
|
+
};
|
|
222
|
+
},
|
|
223
|
+
async regenerateInvoiceDocument(db, invoiceId, input, runtime) {
|
|
224
|
+
return this.generateInvoiceDocument(db, invoiceId, input, runtime);
|
|
225
|
+
},
|
|
226
|
+
};
|