@spaceinvoices/react-ui 0.4.3 → 0.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli/dist/index.js +1 -1
- package/package.json +1 -1
- package/src/common/autocomplete.tsx +18 -2
- package/src/components/advance-invoices/create/create-advance-invoice-form.tsx +61 -12
- package/src/components/advance-invoices/create/locales/de.ts +17 -0
- package/src/components/advance-invoices/create/locales/es.ts +17 -0
- package/src/components/advance-invoices/create/locales/fr.ts +17 -0
- package/src/components/advance-invoices/create/locales/hr.ts +16 -0
- package/src/components/advance-invoices/create/locales/it.ts +17 -0
- package/src/components/advance-invoices/create/locales/nl.ts +17 -0
- package/src/components/advance-invoices/create/locales/pl.ts +16 -0
- package/src/components/advance-invoices/create/locales/pt.ts +16 -0
- package/src/components/advance-invoices/create/locales/sl.ts +16 -0
- package/src/components/advance-invoices/create/prepare-advance-invoice-submission.ts +0 -1
- package/src/components/advance-invoices/list/list-row-actions.tsx +48 -1
- package/src/components/advance-invoices/list/list-table.tsx +100 -50
- package/src/components/advance-invoices/list/locales/de.ts +9 -0
- package/src/components/advance-invoices/list/locales/en.ts +7 -0
- package/src/components/advance-invoices/list/locales/es.ts +9 -0
- package/src/components/advance-invoices/list/locales/fr.ts +9 -0
- package/src/components/advance-invoices/list/locales/hr.ts +8 -0
- package/src/components/advance-invoices/list/locales/it.ts +9 -0
- package/src/components/advance-invoices/list/locales/nl.ts +9 -0
- package/src/components/advance-invoices/list/locales/pl.ts +8 -0
- package/src/components/advance-invoices/list/locales/pt.ts +9 -0
- package/src/components/advance-invoices/list/locales/sl.ts +8 -0
- package/src/components/credit-notes/create/create-credit-note-form.tsx +185 -11
- package/src/components/credit-notes/create/locales/de.ts +18 -0
- package/src/components/credit-notes/create/locales/es.ts +18 -0
- package/src/components/credit-notes/create/locales/fr.ts +18 -0
- package/src/components/credit-notes/create/locales/hr.ts +17 -0
- package/src/components/credit-notes/create/locales/it.ts +18 -0
- package/src/components/credit-notes/create/locales/nl.ts +18 -0
- package/src/components/credit-notes/create/locales/pl.ts +17 -0
- package/src/components/credit-notes/create/locales/pt.ts +17 -0
- package/src/components/credit-notes/create/locales/sl.ts +18 -1
- package/src/components/credit-notes/credit-notes.hooks.ts +30 -0
- package/src/components/credit-notes/list/list-row-actions.tsx +44 -1
- package/src/components/credit-notes/list/list-table.tsx +93 -32
- package/src/components/credit-notes/list/locales/de.ts +7 -0
- package/src/components/credit-notes/list/locales/en.ts +6 -0
- package/src/components/credit-notes/list/locales/es.ts +7 -0
- package/src/components/credit-notes/list/locales/fr.ts +7 -0
- package/src/components/credit-notes/list/locales/hr.ts +7 -0
- package/src/components/credit-notes/list/locales/it.ts +7 -0
- package/src/components/credit-notes/list/locales/nl.ts +7 -0
- package/src/components/credit-notes/list/locales/pl.ts +7 -0
- package/src/components/credit-notes/list/locales/pt.ts +7 -0
- package/src/components/credit-notes/list/locales/sl.ts +7 -0
- package/src/components/customers/customer-list-table/customer-list-table.tsx +0 -3
- package/src/components/customers/customer-list-table/locales/de.ts +1 -0
- package/src/components/customers/customer-list-table/locales/es.ts +1 -0
- package/src/components/customers/customer-list-table/locales/fr.ts +1 -0
- package/src/components/customers/customer-list-table/locales/hr.ts +1 -0
- package/src/components/customers/customer-list-table/locales/it.ts +1 -0
- package/src/components/customers/customer-list-table/locales/nl.ts +1 -0
- package/src/components/customers/customer-list-table/locales/pl.ts +1 -0
- package/src/components/customers/customer-list-table/locales/pt.ts +1 -0
- package/src/components/customers/customer-list-table/locales/sl.ts +1 -0
- package/src/components/dashboard/collection-rate-card/use-collection-rate.ts +48 -9
- package/src/components/dashboard/revenue-trend-chart/use-revenue-trend.ts +77 -48
- package/src/components/dashboard/shared/use-revenue-data.ts +77 -9
- package/src/components/delivery-notes/create/create-delivery-note-form.tsx +67 -7
- package/src/components/delivery-notes/create/locales/de.ts +16 -0
- package/src/components/delivery-notes/create/locales/es.ts +16 -0
- package/src/components/delivery-notes/create/locales/fr.ts +16 -0
- package/src/components/delivery-notes/create/locales/hr.ts +16 -0
- package/src/components/delivery-notes/create/locales/it.ts +16 -0
- package/src/components/delivery-notes/create/locales/nl.ts +16 -0
- package/src/components/delivery-notes/create/locales/pl.ts +16 -0
- package/src/components/delivery-notes/create/locales/pt.ts +16 -0
- package/src/components/delivery-notes/create/locales/sl.ts +17 -1
- package/src/components/delivery-notes/list/list-row-actions.tsx +20 -1
- package/src/components/delivery-notes/list/list-table.tsx +50 -8
- package/src/components/delivery-notes/list/locales/de.ts +35 -0
- package/src/components/delivery-notes/list/locales/en.ts +33 -0
- package/src/components/delivery-notes/list/locales/es.ts +35 -0
- package/src/components/delivery-notes/list/locales/fr.ts +35 -0
- package/src/components/delivery-notes/list/locales/hr.ts +35 -0
- package/src/components/delivery-notes/list/locales/it.ts +35 -0
- package/src/components/delivery-notes/list/locales/nl.ts +35 -0
- package/src/components/delivery-notes/list/locales/pl.ts +35 -0
- package/src/components/delivery-notes/list/locales/pt.ts +35 -0
- package/src/components/delivery-notes/list/locales/sl.ts +35 -0
- package/src/components/documents/create/document-add-item-form.tsx +70 -0
- package/src/components/documents/create/document-details-section.tsx +163 -29
- package/src/components/documents/create/document-items-section.tsx +21 -4
- package/src/components/documents/create/linked-documents-info.tsx +82 -0
- package/src/components/documents/create/live-preview.tsx +25 -5
- package/src/components/documents/create/mark-as-paid-section.tsx +29 -20
- package/src/components/documents/create/prepare-document-submission.ts +19 -7
- package/src/components/documents/shared/document-preview-display.tsx +3 -4
- package/src/components/documents/types.ts +2 -2
- package/src/components/documents/view/document-actions-bar.tsx +7 -27
- package/src/components/documents/view/document-activities-list.tsx +65 -47
- package/src/components/documents/view/document-details-card.tsx +118 -76
- package/src/components/documents/view/document-payments-list.tsx +99 -65
- package/src/components/documents/view/document-relations-list.tsx +43 -28
- package/src/components/documents/view/document-sidebar.tsx +151 -0
- package/src/components/documents/view/index.ts +2 -0
- package/src/components/documents/view/locales/de.ts +4 -0
- package/src/components/documents/view/locales/es.ts +4 -0
- package/src/components/documents/view/locales/fr.ts +4 -0
- package/src/components/documents/view/locales/hr.ts +4 -0
- package/src/components/documents/view/locales/it.ts +4 -0
- package/src/components/documents/view/locales/nl.ts +4 -0
- package/src/components/documents/view/locales/pl.ts +4 -0
- package/src/components/documents/view/locales/pt.ts +4 -0
- package/src/components/documents/view/locales/sl.ts +5 -1
- package/src/components/documents/view/use-document-download.ts +7 -3
- package/src/components/entities/create-entity-form.tsx +166 -13
- package/src/components/entities/entity-settings-form/entity-settings-form.tsx +101 -1
- package/src/components/entities/entity-settings-form/input-with-preview.tsx +30 -2
- package/src/components/entities/entity-settings-form/locales/de.ts +10 -0
- package/src/components/entities/entity-settings-form/locales/es.ts +10 -0
- package/src/components/entities/entity-settings-form/locales/fr.ts +10 -0
- package/src/components/entities/entity-settings-form/locales/hr.ts +10 -0
- package/src/components/entities/entity-settings-form/locales/it.ts +10 -0
- package/src/components/entities/entity-settings-form/locales/nl.ts +10 -0
- package/src/components/entities/entity-settings-form/locales/pl.ts +10 -0
- package/src/components/entities/entity-settings-form/locales/pt.ts +10 -0
- package/src/components/entities/entity-settings-form/locales/sl.ts +10 -0
- package/src/components/entities/fina-settings-form/fina-settings-form.tsx +6 -6
- package/src/components/entities/fina-settings-form/locales/de.ts +2 -2
- package/src/components/entities/fina-settings-form/locales/en.ts +2 -2
- package/src/components/entities/fina-settings-form/locales/es.ts +2 -2
- package/src/components/entities/fina-settings-form/locales/fr.ts +2 -2
- package/src/components/entities/fina-settings-form/locales/hr.ts +2 -2
- package/src/components/entities/fina-settings-form/locales/it.ts +2 -2
- package/src/components/entities/fina-settings-form/locales/nl.ts +2 -2
- package/src/components/entities/fina-settings-form/locales/pl.ts +2 -2
- package/src/components/entities/fina-settings-form/locales/pt.ts +2 -2
- package/src/components/entities/fina-settings-form/locales/sl.ts +2 -2
- package/src/components/entities/furs-settings-form/locales/en.ts +0 -1
- package/src/components/entities/settings/company-settings-form.tsx +173 -20
- package/src/components/entities/settings/pdf-template-selector/locales/de.ts +3 -1
- package/src/components/entities/settings/pdf-template-selector/locales/es.ts +3 -1
- package/src/components/entities/settings/pdf-template-selector/locales/fr.ts +4 -1
- package/src/components/entities/settings/pdf-template-selector/locales/hr.ts +4 -1
- package/src/components/entities/settings/pdf-template-selector/locales/it.ts +3 -1
- package/src/components/entities/settings/pdf-template-selector/locales/nl.ts +3 -1
- package/src/components/entities/settings/pdf-template-selector/locales/pl.ts +3 -1
- package/src/components/entities/settings/pdf-template-selector/locales/pt.ts +3 -1
- package/src/components/entities/settings/pdf-template-selector/locales/sl.ts +3 -1
- package/src/components/entities/settings/pdf-template-selector/pdf-template-cards.tsx +1 -0
- package/src/components/estimates/create/create-estimate-form.tsx +93 -8
- package/src/components/estimates/create/locales/de.ts +16 -0
- package/src/components/estimates/create/locales/es.ts +16 -0
- package/src/components/estimates/create/locales/fr.ts +16 -0
- package/src/components/estimates/create/locales/hr.ts +16 -0
- package/src/components/estimates/create/locales/it.ts +16 -0
- package/src/components/estimates/create/locales/nl.ts +16 -0
- package/src/components/estimates/create/locales/pl.ts +16 -0
- package/src/components/estimates/create/locales/pt.ts +16 -0
- package/src/components/estimates/create/locales/sl.ts +17 -1
- package/src/components/estimates/list/list-table.tsx +14 -8
- package/src/components/estimates/list/locales/de.ts +2 -0
- package/src/components/estimates/list/locales/en.ts +1 -0
- package/src/components/estimates/list/locales/es.ts +2 -0
- package/src/components/estimates/list/locales/fr.ts +2 -0
- package/src/components/estimates/list/locales/hr.ts +2 -0
- package/src/components/estimates/list/locales/it.ts +2 -0
- package/src/components/estimates/list/locales/nl.ts +2 -0
- package/src/components/estimates/list/locales/pl.ts +2 -0
- package/src/components/estimates/list/locales/pt.ts +2 -0
- package/src/components/estimates/list/locales/sl.ts +2 -0
- package/src/components/export/document-export-form.tsx +55 -14
- package/src/components/export/index.ts +2 -0
- package/src/components/export/sales-per-item-export-form.tsx +223 -0
- package/src/components/invoices/create/create-invoice-form.tsx +106 -11
- package/src/components/invoices/create/locales/de.ts +26 -0
- package/src/components/invoices/create/locales/es.ts +26 -0
- package/src/components/invoices/create/locales/fr.ts +26 -0
- package/src/components/invoices/create/locales/hr.ts +25 -0
- package/src/components/invoices/create/locales/it.ts +26 -0
- package/src/components/invoices/create/locales/nl.ts +26 -0
- package/src/components/invoices/create/locales/pl.ts +25 -0
- package/src/components/invoices/create/locales/pt.ts +25 -0
- package/src/components/invoices/create/locales/sl.ts +26 -1
- package/src/components/invoices/invoices-furs.hooks.ts +4 -1
- package/src/components/invoices/list/list-table.tsx +77 -31
- package/src/components/invoices/list/locales/de.ts +5 -0
- package/src/components/invoices/list/locales/en.ts +4 -0
- package/src/components/invoices/list/locales/es.ts +5 -0
- package/src/components/invoices/list/locales/fr.ts +5 -0
- package/src/components/invoices/list/locales/hr.ts +5 -0
- package/src/components/invoices/list/locales/it.ts +5 -0
- package/src/components/invoices/list/locales/nl.ts +5 -0
- package/src/components/invoices/list/locales/pl.ts +5 -0
- package/src/components/invoices/list/locales/pt.ts +5 -0
- package/src/components/invoices/list/locales/sl.ts +5 -0
- package/src/components/invoices/view/fiscalization-status-card.tsx +44 -24
- package/src/components/items/item-combobox.tsx +5 -3
- package/src/components/items/item-list-table/item-list-header.tsx +4 -17
- package/src/components/items/item-list-table/item-list-table.tsx +3 -3
- package/src/components/items/item-list-table/locales/de.ts +1 -0
- package/src/components/items/item-list-table/locales/es.ts +1 -0
- package/src/components/items/item-list-table/locales/fr.ts +1 -0
- package/src/components/items/item-list-table/locales/hr.ts +1 -0
- package/src/components/items/item-list-table/locales/it.ts +1 -0
- package/src/components/items/item-list-table/locales/nl.ts +1 -0
- package/src/components/items/item-list-table/locales/pl.ts +1 -0
- package/src/components/items/item-list-table/locales/pt.ts +1 -0
- package/src/components/items/item-list-table/locales/sl.ts +1 -0
- package/src/components/payments/list/list-table.tsx +0 -4
- package/src/components/payments/list/locales/de.ts +1 -0
- package/src/components/payments/list/locales/es.ts +1 -0
- package/src/components/payments/list/locales/fr.ts +1 -0
- package/src/components/payments/list/locales/hr.ts +1 -0
- package/src/components/payments/list/locales/it.ts +1 -0
- package/src/components/payments/list/locales/nl.ts +1 -0
- package/src/components/payments/list/locales/pl.ts +1 -0
- package/src/components/payments/list/locales/pt.ts +1 -0
- package/src/components/payments/list/locales/sl.ts +1 -0
- package/src/components/recurring-invoices/list/list-table.tsx +0 -7
- package/src/components/recurring-invoices/list/locales/de.ts +1 -0
- package/src/components/recurring-invoices/list/locales/es.ts +1 -0
- package/src/components/recurring-invoices/list/locales/fr.ts +1 -0
- package/src/components/recurring-invoices/list/locales/hr.ts +1 -0
- package/src/components/recurring-invoices/list/locales/it.ts +1 -0
- package/src/components/recurring-invoices/list/locales/nl.ts +1 -0
- package/src/components/recurring-invoices/list/locales/pl.ts +1 -0
- package/src/components/recurring-invoices/list/locales/pt.ts +1 -0
- package/src/components/recurring-invoices/list/locales/sl.ts +1 -0
- package/src/components/request-logs/request-log-list-table.tsx +0 -3
- package/src/components/table/README.md +14 -121
- package/src/components/table/data-table.tsx +22 -37
- package/src/components/table/hooks/use-table-state.ts +3 -27
- package/src/components/table/index.ts +0 -2
- package/src/components/table/search-input.tsx +17 -0
- package/src/components/table/selection-toolbar.tsx +35 -1
- package/src/components/table/table-empty-state.tsx +6 -3
- package/src/components/table/table-no-results.tsx +10 -5
- package/src/components/table/types.ts +0 -5
- package/src/components/taxes/tax-list-table/locales/de.ts +1 -0
- package/src/components/taxes/tax-list-table/locales/es.ts +1 -0
- package/src/components/taxes/tax-list-table/locales/fr.ts +1 -0
- package/src/components/taxes/tax-list-table/locales/hr.ts +1 -0
- package/src/components/taxes/tax-list-table/locales/it.ts +1 -0
- package/src/components/taxes/tax-list-table/locales/nl.ts +1 -0
- package/src/components/taxes/tax-list-table/locales/pl.ts +1 -0
- package/src/components/taxes/tax-list-table/locales/pt.ts +1 -0
- package/src/components/taxes/tax-list-table/locales/sl.ts +1 -0
- package/src/components/taxes/tax-list-table/tax-list-header.tsx +3 -14
- package/src/components/taxes/tax-list-table/tax-list-table.tsx +3 -3
- package/src/components/ui/popover.tsx +3 -1
- package/src/components/ui/tooltip.tsx +3 -1
- package/src/generated/schemas/advanceinvoice.ts +4 -2
- package/src/generated/schemas/creditnote.ts +2 -1
- package/src/generated/schemas/deliverynote.ts +2 -1
- package/src/generated/schemas/estimate.ts +4 -2
- package/src/generated/schemas/index.ts +1 -1
- package/src/generated/schemas/invoice.ts +2 -1
- package/src/generated/schemas/renderadvanceinvoicepreview_body.ts +17 -23
- package/src/generated/schemas/rendercreditnotepreview_body.ts +17 -23
- package/src/generated/schemas/renderdeliverynotepreview_body.ts +17 -23
- package/src/generated/schemas/renderestimatepreview_body.ts +17 -23
- package/src/generated/schemas/renderinvoicepreview_body.ts +19 -23
- package/src/hooks/use-duplicate-document.ts +56 -14
- package/src/hooks/use-vies-check.ts +3 -0
- package/src/lib/fiscalization.ts +12 -0
- package/src/lib/schemas/advance-invoice.ts +0 -1
- package/src/components/table/sortable-header.tsx +0 -56
|
@@ -67,6 +67,12 @@ export default function DocumentAddItemForm({
|
|
|
67
67
|
initialIsGrossPrice = false,
|
|
68
68
|
onPriceModeChange,
|
|
69
69
|
}: DocumentAddItemFormProps) {
|
|
70
|
+
const itemType = useWatch({
|
|
71
|
+
control,
|
|
72
|
+
name: `items.${index}.type`,
|
|
73
|
+
});
|
|
74
|
+
const isSeparator = itemType === "separator";
|
|
75
|
+
|
|
70
76
|
const taxes = useWatch({
|
|
71
77
|
control,
|
|
72
78
|
name: `items.${index}.taxes`,
|
|
@@ -140,6 +146,70 @@ export default function DocumentAddItemForm({
|
|
|
140
146
|
}
|
|
141
147
|
};
|
|
142
148
|
|
|
149
|
+
if (isSeparator) {
|
|
150
|
+
return (
|
|
151
|
+
<div className="space-y-4 rounded-lg border border-muted-foreground/50 border-dashed p-4">
|
|
152
|
+
{/* Header row with name and remove button */}
|
|
153
|
+
<div className="flex items-start gap-4">
|
|
154
|
+
<div className="flex-1">
|
|
155
|
+
<FormField
|
|
156
|
+
control={control}
|
|
157
|
+
name={`items.${index}.name`}
|
|
158
|
+
render={({ field }) => (
|
|
159
|
+
<FormItem>
|
|
160
|
+
<FormLabel className="text-muted-foreground text-xs">{t("Section header")}</FormLabel>
|
|
161
|
+
<FormControl>
|
|
162
|
+
<Input placeholder={t("Section title...")} {...field} />
|
|
163
|
+
</FormControl>
|
|
164
|
+
<FormMessage />
|
|
165
|
+
</FormItem>
|
|
166
|
+
)}
|
|
167
|
+
/>
|
|
168
|
+
</div>
|
|
169
|
+
|
|
170
|
+
{showRemove && (
|
|
171
|
+
<Button type="button" variant="ghost" size="icon" onClick={onRemove} className="mt-6">
|
|
172
|
+
<Trash2 className="h-4 w-4" />
|
|
173
|
+
</Button>
|
|
174
|
+
)}
|
|
175
|
+
</div>
|
|
176
|
+
|
|
177
|
+
{/* Description and move buttons */}
|
|
178
|
+
<div className="flex gap-4">
|
|
179
|
+
<div className="flex-1">
|
|
180
|
+
<FormField
|
|
181
|
+
control={control}
|
|
182
|
+
name={`items.${index}.description`}
|
|
183
|
+
render={({ field }) => (
|
|
184
|
+
<FormItem>
|
|
185
|
+
<FormControl>
|
|
186
|
+
<Textarea placeholder={t("Description")} {...field} />
|
|
187
|
+
</FormControl>
|
|
188
|
+
<FormMessage />
|
|
189
|
+
</FormItem>
|
|
190
|
+
)}
|
|
191
|
+
/>
|
|
192
|
+
</div>
|
|
193
|
+
|
|
194
|
+
{(showMoveUp || showMoveDown) && (
|
|
195
|
+
<div className="flex flex-col gap-2">
|
|
196
|
+
{showMoveUp && (
|
|
197
|
+
<Button type="button" variant="ghost" size="icon" onClick={onMoveUp} className="mt-auto">
|
|
198
|
+
<ChevronUp className="h-4 w-4" />
|
|
199
|
+
</Button>
|
|
200
|
+
)}
|
|
201
|
+
{showMoveDown && (
|
|
202
|
+
<Button type="button" variant="ghost" size="icon" onClick={onMoveDown} className="mt-auto">
|
|
203
|
+
<ChevronDown className="h-4 w-4" />
|
|
204
|
+
</Button>
|
|
205
|
+
)}
|
|
206
|
+
</div>
|
|
207
|
+
)}
|
|
208
|
+
</div>
|
|
209
|
+
</div>
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
|
|
143
213
|
return (
|
|
144
214
|
<div className="space-y-4 rounded-lg border p-4">
|
|
145
215
|
{/* Header row with name and remove button */}
|
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
* Shared document details section for invoices and estimates
|
|
3
3
|
* Handles: number, date, and document-type-specific date field (date_due or date_valid_till)
|
|
4
4
|
*/
|
|
5
|
-
import type { Entity, Estimate, Invoice } from "@spaceinvoices/js-sdk";
|
|
6
|
-
import { CalendarIcon } from "lucide-react";
|
|
5
|
+
import type { Entity, Estimate, Invoice, ViesCheckResponse } from "@spaceinvoices/js-sdk";
|
|
6
|
+
import { CalendarIcon, Globe, Info, Loader2 } from "lucide-react";
|
|
7
7
|
import { useRef, useState } from "react";
|
|
8
|
+
import { Badge } from "@/ui/components/ui/badge";
|
|
8
9
|
import { Button } from "@/ui/components/ui/button";
|
|
9
10
|
import { Calendar } from "@/ui/components/ui/calendar";
|
|
10
11
|
import { FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/ui/components/ui/form";
|
|
@@ -84,11 +85,9 @@ export function DocumentDetailsSection({
|
|
|
84
85
|
}: DocumentDetailsSectionProps) {
|
|
85
86
|
// Determine the date field name based on document type
|
|
86
87
|
// Delivery notes don't have a secondary date field
|
|
87
|
-
const hasSecondaryDate = documentType !== "delivery_note";
|
|
88
|
-
const dateFieldName =
|
|
89
|
-
|
|
90
|
-
const dateFieldLabel =
|
|
91
|
-
documentType === "invoice" || documentType === "advance_invoice" ? t("Due Date") : t("Valid Until");
|
|
88
|
+
const hasSecondaryDate = documentType !== "delivery_note" && documentType !== "advance_invoice";
|
|
89
|
+
const dateFieldName = documentType === "invoice" ? "date_due" : "date_valid_till";
|
|
90
|
+
const dateFieldLabel = documentType === "invoice" ? t("Due Date") : t("Valid Until");
|
|
92
91
|
|
|
93
92
|
// Check if FURS/FINA inline should show premise/device selects
|
|
94
93
|
const showFursSelects = fursInline && !fursInline.isSkipped;
|
|
@@ -216,28 +215,44 @@ export function DocumentDetailsSection({
|
|
|
216
215
|
render={({ field }) => (
|
|
217
216
|
<FormItem>
|
|
218
217
|
<FormLabel className="">{t("Date")} *</FormLabel>
|
|
219
|
-
|
|
220
|
-
<
|
|
221
|
-
<
|
|
222
|
-
<
|
|
223
|
-
variant="outline"
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
218
|
+
{showFinaSelects ? (
|
|
219
|
+
<Tooltip>
|
|
220
|
+
<TooltipTrigger asChild>
|
|
221
|
+
<FormControl>
|
|
222
|
+
<Button variant="outline" disabled className="w-full pl-3 text-left font-normal">
|
|
223
|
+
{new Date().toLocaleDateString()}
|
|
224
|
+
<CalendarIcon className="ml-auto h-4 w-4 opacity-50" />
|
|
225
|
+
</Button>
|
|
226
|
+
</FormControl>
|
|
227
|
+
</TooltipTrigger>
|
|
228
|
+
<TooltipContent>
|
|
229
|
+
<p>{t("FINA fiscalized invoices always use the current date")}</p>
|
|
230
|
+
</TooltipContent>
|
|
231
|
+
</Tooltip>
|
|
232
|
+
) : (
|
|
233
|
+
<Popover>
|
|
234
|
+
<PopoverTrigger asChild>
|
|
235
|
+
<FormControl>
|
|
236
|
+
<Button
|
|
237
|
+
variant="outline"
|
|
238
|
+
className={cn("w-full pl-3 text-left font-normal", !field.value && "text-muted-foreground")}
|
|
239
|
+
>
|
|
240
|
+
{field.value ? new Date(field.value).toLocaleDateString() : <span>{t("Pick a date")}</span>}
|
|
241
|
+
<CalendarIcon className="ml-auto h-4 w-4 opacity-50" />
|
|
242
|
+
</Button>
|
|
243
|
+
</FormControl>
|
|
244
|
+
</PopoverTrigger>
|
|
245
|
+
<PopoverContent className="w-auto p-0" align="start">
|
|
246
|
+
<Calendar
|
|
247
|
+
mode="single"
|
|
248
|
+
selected={field.value ? new Date(field.value) : undefined}
|
|
249
|
+
onSelect={(date) => field.onChange(date?.toISOString())}
|
|
250
|
+
disabled={(date) => date > new Date() || date < new Date("1900-01-01")}
|
|
251
|
+
initialFocus
|
|
252
|
+
/>
|
|
253
|
+
</PopoverContent>
|
|
254
|
+
</Popover>
|
|
255
|
+
)}
|
|
241
256
|
<FormMessage />
|
|
242
257
|
</FormItem>
|
|
243
258
|
)}
|
|
@@ -598,6 +613,125 @@ export function DocumentNoteField({
|
|
|
598
613
|
);
|
|
599
614
|
}
|
|
600
615
|
|
|
616
|
+
/**
|
|
617
|
+
* Tax clause field component with smart code insertion button
|
|
618
|
+
* Similar to DocumentNoteField, auto-populated from entity settings based on transaction type
|
|
619
|
+
*/
|
|
620
|
+
type TransactionType = ViesCheckResponse["transaction_type"];
|
|
621
|
+
|
|
622
|
+
const TRANSACTION_TYPE_LABELS: Record<NonNullable<TransactionType>, string> = {
|
|
623
|
+
domestic: "Domestic",
|
|
624
|
+
intra_eu_b2b: "EU B2B",
|
|
625
|
+
intra_eu_b2c: "EU B2C",
|
|
626
|
+
export: "Export",
|
|
627
|
+
};
|
|
628
|
+
|
|
629
|
+
const TRANSACTION_TYPE_VARIANTS: Record<NonNullable<TransactionType>, "secondary" | "default" | "outline"> = {
|
|
630
|
+
domestic: "secondary",
|
|
631
|
+
intra_eu_b2b: "default",
|
|
632
|
+
intra_eu_b2c: "outline",
|
|
633
|
+
export: "outline",
|
|
634
|
+
};
|
|
635
|
+
|
|
636
|
+
export function DocumentTaxClauseField({
|
|
637
|
+
control,
|
|
638
|
+
t,
|
|
639
|
+
entity,
|
|
640
|
+
document,
|
|
641
|
+
transactionType,
|
|
642
|
+
isTransactionTypeFetching,
|
|
643
|
+
isFinaNonDomestic,
|
|
644
|
+
}: {
|
|
645
|
+
control: AnyControl;
|
|
646
|
+
t: (key: string) => string;
|
|
647
|
+
entity?: Entity | null;
|
|
648
|
+
document?: Partial<Invoice | Estimate> | null;
|
|
649
|
+
transactionType?: TransactionType;
|
|
650
|
+
isTransactionTypeFetching?: boolean;
|
|
651
|
+
isFinaNonDomestic?: boolean;
|
|
652
|
+
}) {
|
|
653
|
+
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
|
654
|
+
const [isFocused, setIsFocused] = useState(false);
|
|
655
|
+
|
|
656
|
+
const effectiveTransactionType = transactionType ?? "domestic";
|
|
657
|
+
const showTransactionInfo = true;
|
|
658
|
+
|
|
659
|
+
return (
|
|
660
|
+
<FormField
|
|
661
|
+
control={control}
|
|
662
|
+
name="tax_clause"
|
|
663
|
+
render={({ field }) => {
|
|
664
|
+
const hasContent = field.value;
|
|
665
|
+
const showPreview = !isFocused && hasContent && entity;
|
|
666
|
+
const preview = showPreview ? replaceTemplateVariablesForPreview(field.value || "", entity, document) : null;
|
|
667
|
+
|
|
668
|
+
return (
|
|
669
|
+
<FormItem>
|
|
670
|
+
<div className="flex items-center justify-between">
|
|
671
|
+
<FormLabel>{t("Tax Clause")}</FormLabel>
|
|
672
|
+
<SmartCodeInsertButton
|
|
673
|
+
textareaRef={textareaRef}
|
|
674
|
+
value={field.value || ""}
|
|
675
|
+
onInsert={(newValue) => field.onChange(newValue)}
|
|
676
|
+
t={t}
|
|
677
|
+
/>
|
|
678
|
+
</div>
|
|
679
|
+
{showTransactionInfo && (
|
|
680
|
+
<div className="flex flex-wrap items-center gap-x-3 gap-y-1.5 rounded-md border border-border/50 bg-muted/30 px-2.5 py-1.5 text-sm">
|
|
681
|
+
{isTransactionTypeFetching ? (
|
|
682
|
+
<div className="flex items-center gap-1.5 text-muted-foreground">
|
|
683
|
+
<Loader2 className="size-3.5 animate-spin" />
|
|
684
|
+
<span>{t("Determining transaction type...")}</span>
|
|
685
|
+
</div>
|
|
686
|
+
) : (
|
|
687
|
+
<>
|
|
688
|
+
<div className="flex items-center gap-1.5">
|
|
689
|
+
<Globe className="size-3.5 text-muted-foreground" />
|
|
690
|
+
<span className="text-muted-foreground">{t("Transaction type")}:</span>
|
|
691
|
+
<Badge variant={TRANSACTION_TYPE_VARIANTS[effectiveTransactionType]}>
|
|
692
|
+
{t(TRANSACTION_TYPE_LABELS[effectiveTransactionType])}
|
|
693
|
+
</Badge>
|
|
694
|
+
</div>
|
|
695
|
+
{isFinaNonDomestic && (
|
|
696
|
+
<div className="flex items-center gap-1.5 text-muted-foreground">
|
|
697
|
+
<Info className="size-3.5" />
|
|
698
|
+
<span>{t("This invoice will not be fiscalized (non-domestic transaction)")}</span>
|
|
699
|
+
</div>
|
|
700
|
+
)}
|
|
701
|
+
</>
|
|
702
|
+
)}
|
|
703
|
+
</div>
|
|
704
|
+
)}
|
|
705
|
+
<FormControl>
|
|
706
|
+
<div className="relative">
|
|
707
|
+
<Textarea
|
|
708
|
+
{...field}
|
|
709
|
+
ref={(e) => {
|
|
710
|
+
field.ref(e);
|
|
711
|
+
(textareaRef as React.MutableRefObject<HTMLTextAreaElement | null>).current = e;
|
|
712
|
+
}}
|
|
713
|
+
value={field.value || ""}
|
|
714
|
+
placeholder={showPreview ? "" : t("Add tax clause...")}
|
|
715
|
+
rows={3}
|
|
716
|
+
className={cn("resize-y", showPreview && "text-transparent caret-transparent")}
|
|
717
|
+
onFocus={() => setIsFocused(true)}
|
|
718
|
+
onBlur={() => setIsFocused(false)}
|
|
719
|
+
/>
|
|
720
|
+
{showPreview && (
|
|
721
|
+
<div className="pointer-events-none absolute inset-0 z-10 flex items-start overflow-hidden rounded-md border border-input bg-background px-3 py-2 shadow-xs">
|
|
722
|
+
<div className="w-full whitespace-pre-wrap text-base md:text-sm">{preview}</div>
|
|
723
|
+
</div>
|
|
724
|
+
)}
|
|
725
|
+
</div>
|
|
726
|
+
</FormControl>
|
|
727
|
+
<FormMessage />
|
|
728
|
+
</FormItem>
|
|
729
|
+
);
|
|
730
|
+
}}
|
|
731
|
+
/>
|
|
732
|
+
);
|
|
733
|
+
}
|
|
734
|
+
|
|
601
735
|
/**
|
|
602
736
|
* Payment terms field component with smart code insertion button
|
|
603
737
|
* Similar to DocumentNoteField, exported for use in document forms
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Shared document items section for invoices and estimates
|
|
3
3
|
* Handles: item management (add, remove, reorder)
|
|
4
4
|
*/
|
|
5
|
-
import { PlusIcon } from "lucide-react";
|
|
5
|
+
import { PlusIcon, SeparatorHorizontal } from "lucide-react";
|
|
6
6
|
import type { MutableRefObject } from "react";
|
|
7
7
|
import type { UseFormGetValues, UseFormSetValue, UseFormWatch } from "react-hook-form";
|
|
8
8
|
import { Button } from "@/ui/components/ui/button";
|
|
@@ -65,6 +65,18 @@ export function DocumentItemsSection({
|
|
|
65
65
|
]);
|
|
66
66
|
};
|
|
67
67
|
|
|
68
|
+
const addSeparator = () => {
|
|
69
|
+
const currentItems = getValues("items") || [];
|
|
70
|
+
setValue("items", [
|
|
71
|
+
...currentItems,
|
|
72
|
+
{
|
|
73
|
+
type: "separator",
|
|
74
|
+
name: "",
|
|
75
|
+
description: "",
|
|
76
|
+
},
|
|
77
|
+
]);
|
|
78
|
+
};
|
|
79
|
+
|
|
68
80
|
const removeItem = (index: number) => {
|
|
69
81
|
const currentItems = getValues("items") || [];
|
|
70
82
|
setValue(
|
|
@@ -125,9 +137,14 @@ export function DocumentItemsSection({
|
|
|
125
137
|
</div>
|
|
126
138
|
))}
|
|
127
139
|
|
|
128
|
-
<
|
|
129
|
-
<
|
|
130
|
-
|
|
140
|
+
<div className="flex gap-2">
|
|
141
|
+
<Button type="button" variant="outline" onClick={addItem} className="flex-1 cursor-pointer border-dashed">
|
|
142
|
+
<PlusIcon className="mr-2 h-4 w-4" /> {t("Add item")}
|
|
143
|
+
</Button>
|
|
144
|
+
<Button type="button" variant="ghost" onClick={addSeparator} className="cursor-pointer text-muted-foreground">
|
|
145
|
+
<SeparatorHorizontal className="mr-2 h-4 w-4" /> {t("Add separator")}
|
|
146
|
+
</Button>
|
|
147
|
+
</div>
|
|
131
148
|
</div>
|
|
132
149
|
);
|
|
133
150
|
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/ui/components/ui/table";
|
|
2
|
+
|
|
3
|
+
export type LinkedDocumentSummary = {
|
|
4
|
+
id: string;
|
|
5
|
+
type: string;
|
|
6
|
+
number: string;
|
|
7
|
+
date: string;
|
|
8
|
+
total_with_tax: number;
|
|
9
|
+
currency_code: string;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
type LinkedDocumentsInfoProps = {
|
|
13
|
+
documents: LinkedDocumentSummary[];
|
|
14
|
+
locale: string;
|
|
15
|
+
t: (key: string) => string;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export function LinkedDocumentsInfo({ documents, locale, t }: LinkedDocumentsInfoProps) {
|
|
19
|
+
if (documents.length === 0) return null;
|
|
20
|
+
|
|
21
|
+
const currencyCode = documents[0].currency_code || "EUR";
|
|
22
|
+
|
|
23
|
+
const formatDate = (dateStr: string) => {
|
|
24
|
+
try {
|
|
25
|
+
return new Date(dateStr).toLocaleDateString(locale, {
|
|
26
|
+
year: "numeric",
|
|
27
|
+
month: "short",
|
|
28
|
+
day: "numeric",
|
|
29
|
+
});
|
|
30
|
+
} catch {
|
|
31
|
+
return dateStr;
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const formatCurrency = (amount: number) => {
|
|
36
|
+
try {
|
|
37
|
+
return new Intl.NumberFormat(locale, {
|
|
38
|
+
style: "currency",
|
|
39
|
+
currency: currencyCode,
|
|
40
|
+
}).format(amount);
|
|
41
|
+
} catch {
|
|
42
|
+
return `${amount.toFixed(2)} ${currencyCode}`;
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const typeLabel = (type: string) => {
|
|
47
|
+
const key = {
|
|
48
|
+
delivery_note: "Delivery note",
|
|
49
|
+
invoice: "Invoice",
|
|
50
|
+
estimate: "Estimate",
|
|
51
|
+
credit_note: "Credit note",
|
|
52
|
+
advance_invoice: "Advance invoice",
|
|
53
|
+
}[type];
|
|
54
|
+
return key ? t(key) : type;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<div className="space-y-2">
|
|
59
|
+
<h3 className="font-medium text-muted-foreground text-sm">{t("Linked documents")}</h3>
|
|
60
|
+
<Table>
|
|
61
|
+
<TableHeader>
|
|
62
|
+
<TableRow>
|
|
63
|
+
<TableHead className="h-8 text-xs">{t("Type")}</TableHead>
|
|
64
|
+
<TableHead className="h-8 text-xs">{t("Number")}</TableHead>
|
|
65
|
+
<TableHead className="h-8 text-xs">{t("Date")}</TableHead>
|
|
66
|
+
<TableHead className="h-8 text-right text-xs">{t("Total")}</TableHead>
|
|
67
|
+
</TableRow>
|
|
68
|
+
</TableHeader>
|
|
69
|
+
<TableBody>
|
|
70
|
+
{documents.map((doc) => (
|
|
71
|
+
<TableRow key={doc.id}>
|
|
72
|
+
<TableCell className="py-1.5 text-sm">{typeLabel(doc.type)}</TableCell>
|
|
73
|
+
<TableCell className="py-1.5 text-sm">{doc.number}</TableCell>
|
|
74
|
+
<TableCell className="py-1.5 text-sm">{formatDate(doc.date)}</TableCell>
|
|
75
|
+
<TableCell className="py-1.5 text-right text-sm">{formatCurrency(doc.total_with_tax)}</TableCell>
|
|
76
|
+
</TableRow>
|
|
77
|
+
))}
|
|
78
|
+
</TableBody>
|
|
79
|
+
</Table>
|
|
80
|
+
</div>
|
|
81
|
+
);
|
|
82
|
+
}
|
|
@@ -11,7 +11,7 @@ import { useA4Scaling } from "../shared/use-a4-scaling";
|
|
|
11
11
|
import type { DocumentTypes } from "../types";
|
|
12
12
|
import { filterUnresolvedTaxes } from "./prepare-preview-data";
|
|
13
13
|
|
|
14
|
-
export type PdfTemplateId = "modern" | "classic" | "minimal" | "fashion";
|
|
14
|
+
export type PdfTemplateId = "modern" | "classic" | "condensed" | "minimal" | "fashion";
|
|
15
15
|
|
|
16
16
|
type LiveInvoicePreviewProps = {
|
|
17
17
|
data: Partial<CreateInvoiceRequest>;
|
|
@@ -30,6 +30,12 @@ type LiveInvoicePreviewProps = {
|
|
|
30
30
|
documentTypeLabel?: string;
|
|
31
31
|
/** Document type to determine which render endpoint to use */
|
|
32
32
|
documentType?: DocumentTypes;
|
|
33
|
+
/** QR settings overrides for preview (before saving) */
|
|
34
|
+
qrOverrides?: {
|
|
35
|
+
upn_qr_enabled?: boolean;
|
|
36
|
+
upn_qr_display_mode?: "qr_only" | "full_slip";
|
|
37
|
+
epc_qr_enabled?: boolean;
|
|
38
|
+
};
|
|
33
39
|
};
|
|
34
40
|
|
|
35
41
|
/**
|
|
@@ -49,11 +55,12 @@ export function LiveInvoicePreview({
|
|
|
49
55
|
currency: _currency = "EUR",
|
|
50
56
|
template,
|
|
51
57
|
className,
|
|
52
|
-
locale,
|
|
58
|
+
locale: _locale,
|
|
53
59
|
fixedScale,
|
|
54
60
|
t: tProp,
|
|
55
61
|
documentTypeLabel,
|
|
56
62
|
documentType = "invoice",
|
|
63
|
+
qrOverrides,
|
|
57
64
|
}: LiveInvoicePreviewProps) {
|
|
58
65
|
const t = tProp ?? ((key: string) => key);
|
|
59
66
|
const [previewHtml, setPreviewHtml] = useState<string>("");
|
|
@@ -103,7 +110,7 @@ export function LiveInvoicePreview({
|
|
|
103
110
|
// Filter out unresolved tax_ids (race condition: form may add
|
|
104
111
|
// { tax_id: undefined } before the tax dropdown auto-selects a value)
|
|
105
112
|
items: filterUnresolvedTaxes(invoiceData.items),
|
|
106
|
-
issuer:
|
|
113
|
+
issuer: {
|
|
107
114
|
name: activeEntity.name,
|
|
108
115
|
address: activeEntity.address,
|
|
109
116
|
address_2: activeEntity.address_2,
|
|
@@ -112,11 +119,22 @@ export function LiveInvoicePreview({
|
|
|
112
119
|
state: activeEntity.state,
|
|
113
120
|
country: activeEntity.country,
|
|
114
121
|
tax_number: activeEntity.tax_number,
|
|
122
|
+
...invoiceData.issuer,
|
|
115
123
|
},
|
|
116
124
|
};
|
|
117
125
|
|
|
118
126
|
// Call the render API using the appropriate SDK method for the document type
|
|
119
|
-
|
|
127
|
+
// Don't send locale — let entity locale drive formatting (decimal separators, date format)
|
|
128
|
+
const renderParams: Record<string, any> = { partial: "true" as const, template };
|
|
129
|
+
if (qrOverrides?.upn_qr_enabled !== undefined) {
|
|
130
|
+
renderParams.upn_qr_enabled = qrOverrides.upn_qr_enabled ? "true" : "false";
|
|
131
|
+
if (qrOverrides.upn_qr_display_mode) {
|
|
132
|
+
renderParams.upn_qr_display_mode = qrOverrides.upn_qr_display_mode;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
if (qrOverrides?.epc_qr_enabled !== undefined) {
|
|
136
|
+
renderParams.epc_qr_enabled = qrOverrides.epc_qr_enabled ? "true" : "false";
|
|
137
|
+
}
|
|
120
138
|
const requestOpts = { entity_id: activeEntity.id };
|
|
121
139
|
let html: string;
|
|
122
140
|
switch (documentType) {
|
|
@@ -170,9 +188,11 @@ export function LiveInvoicePreview({
|
|
|
170
188
|
activeEntity?.city,
|
|
171
189
|
activeEntity?.name,
|
|
172
190
|
template,
|
|
173
|
-
locale,
|
|
174
191
|
sdk,
|
|
175
192
|
documentType,
|
|
193
|
+
qrOverrides?.upn_qr_enabled,
|
|
194
|
+
qrOverrides?.upn_qr_display_mode,
|
|
195
|
+
qrOverrides?.epc_qr_enabled,
|
|
176
196
|
],
|
|
177
197
|
);
|
|
178
198
|
|
|
@@ -31,6 +31,8 @@ type MarkAsPaidSectionProps = {
|
|
|
31
31
|
t: (key: string) => string;
|
|
32
32
|
/** Always show payment type selector (e.g. for FINA fiscalization) */
|
|
33
33
|
alwaysShowPaymentType?: boolean;
|
|
34
|
+
/** Force paid state — hides the checkbox and always shows payment selectors */
|
|
35
|
+
forced?: boolean;
|
|
34
36
|
};
|
|
35
37
|
|
|
36
38
|
export function MarkAsPaidSection({
|
|
@@ -40,31 +42,38 @@ export function MarkAsPaidSection({
|
|
|
40
42
|
onPaymentTypesChange,
|
|
41
43
|
t,
|
|
42
44
|
alwaysShowPaymentType,
|
|
45
|
+
forced,
|
|
43
46
|
}: MarkAsPaidSectionProps) {
|
|
44
|
-
const showPaymentTypes = checked || alwaysShowPaymentType;
|
|
47
|
+
const showPaymentTypes = forced || checked || alwaysShowPaymentType;
|
|
45
48
|
|
|
46
49
|
return (
|
|
47
50
|
<div className={cn("flex flex-col gap-4 rounded-md border p-4", showPaymentTypes && "gap-3")}>
|
|
48
|
-
|
|
49
|
-
<
|
|
50
|
-
|
|
51
|
-
<Label>{checked ? t("Paid") : t("Mark as Paid")}</Label>
|
|
52
|
-
{!checked && (
|
|
53
|
-
<Tooltip>
|
|
54
|
-
<TooltipTrigger asChild>
|
|
55
|
-
<button
|
|
56
|
-
type="button"
|
|
57
|
-
className="rounded-full p-1 transition-colors hover:bg-accent"
|
|
58
|
-
onClick={(e) => e.preventDefault()}
|
|
59
|
-
>
|
|
60
|
-
<HelpCircle className="size-4 text-muted-foreground" />
|
|
61
|
-
</button>
|
|
62
|
-
</TooltipTrigger>
|
|
63
|
-
<TooltipContent side="top">{t("Invoice will be marked as fully paid upon creation")}</TooltipContent>
|
|
64
|
-
</Tooltip>
|
|
65
|
-
)}
|
|
51
|
+
{forced ? (
|
|
52
|
+
<div className="flex flex-row items-center space-x-3 space-y-0">
|
|
53
|
+
<Label>{t("Paid")}</Label>
|
|
66
54
|
</div>
|
|
67
|
-
|
|
55
|
+
) : (
|
|
56
|
+
<div className="flex flex-row items-center space-x-3 space-y-0">
|
|
57
|
+
<Checkbox checked={checked} onCheckedChange={(v) => onCheckedChange(v === true)} />
|
|
58
|
+
<div className="flex items-center gap-1 leading-none">
|
|
59
|
+
<Label>{checked ? t("Paid") : t("Mark as Paid")}</Label>
|
|
60
|
+
{!checked && (
|
|
61
|
+
<Tooltip>
|
|
62
|
+
<TooltipTrigger asChild>
|
|
63
|
+
<button
|
|
64
|
+
type="button"
|
|
65
|
+
className="rounded-full p-1 transition-colors hover:bg-accent"
|
|
66
|
+
onClick={(e) => e.preventDefault()}
|
|
67
|
+
>
|
|
68
|
+
<HelpCircle className="size-4 text-muted-foreground" />
|
|
69
|
+
</button>
|
|
70
|
+
</TooltipTrigger>
|
|
71
|
+
<TooltipContent side="top">{t("Invoice will be marked as fully paid upon creation")}</TooltipContent>
|
|
72
|
+
</Tooltip>
|
|
73
|
+
)}
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
)}
|
|
68
77
|
|
|
69
78
|
{showPaymentTypes && (
|
|
70
79
|
<div className="flex flex-col gap-2">
|
|
@@ -127,6 +127,15 @@ export function prepareDocumentSubmission<T extends BaseDocumentValues>(
|
|
|
127
127
|
if (values.items) {
|
|
128
128
|
const priceModes = options.priceModes ?? {};
|
|
129
129
|
values.items = values.items.map((item: any, index: number) => {
|
|
130
|
+
// Separator items — pass through with only type, name, description
|
|
131
|
+
if (item.type === "separator") {
|
|
132
|
+
return {
|
|
133
|
+
type: "separator",
|
|
134
|
+
name: item.name,
|
|
135
|
+
description: item.description || undefined,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
130
139
|
const { price, ...rest } = item;
|
|
131
140
|
|
|
132
141
|
// Transform price based on price mode (from component state, not form)
|
|
@@ -136,13 +145,16 @@ export function prepareDocumentSubmission<T extends BaseDocumentValues>(
|
|
|
136
145
|
return {
|
|
137
146
|
...rest,
|
|
138
147
|
...priceFields,
|
|
139
|
-
taxes: item.taxes
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
148
|
+
taxes: item.taxes
|
|
149
|
+
?.map((tax: any) => {
|
|
150
|
+
if (tax.tax_id) {
|
|
151
|
+
// Only send tax_id, API will resolve the rate
|
|
152
|
+
return { tax_id: tax.tax_id };
|
|
153
|
+
}
|
|
154
|
+
return tax;
|
|
155
|
+
})
|
|
156
|
+
// Filter out empty placeholder taxes (UI adds { tax_id: undefined } for the dropdown)
|
|
157
|
+
.filter((tax: any) => tax.tax_id || tax.rate !== undefined || tax.classification),
|
|
146
158
|
};
|
|
147
159
|
});
|
|
148
160
|
}
|
|
@@ -80,9 +80,7 @@ export function DocumentPreviewDisplay({
|
|
|
80
80
|
try {
|
|
81
81
|
// Determine document type from shareable ID prefix
|
|
82
82
|
const docTypePath = getDocTypePathFromShareableId(shareableId);
|
|
83
|
-
const response = await fetch(
|
|
84
|
-
`${apiBaseUrl}/${docTypePath}/shareable/${shareableId}/html${locale ? `?locale=${locale}` : ""}`,
|
|
85
|
-
);
|
|
83
|
+
const response = await fetch(`${apiBaseUrl}/${docTypePath}/shareable/${shareableId}/html`);
|
|
86
84
|
if (!response.ok) {
|
|
87
85
|
throw new Error("Failed to load preview");
|
|
88
86
|
}
|
|
@@ -108,7 +106,8 @@ export function DocumentPreviewDisplay({
|
|
|
108
106
|
try {
|
|
109
107
|
// Fetch the rendered HTML by document ID using SDK wrapper
|
|
110
108
|
// Document type is auto-detected from ID prefix (inv_, est_, cre_, adv_)
|
|
111
|
-
|
|
109
|
+
// Don't send locale — let entity locale drive formatting (decimal separators, date format)
|
|
110
|
+
const html = await sdk.invoices.renderHtml(document.id, { template }, { entity_id: activeEntity.id });
|
|
112
111
|
|
|
113
112
|
setPreviewHtml(html);
|
|
114
113
|
setError(null);
|
|
@@ -46,8 +46,8 @@ export const DOCUMENT_CONFIGS: Record<DocumentTypes, DocumentConfig> = {
|
|
|
46
46
|
type: "advance_invoice",
|
|
47
47
|
apiEndpoint: "advance-invoices",
|
|
48
48
|
cacheKey: "advance-invoices",
|
|
49
|
-
dateFieldName:
|
|
50
|
-
dateFieldLabel:
|
|
49
|
+
dateFieldName: null,
|
|
50
|
+
dateFieldLabel: null,
|
|
51
51
|
singularName: "Advance Invoice",
|
|
52
52
|
pluralName: "Advance Invoices",
|
|
53
53
|
},
|