@spaceinvoices/react-ui 0.4.6 → 0.4.8
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/cli/dist/index.js +1 -1
- package/package.json +1 -1
- package/src/components/advance-invoices/create/create-advance-invoice-form.tsx +60 -44
- package/src/components/advance-invoices/create/locales/de.ts +2 -1
- package/src/components/advance-invoices/create/locales/es.ts +2 -1
- package/src/components/advance-invoices/create/locales/fr.ts +2 -1
- package/src/components/advance-invoices/create/locales/hr.ts +2 -1
- package/src/components/advance-invoices/create/locales/it.ts +2 -1
- package/src/components/advance-invoices/create/locales/nl.ts +2 -1
- package/src/components/advance-invoices/create/locales/pl.ts +2 -1
- package/src/components/advance-invoices/create/locales/pt.ts +2 -1
- package/src/components/advance-invoices/create/locales/sl.ts +2 -1
- package/src/components/credit-notes/create/create-credit-note-form.tsx +52 -42
- package/src/components/credit-notes/create/locales/de.ts +2 -1
- package/src/components/credit-notes/create/locales/es.ts +2 -1
- package/src/components/credit-notes/create/locales/fr.ts +2 -1
- package/src/components/credit-notes/create/locales/hr.ts +2 -1
- package/src/components/credit-notes/create/locales/it.ts +2 -1
- package/src/components/credit-notes/create/locales/nl.ts +2 -1
- package/src/components/credit-notes/create/locales/pl.ts +2 -1
- package/src/components/credit-notes/create/locales/pt.ts +2 -1
- package/src/components/credit-notes/create/locales/sl.ts +2 -1
- package/src/components/dashboard/collection-rate-card/use-collection-rate.ts +48 -92
- package/src/components/dashboard/invoice-status-chart/use-invoice-status.ts +48 -82
- package/src/components/dashboard/payment-methods-chart/use-payment-methods.ts +22 -31
- package/src/components/dashboard/payment-trend-chart/use-payment-trend.ts +33 -48
- package/src/components/dashboard/revenue-trend-chart/use-revenue-trend.ts +56 -76
- package/src/components/dashboard/shared/index.ts +1 -1
- package/src/components/dashboard/shared/use-revenue-data.ts +106 -182
- package/src/components/dashboard/shared/use-stats-counts.ts +18 -68
- package/src/components/dashboard/shared/use-stats-query.ts +35 -5
- package/src/components/dashboard/tax-collected-card/use-tax-collected.ts +57 -75
- package/src/components/dashboard/top-customers-chart/use-top-customers.ts +38 -49
- package/src/components/delivery-notes/create/create-delivery-note-form.tsx +3 -2
- package/src/components/delivery-notes/create/locales/de.ts +2 -1
- package/src/components/delivery-notes/create/locales/es.ts +2 -1
- package/src/components/delivery-notes/create/locales/fr.ts +2 -1
- package/src/components/delivery-notes/create/locales/hr.ts +2 -1
- package/src/components/delivery-notes/create/locales/it.ts +2 -1
- package/src/components/delivery-notes/create/locales/nl.ts +2 -1
- package/src/components/delivery-notes/create/locales/pl.ts +2 -1
- package/src/components/delivery-notes/create/locales/pt.ts +2 -1
- package/src/components/delivery-notes/create/locales/sl.ts +2 -1
- package/src/components/documents/create/document-details-section.tsx +6 -4
- package/src/components/documents/create/document-recipient-section.tsx +30 -1
- package/src/components/documents/create/live-preview.tsx +15 -28
- package/src/components/documents/create/prepare-document-submission.ts +1 -0
- package/src/components/documents/create/use-document-customer-form.ts +4 -0
- package/src/components/documents/shared/document-preview-skeleton.tsx +63 -0
- package/src/components/documents/shared/index.ts +1 -0
- package/src/components/documents/view/document-actions-bar.tsx +29 -7
- package/src/components/entities/entity-settings-form/locales/de.ts +6 -3
- package/src/components/entities/entity-settings-form/locales/es.ts +6 -3
- package/src/components/entities/entity-settings-form/locales/fr.ts +6 -3
- package/src/components/entities/entity-settings-form/locales/hr.ts +4 -2
- package/src/components/entities/entity-settings-form/locales/it.ts +6 -3
- package/src/components/entities/entity-settings-form/locales/nl.ts +6 -3
- package/src/components/entities/entity-settings-form/locales/pl.ts +6 -2
- package/src/components/entities/entity-settings-form/locales/pt.ts +6 -3
- package/src/components/entities/entity-settings-form/locales/sl.ts +4 -2
- package/src/components/entities/settings/tax-rules-settings-form.tsx +31 -13
- package/src/components/estimates/create/create-estimate-form.tsx +3 -2
- package/src/components/estimates/create/locales/de.ts +2 -1
- package/src/components/estimates/create/locales/es.ts +2 -1
- package/src/components/estimates/create/locales/fr.ts +2 -1
- package/src/components/estimates/create/locales/hr.ts +2 -1
- package/src/components/estimates/create/locales/it.ts +2 -1
- package/src/components/estimates/create/locales/nl.ts +2 -1
- package/src/components/estimates/create/locales/pl.ts +2 -1
- package/src/components/estimates/create/locales/pt.ts +2 -1
- package/src/components/estimates/create/locales/sl.ts +2 -1
- package/src/components/invoices/create/create-invoice-form.tsx +134 -62
- package/src/components/invoices/create/locales/de.ts +8 -1
- package/src/components/invoices/create/locales/es.ts +8 -1
- package/src/components/invoices/create/locales/fr.ts +8 -1
- package/src/components/invoices/create/locales/hr.ts +8 -1
- package/src/components/invoices/create/locales/it.ts +8 -1
- package/src/components/invoices/create/locales/nl.ts +8 -1
- package/src/components/invoices/create/locales/pl.ts +8 -1
- package/src/components/invoices/create/locales/pt.ts +8 -1
- package/src/components/invoices/create/locales/sl.ts +8 -1
- package/src/components/invoices/invoices.hooks.ts +1 -1
- package/src/components/ui/progress.tsx +27 -0
- package/src/generate-schemas.ts +15 -2
- package/src/generated/schemas/advanceinvoice.ts +2 -0
- package/src/generated/schemas/creditnote.ts +2 -0
- package/src/generated/schemas/customer.ts +2 -0
- package/src/generated/schemas/deliverynote.ts +2 -0
- package/src/generated/schemas/entity.ts +10 -0
- package/src/generated/schemas/estimate.ts +2 -0
- package/src/generated/schemas/finasettings.ts +4 -3
- package/src/generated/schemas/invoice.ts +2 -0
- package/src/generated/schemas/renderadvanceinvoicepreview_body.ts +16 -10
- package/src/generated/schemas/rendercreditnotepreview_body.ts +16 -10
- package/src/generated/schemas/renderdeliverynotepreview_body.ts +14 -7
- package/src/generated/schemas/renderestimatepreview_body.ts +14 -7
- package/src/generated/schemas/renderinvoicepreview_body.ts +16 -10
- package/src/generated/schemas/startpdfexport_body.ts +12 -17
- package/src/hooks/use-transaction-type-check.ts +152 -0
- package/src/hooks/use-vies-check.ts +7 -131
|
@@ -23,6 +23,7 @@ const DocumentEntity = z
|
|
|
23
23
|
tax_number: z.union([z.string(), z.null()]),
|
|
24
24
|
tax_number_2: z.union([z.string(), z.null()]),
|
|
25
25
|
company_number: z.union([z.string(), z.null()]),
|
|
26
|
+
is_end_consumer: z.union([z.boolean(), z.null()]),
|
|
26
27
|
bank_account: z.union([
|
|
27
28
|
z
|
|
28
29
|
.object({
|
|
@@ -71,8 +72,11 @@ const PartialEstimatePreview = z.object({
|
|
|
71
72
|
note: z.union([z.string(), z.null()]).optional(),
|
|
72
73
|
payment_terms: z.union([z.string(), z.null()]).optional(),
|
|
73
74
|
tax_clause: z.union([z.string(), z.null()]).optional(),
|
|
75
|
+
footer: z.union([z.string(), z.null()]).optional(),
|
|
76
|
+
signature: z.union([z.string(), z.null()]).optional(),
|
|
74
77
|
currency_code: z.string().max(3).optional(),
|
|
75
78
|
metadata: z.union([z.record(z.string(), z.any()), z.null()]).optional(),
|
|
79
|
+
reference: z.union([z.string(), z.null()]).optional(),
|
|
76
80
|
date_valid_till: z.union([z.string(), z.null()]).optional(),
|
|
77
81
|
title_type: z.union([z.enum(["estimate", "quote"]), z.null()]).optional(),
|
|
78
82
|
date_due: z.union([z.string(), z.null()]).optional(),
|
|
@@ -108,10 +112,10 @@ const PartialEstimatePreview = z.object({
|
|
|
108
112
|
const DocumentItemTax = z
|
|
109
113
|
.object({
|
|
110
114
|
rate: z.number(),
|
|
111
|
-
tax_id: z.string(),
|
|
112
|
-
classification: z.string(),
|
|
113
|
-
reverse_charge: z.boolean(),
|
|
114
|
-
amount: z.number(),
|
|
115
|
+
tax_id: z.union([z.string(), z.null()]),
|
|
116
|
+
classification: z.union([z.string(), z.null()]),
|
|
117
|
+
reverse_charge: z.union([z.boolean(), z.null()]),
|
|
118
|
+
amount: z.union([z.number(), z.null()]),
|
|
115
119
|
})
|
|
116
120
|
.partial();
|
|
117
121
|
|
|
@@ -126,16 +130,16 @@ const LineDiscount = z.object({
|
|
|
126
130
|
// Dependency schema for renderestimatepreview_body
|
|
127
131
|
const CreateDocumentItem = z
|
|
128
132
|
.object({
|
|
129
|
-
type: z.literal("separator"),
|
|
133
|
+
type: z.union([z.literal("separator"), z.null()]),
|
|
130
134
|
name: z.string().min(1),
|
|
131
135
|
description: z.union([z.string(), z.null()]),
|
|
132
136
|
price: z.number(),
|
|
133
|
-
gross_price: z.number(),
|
|
137
|
+
gross_price: z.union([z.number(), z.null()]),
|
|
134
138
|
quantity: z.number().gte(-140737488355328).lte(140737488355327),
|
|
135
139
|
unit: z.union([z.string(), z.null()]),
|
|
136
140
|
taxes: z.array(DocumentItemTax),
|
|
137
141
|
discounts: z.array(LineDiscount).max(5),
|
|
138
|
-
item_id: z.string(),
|
|
142
|
+
item_id: z.union([z.string(), z.null()]),
|
|
139
143
|
metadata: z.union([z.record(z.string(), z.any()), z.null()]),
|
|
140
144
|
save_item: z.boolean().default(true),
|
|
141
145
|
})
|
|
@@ -155,8 +159,11 @@ const CompleteEstimatePreview = z.object({
|
|
|
155
159
|
note: z.union([z.string(), z.null()]).optional(),
|
|
156
160
|
payment_terms: z.union([z.string(), z.null()]).optional(),
|
|
157
161
|
tax_clause: z.union([z.string(), z.null()]).optional(),
|
|
162
|
+
footer: z.union([z.string(), z.null()]).optional(),
|
|
163
|
+
signature: z.union([z.string(), z.null()]).optional(),
|
|
158
164
|
currency_code: z.string().max(3).optional(),
|
|
159
165
|
metadata: z.union([z.record(z.string(), z.any()), z.null()]).optional(),
|
|
166
|
+
reference: z.union([z.string(), z.null()]).optional(),
|
|
160
167
|
date_valid_till: z.union([z.string(), z.null()]).optional(),
|
|
161
168
|
title_type: z.union([z.enum(["estimate", "quote"]), z.null()]).optional(),
|
|
162
169
|
date_due: z.union([z.string(), z.null()]).optional(),
|
|
@@ -23,6 +23,7 @@ const DocumentEntity = z
|
|
|
23
23
|
tax_number: z.union([z.string(), z.null()]),
|
|
24
24
|
tax_number_2: z.union([z.string(), z.null()]),
|
|
25
25
|
company_number: z.union([z.string(), z.null()]),
|
|
26
|
+
is_end_consumer: z.union([z.boolean(), z.null()]),
|
|
26
27
|
bank_account: z.union([
|
|
27
28
|
z
|
|
28
29
|
.object({
|
|
@@ -62,18 +63,17 @@ const CreateDocumentCustomer = DocumentEntity.and(
|
|
|
62
63
|
const CreateFinaInvoiceData = z.union([
|
|
63
64
|
z
|
|
64
65
|
.object({
|
|
65
|
-
|
|
66
|
+
business_premise_name: z
|
|
66
67
|
.string()
|
|
67
68
|
.min(1)
|
|
68
69
|
.max(20)
|
|
69
70
|
.regex(/^[0-9a-zA-Z]{1,20}$/),
|
|
70
|
-
|
|
71
|
+
electronic_device_name: z
|
|
71
72
|
.string()
|
|
72
73
|
.min(1)
|
|
73
74
|
.max(20)
|
|
74
75
|
.regex(/^\d{1,20}$/),
|
|
75
76
|
operator_oib: z.string().min(11).max(11),
|
|
76
|
-
is_end_consumer: z.boolean(),
|
|
77
77
|
payment_type: z.enum([
|
|
78
78
|
"cash",
|
|
79
79
|
"card",
|
|
@@ -104,8 +104,11 @@ const PartialInvoicePreview = z.object({
|
|
|
104
104
|
note: z.union([z.string(), z.null()]).optional(),
|
|
105
105
|
payment_terms: z.union([z.string(), z.null()]).optional(),
|
|
106
106
|
tax_clause: z.union([z.string(), z.null()]).optional(),
|
|
107
|
+
footer: z.union([z.string(), z.null()]).optional(),
|
|
108
|
+
signature: z.union([z.string(), z.null()]).optional(),
|
|
107
109
|
currency_code: z.string().max(3).optional(),
|
|
108
110
|
metadata: z.union([z.record(z.string(), z.any()), z.null()]).optional(),
|
|
111
|
+
reference: z.union([z.string(), z.null()]).optional(),
|
|
109
112
|
date_due: z.union([z.string(), z.null()]).optional(),
|
|
110
113
|
date_service: z.union([z.string(), z.null()]).optional(),
|
|
111
114
|
date_service_to: z.union([z.string(), z.null()]).optional(),
|
|
@@ -141,10 +144,10 @@ const PartialInvoicePreview = z.object({
|
|
|
141
144
|
const DocumentItemTax = z
|
|
142
145
|
.object({
|
|
143
146
|
rate: z.number(),
|
|
144
|
-
tax_id: z.string(),
|
|
145
|
-
classification: z.string(),
|
|
146
|
-
reverse_charge: z.boolean(),
|
|
147
|
-
amount: z.number(),
|
|
147
|
+
tax_id: z.union([z.string(), z.null()]),
|
|
148
|
+
classification: z.union([z.string(), z.null()]),
|
|
149
|
+
reverse_charge: z.union([z.boolean(), z.null()]),
|
|
150
|
+
amount: z.union([z.number(), z.null()]),
|
|
148
151
|
})
|
|
149
152
|
.partial();
|
|
150
153
|
|
|
@@ -159,16 +162,16 @@ const LineDiscount = z.object({
|
|
|
159
162
|
// Dependency schema for renderinvoicepreview_body
|
|
160
163
|
const CreateDocumentItem = z
|
|
161
164
|
.object({
|
|
162
|
-
type: z.literal("separator"),
|
|
165
|
+
type: z.union([z.literal("separator"), z.null()]),
|
|
163
166
|
name: z.string().min(1),
|
|
164
167
|
description: z.union([z.string(), z.null()]),
|
|
165
168
|
price: z.number(),
|
|
166
|
-
gross_price: z.number(),
|
|
169
|
+
gross_price: z.union([z.number(), z.null()]),
|
|
167
170
|
quantity: z.number().gte(-140737488355328).lte(140737488355327),
|
|
168
171
|
unit: z.union([z.string(), z.null()]),
|
|
169
172
|
taxes: z.array(DocumentItemTax),
|
|
170
173
|
discounts: z.array(LineDiscount).max(5),
|
|
171
|
-
item_id: z.string(),
|
|
174
|
+
item_id: z.union([z.string(), z.null()]),
|
|
172
175
|
metadata: z.union([z.record(z.string(), z.any()), z.null()]),
|
|
173
176
|
save_item: z.boolean().default(true),
|
|
174
177
|
})
|
|
@@ -188,8 +191,11 @@ const CompleteInvoicePreview = z.object({
|
|
|
188
191
|
note: z.union([z.string(), z.null()]).optional(),
|
|
189
192
|
payment_terms: z.union([z.string(), z.null()]).optional(),
|
|
190
193
|
tax_clause: z.union([z.string(), z.null()]).optional(),
|
|
194
|
+
footer: z.union([z.string(), z.null()]).optional(),
|
|
195
|
+
signature: z.union([z.string(), z.null()]).optional(),
|
|
191
196
|
currency_code: z.string().max(3).optional(),
|
|
192
197
|
metadata: z.union([z.record(z.string(), z.any()), z.null()]).optional(),
|
|
198
|
+
reference: z.union([z.string(), z.null()]).optional(),
|
|
193
199
|
date_due: z.union([z.string(), z.null()]).optional(),
|
|
194
200
|
date_service: z.union([z.string(), z.null()]).optional(),
|
|
195
201
|
date_service_to: z.union([z.string(), z.null()]).optional(),
|
|
@@ -10,29 +10,24 @@ import { z } from 'zod';
|
|
|
10
10
|
|
|
11
11
|
// Dependency schema for startpdfexport_body
|
|
12
12
|
const PdfExportByDocumentIds = z
|
|
13
|
-
.object({
|
|
14
|
-
type: z.enum([
|
|
15
|
-
"invoice",
|
|
16
|
-
"estimate",
|
|
17
|
-
"credit_note",
|
|
18
|
-
"advance_invoice",
|
|
19
|
-
"delivery_note",
|
|
20
|
-
]),
|
|
21
|
-
document_ids: z.array(z.string()).min(1),
|
|
22
|
-
})
|
|
13
|
+
.object({ document_ids: z.array(z.string()).min(1) })
|
|
23
14
|
.passthrough();
|
|
24
15
|
|
|
25
16
|
|
|
26
17
|
// Dependency schema for startpdfexport_body
|
|
27
18
|
const PdfExportByDateRange = z
|
|
28
19
|
.object({
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
20
|
+
types: z
|
|
21
|
+
.array(
|
|
22
|
+
z.enum([
|
|
23
|
+
"invoice",
|
|
24
|
+
"estimate",
|
|
25
|
+
"credit_note",
|
|
26
|
+
"advance_invoice",
|
|
27
|
+
"delivery_note",
|
|
28
|
+
])
|
|
29
|
+
)
|
|
30
|
+
.min(1),
|
|
36
31
|
date_from: z.string().optional(),
|
|
37
32
|
date_to: z.string().optional(),
|
|
38
33
|
})
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import type { TransactionTypeCheckRequest, TransactionTypeCheckResponse } from "@spaceinvoices/js-sdk";
|
|
2
|
+
import { useQuery } from "@tanstack/react-query";
|
|
3
|
+
import { useMemo } from "react";
|
|
4
|
+
import { useSDK } from "../providers/sdk-provider";
|
|
5
|
+
import { useDebounce } from "./use-debounce";
|
|
6
|
+
|
|
7
|
+
export const TRANSACTION_TYPE_CHECK_CACHE_KEY = "transaction-type-check";
|
|
8
|
+
|
|
9
|
+
/** Debounce delay for transaction type checks (ms) */
|
|
10
|
+
const CHECK_DEBOUNCE_DELAY = 500;
|
|
11
|
+
|
|
12
|
+
/** Cache time for results - 5 minutes */
|
|
13
|
+
const CHECK_STALE_TIME = 5 * 60 * 1000;
|
|
14
|
+
|
|
15
|
+
export interface UseTransactionTypeCheckParams {
|
|
16
|
+
/** Issuer country name or code */
|
|
17
|
+
issuerCountry?: string | null;
|
|
18
|
+
/** Issuer country code (takes precedence over country name) */
|
|
19
|
+
issuerCountryCode?: string | null;
|
|
20
|
+
/** Whether the issuer is a tax subject (default: true) */
|
|
21
|
+
isTaxSubject?: boolean;
|
|
22
|
+
/** Customer country name or code */
|
|
23
|
+
customerCountry?: string | null;
|
|
24
|
+
/** Customer country code (takes precedence over country name) */
|
|
25
|
+
customerCountryCode?: string | null;
|
|
26
|
+
/** Customer VAT/tax number */
|
|
27
|
+
customerTaxNumber?: string | null;
|
|
28
|
+
/** Whether the customer is an end consumer (B2C override) */
|
|
29
|
+
customerIsEndConsumer?: boolean;
|
|
30
|
+
/** Whether to enable the query (default: true) */
|
|
31
|
+
enabled?: boolean;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface UseTransactionTypeCheckResult {
|
|
35
|
+
/** The check result */
|
|
36
|
+
data: TransactionTypeCheckResponse | undefined;
|
|
37
|
+
/** Whether the query is loading */
|
|
38
|
+
isLoading: boolean;
|
|
39
|
+
/** Whether the query is fetching (includes background refetches) */
|
|
40
|
+
isFetching: boolean;
|
|
41
|
+
/** Error if the query failed */
|
|
42
|
+
error: Error | null;
|
|
43
|
+
/** Whether reverse charge should be applied */
|
|
44
|
+
reverseChargeApplies: boolean;
|
|
45
|
+
/** Transaction type determined by check */
|
|
46
|
+
transactionType: TransactionTypeCheckResponse["transaction_type"] | undefined;
|
|
47
|
+
/** Customer country code returned by check */
|
|
48
|
+
customerCountryCode: string | null;
|
|
49
|
+
/** Warning message from VIES validation */
|
|
50
|
+
warning: string | null;
|
|
51
|
+
/** Whether VIES validation was successful */
|
|
52
|
+
viesValid: boolean | null;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Hook to check transaction type for a given issuer/customer combination.
|
|
57
|
+
* Uses debouncing to avoid excessive API calls during typing.
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```tsx
|
|
61
|
+
* const { reverseChargeApplies, transactionType, warning } = useTransactionTypeCheck({
|
|
62
|
+
* issuerCountryCode: entity.country_code,
|
|
63
|
+
* isTaxSubject: entity.is_tax_subject,
|
|
64
|
+
* customerCountry: customer.country,
|
|
65
|
+
* customerTaxNumber: customer.tax_number,
|
|
66
|
+
* customerIsEndConsumer: customer.is_end_consumer,
|
|
67
|
+
* });
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export function useTransactionTypeCheck({
|
|
71
|
+
issuerCountry,
|
|
72
|
+
issuerCountryCode,
|
|
73
|
+
isTaxSubject = true,
|
|
74
|
+
customerCountry,
|
|
75
|
+
customerCountryCode,
|
|
76
|
+
customerTaxNumber,
|
|
77
|
+
customerIsEndConsumer,
|
|
78
|
+
enabled = true,
|
|
79
|
+
}: UseTransactionTypeCheckParams): UseTransactionTypeCheckResult {
|
|
80
|
+
const { sdk } = useSDK();
|
|
81
|
+
|
|
82
|
+
// Build the request object
|
|
83
|
+
const requestData = useMemo((): TransactionTypeCheckRequest | null => {
|
|
84
|
+
// Need at least issuer info to make a check
|
|
85
|
+
if (!issuerCountry && !issuerCountryCode) return null;
|
|
86
|
+
|
|
87
|
+
// Need at least some customer info to make a meaningful check
|
|
88
|
+
if (!customerCountry && !customerCountryCode && !customerTaxNumber) return null;
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
issuer: {
|
|
92
|
+
country: issuerCountry || undefined,
|
|
93
|
+
country_code: issuerCountryCode || undefined,
|
|
94
|
+
is_tax_subject: isTaxSubject,
|
|
95
|
+
},
|
|
96
|
+
customer: {
|
|
97
|
+
country: customerCountry || undefined,
|
|
98
|
+
country_code: customerCountryCode || undefined,
|
|
99
|
+
tax_number: customerTaxNumber || undefined,
|
|
100
|
+
is_end_consumer: customerIsEndConsumer,
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
}, [
|
|
104
|
+
issuerCountry,
|
|
105
|
+
issuerCountryCode,
|
|
106
|
+
isTaxSubject,
|
|
107
|
+
customerCountry,
|
|
108
|
+
customerCountryCode,
|
|
109
|
+
customerTaxNumber,
|
|
110
|
+
customerIsEndConsumer,
|
|
111
|
+
]);
|
|
112
|
+
|
|
113
|
+
// Debounce the request data to avoid excessive API calls
|
|
114
|
+
const debouncedRequest = useDebounce(requestData, CHECK_DEBOUNCE_DELAY);
|
|
115
|
+
|
|
116
|
+
// Create a stable query key
|
|
117
|
+
const queryKey = useMemo(() => [TRANSACTION_TYPE_CHECK_CACHE_KEY, debouncedRequest], [debouncedRequest]);
|
|
118
|
+
|
|
119
|
+
const query = useQuery({
|
|
120
|
+
queryKey,
|
|
121
|
+
queryFn: async () => {
|
|
122
|
+
if (!debouncedRequest) throw new Error("No request data");
|
|
123
|
+
// Use sdk.vies.checkVies which hits the same endpoint types
|
|
124
|
+
// (sdk.transactionType is not reliably available in Vite pre-bundled builds)
|
|
125
|
+
const checkFn = sdk.transactionType?.checkTransactionType ?? sdk.vies.checkVies;
|
|
126
|
+
return checkFn(debouncedRequest);
|
|
127
|
+
},
|
|
128
|
+
enabled: enabled && !!sdk && !!debouncedRequest,
|
|
129
|
+
staleTime: CHECK_STALE_TIME,
|
|
130
|
+
refetchOnWindowFocus: false,
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
return {
|
|
134
|
+
data: query.data,
|
|
135
|
+
isLoading: query.isLoading,
|
|
136
|
+
isFetching: query.isFetching,
|
|
137
|
+
error: query.error,
|
|
138
|
+
reverseChargeApplies: query.data?.reverse_charge_applies ?? false,
|
|
139
|
+
transactionType: query.data?.transaction_type,
|
|
140
|
+
customerCountryCode: query.data?.customer_country_code ?? null,
|
|
141
|
+
warning: query.data?.warning ?? null,
|
|
142
|
+
viesValid: query.data?.vies_valid ?? null,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* @deprecated Use useTransactionTypeCheck instead
|
|
148
|
+
*/
|
|
149
|
+
export const useViesCheck = useTransactionTypeCheck;
|
|
150
|
+
export type UseViesCheckParams = UseTransactionTypeCheckParams;
|
|
151
|
+
export type UseViesCheckResult = UseTransactionTypeCheckResult;
|
|
152
|
+
export const VIES_CHECK_CACHE_KEY = TRANSACTION_TYPE_CHECK_CACHE_KEY;
|
|
@@ -1,133 +1,9 @@
|
|
|
1
|
-
import type { ViesCheckRequest, ViesCheckResponse } from "@spaceinvoices/js-sdk";
|
|
2
|
-
import { useQuery } from "@tanstack/react-query";
|
|
3
|
-
import { useMemo } from "react";
|
|
4
|
-
import { useSDK } from "../providers/sdk-provider";
|
|
5
|
-
import { useDebounce } from "./use-debounce";
|
|
6
|
-
|
|
7
|
-
export const VIES_CHECK_CACHE_KEY = "vies-check";
|
|
8
|
-
|
|
9
|
-
/** Debounce delay for VIES checks (ms) */
|
|
10
|
-
const VIES_DEBOUNCE_DELAY = 500;
|
|
11
|
-
|
|
12
|
-
/** Cache time for VIES results - 5 minutes */
|
|
13
|
-
const VIES_STALE_TIME = 5 * 60 * 1000;
|
|
14
|
-
|
|
15
|
-
export interface UseViesCheckParams {
|
|
16
|
-
/** Issuer country name or code */
|
|
17
|
-
issuerCountry?: string | null;
|
|
18
|
-
/** Issuer country code (takes precedence over country name) */
|
|
19
|
-
issuerCountryCode?: string | null;
|
|
20
|
-
/** Whether the issuer is a tax subject (default: true) */
|
|
21
|
-
isTaxSubject?: boolean;
|
|
22
|
-
/** Customer country name or code */
|
|
23
|
-
customerCountry?: string | null;
|
|
24
|
-
/** Customer country code (takes precedence over country name) */
|
|
25
|
-
customerCountryCode?: string | null;
|
|
26
|
-
/** Customer VAT/tax number */
|
|
27
|
-
customerTaxNumber?: string | null;
|
|
28
|
-
/** Whether to enable the query (default: true) */
|
|
29
|
-
enabled?: boolean;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export interface UseViesCheckResult {
|
|
33
|
-
/** The VIES check result */
|
|
34
|
-
data: ViesCheckResponse | undefined;
|
|
35
|
-
/** Whether the query is loading */
|
|
36
|
-
isLoading: boolean;
|
|
37
|
-
/** Whether the query is fetching (includes background refetches) */
|
|
38
|
-
isFetching: boolean;
|
|
39
|
-
/** Error if the query failed */
|
|
40
|
-
error: Error | null;
|
|
41
|
-
/** Whether reverse charge should be applied */
|
|
42
|
-
reverseChargeApplies: boolean;
|
|
43
|
-
/** Transaction type determined by VIES check */
|
|
44
|
-
transactionType: ViesCheckResponse["transaction_type"] | undefined;
|
|
45
|
-
/** Customer country code returned by VIES check */
|
|
46
|
-
customerCountryCode: string | null;
|
|
47
|
-
/** Warning message from VIES validation */
|
|
48
|
-
warning: string | null;
|
|
49
|
-
/** Whether VIES validation was successful */
|
|
50
|
-
viesValid: boolean | null;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
1
|
/**
|
|
54
|
-
*
|
|
55
|
-
* Uses debouncing to avoid excessive API calls during typing.
|
|
56
|
-
*
|
|
57
|
-
* @example
|
|
58
|
-
* ```tsx
|
|
59
|
-
* const { reverseChargeApplies, transactionType, warning } = useViesCheck({
|
|
60
|
-
* issuerCountryCode: entity.country_code,
|
|
61
|
-
* isTaxSubject: entity.is_tax_subject,
|
|
62
|
-
* customerCountry: customer.country,
|
|
63
|
-
* customerTaxNumber: customer.tax_number,
|
|
64
|
-
* });
|
|
65
|
-
*
|
|
66
|
-
* // Disable taxes when reverse charge applies
|
|
67
|
-
* if (reverseChargeApplies) {
|
|
68
|
-
* // Show reverse charge message and disable tax controls
|
|
69
|
-
* }
|
|
70
|
-
* ```
|
|
2
|
+
* @deprecated Use use-transaction-type-check.ts instead
|
|
71
3
|
*/
|
|
72
|
-
export
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
customerTaxNumber,
|
|
79
|
-
enabled = true,
|
|
80
|
-
}: UseViesCheckParams): UseViesCheckResult {
|
|
81
|
-
const { sdk } = useSDK();
|
|
82
|
-
|
|
83
|
-
// Build the request object
|
|
84
|
-
const requestData = useMemo((): ViesCheckRequest | null => {
|
|
85
|
-
// Need at least issuer info to make a check
|
|
86
|
-
if (!issuerCountry && !issuerCountryCode) return null;
|
|
87
|
-
|
|
88
|
-
// Need at least some customer info to make a meaningful check
|
|
89
|
-
if (!customerCountry && !customerCountryCode && !customerTaxNumber) return null;
|
|
90
|
-
|
|
91
|
-
return {
|
|
92
|
-
issuer: {
|
|
93
|
-
country: issuerCountry || undefined,
|
|
94
|
-
country_code: issuerCountryCode || undefined,
|
|
95
|
-
is_tax_subject: isTaxSubject,
|
|
96
|
-
},
|
|
97
|
-
customer: {
|
|
98
|
-
country: customerCountry || undefined,
|
|
99
|
-
country_code: customerCountryCode || undefined,
|
|
100
|
-
tax_number: customerTaxNumber || undefined,
|
|
101
|
-
},
|
|
102
|
-
};
|
|
103
|
-
}, [issuerCountry, issuerCountryCode, isTaxSubject, customerCountry, customerCountryCode, customerTaxNumber]);
|
|
104
|
-
|
|
105
|
-
// Debounce the request data to avoid excessive API calls
|
|
106
|
-
const debouncedRequest = useDebounce(requestData, VIES_DEBOUNCE_DELAY);
|
|
107
|
-
|
|
108
|
-
// Create a stable query key
|
|
109
|
-
const queryKey = useMemo(() => [VIES_CHECK_CACHE_KEY, debouncedRequest], [debouncedRequest]);
|
|
110
|
-
|
|
111
|
-
const query = useQuery({
|
|
112
|
-
queryKey,
|
|
113
|
-
queryFn: async () => {
|
|
114
|
-
if (!debouncedRequest) throw new Error("No request data");
|
|
115
|
-
return sdk.vies.checkVies(debouncedRequest);
|
|
116
|
-
},
|
|
117
|
-
enabled: enabled && !!sdk && !!debouncedRequest,
|
|
118
|
-
staleTime: VIES_STALE_TIME,
|
|
119
|
-
refetchOnWindowFocus: false,
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
return {
|
|
123
|
-
data: query.data,
|
|
124
|
-
isLoading: query.isLoading,
|
|
125
|
-
isFetching: query.isFetching,
|
|
126
|
-
error: query.error,
|
|
127
|
-
reverseChargeApplies: query.data?.reverse_charge_applies ?? false,
|
|
128
|
-
transactionType: query.data?.transaction_type,
|
|
129
|
-
customerCountryCode: query.data?.customer_country_code ?? null,
|
|
130
|
-
warning: query.data?.warning ?? null,
|
|
131
|
-
viesValid: query.data?.vies_valid ?? null,
|
|
132
|
-
};
|
|
133
|
-
}
|
|
4
|
+
export {
|
|
5
|
+
TRANSACTION_TYPE_CHECK_CACHE_KEY as VIES_CHECK_CACHE_KEY,
|
|
6
|
+
type UseTransactionTypeCheckParams as UseViesCheckParams,
|
|
7
|
+
type UseTransactionTypeCheckResult as UseViesCheckResult,
|
|
8
|
+
useTransactionTypeCheck as useViesCheck,
|
|
9
|
+
} from "./use-transaction-type-check";
|