@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
|
@@ -182,8 +182,10 @@ export default {
|
|
|
182
182
|
"tax-clauses.intra_eu_b2b.description":
|
|
183
183
|
"Za prodaju EU tvrtkama s valjanim PDV brojevima. Obično uključuje izjavu o prijenosu porezne obveze.",
|
|
184
184
|
"Enter reverse charge clause...": "Unesite klauzulu o prijenosu porezne obveze...",
|
|
185
|
-
"tax-clauses.
|
|
186
|
-
"tax-clauses.
|
|
185
|
+
"tax-clauses.3w_b2b.label": "Izvan EU B2B (izvoz)",
|
|
186
|
+
"tax-clauses.3w_b2b.description": "Za prodaju poduzećima izvan EU. Obično navodi oslobođenje od PDV-a za izvoz.",
|
|
187
|
+
"tax-clauses.3w_b2c.label": "Izvan EU B2C (izvoz)",
|
|
188
|
+
"tax-clauses.3w_b2c.description": "Za prodaju potrošačima izvan EU. Obično navodi oslobođenje od PDV-a za izvoz.",
|
|
187
189
|
"Enter export exemption clause...": "Unesite klauzulu o oslobođenju od izvoza...",
|
|
188
190
|
"tax-clauses.domestic.label": "Zadano / Domaće",
|
|
189
191
|
"tax-clauses.domestic.description":
|
|
@@ -187,9 +187,12 @@ export default {
|
|
|
187
187
|
"tax-clauses.intra_eu_b2b.description":
|
|
188
188
|
"Per vendite a imprese UE con numeri IVA validi. Di solito include una dichiarazione di inversione contabile.",
|
|
189
189
|
"Enter reverse charge clause...": "Inserisci la clausola di inversione contabile...",
|
|
190
|
-
"tax-clauses.
|
|
191
|
-
"tax-clauses.
|
|
192
|
-
"Per vendite a
|
|
190
|
+
"tax-clauses.3w_b2b.label": "Extra-UE B2B (esportazione)",
|
|
191
|
+
"tax-clauses.3w_b2b.description":
|
|
192
|
+
"Per vendite a imprese extra-UE. Di solito indica l'esenzione IVA per esportazione.",
|
|
193
|
+
"tax-clauses.3w_b2c.label": "Extra-UE B2C (esportazione)",
|
|
194
|
+
"tax-clauses.3w_b2c.description":
|
|
195
|
+
"Per vendite a consumatori extra-UE. Di solito indica l'esenzione IVA per esportazione.",
|
|
193
196
|
"Enter export exemption clause...": "Inserisci la clausola di esenzione per esportazione...",
|
|
194
197
|
"tax-clauses.domestic.label": "Predefinito / Nazionale",
|
|
195
198
|
"tax-clauses.domestic.description":
|
|
@@ -184,9 +184,12 @@ export default {
|
|
|
184
184
|
"tax-clauses.intra_eu_b2b.description":
|
|
185
185
|
"Voor verkopen aan EU-bedrijven met geldige btw-nummers. Bevat meestal een verklaring van verlegging.",
|
|
186
186
|
"Enter reverse charge clause...": "Voer de verleggingsclausule in...",
|
|
187
|
-
"tax-clauses.
|
|
188
|
-
"tax-clauses.
|
|
189
|
-
"Voor verkopen aan
|
|
187
|
+
"tax-clauses.3w_b2b.label": "Niet-EU B2B (export)",
|
|
188
|
+
"tax-clauses.3w_b2b.description":
|
|
189
|
+
"Voor verkopen aan bedrijven buiten de EU. Vermeldt meestal de btw-vrijstelling voor export.",
|
|
190
|
+
"tax-clauses.3w_b2c.label": "Niet-EU B2C (export)",
|
|
191
|
+
"tax-clauses.3w_b2c.description":
|
|
192
|
+
"Voor verkopen aan consumenten buiten de EU. Vermeldt meestal de btw-vrijstelling voor export.",
|
|
190
193
|
"Enter export exemption clause...": "Voer de exportvrijstellingsclausule in...",
|
|
191
194
|
"tax-clauses.domestic.label": "Standaard / Binnenlands",
|
|
192
195
|
"tax-clauses.domestic.description":
|
|
@@ -186,8 +186,12 @@ export default {
|
|
|
186
186
|
"tax-clauses.intra_eu_b2b.description":
|
|
187
187
|
"Dla sprzedaży firmom w UE z ważnymi numerami VAT. Zwykle zawiera oświadczenie o odwrotnym obciążeniu.",
|
|
188
188
|
"Enter reverse charge clause...": "Wprowadź klauzulę odwrotnego obciążenia...",
|
|
189
|
-
"tax-clauses.
|
|
190
|
-
"tax-clauses.
|
|
189
|
+
"tax-clauses.3w_b2b.label": "Poza UE B2B (eksport)",
|
|
190
|
+
"tax-clauses.3w_b2b.description":
|
|
191
|
+
"Dla sprzedaży do przedsiębiorstw spoza UE. Zwykle wskazuje zwolnienie z VAT na eksport.",
|
|
192
|
+
"tax-clauses.3w_b2c.label": "Poza UE B2C (eksport)",
|
|
193
|
+
"tax-clauses.3w_b2c.description":
|
|
194
|
+
"Dla sprzedaży do konsumentów spoza UE. Zwykle wskazuje zwolnienie z VAT na eksport.",
|
|
191
195
|
"Enter export exemption clause...": "Wprowadź klauzulę zwolnienia eksportowego...",
|
|
192
196
|
"tax-clauses.domestic.label": "Domyślne / Krajowe",
|
|
193
197
|
"tax-clauses.domestic.description":
|
|
@@ -186,9 +186,12 @@ export default {
|
|
|
186
186
|
"tax-clauses.intra_eu_b2b.description":
|
|
187
187
|
"Para vendas a empresas da UE com números de IVA válidos. Normalmente inclui uma declaração de autoliquidação.",
|
|
188
188
|
"Enter reverse charge clause...": "Introduza a cláusula de autoliquidação...",
|
|
189
|
-
"tax-clauses.
|
|
190
|
-
"tax-clauses.
|
|
191
|
-
"Para vendas a
|
|
189
|
+
"tax-clauses.3w_b2b.label": "Fora da UE B2B (exportação)",
|
|
190
|
+
"tax-clauses.3w_b2b.description":
|
|
191
|
+
"Para vendas a empresas fora da UE. Normalmente indica a isenção de IVA por exportação.",
|
|
192
|
+
"tax-clauses.3w_b2c.label": "Fora da UE B2C (exportação)",
|
|
193
|
+
"tax-clauses.3w_b2c.description":
|
|
194
|
+
"Para vendas a consumidores fora da UE. Normalmente indica a isenção de IVA por exportação.",
|
|
192
195
|
"Enter export exemption clause...": "Introduza a cláusula de isenção de exportação...",
|
|
193
196
|
"tax-clauses.domestic.label": "Predefinido / Nacional",
|
|
194
197
|
"tax-clauses.domestic.description":
|
|
@@ -181,8 +181,10 @@ export default {
|
|
|
181
181
|
"tax-clauses.intra_eu_b2b.description":
|
|
182
182
|
"Za prodajo EU podjetjem z veljavnimi DDV številkami. Običajno vključuje izjavo o obrnjeni davčni obveznosti.",
|
|
183
183
|
"Enter reverse charge clause...": "Vnesite klavzulo za samoobdavčitev...",
|
|
184
|
-
"tax-clauses.
|
|
185
|
-
"tax-clauses.
|
|
184
|
+
"tax-clauses.3w_b2b.label": "Izven EU B2B (izvoz)",
|
|
185
|
+
"tax-clauses.3w_b2b.description": "Za prodajo podjetjem izven EU. Običajno navaja oprostitev DDV za izvoz.",
|
|
186
|
+
"tax-clauses.3w_b2c.label": "Izven EU B2C (izvoz)",
|
|
187
|
+
"tax-clauses.3w_b2c.description": "Za prodajo potrošnikom izven EU. Običajno navaja oprostitev DDV za izvoz.",
|
|
186
188
|
"Enter export exemption clause...": "Vnesite klavzulo za izvozno oprostitev...",
|
|
187
189
|
"tax-clauses.domestic.label": "Privzeto / Domače",
|
|
188
190
|
"tax-clauses.domestic.description":
|
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
import { zodResolver } from "@hookform/resolvers/zod";
|
|
2
|
-
import type {
|
|
3
|
-
Entity,
|
|
4
|
-
EntitySettings,
|
|
5
|
-
EntitySettingsTaxClauseDefaults,
|
|
6
|
-
TaxRules,
|
|
7
|
-
} from "@spaceinvoices/js-sdk";
|
|
2
|
+
import type { Entity, EntitySettings, EntitySettingsTaxClauseDefaults, TaxRules } from "@spaceinvoices/js-sdk";
|
|
8
3
|
import { ChevronDown, Globe, MessageSquareText } from "lucide-react";
|
|
9
4
|
import type { ReactNode } from "react";
|
|
10
5
|
import { useState } from "react";
|
|
@@ -39,7 +34,8 @@ const taxRulesSettingsSchema = z.object({
|
|
|
39
34
|
require_gross_prices: z.boolean(),
|
|
40
35
|
// Tax clause defaults per transaction type
|
|
41
36
|
tax_clause_intra_eu_b2b: z.string().optional(),
|
|
42
|
-
|
|
37
|
+
tax_clause_3w_b2b: z.string().optional(),
|
|
38
|
+
tax_clause_3w_b2c: z.string().optional(),
|
|
43
39
|
tax_clause_domestic: z.string().optional(),
|
|
44
40
|
tax_clause_intra_eu_b2c: z.string().optional(),
|
|
45
41
|
});
|
|
@@ -92,7 +88,8 @@ export function TaxRulesSettingsForm({
|
|
|
92
88
|
auto_remove_tax_export: currentTaxRules.auto_remove_tax_export ?? false,
|
|
93
89
|
require_gross_prices: currentTaxRules.require_gross_prices ?? false,
|
|
94
90
|
tax_clause_intra_eu_b2b: currentTaxClauseDefaults.intra_eu_b2b ?? "",
|
|
95
|
-
|
|
91
|
+
tax_clause_3w_b2b: (currentTaxClauseDefaults as any)["3w_b2b"] ?? currentTaxClauseDefaults.export ?? "",
|
|
92
|
+
tax_clause_3w_b2c: (currentTaxClauseDefaults as any)["3w_b2c"] ?? currentTaxClauseDefaults.export ?? "",
|
|
96
93
|
tax_clause_domestic: currentTaxClauseDefaults.domestic ?? "",
|
|
97
94
|
tax_clause_intra_eu_b2c: currentTaxClauseDefaults.intra_eu_b2c ?? "",
|
|
98
95
|
},
|
|
@@ -127,7 +124,8 @@ export function TaxRulesSettingsForm({
|
|
|
127
124
|
},
|
|
128
125
|
tax_clause_defaults: {
|
|
129
126
|
intra_eu_b2b: values.tax_clause_intra_eu_b2b || null,
|
|
130
|
-
|
|
127
|
+
"3w_b2b": values.tax_clause_3w_b2b || null,
|
|
128
|
+
"3w_b2c": values.tax_clause_3w_b2c || null,
|
|
131
129
|
domestic: values.tax_clause_domestic || null,
|
|
132
130
|
intra_eu_b2c: values.tax_clause_intra_eu_b2c || null,
|
|
133
131
|
},
|
|
@@ -288,14 +286,34 @@ export function TaxRulesSettingsForm({
|
|
|
288
286
|
)}
|
|
289
287
|
/>
|
|
290
288
|
|
|
291
|
-
{/*
|
|
289
|
+
{/* 3W B2B (non-EU business) */}
|
|
292
290
|
<FormField
|
|
293
291
|
control={form.control}
|
|
294
|
-
name="
|
|
292
|
+
name="tax_clause_3w_b2b"
|
|
295
293
|
render={({ field }) => (
|
|
296
294
|
<FormItem className="rounded-lg border p-4">
|
|
297
|
-
<FormLabel>{t("tax-clauses.
|
|
298
|
-
<FormDescription>{t("tax-clauses.
|
|
295
|
+
<FormLabel>{t("tax-clauses.3w_b2b.label")}</FormLabel>
|
|
296
|
+
<FormDescription>{t("tax-clauses.3w_b2b.description")}</FormDescription>
|
|
297
|
+
<FormControl>
|
|
298
|
+
<Textarea
|
|
299
|
+
placeholder={t("Enter export exemption clause...")}
|
|
300
|
+
className="min-h-[80px] resize-y"
|
|
301
|
+
{...field}
|
|
302
|
+
/>
|
|
303
|
+
</FormControl>
|
|
304
|
+
<FormMessage />
|
|
305
|
+
</FormItem>
|
|
306
|
+
)}
|
|
307
|
+
/>
|
|
308
|
+
|
|
309
|
+
{/* 3W B2C (non-EU consumer) */}
|
|
310
|
+
<FormField
|
|
311
|
+
control={form.control}
|
|
312
|
+
name="tax_clause_3w_b2c"
|
|
313
|
+
render={({ field }) => (
|
|
314
|
+
<FormItem className="rounded-lg border p-4">
|
|
315
|
+
<FormLabel>{t("tax-clauses.3w_b2c.label")}</FormLabel>
|
|
316
|
+
<FormDescription>{t("tax-clauses.3w_b2c.description")}</FormDescription>
|
|
299
317
|
<FormControl>
|
|
300
318
|
<Textarea
|
|
301
319
|
placeholder={t("Enter export exemption clause...")}
|
|
@@ -11,7 +11,7 @@ import { Form } from "@/ui/components/ui/form";
|
|
|
11
11
|
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/ui/components/ui/tooltip";
|
|
12
12
|
import { createEstimateSchema } from "@/ui/generated/schemas";
|
|
13
13
|
import { useNextDocumentNumber } from "@/ui/hooks/use-next-document-number";
|
|
14
|
-
import {
|
|
14
|
+
import { useTransactionTypeCheck } from "@/ui/hooks/use-transaction-type-check";
|
|
15
15
|
import type { ComponentTranslationProps } from "@/ui/lib/translation";
|
|
16
16
|
import { createTranslation } from "@/ui/lib/translation";
|
|
17
17
|
import { useEntities } from "@/ui/providers/entities-context";
|
|
@@ -259,12 +259,13 @@ export default function CreateEstimateForm({
|
|
|
259
259
|
transactionType,
|
|
260
260
|
isFetching: isViesFetching,
|
|
261
261
|
warning: viesWarning,
|
|
262
|
-
} =
|
|
262
|
+
} = useTransactionTypeCheck({
|
|
263
263
|
issuerCountryCode: activeEntity?.country_code,
|
|
264
264
|
isTaxSubject: activeEntity?.is_tax_subject ?? true,
|
|
265
265
|
customerCountry: formValues.customer?.country,
|
|
266
266
|
customerCountryCode: formValues.customer?.country_code,
|
|
267
267
|
customerTaxNumber: formValues.customer?.tax_number,
|
|
268
|
+
customerIsEndConsumer: (formValues.customer as any)?.is_end_consumer,
|
|
268
269
|
enabled: !!activeEntity,
|
|
269
270
|
});
|
|
270
271
|
|
|
@@ -73,7 +73,8 @@ export default {
|
|
|
73
73
|
Domestic: "Inland",
|
|
74
74
|
"EU B2B": "EU B2B",
|
|
75
75
|
"EU B2C": "EU B2C",
|
|
76
|
-
|
|
76
|
+
"3W B2B": "3W B2B",
|
|
77
|
+
"3W B2C": "3W B2C",
|
|
77
78
|
"Determining transaction type...": "Transaktionstyp wird ermittelt...",
|
|
78
79
|
"This invoice will not be fiscalized (non-domestic transaction)":
|
|
79
80
|
"Diese Rechnung wird nicht fiskalisiert (nicht-inländische Transaktion)",
|
|
@@ -66,7 +66,8 @@ export default {
|
|
|
66
66
|
Domestic: "Nacional",
|
|
67
67
|
"EU B2B": "EU B2B",
|
|
68
68
|
"EU B2C": "EU B2C",
|
|
69
|
-
|
|
69
|
+
"3W B2B": "3W B2B",
|
|
70
|
+
"3W B2C": "3W B2C",
|
|
70
71
|
"Determining transaction type...": "Determinando tipo de transacción...",
|
|
71
72
|
"This invoice will not be fiscalized (non-domestic transaction)":
|
|
72
73
|
"Esta factura no será fiscalizada (transacción no nacional)",
|
|
@@ -67,7 +67,8 @@ export default {
|
|
|
67
67
|
Domestic: "Nationale",
|
|
68
68
|
"EU B2B": "EU B2B",
|
|
69
69
|
"EU B2C": "EU B2C",
|
|
70
|
-
|
|
70
|
+
"3W B2B": "3W B2B",
|
|
71
|
+
"3W B2C": "3W B2C",
|
|
71
72
|
"Determining transaction type...": "Détermination du type de transaction...",
|
|
72
73
|
"This invoice will not be fiscalized (non-domestic transaction)":
|
|
73
74
|
"Cette facture ne sera pas fiscalisée (transaction non nationale)",
|
|
@@ -66,7 +66,8 @@ export default {
|
|
|
66
66
|
Domestic: "Domaća",
|
|
67
67
|
"EU B2B": "EU B2B",
|
|
68
68
|
"EU B2C": "EU B2C",
|
|
69
|
-
|
|
69
|
+
"3W B2B": "3W B2B",
|
|
70
|
+
"3W B2C": "3W B2C",
|
|
70
71
|
"Determining transaction type...": "Određivanje vrste transakcije...",
|
|
71
72
|
"This invoice will not be fiscalized (non-domestic transaction)":
|
|
72
73
|
"Ovaj račun neće biti fiskaliziran (nedomaća transakcija)",
|
|
@@ -66,7 +66,8 @@ export default {
|
|
|
66
66
|
Domestic: "Nazionale",
|
|
67
67
|
"EU B2B": "EU B2B",
|
|
68
68
|
"EU B2C": "EU B2C",
|
|
69
|
-
|
|
69
|
+
"3W B2B": "3W B2B",
|
|
70
|
+
"3W B2C": "3W B2C",
|
|
70
71
|
"Determining transaction type...": "Determinazione tipo di transazione...",
|
|
71
72
|
"This invoice will not be fiscalized (non-domestic transaction)":
|
|
72
73
|
"Questa fattura non sarà fiscalizzata (transazione non nazionale)",
|
|
@@ -67,7 +67,8 @@ export default {
|
|
|
67
67
|
Domestic: "Binnenland",
|
|
68
68
|
"EU B2B": "EU B2B",
|
|
69
69
|
"EU B2C": "EU B2C",
|
|
70
|
-
|
|
70
|
+
"3W B2B": "3W B2B",
|
|
71
|
+
"3W B2C": "3W B2C",
|
|
71
72
|
"Determining transaction type...": "Transactietype bepalen...",
|
|
72
73
|
"This invoice will not be fiscalized (non-domestic transaction)":
|
|
73
74
|
"Deze factuur wordt niet gefiscaliseerd (niet-binnenlandse transactie)",
|
|
@@ -66,7 +66,8 @@ export default {
|
|
|
66
66
|
Domestic: "Krajowa",
|
|
67
67
|
"EU B2B": "EU B2B",
|
|
68
68
|
"EU B2C": "EU B2C",
|
|
69
|
-
|
|
69
|
+
"3W B2B": "3W B2B",
|
|
70
|
+
"3W B2C": "3W B2C",
|
|
70
71
|
"Determining transaction type...": "Określanie typu transakcji...",
|
|
71
72
|
"This invoice will not be fiscalized (non-domestic transaction)":
|
|
72
73
|
"Ta faktura nie będzie fiskalizowana (transakcja niekrajowa)",
|
|
@@ -67,7 +67,8 @@ export default {
|
|
|
67
67
|
Domestic: "Nacional",
|
|
68
68
|
"EU B2B": "EU B2B",
|
|
69
69
|
"EU B2C": "EU B2C",
|
|
70
|
-
|
|
70
|
+
"3W B2B": "3W B2B",
|
|
71
|
+
"3W B2C": "3W B2C",
|
|
71
72
|
"Determining transaction type...": "Determinando tipo de transação...",
|
|
72
73
|
"This invoice will not be fiscalized (non-domestic transaction)":
|
|
73
74
|
"Esta fatura não será fiscalizada (transação não nacional)",
|
|
@@ -72,7 +72,8 @@ export default {
|
|
|
72
72
|
Domestic: "Domača",
|
|
73
73
|
"EU B2B": "EU B2B",
|
|
74
74
|
"EU B2C": "EU B2C",
|
|
75
|
-
|
|
75
|
+
"3W B2B": "3W B2B",
|
|
76
|
+
"3W B2C": "3W B2C",
|
|
76
77
|
"Determining transaction type...": "Določanje vrste transakcije...",
|
|
77
78
|
"This invoice will not be fiscalized (non-domestic transaction)":
|
|
78
79
|
"Ta račun ne bo fiskaliziran (nedomača transakcija)",
|
|
@@ -13,7 +13,7 @@ import { Form } from "@/ui/components/ui/form";
|
|
|
13
13
|
import { Skeleton } from "@/ui/components/ui/skeleton";
|
|
14
14
|
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/ui/components/ui/tooltip";
|
|
15
15
|
import { createInvoiceSchema } from "@/ui/generated/schemas";
|
|
16
|
-
import {
|
|
16
|
+
import { useTransactionTypeCheck } from "@/ui/hooks/use-transaction-type-check";
|
|
17
17
|
import type { ComponentTranslationProps } from "@/ui/lib/translation";
|
|
18
18
|
import { createTranslation } from "@/ui/lib/translation";
|
|
19
19
|
import { cn } from "@/ui/lib/utils";
|
|
@@ -416,14 +416,56 @@ export default function CreateInvoiceForm({
|
|
|
416
416
|
const isFinaActive =
|
|
417
417
|
isFinaEnabled && hasFinaPremises && selectedFinaBusinessPremiseName && selectedFinaElectronicDeviceName;
|
|
418
418
|
|
|
419
|
+
// ============================================================================
|
|
420
|
+
// VIES Check - determine transaction type early (needed for number preview)
|
|
421
|
+
// ============================================================================
|
|
422
|
+
const customerCountry = useWatch({ control: form.control, name: "customer.country" });
|
|
423
|
+
const customerCountryCode = useWatch({ control: form.control, name: "customer.country_code" });
|
|
424
|
+
const customerTaxNumber = useWatch({ control: form.control, name: "customer.tax_number" });
|
|
425
|
+
const customerIsEndConsumerWatch =
|
|
426
|
+
useWatch({ control: form.control, name: "customer.is_end_consumer" as any }) === true;
|
|
427
|
+
|
|
428
|
+
const {
|
|
429
|
+
reverseChargeApplies,
|
|
430
|
+
transactionType,
|
|
431
|
+
isFetching: isViesFetching,
|
|
432
|
+
warning: viesWarning,
|
|
433
|
+
} = useTransactionTypeCheck({
|
|
434
|
+
issuerCountryCode: activeEntity?.country_code,
|
|
435
|
+
isTaxSubject: activeEntity?.is_tax_subject ?? true,
|
|
436
|
+
customerCountry,
|
|
437
|
+
customerCountryCode,
|
|
438
|
+
customerTaxNumber,
|
|
439
|
+
customerIsEndConsumer: customerIsEndConsumerWatch,
|
|
440
|
+
enabled: !!activeEntity,
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
// FINA numbering guard: use FINA numbering for domestic transactions (or all if unified numbering is on)
|
|
444
|
+
const finaUnifiedNumbering = finaSettings?.unified_numbering !== false;
|
|
445
|
+
const useFinaNumbering =
|
|
446
|
+
!!isFinaActive && (finaUnifiedNumbering || transactionType == null || transactionType === "domestic");
|
|
447
|
+
const isFinaNonDomestic = !!isFinaActive && !useFinaNumbering;
|
|
448
|
+
|
|
419
449
|
// ============================================================================
|
|
420
450
|
// Next Invoice Number Preview
|
|
421
451
|
// ============================================================================
|
|
422
452
|
// Wait for FURS selection to be ready before querying to prevent number flashing
|
|
423
453
|
// Skip in edit mode - we use the existing document number
|
|
454
|
+
// Use the same premise/device params for both FURS and FINA (an entity is either one, never both)
|
|
455
|
+
const activePremiseName = isFursActive
|
|
456
|
+
? selectedPremiseName
|
|
457
|
+
: useFinaNumbering
|
|
458
|
+
? selectedFinaBusinessPremiseName
|
|
459
|
+
: undefined;
|
|
460
|
+
const activeDeviceNameForNumber = isFursActive
|
|
461
|
+
? selectedDeviceName
|
|
462
|
+
: useFinaNumbering
|
|
463
|
+
? selectedFinaElectronicDeviceName
|
|
464
|
+
: undefined;
|
|
465
|
+
|
|
424
466
|
const { data: nextNumberData, isLoading: isNextNumberLoading } = useNextInvoiceNumber(entityId, {
|
|
425
|
-
business_premise_name:
|
|
426
|
-
electronic_device_name:
|
|
467
|
+
business_premise_name: activePremiseName,
|
|
468
|
+
electronic_device_name: activeDeviceNameForNumber,
|
|
427
469
|
enabled:
|
|
428
470
|
!!entityId && !isFursLoading && isFursSelectionReady && !isFinaLoading && isFinaSelectionReady && !isEditMode,
|
|
429
471
|
});
|
|
@@ -551,11 +593,6 @@ export default function CreateInvoiceForm({
|
|
|
551
593
|
}
|
|
552
594
|
}, [nextNumberData?.number, form]);
|
|
553
595
|
|
|
554
|
-
// Watch specific fields for VIES check (stable references)
|
|
555
|
-
const customerCountry = useWatch({ control: form.control, name: "customer.country" });
|
|
556
|
-
const customerCountryCode = useWatch({ control: form.control, name: "customer.country_code" });
|
|
557
|
-
const customerTaxNumber = useWatch({ control: form.control, name: "customer.tax_number" });
|
|
558
|
-
|
|
559
596
|
// Watch fields needed for document note/payment terms preview
|
|
560
597
|
const watchedNumber = useWatch({ control: form.control, name: "number" });
|
|
561
598
|
const watchedDate = useWatch({ control: form.control, name: "date" });
|
|
@@ -563,29 +600,45 @@ export default function CreateInvoiceForm({
|
|
|
563
600
|
const watchedCurrencyCode = useWatch({ control: form.control, name: "currency_code" });
|
|
564
601
|
const watchedCustomer = useWatch({ control: form.control, name: "customer" });
|
|
565
602
|
|
|
566
|
-
//
|
|
567
|
-
//
|
|
568
|
-
//
|
|
569
|
-
const
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
customerTaxNumber
|
|
581
|
-
|
|
582
|
-
|
|
603
|
+
// Croatian invoice validation:
|
|
604
|
+
// - Domestic/3w B2C requires FINA
|
|
605
|
+
// - Domestic B2B (customer has tax number and NOT end consumer) is blocked
|
|
606
|
+
const isCroatianEntity = activeEntity?.country_code === "HR";
|
|
607
|
+
const customerHasTaxNumber = !!customerTaxNumber?.trim();
|
|
608
|
+
const isDomesticTransaction = transactionType === "domestic";
|
|
609
|
+
const requiresFinaFiscalization = isDomesticTransaction || transactionType === "3w_b2c";
|
|
610
|
+
const is3wTransaction = transactionType === "3w_b2b" || transactionType === "3w_b2c";
|
|
611
|
+
|
|
612
|
+
// Auto-toggle is_end_consumer based on tax number for Croatian domestic/3w customers
|
|
613
|
+
// Default: checked (end consumer). When tax number is entered: uncheck (business). User can override.
|
|
614
|
+
const prevAutoSetTaxRef = useRef<string | undefined>(undefined);
|
|
615
|
+
useEffect(() => {
|
|
616
|
+
if (!isCroatianEntity || !(isDomesticTransaction || is3wTransaction)) return;
|
|
617
|
+
const hasTaxNumber = !!customerTaxNumber?.trim();
|
|
618
|
+
const hadTaxNumber = !!prevAutoSetTaxRef.current?.trim();
|
|
619
|
+
prevAutoSetTaxRef.current = customerTaxNumber ?? undefined;
|
|
620
|
+
|
|
621
|
+
// Auto-uncheck when tax number goes from empty to filled (likely a business)
|
|
622
|
+
if (hasTaxNumber && !hadTaxNumber && customerIsEndConsumerWatch) {
|
|
623
|
+
form.setValue("customer.is_end_consumer" as any, false);
|
|
624
|
+
}
|
|
625
|
+
// Auto-check when tax number goes from filled to empty (likely an individual)
|
|
626
|
+
if (!hasTaxNumber && hadTaxNumber && !customerIsEndConsumerWatch) {
|
|
627
|
+
form.setValue("customer.is_end_consumer" as any, true);
|
|
628
|
+
}
|
|
629
|
+
}, [customerTaxNumber, isCroatianEntity, isDomesticTransaction, is3wTransaction, customerIsEndConsumerWatch, form]);
|
|
583
630
|
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
631
|
+
const finaValidationError = (() => {
|
|
632
|
+
if (!isCroatianEntity || !requiresFinaFiscalization) return undefined;
|
|
633
|
+
// Domestic B2B is always blocked (3w B2B never reaches here since requiresFinaFiscalization is false for 3w B2B)
|
|
634
|
+
if (isDomesticTransaction && customerHasTaxNumber && !customerIsEndConsumerWatch) {
|
|
635
|
+
return t("Domestic B2B invoicing in Croatia is not supported");
|
|
636
|
+
}
|
|
637
|
+
if (!isFinaEnabled) {
|
|
638
|
+
return t("FINA fiscalization must be enabled for domestic invoices");
|
|
639
|
+
}
|
|
640
|
+
return undefined;
|
|
641
|
+
})();
|
|
589
642
|
|
|
590
643
|
// Auto-populate tax_clause from entity settings when transaction type changes
|
|
591
644
|
const effectiveTransactionType = transactionType ?? "domestic";
|
|
@@ -658,6 +711,9 @@ export default function CreateInvoiceForm({
|
|
|
658
711
|
// Shared submit logic for both regular save and save as draft
|
|
659
712
|
const submitInvoice = useCallback(
|
|
660
713
|
(values: CreateInvoiceFormValues, isDraft: boolean) => {
|
|
714
|
+
// Block Croatian domestic B2B and domestic B2C without FINA
|
|
715
|
+
if (finaValidationError) return;
|
|
716
|
+
|
|
661
717
|
// Skip e-SLOG validation for drafts and edit mode
|
|
662
718
|
if (!isDraft && !isEditMode && eslogValidationEnabled) {
|
|
663
719
|
const validationErrors = validateEslogForm(values as any, activeEntity);
|
|
@@ -691,8 +747,7 @@ export default function CreateInvoiceForm({
|
|
|
691
747
|
const finaOptions =
|
|
692
748
|
!isDraft &&
|
|
693
749
|
!isEditMode &&
|
|
694
|
-
|
|
695
|
-
!isFinaNonDomestic &&
|
|
750
|
+
useFinaNumbering &&
|
|
696
751
|
selectedFinaBusinessPremiseName &&
|
|
697
752
|
selectedFinaElectronicDeviceName
|
|
698
753
|
? {
|
|
@@ -740,13 +795,13 @@ export default function CreateInvoiceForm({
|
|
|
740
795
|
updateInvoice,
|
|
741
796
|
documentId,
|
|
742
797
|
eslogValidationEnabled,
|
|
798
|
+
finaValidationError,
|
|
743
799
|
forceLinkedDocuments,
|
|
744
800
|
form,
|
|
745
801
|
isEditMode,
|
|
746
802
|
isEslogAvailable,
|
|
747
803
|
isFursEnabled,
|
|
748
|
-
|
|
749
|
-
isFinaNonDomestic,
|
|
804
|
+
useFinaNumbering,
|
|
750
805
|
markAsPaid,
|
|
751
806
|
originalCustomer,
|
|
752
807
|
paymentTypes,
|
|
@@ -916,25 +971,36 @@ export default function CreateInvoiceForm({
|
|
|
916
971
|
<div className="flex w-full flex-col md:flex-row md:gap-6">
|
|
917
972
|
{/* Recipient section skeleton */}
|
|
918
973
|
<div className="flex-1 space-y-4">
|
|
919
|
-
<Skeleton className="h-7 w-24" />
|
|
920
|
-
<Skeleton className="h-10 w-full" />
|
|
974
|
+
<Skeleton className="h-7 w-24" />
|
|
975
|
+
<Skeleton className="h-10 w-full" />
|
|
921
976
|
</div>
|
|
922
|
-
{/* Details section skeleton */}
|
|
923
|
-
<div className="flex-1 space-y-
|
|
924
|
-
<Skeleton className="h-7 w-20" />
|
|
925
|
-
<
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
<
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
977
|
+
{/* Details section skeleton — inline label rows */}
|
|
978
|
+
<div className="flex-1 space-y-3">
|
|
979
|
+
<Skeleton className="h-7 w-20" />
|
|
980
|
+
<div className="flex items-center gap-3">
|
|
981
|
+
<Skeleton className="h-5 w-[6.5rem] shrink-0" />
|
|
982
|
+
<Skeleton className="h-10 flex-1" />
|
|
983
|
+
</div>
|
|
984
|
+
<div className="flex items-center gap-3">
|
|
985
|
+
<Skeleton className="h-5 w-[6.5rem] shrink-0" />
|
|
986
|
+
<Skeleton className="h-10 flex-1" />
|
|
987
|
+
</div>
|
|
988
|
+
<div className="flex items-center gap-3">
|
|
989
|
+
<Skeleton className="h-5 w-[6.5rem] shrink-0" />
|
|
990
|
+
<Skeleton className="h-10 flex-1" />
|
|
991
|
+
</div>
|
|
992
|
+
<div className="flex items-center gap-3">
|
|
993
|
+
<Skeleton className="h-5 w-[6.5rem] shrink-0" />
|
|
994
|
+
<Skeleton className="h-10 flex-1" />
|
|
995
|
+
</div>
|
|
996
|
+
<div className="flex items-center gap-3">
|
|
997
|
+
<Skeleton className="h-5 w-[6.5rem] shrink-0" />
|
|
998
|
+
<Skeleton className="h-10 flex-1" />
|
|
999
|
+
</div>
|
|
934
1000
|
<div className="space-y-3 rounded-md border p-4">
|
|
935
1001
|
<div className="flex items-center gap-3">
|
|
936
|
-
<Skeleton className="h-4 w-4 rounded" />
|
|
937
|
-
<Skeleton className="h-5 w-28" />
|
|
1002
|
+
<Skeleton className="h-4 w-4 rounded" />
|
|
1003
|
+
<Skeleton className="h-5 w-28" />
|
|
938
1004
|
</div>
|
|
939
1005
|
</div>
|
|
940
1006
|
</div>
|
|
@@ -942,25 +1008,22 @@ export default function CreateInvoiceForm({
|
|
|
942
1008
|
|
|
943
1009
|
{/* Items section skeleton */}
|
|
944
1010
|
<div className="space-y-4">
|
|
945
|
-
<Skeleton className="h-7 w-16" />
|
|
1011
|
+
<Skeleton className="h-7 w-16" />
|
|
946
1012
|
<div className="space-y-4 rounded-lg border p-4">
|
|
947
|
-
<Skeleton className="h-10 w-full" />
|
|
1013
|
+
<Skeleton className="h-10 w-full" />
|
|
948
1014
|
<div className="flex gap-4">
|
|
949
|
-
<Skeleton className="h-10 w-24" />
|
|
950
|
-
<Skeleton className="h-10 flex-1" />
|
|
1015
|
+
<Skeleton className="h-10 w-24" />
|
|
1016
|
+
<Skeleton className="h-10 flex-1" />
|
|
951
1017
|
</div>
|
|
952
1018
|
</div>
|
|
953
|
-
<Skeleton className="h-9 w-24" />
|
|
1019
|
+
<Skeleton className="h-9 w-24" />
|
|
954
1020
|
</div>
|
|
955
1021
|
|
|
956
1022
|
{/* Note field skeleton */}
|
|
957
1023
|
<div className="space-y-2">
|
|
958
|
-
<Skeleton className="h-5 w-12" />
|
|
959
|
-
<Skeleton className="h-24 w-full" />
|
|
1024
|
+
<Skeleton className="h-5 w-12" />
|
|
1025
|
+
<Skeleton className="h-24 w-full" />
|
|
960
1026
|
</div>
|
|
961
|
-
|
|
962
|
-
{/* Save button skeleton */}
|
|
963
|
-
<Skeleton className="h-10 w-24" />
|
|
964
1027
|
</div>
|
|
965
1028
|
);
|
|
966
1029
|
}
|
|
@@ -968,6 +1031,14 @@ export default function CreateInvoiceForm({
|
|
|
968
1031
|
return (
|
|
969
1032
|
<Form {...form}>
|
|
970
1033
|
<form id="create-invoice-form" onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
|
|
1034
|
+
{/* Croatian domestic invoice validation errors */}
|
|
1035
|
+
{finaValidationError && (
|
|
1036
|
+
<Alert variant="destructive">
|
|
1037
|
+
<AlertCircle className="h-4 w-4" />
|
|
1038
|
+
<AlertTitle>{finaValidationError}</AlertTitle>
|
|
1039
|
+
</Alert>
|
|
1040
|
+
)}
|
|
1041
|
+
|
|
971
1042
|
{/* e-SLOG entity-level validation errors */}
|
|
972
1043
|
{eslogEntityErrors.length > 0 && (
|
|
973
1044
|
<Alert variant="destructive">
|
|
@@ -996,6 +1067,7 @@ export default function CreateInvoiceForm({
|
|
|
996
1067
|
shouldFocusName={shouldFocusName}
|
|
997
1068
|
selectedCustomerId={selectedCustomerId}
|
|
998
1069
|
initialCustomerName={initialCustomerName}
|
|
1070
|
+
showEndConsumerToggle={isCroatianEntity && (isDomesticTransaction || is3wTransaction)}
|
|
999
1071
|
t={t}
|
|
1000
1072
|
/>
|
|
1001
1073
|
<DocumentDetailsSection
|
|
@@ -1017,7 +1089,7 @@ export default function CreateInvoiceForm({
|
|
|
1017
1089
|
: undefined
|
|
1018
1090
|
}
|
|
1019
1091
|
finaInline={
|
|
1020
|
-
!isEditMode &&
|
|
1092
|
+
!isEditMode && useFinaNumbering
|
|
1021
1093
|
? {
|
|
1022
1094
|
premises: activeFinaPremises.map((p: any) => ({
|
|
1023
1095
|
id: p.id,
|
|
@@ -1052,7 +1124,7 @@ export default function CreateInvoiceForm({
|
|
|
1052
1124
|
paymentTypes={paymentTypes}
|
|
1053
1125
|
onPaymentTypesChange={setPaymentTypes}
|
|
1054
1126
|
t={t}
|
|
1055
|
-
alwaysShowPaymentType={!!isFinaActive}
|
|
1127
|
+
alwaysShowPaymentType={!!isFinaActive && requiresFinaFiscalization}
|
|
1056
1128
|
/>
|
|
1057
1129
|
)}
|
|
1058
1130
|
</DocumentDetailsSection>
|
|
@@ -146,7 +146,8 @@ export default {
|
|
|
146
146
|
Domestic: "Inland",
|
|
147
147
|
"EU B2B": "EU B2B",
|
|
148
148
|
"EU B2C": "EU B2C",
|
|
149
|
-
|
|
149
|
+
"3W B2B": "3W B2B",
|
|
150
|
+
"3W B2C": "3W B2C",
|
|
150
151
|
"Determining transaction type...": "Transaktionstyp wird ermittelt...",
|
|
151
152
|
"This invoice will not be fiscalized (non-domestic transaction)":
|
|
152
153
|
"Diese Rechnung wird nicht fiskalisiert (nicht-inländische Transaktion)",
|
|
@@ -154,4 +155,10 @@ export default {
|
|
|
154
155
|
"Add tax clause...": "Steuerklausel hinzufügen...",
|
|
155
156
|
Footer: "Fußzeile",
|
|
156
157
|
"Add document footer...": "Dokumentfußzeile hinzufügen...",
|
|
158
|
+
// Croatian domestic invoice validation
|
|
159
|
+
"End consumer": "Endverbraucher",
|
|
160
|
+
"Domestic B2B invoicing in Croatia is not supported":
|
|
161
|
+
"Inländische B2B-Rechnungsstellung in Kroatien wird nicht unterstützt. Kroatien erfordert die Einhaltung von Fiskalisierung 2.0 für B2B-Rechnungsstellung.",
|
|
162
|
+
"FINA fiscalization must be enabled for domestic invoices":
|
|
163
|
+
"FINA-Fiskalisierung muss für inländische Rechnungen aktiviert sein. Aktivieren Sie sie in den Unternehmenseinstellungen.",
|
|
157
164
|
} as const;
|