@voyantjs/finance 0.53.2 → 0.54.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/README.md +53 -0
- package/dist/booking-tax.d.ts +124 -0
- package/dist/booking-tax.d.ts.map +1 -0
- package/dist/booking-tax.js +254 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/service-booking-create.d.ts +2 -2
- package/dist/service-bookings-dual-create.d.ts +4 -4
- package/package.json +14 -8
package/README.md
CHANGED
|
@@ -73,6 +73,58 @@ The by-reference variant resolves invoice numbers and payment reference numbers
|
|
|
73
73
|
only inside that booking, so a valid capability for one booking cannot retrieve
|
|
74
74
|
documents from another booking.
|
|
75
75
|
|
|
76
|
+
## Booking Tax Preview
|
|
77
|
+
|
|
78
|
+
Booking creation UIs can show the same tax line that booking finalization will
|
|
79
|
+
persist by mounting the booking-tax extension:
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
import { createBookingTaxHonoExtension } from "@voyantjs/finance/booking-tax"
|
|
83
|
+
|
|
84
|
+
createApp({
|
|
85
|
+
extensions: [
|
|
86
|
+
createBookingTaxHonoExtension({
|
|
87
|
+
resolveBookingTaxSettings: async (db) => {
|
|
88
|
+
const settings = await getTaxSettings(db)
|
|
89
|
+
return {
|
|
90
|
+
taxPriceMode: settings?.taxPriceMode ?? "inclusive",
|
|
91
|
+
taxPolicyProfileId: settings?.taxPolicyProfileId ?? null,
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
}),
|
|
95
|
+
],
|
|
96
|
+
})
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
The settings callback is the storage seam. A template can read a singleton
|
|
100
|
+
settings table, KV, environment configuration, or any other deployment-owned
|
|
101
|
+
store, while `@voyantjs/finance` owns the tax policy rule walker, tax-regime
|
|
102
|
+
lookup, product tax-class fallback, and inclusive/exclusive math.
|
|
103
|
+
|
|
104
|
+
Templates that already mount custom routes can call `mountBookingTaxRoutes(...)`
|
|
105
|
+
from the same entrypoint instead of using the Hono extension.
|
|
106
|
+
|
|
107
|
+
Mounting this route registers:
|
|
108
|
+
|
|
109
|
+
- `GET /v1/admin/bookings/tax-settings`
|
|
110
|
+
- `PATCH /v1/admin/bookings/tax-settings` when `updateBookingTaxSettings` is supplied
|
|
111
|
+
- `POST /v1/admin/bookings/tax-preview`
|
|
112
|
+
|
|
113
|
+
The preview endpoint is consumed by `@voyantjs/bookings-react` tax-preview
|
|
114
|
+
hooks. Consumers that use the booking-create dialog without mounting the route
|
|
115
|
+
will silently lose tax rows in the dialog summary because the client treats a
|
|
116
|
+
missing preview as "no tax to show".
|
|
117
|
+
|
|
118
|
+
Server-side booking-finalize code can use the same helpers directly:
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
import {
|
|
122
|
+
computeBookingItemTaxLine,
|
|
123
|
+
loadProductTaxFacts,
|
|
124
|
+
resolveBookingSellTaxRate,
|
|
125
|
+
} from "@voyantjs/finance/booking-tax"
|
|
126
|
+
```
|
|
127
|
+
|
|
76
128
|
## Exports
|
|
77
129
|
|
|
78
130
|
| Entry | Description |
|
|
@@ -80,6 +132,7 @@ documents from another booking.
|
|
|
80
132
|
| `.` | Module export |
|
|
81
133
|
| `./schema` | Drizzle tables |
|
|
82
134
|
| `./validation` | Zod schemas |
|
|
135
|
+
| `./booking-tax` | Booking sell-side tax policy helpers and route mounting |
|
|
83
136
|
| `./routes` | Hono routes |
|
|
84
137
|
|
|
85
138
|
## License
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import type { HonoExtension } from "@voyantjs/hono/module";
|
|
2
|
+
import type { PostgresJsDatabase } from "drizzle-orm/postgres-js";
|
|
3
|
+
import type { Hono } from "hono";
|
|
4
|
+
export type ProductTaxFacts = {
|
|
5
|
+
hasAccommodation: boolean;
|
|
6
|
+
accommodationCountries: string[];
|
|
7
|
+
};
|
|
8
|
+
export type ResolvedBookingSellTaxRate = {
|
|
9
|
+
code: string;
|
|
10
|
+
label: string;
|
|
11
|
+
rate: number;
|
|
12
|
+
priceMode: "inclusive" | "exclusive";
|
|
13
|
+
};
|
|
14
|
+
export type BookingTaxSettings = {
|
|
15
|
+
taxPriceMode?: "inclusive" | "exclusive" | null;
|
|
16
|
+
taxPolicyProfileId?: string | null;
|
|
17
|
+
};
|
|
18
|
+
export type ResolveBookingTaxSettings = (db: PostgresJsDatabase) => BookingTaxSettings | null | undefined | Promise<BookingTaxSettings | null | undefined>;
|
|
19
|
+
export type UpdateBookingTaxSettings = (db: PostgresJsDatabase, settings: BookingTaxSettings) => BookingTaxSettings | null | undefined | Promise<BookingTaxSettings | null | undefined>;
|
|
20
|
+
export type TaxPolicyCondition = {
|
|
21
|
+
always: true;
|
|
22
|
+
} | {
|
|
23
|
+
all: TaxPolicyCondition[];
|
|
24
|
+
} | {
|
|
25
|
+
any: TaxPolicyCondition[];
|
|
26
|
+
} | {
|
|
27
|
+
fact: keyof ProductTaxFacts;
|
|
28
|
+
eq?: unknown;
|
|
29
|
+
contains?: unknown;
|
|
30
|
+
};
|
|
31
|
+
export interface ResolveBookingSellTaxRateOptions {
|
|
32
|
+
settings?: BookingTaxSettings | null;
|
|
33
|
+
resolveBookingTaxSettings?: ResolveBookingTaxSettings;
|
|
34
|
+
}
|
|
35
|
+
export interface BookingTaxRouteOptions extends ResolveBookingSellTaxRateOptions {
|
|
36
|
+
updateBookingTaxSettings?: UpdateBookingTaxSettings;
|
|
37
|
+
}
|
|
38
|
+
export declare function resolveBookingSellTaxRate(db: PostgresJsDatabase, args: {
|
|
39
|
+
productId?: string | null;
|
|
40
|
+
facts?: Partial<ProductTaxFacts>;
|
|
41
|
+
}, options?: ResolveBookingSellTaxRateOptions): Promise<ResolvedBookingSellTaxRate | null>;
|
|
42
|
+
export declare function computeBookingItemTaxLine(taxRate: ResolvedBookingSellTaxRate | null, amountCents: number, currency: string, sortOrder?: number): {
|
|
43
|
+
code: string;
|
|
44
|
+
name: string;
|
|
45
|
+
scope: "included" | "excluded";
|
|
46
|
+
currency: string;
|
|
47
|
+
amountCents: number;
|
|
48
|
+
rateBasisPoints: number;
|
|
49
|
+
includedInPrice: boolean;
|
|
50
|
+
sortOrder: number;
|
|
51
|
+
} | null;
|
|
52
|
+
export declare function loadProductTaxFacts(db: PostgresJsDatabase, productId: string): Promise<ProductTaxFacts>;
|
|
53
|
+
export declare function matchesTaxPolicyCondition(condition: TaxPolicyCondition | null | undefined, facts: ProductTaxFacts): boolean;
|
|
54
|
+
export declare function createBookingTaxRoutes(options?: BookingTaxRouteOptions): import("hono/hono-base").HonoBase<{
|
|
55
|
+
Variables: {
|
|
56
|
+
db: PostgresJsDatabase;
|
|
57
|
+
};
|
|
58
|
+
}, {
|
|
59
|
+
"/tax-settings": {
|
|
60
|
+
$get: {
|
|
61
|
+
input: {};
|
|
62
|
+
output: {
|
|
63
|
+
data: {
|
|
64
|
+
taxPriceMode?: "inclusive" | "exclusive" | null | undefined;
|
|
65
|
+
taxPolicyProfileId?: string | null | undefined;
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
outputFormat: "json";
|
|
69
|
+
status: import("hono/utils/http-status").ContentfulStatusCode;
|
|
70
|
+
};
|
|
71
|
+
};
|
|
72
|
+
} & {
|
|
73
|
+
"/tax-settings": {
|
|
74
|
+
$patch: {
|
|
75
|
+
input: {};
|
|
76
|
+
output: {
|
|
77
|
+
data: {
|
|
78
|
+
taxPriceMode?: "inclusive" | "exclusive" | null | undefined;
|
|
79
|
+
taxPolicyProfileId?: string | null | undefined;
|
|
80
|
+
};
|
|
81
|
+
};
|
|
82
|
+
outputFormat: "json";
|
|
83
|
+
status: import("hono/utils/http-status").ContentfulStatusCode;
|
|
84
|
+
};
|
|
85
|
+
};
|
|
86
|
+
} & {
|
|
87
|
+
"/tax-preview": {
|
|
88
|
+
$post: {
|
|
89
|
+
input: {};
|
|
90
|
+
output: {
|
|
91
|
+
data: {
|
|
92
|
+
subtotalCents: number;
|
|
93
|
+
taxCents: number;
|
|
94
|
+
totalCents: number;
|
|
95
|
+
currency: string;
|
|
96
|
+
taxRate: null;
|
|
97
|
+
};
|
|
98
|
+
};
|
|
99
|
+
outputFormat: "json";
|
|
100
|
+
status: import("hono/utils/http-status").ContentfulStatusCode;
|
|
101
|
+
} | {
|
|
102
|
+
input: {};
|
|
103
|
+
output: {
|
|
104
|
+
data: {
|
|
105
|
+
subtotalCents: number;
|
|
106
|
+
taxCents: number;
|
|
107
|
+
totalCents: number;
|
|
108
|
+
currency: string;
|
|
109
|
+
taxRate: {
|
|
110
|
+
code: string;
|
|
111
|
+
label: string;
|
|
112
|
+
rateBasisPoints: number;
|
|
113
|
+
priceMode: "inclusive" | "exclusive";
|
|
114
|
+
};
|
|
115
|
+
};
|
|
116
|
+
};
|
|
117
|
+
outputFormat: "json";
|
|
118
|
+
status: import("hono/utils/http-status").ContentfulStatusCode;
|
|
119
|
+
};
|
|
120
|
+
};
|
|
121
|
+
}, "/", "/tax-preview">;
|
|
122
|
+
export declare function mountBookingTaxRoutes(hono: Hono, options?: BookingTaxRouteOptions): void;
|
|
123
|
+
export declare function createBookingTaxHonoExtension(options?: BookingTaxRouteOptions): HonoExtension;
|
|
124
|
+
//# sourceMappingURL=booking-tax.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"booking-tax.d.ts","sourceRoot":"","sources":["../src/booking-tax.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import { ApiHttpError, parseJsonBody } from "@voyantjs/hono";
|
|
2
|
+
import { productDayServices, productDays, productItineraries, productLocations, products as productsTable, } from "@voyantjs/products/schema";
|
|
3
|
+
import { and, asc, eq } from "drizzle-orm";
|
|
4
|
+
import { Hono as HonoApp } from "hono";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { taxClasses, taxPolicyProfiles, taxPolicyRules, taxRegimes } from "./schema.js";
|
|
7
|
+
const taxPreviewBodySchema = z.object({
|
|
8
|
+
productId: z.string().min(1),
|
|
9
|
+
subtotalCents: z.number().int().min(0),
|
|
10
|
+
currency: z.string().min(3).max(8),
|
|
11
|
+
});
|
|
12
|
+
const bookingTaxSettingsPatchSchema = z.object({
|
|
13
|
+
taxPriceMode: z.enum(["inclusive", "exclusive"]).optional(),
|
|
14
|
+
taxPolicyProfileId: z.string().min(1).nullable().optional(),
|
|
15
|
+
});
|
|
16
|
+
export async function resolveBookingSellTaxRate(db, args, options = {}) {
|
|
17
|
+
const resolvedSettings = options.settings !== undefined
|
|
18
|
+
? options.settings
|
|
19
|
+
: ((await options.resolveBookingTaxSettings?.(db)) ?? null);
|
|
20
|
+
const priceMode = resolvedSettings?.taxPriceMode === "exclusive" ? "exclusive" : "inclusive";
|
|
21
|
+
const policyProfile = await resolveTaxPolicyProfile(db, resolvedSettings?.taxPolicyProfileId);
|
|
22
|
+
if (policyProfile) {
|
|
23
|
+
const facts = normalizeTaxFacts(args.facts ?? (args.productId ? await loadProductTaxFacts(db, args.productId) : undefined));
|
|
24
|
+
const rules = await db
|
|
25
|
+
.select({
|
|
26
|
+
condition: taxPolicyRules.condition,
|
|
27
|
+
taxRegimeId: taxPolicyRules.taxRegimeId,
|
|
28
|
+
})
|
|
29
|
+
.from(taxPolicyRules)
|
|
30
|
+
.where(and(eq(taxPolicyRules.profileId, policyProfile.id), eq(taxPolicyRules.side, "sell"), eq(taxPolicyRules.active, true)))
|
|
31
|
+
.orderBy(asc(taxPolicyRules.priority), asc(taxPolicyRules.createdAt));
|
|
32
|
+
for (const rule of rules) {
|
|
33
|
+
if (!matchesTaxPolicyCondition(rule.condition, facts))
|
|
34
|
+
continue;
|
|
35
|
+
const resolved = await loadResolvedTaxRegime(db, rule.taxRegimeId, policyProfile.code);
|
|
36
|
+
if (resolved)
|
|
37
|
+
return { ...resolved, priceMode };
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return args.productId ? resolveProductTaxClassRate(db, args.productId, priceMode) : null;
|
|
41
|
+
}
|
|
42
|
+
async function resolveBookingTaxSettingsOrDefault(db, options = {}) {
|
|
43
|
+
const settings = options.settings !== undefined
|
|
44
|
+
? options.settings
|
|
45
|
+
: ((await options.resolveBookingTaxSettings?.(db)) ?? null);
|
|
46
|
+
return {
|
|
47
|
+
taxPriceMode: settings?.taxPriceMode === "exclusive" ? "exclusive" : "inclusive",
|
|
48
|
+
taxPolicyProfileId: settings?.taxPolicyProfileId ?? null,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
export function computeBookingItemTaxLine(taxRate, amountCents, currency, sortOrder = 0) {
|
|
52
|
+
if (!taxRate || taxRate.rate <= 0 || amountCents <= 0)
|
|
53
|
+
return null;
|
|
54
|
+
const includedInPrice = taxRate.priceMode === "inclusive";
|
|
55
|
+
const taxCents = includedInPrice
|
|
56
|
+
? Math.round(amountCents - amountCents / (1 + taxRate.rate))
|
|
57
|
+
: Math.round(amountCents * taxRate.rate);
|
|
58
|
+
if (taxCents <= 0)
|
|
59
|
+
return null;
|
|
60
|
+
return {
|
|
61
|
+
code: taxRate.code,
|
|
62
|
+
name: taxRate.label,
|
|
63
|
+
scope: includedInPrice ? "included" : "excluded",
|
|
64
|
+
currency,
|
|
65
|
+
amountCents: taxCents,
|
|
66
|
+
rateBasisPoints: Math.round(taxRate.rate * 10_000),
|
|
67
|
+
includedInPrice,
|
|
68
|
+
sortOrder,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
export async function loadProductTaxFacts(db, productId) {
|
|
72
|
+
const [accommodationLocations, accommodationServices] = await Promise.all([
|
|
73
|
+
db
|
|
74
|
+
.select({ countryCode: productLocations.countryCode })
|
|
75
|
+
.from(productLocations)
|
|
76
|
+
.where(eq(productLocations.productId, productId)),
|
|
77
|
+
db
|
|
78
|
+
.select({ id: productDayServices.id, countryCode: productDayServices.countryCode })
|
|
79
|
+
.from(productDayServices)
|
|
80
|
+
.innerJoin(productDays, eq(productDayServices.dayId, productDays.id))
|
|
81
|
+
.innerJoin(productItineraries, eq(productDays.itineraryId, productItineraries.id))
|
|
82
|
+
.where(and(eq(productItineraries.productId, productId), eq(productDayServices.serviceType, "accommodation"))),
|
|
83
|
+
]);
|
|
84
|
+
const accommodationCountries = [...accommodationServices, ...accommodationLocations]
|
|
85
|
+
.map((entry) => entry.countryCode?.trim().toUpperCase())
|
|
86
|
+
.filter((countryCode) => Boolean(countryCode));
|
|
87
|
+
return {
|
|
88
|
+
hasAccommodation: accommodationLocations.length > 0 || accommodationServices.length > 0,
|
|
89
|
+
accommodationCountries: [...new Set(accommodationCountries)],
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
export function matchesTaxPolicyCondition(condition, facts) {
|
|
93
|
+
if (!condition)
|
|
94
|
+
return true;
|
|
95
|
+
if ("always" in condition)
|
|
96
|
+
return condition.always === true;
|
|
97
|
+
if ("all" in condition)
|
|
98
|
+
return condition.all.every((entry) => matchesTaxPolicyCondition(entry, facts));
|
|
99
|
+
if ("any" in condition)
|
|
100
|
+
return condition.any.some((entry) => matchesTaxPolicyCondition(entry, facts));
|
|
101
|
+
if (!("fact" in condition))
|
|
102
|
+
return false;
|
|
103
|
+
const value = facts[condition.fact];
|
|
104
|
+
if ("eq" in condition)
|
|
105
|
+
return value === condition.eq;
|
|
106
|
+
if ("contains" in condition) {
|
|
107
|
+
return Array.isArray(value) && value.includes(String(condition.contains).toUpperCase());
|
|
108
|
+
}
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
function normalizeTaxFacts(facts) {
|
|
112
|
+
return {
|
|
113
|
+
hasAccommodation: facts?.hasAccommodation === true,
|
|
114
|
+
accommodationCountries: [
|
|
115
|
+
...new Set((facts?.accommodationCountries ?? [])
|
|
116
|
+
.map((countryCode) => countryCode.trim().toUpperCase())
|
|
117
|
+
.filter(Boolean)),
|
|
118
|
+
],
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
async function resolveTaxPolicyProfile(db, configuredProfileId) {
|
|
122
|
+
if (configuredProfileId) {
|
|
123
|
+
const [configured] = await db
|
|
124
|
+
.select()
|
|
125
|
+
.from(taxPolicyProfiles)
|
|
126
|
+
.where(eq(taxPolicyProfiles.id, configuredProfileId))
|
|
127
|
+
.limit(1);
|
|
128
|
+
if (configured?.active)
|
|
129
|
+
return configured;
|
|
130
|
+
}
|
|
131
|
+
const [active] = await db
|
|
132
|
+
.select()
|
|
133
|
+
.from(taxPolicyProfiles)
|
|
134
|
+
.where(eq(taxPolicyProfiles.active, true))
|
|
135
|
+
.orderBy(asc(taxPolicyProfiles.createdAt))
|
|
136
|
+
.limit(1);
|
|
137
|
+
return active ?? null;
|
|
138
|
+
}
|
|
139
|
+
async function loadResolvedTaxRegime(db, taxRegimeId, codePrefix) {
|
|
140
|
+
const [regime] = await db
|
|
141
|
+
.select({
|
|
142
|
+
ratePercent: taxRegimes.ratePercent,
|
|
143
|
+
code: taxRegimes.code,
|
|
144
|
+
name: taxRegimes.name,
|
|
145
|
+
})
|
|
146
|
+
.from(taxRegimes)
|
|
147
|
+
.where(eq(taxRegimes.id, taxRegimeId))
|
|
148
|
+
.limit(1);
|
|
149
|
+
if (!regime || regime.ratePercent == null)
|
|
150
|
+
return null;
|
|
151
|
+
return {
|
|
152
|
+
code: `${codePrefix}/${regime.code}`,
|
|
153
|
+
label: regime.name,
|
|
154
|
+
rate: regime.ratePercent / 100,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
async function resolveProductTaxClassRate(db, productId, priceMode) {
|
|
158
|
+
const productRows = await db
|
|
159
|
+
.select({ taxClassId: productsTable.taxClassId })
|
|
160
|
+
.from(productsTable)
|
|
161
|
+
.where(eq(productsTable.id, productId))
|
|
162
|
+
.limit(1);
|
|
163
|
+
const taxClassId = productRows[0]?.taxClassId;
|
|
164
|
+
if (!taxClassId)
|
|
165
|
+
return null;
|
|
166
|
+
const classRows = await db
|
|
167
|
+
.select({
|
|
168
|
+
defaultRegimeId: taxClasses.defaultRegimeId,
|
|
169
|
+
code: taxClasses.code,
|
|
170
|
+
})
|
|
171
|
+
.from(taxClasses)
|
|
172
|
+
.where(eq(taxClasses.id, taxClassId))
|
|
173
|
+
.limit(1);
|
|
174
|
+
const klass = classRows[0];
|
|
175
|
+
if (!klass?.defaultRegimeId)
|
|
176
|
+
return null;
|
|
177
|
+
const resolved = await loadResolvedTaxRegime(db, klass.defaultRegimeId, klass.code);
|
|
178
|
+
return resolved ? { ...resolved, priceMode } : null;
|
|
179
|
+
}
|
|
180
|
+
export function createBookingTaxRoutes(options = {}) {
|
|
181
|
+
return new HonoApp()
|
|
182
|
+
.get("/tax-settings", async (c) => {
|
|
183
|
+
return c.json({
|
|
184
|
+
data: await resolveBookingTaxSettingsOrDefault(c.get("db"), options),
|
|
185
|
+
});
|
|
186
|
+
})
|
|
187
|
+
.patch("/tax-settings", async (c) => {
|
|
188
|
+
if (!options.updateBookingTaxSettings) {
|
|
189
|
+
throw new ApiHttpError("Booking tax settings updates are not configured", {
|
|
190
|
+
status: 409,
|
|
191
|
+
code: "booking_tax_settings_update_not_configured",
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
const current = await resolveBookingTaxSettingsOrDefault(c.get("db"), options);
|
|
195
|
+
const patch = await parseJsonBody(c, bookingTaxSettingsPatchSchema);
|
|
196
|
+
const next = await options.updateBookingTaxSettings(c.get("db"), {
|
|
197
|
+
taxPriceMode: patch.taxPriceMode ?? current.taxPriceMode,
|
|
198
|
+
taxPolicyProfileId: patch.taxPolicyProfileId === undefined
|
|
199
|
+
? current.taxPolicyProfileId
|
|
200
|
+
: patch.taxPolicyProfileId,
|
|
201
|
+
});
|
|
202
|
+
return c.json({
|
|
203
|
+
data: await resolveBookingTaxSettingsOrDefault(c.get("db"), { settings: next }),
|
|
204
|
+
});
|
|
205
|
+
})
|
|
206
|
+
.post("/tax-preview", async (c) => {
|
|
207
|
+
const body = await parseJsonBody(c, taxPreviewBodySchema);
|
|
208
|
+
const taxRate = await resolveBookingSellTaxRate(c.get("db"), { productId: body.productId }, options);
|
|
209
|
+
const taxLine = computeBookingItemTaxLine(taxRate, body.subtotalCents, body.currency);
|
|
210
|
+
if (!taxRate || !taxLine) {
|
|
211
|
+
return c.json({
|
|
212
|
+
data: {
|
|
213
|
+
subtotalCents: body.subtotalCents,
|
|
214
|
+
taxCents: 0,
|
|
215
|
+
totalCents: body.subtotalCents,
|
|
216
|
+
currency: body.currency,
|
|
217
|
+
taxRate: null,
|
|
218
|
+
},
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
const inclusive = taxLine.includedInPrice;
|
|
222
|
+
const displaySubtotal = inclusive
|
|
223
|
+
? Math.max(0, body.subtotalCents - taxLine.amountCents)
|
|
224
|
+
: body.subtotalCents;
|
|
225
|
+
const total = inclusive ? body.subtotalCents : body.subtotalCents + taxLine.amountCents;
|
|
226
|
+
return c.json({
|
|
227
|
+
data: {
|
|
228
|
+
subtotalCents: displaySubtotal,
|
|
229
|
+
taxCents: taxLine.amountCents,
|
|
230
|
+
totalCents: total,
|
|
231
|
+
currency: body.currency,
|
|
232
|
+
taxRate: {
|
|
233
|
+
code: taxRate.code,
|
|
234
|
+
label: taxRate.label,
|
|
235
|
+
rateBasisPoints: Math.round(taxRate.rate * 10_000),
|
|
236
|
+
priceMode: taxRate.priceMode,
|
|
237
|
+
},
|
|
238
|
+
},
|
|
239
|
+
});
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
export function mountBookingTaxRoutes(hono, options = {}) {
|
|
243
|
+
hono.route("/v1/admin/bookings", createBookingTaxRoutes(options));
|
|
244
|
+
}
|
|
245
|
+
export function createBookingTaxHonoExtension(options = {}) {
|
|
246
|
+
const extension = {
|
|
247
|
+
name: "booking-tax",
|
|
248
|
+
module: "bookings",
|
|
249
|
+
};
|
|
250
|
+
return {
|
|
251
|
+
extension,
|
|
252
|
+
adminRoutes: createBookingTaxRoutes(options),
|
|
253
|
+
};
|
|
254
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -19,6 +19,7 @@ export interface FinanceHonoModuleOptions extends FinanceRuntimeOptions, PublicF
|
|
|
19
19
|
}
|
|
20
20
|
export declare function createFinanceHonoModule(options?: FinanceHonoModuleOptions): HonoModule;
|
|
21
21
|
export declare const financeHonoModule: HonoModule;
|
|
22
|
+
export { type BookingTaxRouteOptions, type BookingTaxSettings, computeBookingItemTaxLine, createBookingTaxHonoExtension, createBookingTaxRoutes, loadProductTaxFacts, matchesTaxPolicyCondition, mountBookingTaxRoutes, type ProductTaxFacts, type ResolveBookingSellTaxRateOptions, type ResolveBookingTaxSettings, type ResolvedBookingSellTaxRate, resolveBookingSellTaxRate, type TaxPolicyCondition, type UpdateBookingTaxSettings, } from "./booking-tax.js";
|
|
22
23
|
export type { ComputedScheduleEntry, ComputeScheduleInput, DepositKind, DepositRule, PaymentPolicy, PaymentPolicyCascadeLayers, PaymentPolicySource, PaymentScheduleEntryType, ResolvedPaymentPolicy, } from "./payment-policy.js";
|
|
23
24
|
export { computePaymentSchedule, isPaymentPolicyEmpty, noDepositPolicy, policyShouldRequireFullPayment, resolveEffectivePaymentPolicy, } from "./payment-policy.js";
|
|
24
25
|
export { buildFinanceRouteRuntime, FINANCE_ROUTE_RUNTIME_CONTAINER_KEY, type FinanceRouteRuntime, type FinanceRuntimeOptions, } from "./route-runtime.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -62,6 +62,7 @@ export function createFinanceHonoModule(options = {}) {
|
|
|
62
62
|
};
|
|
63
63
|
}
|
|
64
64
|
export const financeHonoModule = createFinanceHonoModule();
|
|
65
|
+
export { computeBookingItemTaxLine, createBookingTaxHonoExtension, createBookingTaxRoutes, loadProductTaxFacts, matchesTaxPolicyCondition, mountBookingTaxRoutes, resolveBookingSellTaxRate, } from "./booking-tax.js";
|
|
65
66
|
export { computePaymentSchedule, isPaymentPolicyEmpty, noDepositPolicy, policyShouldRequireFullPayment, resolveEffectivePaymentPolicy, } from "./payment-policy.js";
|
|
66
67
|
export { buildFinanceRouteRuntime, FINANCE_ROUTE_RUNTIME_CONTAINER_KEY, } from "./route-runtime.js";
|
|
67
68
|
export { bookingsCreateExtension } from "./routes-booking-create.js";
|
|
@@ -143,6 +143,8 @@ export declare const bookingCreateSchema: z.ZodObject<{
|
|
|
143
143
|
export declare const bookingCreateSubSchema: z.ZodObject<{
|
|
144
144
|
organizationId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
145
145
|
personId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
146
|
+
productId: z.ZodString;
|
|
147
|
+
optionId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
146
148
|
bookingNumber: z.ZodString;
|
|
147
149
|
contactFirstName: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
148
150
|
contactLastName: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
@@ -155,8 +157,6 @@ export declare const bookingCreateSubSchema: z.ZodObject<{
|
|
|
155
157
|
contactAddressLine1: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
156
158
|
contactPostalCode: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
157
159
|
internalNotes: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
158
|
-
productId: z.ZodString;
|
|
159
|
-
optionId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
160
160
|
travelers: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
161
161
|
firstName: z.ZodString;
|
|
162
162
|
lastName: z.ZodString;
|
|
@@ -7,6 +7,8 @@ export declare const dualCreateBookingSchema: z.ZodObject<{
|
|
|
7
7
|
primary: z.ZodObject<{
|
|
8
8
|
organizationId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
9
9
|
personId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
10
|
+
productId: z.ZodString;
|
|
11
|
+
optionId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
10
12
|
bookingNumber: z.ZodString;
|
|
11
13
|
contactFirstName: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
12
14
|
contactLastName: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
@@ -19,8 +21,6 @@ export declare const dualCreateBookingSchema: z.ZodObject<{
|
|
|
19
21
|
contactAddressLine1: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
20
22
|
contactPostalCode: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
21
23
|
internalNotes: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
22
|
-
productId: z.ZodString;
|
|
23
|
-
optionId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
24
24
|
travelers: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
25
25
|
firstName: z.ZodString;
|
|
26
26
|
lastName: z.ZodString;
|
|
@@ -102,6 +102,8 @@ export declare const dualCreateBookingSchema: z.ZodObject<{
|
|
|
102
102
|
secondary: z.ZodObject<{
|
|
103
103
|
organizationId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
104
104
|
personId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
105
|
+
productId: z.ZodString;
|
|
106
|
+
optionId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
105
107
|
bookingNumber: z.ZodString;
|
|
106
108
|
contactFirstName: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
107
109
|
contactLastName: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
@@ -114,8 +116,6 @@ export declare const dualCreateBookingSchema: z.ZodObject<{
|
|
|
114
116
|
contactAddressLine1: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
115
117
|
contactPostalCode: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
116
118
|
internalNotes: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
117
|
-
productId: z.ZodString;
|
|
118
|
-
optionId: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
119
119
|
travelers: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
120
120
|
firstName: z.ZodString;
|
|
121
121
|
lastName: z.ZodString;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voyantjs/finance",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.54.0",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -24,6 +24,11 @@
|
|
|
24
24
|
"import": "./dist/validation.js",
|
|
25
25
|
"default": "./dist/validation.js"
|
|
26
26
|
},
|
|
27
|
+
"./booking-tax": {
|
|
28
|
+
"types": "./dist/booking-tax.d.ts",
|
|
29
|
+
"import": "./dist/booking-tax.js",
|
|
30
|
+
"default": "./dist/booking-tax.js"
|
|
31
|
+
},
|
|
27
32
|
"./routes": {
|
|
28
33
|
"types": "./dist/routes.d.ts",
|
|
29
34
|
"import": "./dist/routes.js",
|
|
@@ -44,13 +49,14 @@
|
|
|
44
49
|
"drizzle-orm": "^0.45.2",
|
|
45
50
|
"hono": "^4.12.10",
|
|
46
51
|
"zod": "^4.3.6",
|
|
47
|
-
"@voyantjs/action-ledger": "0.
|
|
48
|
-
"@voyantjs/bookings": "0.
|
|
49
|
-
"@voyantjs/core": "0.
|
|
50
|
-
"@voyantjs/db": "0.
|
|
51
|
-
"@voyantjs/hono": "0.
|
|
52
|
-
"@voyantjs/
|
|
53
|
-
"@voyantjs/
|
|
52
|
+
"@voyantjs/action-ledger": "0.54.0",
|
|
53
|
+
"@voyantjs/bookings": "0.54.0",
|
|
54
|
+
"@voyantjs/core": "0.54.0",
|
|
55
|
+
"@voyantjs/db": "0.54.0",
|
|
56
|
+
"@voyantjs/hono": "0.54.0",
|
|
57
|
+
"@voyantjs/products": "0.54.0",
|
|
58
|
+
"@voyantjs/utils": "0.54.0",
|
|
59
|
+
"@voyantjs/storage": "0.54.0"
|
|
54
60
|
},
|
|
55
61
|
"devDependencies": {
|
|
56
62
|
"typescript": "^6.0.2",
|