@codemind.ec/medusa-plugin-invoice 1.0.6 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,13 +1,12 @@
1
- import { jsxs, jsx } from "react/jsx-runtime";
1
+ import { jsxs, jsx, Fragment } from "react/jsx-runtime";
2
2
  import { defineWidgetConfig, defineRouteConfig } from "@medusajs/admin-sdk";
3
- import { Container, Heading, Text, Button, toast, Label, Input, Textarea, Table, Badge, Select } from "@medusajs/ui";
3
+ import { Container, Heading, Text, Button, toast, Badge, Table, Label, Input, Textarea, Switch, Select } from "@medusajs/ui";
4
4
  import Medusa from "@medusajs/js-sdk";
5
5
  import { useState, useCallback, useEffect, useRef, useMemo } from "react";
6
- import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
7
- import { useForm, FormProvider, Controller } from "react-hook-form";
8
- import { z } from "@medusajs/framework/zod";
6
+ import { useQuery, useQueryClient, useMutation } from "@tanstack/react-query";
9
7
  import { useNavigate, useParams } from "react-router-dom";
10
8
  import { DocumentText } from "@medusajs/icons";
9
+ import { useForm, FormProvider, Controller } from "react-hook-form";
11
10
  import CodeMirror from "@uiw/react-codemirror";
12
11
  import { html } from "@codemirror/lang-html";
13
12
  import { oneDark } from "@codemirror/theme-one-dark";
@@ -67,202 +66,167 @@ const OrderInvoiceWidget = ({ data: order }) => {
67
66
  defineWidgetConfig({
68
67
  zone: "order.details.side.before"
69
68
  });
70
- z.object({
71
- company_name: z.string().optional(),
72
- company_ruc: z.string().optional(),
73
- company_address: z.string().optional(),
74
- company_phone: z.string().optional(),
75
- company_email: z.string().email().optional().or(z.literal("")),
76
- company_logo: z.string().optional(),
77
- notes: z.string().optional(),
78
- admin_notification_email: z.string().email().optional().or(z.literal(""))
79
- });
80
69
  const InvoiceConfigPage = () => {
81
70
  const navigate = useNavigate();
82
- const { data, isLoading, refetch } = useQuery({
71
+ const { data: configData, isLoading: loadingConfigs } = useQuery({
83
72
  queryFn: () => sdk.client.fetch("/admin/invoice-config"),
84
- queryKey: ["invoice-config"]
73
+ queryKey: ["invoice-configs"]
85
74
  });
86
- const { mutateAsync, isPending } = useMutation({
87
- mutationFn: (payload) => sdk.client.fetch("/admin/invoice-config", {
88
- method: "POST",
89
- body: payload
90
- }),
75
+ const { data: templateData, isLoading: loadingTemplates } = useQuery({
76
+ queryFn: () => sdk.client.fetch("/admin/invoice-templates"),
77
+ queryKey: ["invoice-templates"]
78
+ });
79
+ const configs = (configData == null ? void 0 : configData.invoice_configs) ?? [];
80
+ const templates = (templateData == null ? void 0 : templateData.invoice_templates) ?? [];
81
+ const defaultCompany = configs.find((c) => c.is_default);
82
+ return /* @__PURE__ */ jsxs(Container, { className: "divide-y p-0", children: [
83
+ /* @__PURE__ */ jsxs("div", { className: "px-6 py-4", children: [
84
+ /* @__PURE__ */ jsx(Heading, { level: "h1", children: "Comprobantes y Cotizaciones" }),
85
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle mt-1", children: "Gestiona empresas emisoras y plantillas de documentos." })
86
+ ] }),
87
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4 p-6", children: [
88
+ /* @__PURE__ */ jsxs("div", { className: "border border-ui-border-base rounded-lg p-5 flex flex-col gap-3", children: [
89
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
90
+ /* @__PURE__ */ jsx(Heading, { level: "h2", children: "Empresas" }),
91
+ /* @__PURE__ */ jsx(Badge, { color: configs.length > 0 ? "blue" : "grey", children: configs.length })
92
+ ] }),
93
+ loadingConfigs ? /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle text-sm", children: "Cargando..." }) : defaultCompany ? /* @__PURE__ */ jsxs("div", { className: "bg-ui-bg-subtle rounded-md p-3", children: [
94
+ /* @__PURE__ */ jsx(Text, { className: "text-sm font-medium", children: defaultCompany.company_name }),
95
+ defaultCompany.company_ruc && /* @__PURE__ */ jsxs(Text, { className: "text-ui-fg-subtle text-xs", children: [
96
+ "RUC: ",
97
+ defaultCompany.company_ruc
98
+ ] }),
99
+ /* @__PURE__ */ jsx(Badge, { color: "green", className: "mt-1", children: "Default" })
100
+ ] }) : /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle text-sm", children: "No hay empresas configuradas." }),
101
+ /* @__PURE__ */ jsx(
102
+ Button,
103
+ {
104
+ variant: "secondary",
105
+ className: "mt-auto",
106
+ onClick: () => navigate("/invoice-config/companies"),
107
+ children: "Gestionar Empresas"
108
+ }
109
+ )
110
+ ] }),
111
+ /* @__PURE__ */ jsxs("div", { className: "border border-ui-border-base rounded-lg p-5 flex flex-col gap-3", children: [
112
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
113
+ /* @__PURE__ */ jsx(Heading, { level: "h2", children: "Plantillas" }),
114
+ /* @__PURE__ */ jsx(Badge, { color: templates.length > 0 ? "blue" : "grey", children: templates.length })
115
+ ] }),
116
+ loadingTemplates ? /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle text-sm", children: "Cargando..." }) : templates.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "bg-ui-bg-subtle rounded-md p-3 flex flex-col gap-1", children: [
117
+ templates.slice(0, 3).map((t) => /* @__PURE__ */ jsx(Text, { className: "text-sm", children: t.name }, t.id)),
118
+ templates.length > 3 && /* @__PURE__ */ jsxs(Text, { className: "text-ui-fg-subtle text-xs", children: [
119
+ "+",
120
+ templates.length - 3,
121
+ " más..."
122
+ ] })
123
+ ] }) : /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle text-sm", children: "No hay plantillas. Se crearán al reiniciar el servidor." }),
124
+ /* @__PURE__ */ jsx(
125
+ Button,
126
+ {
127
+ variant: "secondary",
128
+ className: "mt-auto",
129
+ onClick: () => navigate("/invoice-config/invoice-templates"),
130
+ children: "Gestionar Plantillas"
131
+ }
132
+ )
133
+ ] })
134
+ ] })
135
+ ] });
136
+ };
137
+ const config$1 = defineRouteConfig({
138
+ label: "Comprobantes y Cotizaciones"
139
+ });
140
+ const CompaniesPage = () => {
141
+ const navigate = useNavigate();
142
+ const queryClient = useQueryClient();
143
+ const { data, isLoading } = useQuery({
144
+ queryFn: () => sdk.client.fetch("/admin/invoice-config"),
145
+ queryKey: ["invoice-configs"]
146
+ });
147
+ const setDefaultMutation = useMutation({
148
+ mutationFn: (id) => sdk.client.fetch(`/admin/invoice-config/${id}/set-default`, { method: "POST" }),
91
149
  onSuccess: () => {
92
- refetch();
93
- toast.success("Configuración actualizada exitosamente");
150
+ queryClient.invalidateQueries({ queryKey: ["invoice-configs"] });
151
+ toast.success("Empresa marcada como default");
94
152
  },
95
- onError: () => {
96
- toast.error("Error al guardar la configuración");
97
- }
153
+ onError: () => toast.error("Error al cambiar empresa default")
98
154
  });
99
- const getFormDefaultValues = useCallback(() => {
100
- return {
101
- company_name: (data == null ? void 0 : data.invoice_config.company_name) || "",
102
- company_ruc: (data == null ? void 0 : data.invoice_config.company_ruc) || "",
103
- company_address: (data == null ? void 0 : data.invoice_config.company_address) || "",
104
- company_phone: (data == null ? void 0 : data.invoice_config.company_phone) || "",
105
- company_email: (data == null ? void 0 : data.invoice_config.company_email) || "",
106
- company_logo: (data == null ? void 0 : data.invoice_config.company_logo) || "",
107
- notes: (data == null ? void 0 : data.invoice_config.notes) || "",
108
- admin_notification_email: (data == null ? void 0 : data.invoice_config.admin_notification_email) || ""
109
- };
110
- }, [data]);
111
- const form = useForm({
112
- defaultValues: getFormDefaultValues()
155
+ const deleteMutation = useMutation({
156
+ mutationFn: (id) => sdk.client.fetch(`/admin/invoice-config/${id}`, { method: "DELETE" }),
157
+ onSuccess: () => {
158
+ queryClient.invalidateQueries({ queryKey: ["invoice-configs"] });
159
+ toast.success("Empresa eliminada");
160
+ },
161
+ onError: () => toast.error("No se pudo eliminar la empresa")
113
162
  });
114
- const handleSubmit = form.handleSubmit((formData) => mutateAsync(formData));
115
- const uploadLogo = async (event) => {
116
- var _a;
117
- const file = (_a = event.target.files) == null ? void 0 : _a[0];
118
- if (!file) {
119
- return;
120
- }
121
- try {
122
- const { files } = await sdk.admin.upload.create({
123
- files: [file]
124
- });
125
- form.setValue("company_logo", files[0].url);
126
- } catch (error) {
127
- toast.error("Error al subir el logo. Verifica que el archivo sea una imagen válida.");
128
- }
129
- };
130
- useEffect(() => {
131
- form.reset(getFormDefaultValues());
132
- }, [getFormDefaultValues]);
163
+ const configs = (data == null ? void 0 : data.invoice_configs) ?? [];
133
164
  return /* @__PURE__ */ jsxs(Container, { className: "divide-y p-0", children: [
134
165
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-6 py-4", children: [
135
- /* @__PURE__ */ jsx(Heading, { level: "h1", children: "Configuración de Comprobante" }),
136
- /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => navigate("/invoice-config/invoice-templates"), children: "Gestionar Plantillas" })
166
+ /* @__PURE__ */ jsxs("div", { children: [
167
+ /* @__PURE__ */ jsx(Heading, { level: "h1", children: "Empresas" }),
168
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle text-sm mt-1", children: "Empresas emisoras de comprobantes y cotizaciones." })
169
+ ] }),
170
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
171
+ /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => navigate("/invoice-config"), children: "← Panel" }),
172
+ /* @__PURE__ */ jsx(Button, { onClick: () => navigate("/invoice-config/companies/new"), children: "+ Nueva Empresa" })
173
+ ] })
137
174
  ] }),
138
- /* @__PURE__ */ jsx(FormProvider, { ...form, children: /* @__PURE__ */ jsxs(
139
- "form",
140
- {
141
- onSubmit: handleSubmit,
142
- className: "flex h-full flex-col overflow-hidden p-2 gap-2",
143
- children: [
144
- /* @__PURE__ */ jsx("div", { className: "bg-ui-bg-subtle border border-ui-border-base rounded-lg p-3 mb-2", children: /* @__PURE__ */ jsx(
145
- Controller,
146
- {
147
- control: form.control,
148
- name: "admin_notification_email",
149
- render: ({ field }) => {
150
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-col space-y-2", children: [
151
- /* @__PURE__ */ jsx("div", { className: "flex items-center gap-x-1", children: /* @__PURE__ */ jsx(Label, { size: "small", weight: "plus", children: "📧 Email de Notificaciones (Admin)" }) }),
152
- /* @__PURE__ */ jsx(Input, { ...field, onChange: field.onChange, value: field.value, placeholder: "admin@mariquita.food" }),
153
- /* @__PURE__ */ jsx("span", { className: "text-ui-fg-subtle text-xs", children: "Se enviarán notificaciones de nuevos pedidos y comprobantes de pago a este email." })
154
- ] });
155
- }
156
- }
157
- ) }),
158
- /* @__PURE__ */ jsx(
159
- Controller,
160
- {
161
- control: form.control,
162
- name: "company_name",
163
- render: ({ field }) => {
164
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-col space-y-2", children: [
165
- /* @__PURE__ */ jsx("div", { className: "flex items-center gap-x-1", children: /* @__PURE__ */ jsx(Label, { size: "small", weight: "plus", children: "Nombre de la Empresa" }) }),
166
- /* @__PURE__ */ jsx(Input, { ...field, onChange: field.onChange, value: field.value })
167
- ] });
168
- }
169
- }
170
- ),
171
- /* @__PURE__ */ jsx(
172
- Controller,
173
- {
174
- control: form.control,
175
- name: "company_ruc",
176
- render: ({ field }) => {
177
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-col space-y-2", children: [
178
- /* @__PURE__ */ jsx("div", { className: "flex items-center gap-x-1", children: /* @__PURE__ */ jsx(Label, { size: "small", weight: "plus", children: "RUC" }) }),
179
- /* @__PURE__ */ jsx(Input, { ...field, onChange: field.onChange, value: field.value, placeholder: "1234567890001" })
180
- ] });
181
- }
182
- }
183
- ),
184
- /* @__PURE__ */ jsx(
185
- Controller,
186
- {
187
- control: form.control,
188
- name: "company_address",
189
- render: ({ field }) => {
190
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-col space-y-2", children: [
191
- /* @__PURE__ */ jsx("div", { className: "flex items-center gap-x-1", children: /* @__PURE__ */ jsx(Label, { size: "small", weight: "plus", children: "Dirección de la Empresa" }) }),
192
- /* @__PURE__ */ jsx(Textarea, { ...field })
193
- ] });
194
- }
195
- }
196
- ),
197
- /* @__PURE__ */ jsx(
198
- Controller,
199
- {
200
- control: form.control,
201
- name: "company_phone",
202
- render: ({ field }) => {
203
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-col space-y-2", children: [
204
- /* @__PURE__ */ jsx("div", { className: "flex items-center gap-x-1", children: /* @__PURE__ */ jsx(Label, { size: "small", weight: "plus", children: "Teléfono de la Empresa" }) }),
205
- /* @__PURE__ */ jsx(Input, { ...field })
206
- ] });
207
- }
208
- }
209
- ),
210
- /* @__PURE__ */ jsx(
211
- Controller,
212
- {
213
- control: form.control,
214
- name: "company_email",
215
- render: ({ field }) => {
216
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-col space-y-2", children: [
217
- /* @__PURE__ */ jsx("div", { className: "flex items-center gap-x-1", children: /* @__PURE__ */ jsx(Label, { size: "small", weight: "plus", children: "Email de la Empresa" }) }),
218
- /* @__PURE__ */ jsx(Input, { ...field })
219
- ] });
220
- }
221
- }
222
- ),
223
- /* @__PURE__ */ jsx(
224
- Controller,
225
- {
226
- control: form.control,
227
- name: "notes",
228
- render: ({ field }) => {
229
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-col space-y-2", children: [
230
- /* @__PURE__ */ jsx("div", { className: "flex items-center gap-x-1", children: /* @__PURE__ */ jsx(Label, { size: "small", weight: "plus", children: "Notas" }) }),
231
- /* @__PURE__ */ jsx(Textarea, { ...field })
232
- ] });
233
- }
234
- }
235
- ),
236
- /* @__PURE__ */ jsx(
237
- Controller,
238
- {
239
- control: form.control,
240
- name: "company_logo",
241
- render: ({ field }) => {
242
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-col space-y-2", children: [
243
- /* @__PURE__ */ jsx("div", { className: "flex items-center gap-x-1", children: /* @__PURE__ */ jsx(Label, { size: "small", weight: "plus", children: "Logo de la Empresa" }) }),
244
- /* @__PURE__ */ jsx(Input, { type: "file", onChange: uploadLogo, className: "py-1" }),
245
- field.value && /* @__PURE__ */ jsx(
246
- "img",
247
- {
248
- src: field.value,
249
- alt: "Logo de la Empresa",
250
- className: "mt-2 h-24 w-24"
175
+ /* @__PURE__ */ jsx("div", { className: "px-6 pb-4", children: isLoading ? /* @__PURE__ */ jsx("div", { className: "text-center py-10 text-ui-fg-subtle", children: "Cargando..." }) : configs.length === 0 ? /* @__PURE__ */ jsx("div", { className: "text-center py-10 text-ui-fg-subtle", children: "No hay empresas configuradas." }) : /* @__PURE__ */ jsxs(Table, { children: [
176
+ /* @__PURE__ */ jsx(Table.Header, { children: /* @__PURE__ */ jsxs(Table.Row, { children: [
177
+ /* @__PURE__ */ jsx(Table.HeaderCell, { children: "Nombre" }),
178
+ /* @__PURE__ */ jsx(Table.HeaderCell, { children: "RUC" }),
179
+ /* @__PURE__ */ jsx(Table.HeaderCell, { children: "Email" }),
180
+ /* @__PURE__ */ jsx(Table.HeaderCell, { children: "Teléfono" }),
181
+ /* @__PURE__ */ jsx(Table.HeaderCell, { children: "Estado" }),
182
+ /* @__PURE__ */ jsx(Table.HeaderCell, { style: { textAlign: "right" }, children: "Acciones" })
183
+ ] }) }),
184
+ /* @__PURE__ */ jsx(Table.Body, { children: configs.map((cfg) => /* @__PURE__ */ jsxs(
185
+ Table.Row,
186
+ {
187
+ onClick: () => navigate(`/invoice-config/companies/${cfg.id}`),
188
+ style: { cursor: "pointer" },
189
+ children: [
190
+ /* @__PURE__ */ jsx(Table.Cell, { className: "font-medium", children: cfg.company_name }),
191
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx("code", { className: "text-xs", children: cfg.company_ruc || "—" }) }),
192
+ /* @__PURE__ */ jsx(Table.Cell, { children: cfg.company_email }),
193
+ /* @__PURE__ */ jsx(Table.Cell, { children: cfg.company_phone }),
194
+ /* @__PURE__ */ jsx(Table.Cell, { children: cfg.is_default ? /* @__PURE__ */ jsx(Badge, { color: "green", children: "Default" }) : /* @__PURE__ */ jsx(Badge, { color: "grey", children: "—" }) }),
195
+ /* @__PURE__ */ jsx(Table.Cell, { style: { textAlign: "right" }, children: /* @__PURE__ */ jsx("div", { className: "flex gap-2 justify-end", children: !cfg.is_default && /* @__PURE__ */ jsxs(Fragment, { children: [
196
+ /* @__PURE__ */ jsx(
197
+ Button,
198
+ {
199
+ variant: "secondary",
200
+ size: "small",
201
+ onClick: (e) => {
202
+ e.stopPropagation();
203
+ setDefaultMutation.mutate(cfg.id);
204
+ },
205
+ children: "Default"
206
+ }
207
+ ),
208
+ /* @__PURE__ */ jsx(
209
+ Button,
210
+ {
211
+ variant: "danger",
212
+ size: "small",
213
+ onClick: (e) => {
214
+ e.stopPropagation();
215
+ if (confirm("¿Eliminar esta empresa?")) {
216
+ deleteMutation.mutate(cfg.id);
251
217
  }
252
- )
253
- ] });
254
- }
255
- }
256
- ),
257
- /* @__PURE__ */ jsx(Button, { type: "submit", disabled: isLoading || isPending, children: "Guardar" })
258
- ]
259
- }
260
- ) })
218
+ },
219
+ children: "Eliminar"
220
+ }
221
+ )
222
+ ] }) }) })
223
+ ]
224
+ },
225
+ cfg.id
226
+ )) })
227
+ ] }) })
261
228
  ] });
262
229
  };
263
- const config$1 = defineRouteConfig({
264
- label: "Comprobante de Pedido"
265
- });
266
230
  const TYPE_LABELS = {
267
231
  order_invoice: "Comprobante de Pedido",
268
232
  quote_proforma: "Cotización Proforma"
@@ -274,6 +238,10 @@ const InvoiceTemplatesPage = () => {
274
238
  queryFn: () => sdk.client.fetch("/admin/invoice-templates"),
275
239
  queryKey: ["invoice-templates"]
276
240
  });
241
+ const { data: companiesData } = useQuery({
242
+ queryFn: () => sdk.client.fetch("/admin/invoice-config"),
243
+ queryKey: ["invoice-configs"]
244
+ });
277
245
  const deleteMutation = useMutation({
278
246
  mutationFn: (id) => sdk.client.fetch(`/admin/invoice-templates/${id}`, { method: "DELETE" }),
279
247
  onSuccess: () => {
@@ -285,19 +253,21 @@ const InvoiceTemplatesPage = () => {
285
253
  }
286
254
  });
287
255
  const templates = (data == null ? void 0 : data.invoice_templates) ?? [];
288
- return /* @__PURE__ */ jsxs(Container, { children: [
289
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 24 }, children: [
256
+ const companiesMap = new Map(((companiesData == null ? void 0 : companiesData.invoice_configs) ?? []).map((c) => [c.id, c.company_name]));
257
+ return /* @__PURE__ */ jsxs(Container, { className: "divide-y p-0", children: [
258
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-6 py-4", children: [
290
259
  /* @__PURE__ */ jsx(Heading, { level: "h1", children: "Plantillas de Documentos" }),
291
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 8 }, children: [
292
- /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => navigate("/invoice-config"), children: "Configuración" }),
260
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
261
+ /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => navigate("/invoice-config"), children: "← Panel" }),
293
262
  /* @__PURE__ */ jsx(Button, { onClick: () => navigate("/invoice-config/invoice-templates/new"), children: "+ Nueva Plantilla" })
294
263
  ] })
295
264
  ] }),
296
- isLoading ? /* @__PURE__ */ jsx("div", { style: { textAlign: "center", padding: 40 }, children: "Cargando..." }) : templates.length === 0 ? /* @__PURE__ */ jsx("div", { style: { textAlign: "center", padding: 40, color: "#6c757d" }, children: "No hay plantillas. Se crearán automáticamente al reiniciar el servidor." }) : /* @__PURE__ */ jsxs(Table, { children: [
265
+ /* @__PURE__ */ jsx("div", { className: "px-6 pb-4", children: isLoading ? /* @__PURE__ */ jsx("div", { className: "text-center py-10 text-ui-fg-subtle", children: "Cargando..." }) : templates.length === 0 ? /* @__PURE__ */ jsx("div", { className: "text-center py-10 text-ui-fg-subtle", children: "No hay plantillas. Se crearán automáticamente al reiniciar el servidor." }) : /* @__PURE__ */ jsxs(Table, { children: [
297
266
  /* @__PURE__ */ jsx(Table.Header, { children: /* @__PURE__ */ jsxs(Table.Row, { children: [
298
267
  /* @__PURE__ */ jsx(Table.HeaderCell, { children: "Nombre" }),
299
268
  /* @__PURE__ */ jsx(Table.HeaderCell, { children: "Slug" }),
300
269
  /* @__PURE__ */ jsx(Table.HeaderCell, { children: "Tipo" }),
270
+ /* @__PURE__ */ jsx(Table.HeaderCell, { children: "Empresa" }),
301
271
  /* @__PURE__ */ jsx(Table.HeaderCell, { children: "Estado" }),
302
272
  /* @__PURE__ */ jsx(Table.HeaderCell, { children: "Actualizado" }),
303
273
  /* @__PURE__ */ jsx(Table.HeaderCell, { style: { textAlign: "right" }, children: "Acciones" })
@@ -308,9 +278,10 @@ const InvoiceTemplatesPage = () => {
308
278
  onClick: () => navigate(`/invoice-config/invoice-templates/${tpl.id}`),
309
279
  style: { cursor: "pointer" },
310
280
  children: [
311
- /* @__PURE__ */ jsx(Table.Cell, { children: tpl.name }),
312
- /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx("code", { style: { fontSize: 12 }, children: tpl.slug }) }),
281
+ /* @__PURE__ */ jsx(Table.Cell, { className: "font-medium", children: tpl.name }),
282
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx("code", { className: "text-xs", children: tpl.slug }) }),
313
283
  /* @__PURE__ */ jsx(Table.Cell, { children: TYPE_LABELS[tpl.type] ?? tpl.type }),
284
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Text, { className: "text-sm", children: tpl.company_id ? companiesMap.get(tpl.company_id) ?? "—" : "—" }) }),
314
285
  /* @__PURE__ */ jsx(Table.Cell, { children: tpl.is_default ? /* @__PURE__ */ jsx(Badge, { color: "blue", children: "Por defecto" }) : /* @__PURE__ */ jsx(Badge, { color: "grey", children: "Personalizada" }) }),
315
286
  /* @__PURE__ */ jsx(Table.Cell, { children: new Date(tpl.updated_at).toLocaleDateString("es-ES") }),
316
287
  /* @__PURE__ */ jsx(Table.Cell, { style: { textAlign: "right" }, children: /* @__PURE__ */ jsx(
@@ -332,163 +303,491 @@ const InvoiceTemplatesPage = () => {
332
303
  },
333
304
  tpl.id
334
305
  )) })
335
- ] })
306
+ ] }) })
336
307
  ] });
337
308
  };
338
309
  const config = defineRouteConfig({
339
310
  label: "Plantillas PDF",
340
311
  icon: DocumentText
341
312
  });
342
- const NewTemplatePage = () => {
313
+ const NewCompanyPage = () => {
343
314
  const navigate = useNavigate();
344
- const [name, setName] = useState("");
345
- const [slug, setSlug] = useState("");
346
- const [type, setType] = useState("order_invoice");
315
+ const form = useForm({
316
+ defaultValues: {
317
+ company_name: "",
318
+ company_ruc: "",
319
+ company_address: "",
320
+ company_phone: "",
321
+ company_email: "",
322
+ company_logo: "",
323
+ notes: "",
324
+ admin_notification_email: "",
325
+ is_default: false
326
+ }
327
+ });
347
328
  const createMutation = useMutation({
348
- mutationFn: (payload) => sdk.client.fetch("/admin/invoice-templates", {
329
+ mutationFn: (payload) => sdk.client.fetch("/admin/invoice-config", {
349
330
  method: "POST",
350
331
  body: payload
351
332
  }),
352
- onSuccess: (data) => {
353
- toast.success("Plantilla creada");
354
- navigate(`/invoice-config/invoice-templates/${data.invoice_template.id}`);
333
+ onSuccess: () => {
334
+ toast.success("Empresa creada exitosamente");
335
+ navigate("/invoice-config/companies");
355
336
  },
356
- onError: () => {
357
- toast.error("Error al crear la plantilla");
358
- }
337
+ onError: () => toast.error("Error al crear la empresa")
359
338
  });
360
- const handleCreate = () => {
361
- if (!name || !slug) {
362
- toast.error("Nombre y slug son requeridos");
363
- return;
339
+ const uploadLogo = async (event) => {
340
+ var _a;
341
+ const file = (_a = event.target.files) == null ? void 0 : _a[0];
342
+ if (!file) return;
343
+ try {
344
+ const { files } = await sdk.admin.upload.create({ files: [file] });
345
+ form.setValue("company_logo", files[0].url);
346
+ } catch {
347
+ toast.error("Error al subir el logo.");
364
348
  }
365
- createMutation.mutate({
366
- name,
367
- slug,
368
- type,
369
- html_content: getDefaultHtml(type)
370
- });
371
349
  };
372
- return /* @__PURE__ */ jsxs(Container, { children: [
373
- /* @__PURE__ */ jsx(Heading, { level: "h1", style: { marginBottom: 24 }, children: "Nueva Plantilla" }),
374
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 16, maxWidth: 500 }, children: [
375
- /* @__PURE__ */ jsxs("div", { children: [
376
- /* @__PURE__ */ jsx(Label, { htmlFor: "name", children: "Nombre" }),
377
- /* @__PURE__ */ jsx(Input, { id: "name", value: name, onChange: (e) => setName(e.target.value), placeholder: "Ej: Mi Comprobante" })
378
- ] }),
379
- /* @__PURE__ */ jsxs("div", { children: [
380
- /* @__PURE__ */ jsx(Label, { htmlFor: "slug", children: "Slug (identificador único)" }),
350
+ const handleSubmit = form.handleSubmit((data) => createMutation.mutate(data));
351
+ return /* @__PURE__ */ jsxs(Container, { className: "divide-y p-0", children: [
352
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-6 py-4", children: [
353
+ /* @__PURE__ */ jsx(Heading, { level: "h1", children: "Nueva Empresa" }),
354
+ /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => navigate("/invoice-config/companies"), children: "← Volver" })
355
+ ] }),
356
+ /* @__PURE__ */ jsx(FormProvider, { ...form, children: /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, className: "flex flex-col gap-4 p-6 max-w-2xl", children: [
357
+ /* @__PURE__ */ jsx("div", { className: "bg-ui-bg-subtle border border-ui-border-base rounded-lg p-4 mb-2", children: /* @__PURE__ */ jsx(
358
+ Controller,
359
+ {
360
+ control: form.control,
361
+ name: "admin_notification_email",
362
+ render: ({ field }) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
363
+ /* @__PURE__ */ jsx(Label, { size: "small", weight: "plus", children: "📧 Email de Notificaciones (Admin)" }),
364
+ /* @__PURE__ */ jsx(Input, { ...field, placeholder: "admin@empresa.com" }),
365
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle text-xs", children: "Notificaciones de nuevos pedidos a este email." })
366
+ ] })
367
+ }
368
+ ) }),
369
+ /* @__PURE__ */ jsx(
370
+ Controller,
371
+ {
372
+ control: form.control,
373
+ name: "company_name",
374
+ render: ({ field }) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
375
+ /* @__PURE__ */ jsx(Label, { size: "small", weight: "plus", children: "Nombre de la Empresa *" }),
376
+ /* @__PURE__ */ jsx(Input, { ...field, placeholder: "Mi Empresa S.A.S." })
377
+ ] })
378
+ }
379
+ ),
380
+ /* @__PURE__ */ jsx(
381
+ Controller,
382
+ {
383
+ control: form.control,
384
+ name: "company_ruc",
385
+ render: ({ field }) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
386
+ /* @__PURE__ */ jsx(Label, { size: "small", weight: "plus", children: "RUC" }),
387
+ /* @__PURE__ */ jsx(Input, { ...field, placeholder: "1234567890001" })
388
+ ] })
389
+ }
390
+ ),
391
+ /* @__PURE__ */ jsx(
392
+ Controller,
393
+ {
394
+ control: form.control,
395
+ name: "company_address",
396
+ render: ({ field }) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
397
+ /* @__PURE__ */ jsx(Label, { size: "small", weight: "plus", children: "Dirección" }),
398
+ /* @__PURE__ */ jsx(Textarea, { ...field, placeholder: "Av. Principal 123, Quito" })
399
+ ] })
400
+ }
401
+ ),
402
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-4", children: [
381
403
  /* @__PURE__ */ jsx(
382
- Input,
404
+ Controller,
383
405
  {
384
- id: "slug",
385
- value: slug,
386
- onChange: (e) => setSlug(e.target.value.toLowerCase().replace(/[^a-z0-9_]/g, "_")),
387
- placeholder: "Ej: my_custom_invoice"
406
+ control: form.control,
407
+ name: "company_phone",
408
+ render: ({ field }) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
409
+ /* @__PURE__ */ jsx(Label, { size: "small", weight: "plus", children: "Teléfono" }),
410
+ /* @__PURE__ */ jsx(Input, { ...field, placeholder: "+593 99 123 4567" })
411
+ ] })
412
+ }
413
+ ),
414
+ /* @__PURE__ */ jsx(
415
+ Controller,
416
+ {
417
+ control: form.control,
418
+ name: "company_email",
419
+ render: ({ field }) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
420
+ /* @__PURE__ */ jsx(Label, { size: "small", weight: "plus", children: "Email de la Empresa" }),
421
+ /* @__PURE__ */ jsx(Input, { ...field, placeholder: "info@empresa.com" })
422
+ ] })
388
423
  }
389
424
  )
390
425
  ] }),
391
- /* @__PURE__ */ jsxs("div", { children: [
392
- /* @__PURE__ */ jsx(Label, { htmlFor: "type", children: "Tipo de documento" }),
393
- /* @__PURE__ */ jsxs(Select, { value: type, onValueChange: setType, children: [
394
- /* @__PURE__ */ jsx(Select.Trigger, { children: /* @__PURE__ */ jsx(Select.Value, { placeholder: "Seleccionar tipo" }) }),
395
- /* @__PURE__ */ jsxs(Select.Content, { children: [
396
- /* @__PURE__ */ jsx(Select.Item, { value: "order_invoice", children: "Comprobante de Pedido" }),
397
- /* @__PURE__ */ jsx(Select.Item, { value: "quote_proforma", children: "Cotización Proforma" })
426
+ /* @__PURE__ */ jsx(
427
+ Controller,
428
+ {
429
+ control: form.control,
430
+ name: "notes",
431
+ render: ({ field }) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
432
+ /* @__PURE__ */ jsx(Label, { size: "small", weight: "plus", children: "Notas" }),
433
+ /* @__PURE__ */ jsx(Textarea, { ...field, placeholder: "Notas internas o pie de página del documento" })
398
434
  ] })
399
- ] })
435
+ }
436
+ ),
437
+ /* @__PURE__ */ jsx(
438
+ Controller,
439
+ {
440
+ control: form.control,
441
+ name: "company_logo",
442
+ render: ({ field }) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
443
+ /* @__PURE__ */ jsx(Label, { size: "small", weight: "plus", children: "Logo de la Empresa" }),
444
+ /* @__PURE__ */ jsx(Input, { type: "file", onChange: uploadLogo, className: "py-1" }),
445
+ field.value && /* @__PURE__ */ jsx("img", { src: field.value, alt: "Logo", className: "mt-2 h-24 w-24 object-contain" })
446
+ ] })
447
+ }
448
+ ),
449
+ /* @__PURE__ */ jsx(
450
+ Controller,
451
+ {
452
+ control: form.control,
453
+ name: "is_default",
454
+ render: ({ field }) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 bg-ui-bg-subtle rounded-lg p-3", children: [
455
+ /* @__PURE__ */ jsx(
456
+ Switch,
457
+ {
458
+ checked: field.value,
459
+ onCheckedChange: field.onChange
460
+ }
461
+ ),
462
+ /* @__PURE__ */ jsxs("div", { children: [
463
+ /* @__PURE__ */ jsx(Label, { size: "small", weight: "plus", children: "Empresa por defecto" }),
464
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle text-xs", children: "Se usará en plantillas que no tengan empresa asignada." })
465
+ ] })
466
+ ] })
467
+ }
468
+ ),
469
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2 pt-2", children: [
470
+ /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => navigate("/invoice-config/companies"), children: "Cancelar" }),
471
+ /* @__PURE__ */ jsx(Button, { type: "submit", isLoading: createMutation.isPending, children: "Crear Empresa" })
472
+ ] })
473
+ ] }) })
474
+ ] });
475
+ };
476
+ const EditCompanyPage = () => {
477
+ const { id } = useParams();
478
+ const navigate = useNavigate();
479
+ const queryClient = useQueryClient();
480
+ const { data, isLoading } = useQuery({
481
+ queryFn: () => sdk.client.fetch(`/admin/invoice-config/${id}`),
482
+ queryKey: ["invoice-config", id],
483
+ enabled: !!id
484
+ });
485
+ const config2 = data == null ? void 0 : data.invoice_config;
486
+ const getDefaults = useCallback(() => ({
487
+ company_name: (config2 == null ? void 0 : config2.company_name) || "",
488
+ company_ruc: (config2 == null ? void 0 : config2.company_ruc) || "",
489
+ company_address: (config2 == null ? void 0 : config2.company_address) || "",
490
+ company_phone: (config2 == null ? void 0 : config2.company_phone) || "",
491
+ company_email: (config2 == null ? void 0 : config2.company_email) || "",
492
+ company_logo: (config2 == null ? void 0 : config2.company_logo) || "",
493
+ notes: (config2 == null ? void 0 : config2.notes) || "",
494
+ admin_notification_email: (config2 == null ? void 0 : config2.admin_notification_email) || "",
495
+ is_default: (config2 == null ? void 0 : config2.is_default) || false
496
+ }), [config2]);
497
+ const form = useForm({ defaultValues: getDefaults() });
498
+ useEffect(() => {
499
+ form.reset(getDefaults());
500
+ }, [getDefaults]);
501
+ const saveMutation = useMutation({
502
+ mutationFn: (payload) => sdk.client.fetch(`/admin/invoice-config/${id}`, {
503
+ method: "POST",
504
+ body: payload
505
+ }),
506
+ onSuccess: () => {
507
+ queryClient.invalidateQueries({ queryKey: ["invoice-config", id] });
508
+ queryClient.invalidateQueries({ queryKey: ["invoice-configs"] });
509
+ toast.success("Empresa actualizada");
510
+ },
511
+ onError: () => toast.error("Error al guardar")
512
+ });
513
+ const uploadLogo = async (event) => {
514
+ var _a;
515
+ const file = (_a = event.target.files) == null ? void 0 : _a[0];
516
+ if (!file) return;
517
+ try {
518
+ const { files } = await sdk.admin.upload.create({ files: [file] });
519
+ form.setValue("company_logo", files[0].url);
520
+ } catch {
521
+ toast.error("Error al subir el logo.");
522
+ }
523
+ };
524
+ const handleSubmit = form.handleSubmit((data2) => saveMutation.mutate(data2));
525
+ if (isLoading) {
526
+ return /* @__PURE__ */ jsx(Container, { children: /* @__PURE__ */ jsx("div", { className: "text-center py-10", children: "Cargando..." }) });
527
+ }
528
+ if (!config2) {
529
+ return /* @__PURE__ */ jsx(Container, { children: /* @__PURE__ */ jsx("div", { className: "text-center py-10", children: "Empresa no encontrada" }) });
530
+ }
531
+ return /* @__PURE__ */ jsxs(Container, { className: "divide-y p-0", children: [
532
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-6 py-4", children: [
533
+ /* @__PURE__ */ jsx(Heading, { level: "h1", children: "Editar Empresa" }),
534
+ /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => navigate("/invoice-config/companies"), children: "← Volver" })
535
+ ] }),
536
+ /* @__PURE__ */ jsx(FormProvider, { ...form, children: /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, className: "flex flex-col gap-4 p-6 max-w-2xl", children: [
537
+ /* @__PURE__ */ jsx("div", { className: "bg-ui-bg-subtle border border-ui-border-base rounded-lg p-4 mb-2", children: /* @__PURE__ */ jsx(
538
+ Controller,
539
+ {
540
+ control: form.control,
541
+ name: "admin_notification_email",
542
+ render: ({ field }) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
543
+ /* @__PURE__ */ jsx(Label, { size: "small", weight: "plus", children: "📧 Email de Notificaciones (Admin)" }),
544
+ /* @__PURE__ */ jsx(Input, { ...field, placeholder: "admin@empresa.com" }),
545
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle text-xs", children: "Notificaciones de nuevos pedidos a este email." })
546
+ ] })
547
+ }
548
+ ) }),
549
+ /* @__PURE__ */ jsx(
550
+ Controller,
551
+ {
552
+ control: form.control,
553
+ name: "company_name",
554
+ render: ({ field }) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
555
+ /* @__PURE__ */ jsx(Label, { size: "small", weight: "plus", children: "Nombre de la Empresa *" }),
556
+ /* @__PURE__ */ jsx(Input, { ...field })
557
+ ] })
558
+ }
559
+ ),
560
+ /* @__PURE__ */ jsx(
561
+ Controller,
562
+ {
563
+ control: form.control,
564
+ name: "company_ruc",
565
+ render: ({ field }) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
566
+ /* @__PURE__ */ jsx(Label, { size: "small", weight: "plus", children: "RUC" }),
567
+ /* @__PURE__ */ jsx(Input, { ...field, placeholder: "1234567890001" })
568
+ ] })
569
+ }
570
+ ),
571
+ /* @__PURE__ */ jsx(
572
+ Controller,
573
+ {
574
+ control: form.control,
575
+ name: "company_address",
576
+ render: ({ field }) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
577
+ /* @__PURE__ */ jsx(Label, { size: "small", weight: "plus", children: "Dirección" }),
578
+ /* @__PURE__ */ jsx(Textarea, { ...field })
579
+ ] })
580
+ }
581
+ ),
582
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-4", children: [
583
+ /* @__PURE__ */ jsx(
584
+ Controller,
585
+ {
586
+ control: form.control,
587
+ name: "company_phone",
588
+ render: ({ field }) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
589
+ /* @__PURE__ */ jsx(Label, { size: "small", weight: "plus", children: "Teléfono" }),
590
+ /* @__PURE__ */ jsx(Input, { ...field })
591
+ ] })
592
+ }
593
+ ),
594
+ /* @__PURE__ */ jsx(
595
+ Controller,
596
+ {
597
+ control: form.control,
598
+ name: "company_email",
599
+ render: ({ field }) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
600
+ /* @__PURE__ */ jsx(Label, { size: "small", weight: "plus", children: "Email de la Empresa" }),
601
+ /* @__PURE__ */ jsx(Input, { ...field })
602
+ ] })
603
+ }
604
+ )
400
605
  ] }),
401
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 8, marginTop: 16 }, children: [
402
- /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => navigate("/invoice-config/invoice-templates"), children: "Cancelar" }),
403
- /* @__PURE__ */ jsx(Button, { onClick: handleCreate, isLoading: createMutation.isPending, children: "Crear Plantilla" })
606
+ /* @__PURE__ */ jsx(
607
+ Controller,
608
+ {
609
+ control: form.control,
610
+ name: "notes",
611
+ render: ({ field }) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
612
+ /* @__PURE__ */ jsx(Label, { size: "small", weight: "plus", children: "Notas" }),
613
+ /* @__PURE__ */ jsx(Textarea, { ...field })
614
+ ] })
615
+ }
616
+ ),
617
+ /* @__PURE__ */ jsx(
618
+ Controller,
619
+ {
620
+ control: form.control,
621
+ name: "company_logo",
622
+ render: ({ field }) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
623
+ /* @__PURE__ */ jsx(Label, { size: "small", weight: "plus", children: "Logo de la Empresa" }),
624
+ /* @__PURE__ */ jsx(Input, { type: "file", onChange: uploadLogo, className: "py-1" }),
625
+ field.value && /* @__PURE__ */ jsx("img", { src: field.value, alt: "Logo", className: "mt-2 h-24 w-24 object-contain" })
626
+ ] })
627
+ }
628
+ ),
629
+ /* @__PURE__ */ jsx(
630
+ Controller,
631
+ {
632
+ control: form.control,
633
+ name: "is_default",
634
+ render: ({ field }) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 bg-ui-bg-subtle rounded-lg p-3", children: [
635
+ /* @__PURE__ */ jsx(
636
+ Switch,
637
+ {
638
+ checked: field.value,
639
+ onCheckedChange: field.onChange
640
+ }
641
+ ),
642
+ /* @__PURE__ */ jsxs("div", { children: [
643
+ /* @__PURE__ */ jsx(Label, { size: "small", weight: "plus", children: "Empresa por defecto" }),
644
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle text-xs", children: "Se usará en plantillas que no tengan empresa asignada." })
645
+ ] })
646
+ ] })
647
+ }
648
+ ),
649
+ /* @__PURE__ */ jsxs("div", { className: "flex gap-2 pt-2", children: [
650
+ /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => navigate("/invoice-config/companies"), children: "Cancelar" }),
651
+ /* @__PURE__ */ jsx(Button, { type: "submit", isLoading: saveMutation.isPending, children: "Guardar Cambios" })
404
652
  ] })
405
- ] })
653
+ ] }) })
406
654
  ] });
407
655
  };
408
- function getDefaultHtml(type) {
409
- if (type === "quote_proforma") {
410
- return `<!DOCTYPE html>
411
- <html>
412
- <head><style>body { font-family: Helvetica, sans-serif; }</style></head>
413
- <body>
414
- <h1>COTIZACIÓN {{quote_number}}</h1>
415
- <p>Fecha: {{date_str}}</p>
416
- <p>Servicio: {{service_name}}</p>
417
- <!-- Personaliza tu plantilla aquí -->
418
- </body>
419
- </html>`;
656
+ const ORDER_INVOICE_CATEGORIES = [
657
+ {
658
+ label: "Empresa",
659
+ icon: "🏢",
660
+ variables: [
661
+ { name: "company_name" },
662
+ { name: "company_ruc" },
663
+ { name: "company_address" },
664
+ { name: "company_phone" },
665
+ { name: "company_email" },
666
+ { name: "company_logo_base64" }
667
+ ]
668
+ },
669
+ {
670
+ label: "Documento",
671
+ icon: "📄",
672
+ variables: [
673
+ { name: "invoice_id" },
674
+ { name: "invoice_date" },
675
+ { name: "order_display_id" },
676
+ { name: "order_date" }
677
+ ]
678
+ },
679
+ {
680
+ label: "Cliente",
681
+ icon: "👤",
682
+ variables: [
683
+ { name: "billing_address" },
684
+ { name: "shipping_address" },
685
+ { name: "cedula" }
686
+ ]
687
+ },
688
+ {
689
+ label: "Productos",
690
+ icon: "📦",
691
+ variables: [
692
+ { name: "{{#each items}}", isBlock: true },
693
+ { name: "this.title" },
694
+ { name: "this.variant_title" },
695
+ { name: "this.quantity" },
696
+ { name: "this.unit_price" },
697
+ { name: "this.total" },
698
+ { name: "{{/each}}", isBlock: true }
699
+ ]
700
+ },
701
+ {
702
+ label: "Totales",
703
+ icon: "💰",
704
+ variables: [
705
+ { name: "subtotal" },
706
+ { name: "tax_total" },
707
+ { name: "shipping_total" },
708
+ { name: "discount_total" },
709
+ { name: "total" }
710
+ ]
711
+ },
712
+ {
713
+ label: "Otros",
714
+ icon: "📝",
715
+ variables: [
716
+ { name: "is_home_delivery" },
717
+ { name: "notes" }
718
+ ]
420
719
  }
421
- return `<!DOCTYPE html>
422
- <html>
423
- <head><style>body { font-family: Helvetica, sans-serif; }</style></head>
424
- <body>
425
- <h1>COMPROBANTE {{invoice_id}}</h1>
426
- <p>Fecha: {{invoice_date}}</p>
427
- <p>Empresa: {{company_name}}</p>
428
- <!-- Personaliza tu plantilla aquí -->
429
- </body>
430
- </html>`;
431
- }
432
- const VARIABLES = {
433
- order_invoice: [
434
- "company_name",
435
- "company_ruc",
436
- "company_address",
437
- "company_phone",
438
- "company_email",
439
- "company_logo_base64",
440
- "invoice_id",
441
- "invoice_date",
442
- "order_display_id",
443
- "order_date",
444
- "billing_address",
445
- "shipping_address",
446
- "cedula",
447
- "subtotal",
448
- "tax_total",
449
- "shipping_total",
450
- "discount_total",
451
- "total",
452
- "is_home_delivery",
453
- "notes",
454
- "{{#each items}}",
455
- "this.title",
456
- "this.variant_title",
457
- "this.quantity",
458
- "this.unit_price",
459
- "this.total",
460
- "{{/each}}"
461
- ],
462
- quote_proforma: [
463
- "company_name",
464
- "company_website",
465
- "quote_number",
466
- "date_str",
467
- "service_name",
468
- "is_home_delivery",
469
- "{{#each config_fields}}",
470
- "this.label",
471
- "this.value",
472
- "{{/each}}",
473
- "{{#each breakdown}}",
474
- "this.label",
475
- "this.total_formatted",
476
- "{{/each}}",
477
- "totals.subtotal_formatted",
478
- "totals.extras_formatted",
479
- "totals.discount_formatted",
480
- "totals.shipping_formatted",
481
- "totals.taxes_provided",
482
- "totals.taxes_formatted",
483
- "totals.total_formatted",
484
- "{{#each includes_left}}",
485
- "{{#each includes_right}}",
486
- "{{#each contact_rows}}",
487
- "this.label",
488
- "this.value",
489
- "{{/each}}"
490
- ]
720
+ ];
721
+ const QUOTE_PROFORMA_CATEGORIES = [
722
+ {
723
+ label: "Empresa",
724
+ icon: "🏢",
725
+ variables: [
726
+ { name: "company_name" },
727
+ { name: "company_website" }
728
+ ]
729
+ },
730
+ {
731
+ label: "Documento",
732
+ icon: "📄",
733
+ variables: [
734
+ { name: "quote_number" },
735
+ { name: "date_str" },
736
+ { name: "service_name" },
737
+ { name: "is_home_delivery" }
738
+ ]
739
+ },
740
+ {
741
+ label: "Configuración",
742
+ icon: "⚙️",
743
+ variables: [
744
+ { name: "{{#each config_fields}}", isBlock: true },
745
+ { name: "this.label" },
746
+ { name: "this.value" },
747
+ { name: "{{/each}}", isBlock: true }
748
+ ]
749
+ },
750
+ {
751
+ label: "Desglose",
752
+ icon: "📊",
753
+ variables: [
754
+ { name: "{{#each breakdown}}", isBlock: true },
755
+ { name: "this.label" },
756
+ { name: "this.total_formatted" },
757
+ { name: "{{/each}}", isBlock: true }
758
+ ]
759
+ },
760
+ {
761
+ label: "Totales",
762
+ icon: "💰",
763
+ variables: [
764
+ { name: "totals.subtotal_formatted" },
765
+ { name: "totals.extras_formatted" },
766
+ { name: "totals.discount_formatted" },
767
+ { name: "totals.shipping_formatted" },
768
+ { name: "totals.taxes_provided" },
769
+ { name: "totals.taxes_formatted" },
770
+ { name: "totals.total_formatted" }
771
+ ]
772
+ },
773
+ {
774
+ label: "Incluye y Contacto",
775
+ icon: "📋",
776
+ variables: [
777
+ { name: "{{#each includes_left}}", isBlock: true },
778
+ { name: "{{#each includes_right}}", isBlock: true },
779
+ { name: "{{#each contact_rows}}", isBlock: true },
780
+ { name: "this.label" },
781
+ { name: "this.value" },
782
+ { name: "{{/each}}", isBlock: true }
783
+ ]
784
+ }
785
+ ];
786
+ const CATEGORIES = {
787
+ order_invoice: ORDER_INVOICE_CATEGORIES,
788
+ quote_proforma: QUOTE_PROFORMA_CATEGORIES
491
789
  };
790
+ const PLACEHOLDER_LOGO_BASE64 = "data:image/svg+xml;base64," + btoa(`<svg xmlns="http://www.w3.org/2000/svg" width="120" height="40" viewBox="0 0 120 40"><rect width="120" height="40" rx="4" fill="#e2e8f0"/><text x="60" y="24" text-anchor="middle" fill="#64748b" font-family="sans-serif" font-size="11">LOGO</text></svg>`);
492
791
  const SAMPLE_DATA = {
493
792
  order_invoice: {
494
793
  company_name: "Mi Empresa",
@@ -496,7 +795,7 @@ const SAMPLE_DATA = {
496
795
  company_address: "Av. Principal 123, Quito",
497
796
  company_phone: "+593 99 123 4567",
498
797
  company_email: "info@miempresa.com",
499
- company_logo_base64: "",
798
+ company_logo_base64: PLACEHOLDER_LOGO_BASE64,
500
799
  invoice_id: "INV-000001",
501
800
  invoice_date: "19/06/2025",
502
801
  order_display_id: "000042",
@@ -561,14 +860,22 @@ const TemplateEditorPage = () => {
561
860
  queryKey: ["invoice-template", id],
562
861
  enabled: !!id
563
862
  });
863
+ const { data: companiesData } = useQuery({
864
+ queryFn: () => sdk.client.fetch("/admin/invoice-config"),
865
+ queryKey: ["invoice-configs"]
866
+ });
564
867
  const template = data == null ? void 0 : data.invoice_template;
868
+ const companies = (companiesData == null ? void 0 : companiesData.invoice_configs) ?? [];
565
869
  const [name, setName] = useState("");
566
870
  const [htmlContent, setHtmlContent] = useState("");
871
+ const [companyId, setCompanyId] = useState(null);
567
872
  const [showVariables, setShowVariables] = useState(false);
873
+ const [collapsedSections, setCollapsedSections] = useState({});
568
874
  useEffect(() => {
569
875
  if (template) {
570
876
  setName(template.name);
571
877
  setHtmlContent(template.html_content);
878
+ setCompanyId(template.company_id);
572
879
  }
573
880
  }, [template]);
574
881
  const saveMutation = useMutation({
@@ -585,7 +892,7 @@ const TemplateEditorPage = () => {
585
892
  }
586
893
  });
587
894
  const handleSave = () => {
588
- saveMutation.mutate({ name, html_content: htmlContent });
895
+ saveMutation.mutate({ name, html_content: htmlContent, company_id: companyId });
589
896
  };
590
897
  const handlePreviewPdf = async () => {
591
898
  try {
@@ -606,7 +913,7 @@ const TemplateEditorPage = () => {
606
913
  if (!(template == null ? void 0 : template.is_default)) return;
607
914
  if (!confirm("¿Restaurar la plantilla a su contenido original?")) return;
608
915
  try {
609
- const res = await sdk.client.fetch(
916
+ await sdk.client.fetch(
610
917
  `/admin/invoice-templates/${id}/restore`,
611
918
  { method: "POST" }
612
919
  );
@@ -625,77 +932,102 @@ const TemplateEditorPage = () => {
625
932
  return `<div style="color:red;padding:20px;">Error en la plantilla Handlebars</div>`;
626
933
  }
627
934
  }, [htmlContent, template]);
628
- const insertVariable = useCallback((variable) => {
629
- const isBlock = variable.startsWith("{{#") || variable.startsWith("{{/");
935
+ const insertVariable = useCallback((variable, isBlock) => {
630
936
  const insertion = isBlock ? variable : `{{${variable}}}`;
631
937
  setHtmlContent((prev) => prev + insertion);
632
938
  }, []);
633
- const availableVars = template ? VARIABLES[template.type] ?? [] : [];
939
+ const toggleSection = useCallback((label) => {
940
+ setCollapsedSections((prev) => ({ ...prev, [label]: !prev[label] }));
941
+ }, []);
942
+ const categories = template ? CATEGORIES[template.type] ?? [] : [];
634
943
  if (isLoading) {
635
- return /* @__PURE__ */ jsx(Container, { children: /* @__PURE__ */ jsx("div", { style: { textAlign: "center", padding: 40 }, children: "Cargando..." }) });
944
+ return /* @__PURE__ */ jsx(Container, { children: /* @__PURE__ */ jsx("div", { className: "text-center py-10", children: "Cargando..." }) });
636
945
  }
637
946
  if (!template) {
638
- return /* @__PURE__ */ jsx(Container, { children: /* @__PURE__ */ jsx("div", { style: { textAlign: "center", padding: 40 }, children: "Plantilla no encontrada" }) });
947
+ return /* @__PURE__ */ jsx(Container, { children: /* @__PURE__ */ jsx("div", { className: "text-center py-10", children: "Plantilla no encontrada" }) });
639
948
  }
640
- return /* @__PURE__ */ jsxs(Container, { children: [
641
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 16 }, children: [
642
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 12 }, children: [
949
+ return /* @__PURE__ */ jsxs(Container, { className: "p-0", children: [
950
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-4 py-3 border-b border-ui-border-base", children: [
951
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
643
952
  /* @__PURE__ */ jsx(Button, { variant: "secondary", size: "small", onClick: () => navigate("/invoice-config/invoice-templates"), children: "← Volver" }),
644
- /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(
953
+ /* @__PURE__ */ jsx(
645
954
  Input,
646
955
  {
647
956
  value: name,
648
957
  onChange: (e) => setName(e.target.value),
649
- style: { fontWeight: "bold", fontSize: 16 }
958
+ className: "font-semibold text-base w-64"
650
959
  }
651
- ) }),
652
- /* @__PURE__ */ jsxs("code", { style: { fontSize: 12, color: "#6c757d" }, children: [
960
+ ),
961
+ /* @__PURE__ */ jsxs(Text, { className: "text-ui-fg-muted text-xs", children: [
653
962
  template.slug,
654
963
  " (",
655
964
  template.type,
656
965
  ")"
657
966
  ] })
658
967
  ] }),
659
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 8 }, children: [
660
- template.is_default && /* @__PURE__ */ jsx(Button, { variant: "secondary", size: "small", onClick: handleRestoreDefault, children: "Restaurar Default" }),
968
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
969
+ /* @__PURE__ */ jsxs(
970
+ Select,
971
+ {
972
+ value: companyId ?? "__none__",
973
+ onValueChange: (v) => setCompanyId(v === "__none__" ? null : v),
974
+ children: [
975
+ /* @__PURE__ */ jsx(Select.Trigger, { className: "w-48", children: /* @__PURE__ */ jsx(Select.Value, { placeholder: "Empresa" }) }),
976
+ /* @__PURE__ */ jsxs(Select.Content, { children: [
977
+ /* @__PURE__ */ jsx(Select.Item, { value: "__none__", children: "Sin empresa (usa default)" }),
978
+ companies.map((c) => /* @__PURE__ */ jsxs(Select.Item, { value: c.id, children: [
979
+ c.company_name,
980
+ c.is_default ? " ★" : ""
981
+ ] }, c.id))
982
+ ] })
983
+ ]
984
+ }
985
+ ),
986
+ template.is_default && /* @__PURE__ */ jsx(Button, { variant: "secondary", size: "small", onClick: handleRestoreDefault, children: "Restaurar" }),
661
987
  /* @__PURE__ */ jsx(Button, { variant: "secondary", size: "small", onClick: () => setShowVariables(!showVariables), children: showVariables ? "Ocultar Variables" : "Variables" }),
662
988
  /* @__PURE__ */ jsx(Button, { variant: "secondary", size: "small", onClick: handlePreviewPdf, children: "Preview PDF" }),
663
989
  /* @__PURE__ */ jsx(Button, { onClick: handleSave, isLoading: saveMutation.isPending, children: "Guardar" })
664
990
  ] })
665
991
  ] }),
666
- showVariables && /* @__PURE__ */ jsxs("div", { style: {
667
- background: "#f8f9fa",
668
- border: "1px solid #e2e8f0",
669
- borderRadius: 8,
670
- padding: 12,
671
- marginBottom: 16,
672
- display: "flex",
673
- flexWrap: "wrap",
674
- gap: 6
675
- }, children: [
676
- /* @__PURE__ */ jsx(Label, { style: { width: "100%", marginBottom: 4 }, children: "Variables Handlebars — click para insertar:" }),
677
- availableVars.map((v, i) => /* @__PURE__ */ jsx(
678
- "button",
679
- {
680
- onClick: () => insertVariable(v),
681
- style: {
682
- background: v.startsWith("{{") ? "#e2e8f0" : "#dbeafe",
683
- border: "1px solid #cbd5e0",
684
- borderRadius: 4,
685
- padding: "2px 8px",
686
- fontSize: 11,
687
- cursor: "pointer",
688
- fontFamily: "monospace"
992
+ showVariables && /* @__PURE__ */ jsxs("div", { className: "border-b border-ui-border-base bg-ui-bg-subtle px-4 py-3", children: [
993
+ /* @__PURE__ */ jsx(Label, { className: "block mb-2 text-sm", children: "Variables Handlebars — click para insertar" }),
994
+ /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-2", children: categories.map((cat) => /* @__PURE__ */ jsxs("div", { className: "border border-ui-border-base rounded-lg bg-ui-bg-base overflow-hidden", children: [
995
+ /* @__PURE__ */ jsxs(
996
+ "button",
997
+ {
998
+ type: "button",
999
+ className: "w-full flex items-center justify-between px-3 py-2 text-left text-sm font-medium hover:bg-ui-bg-subtle-hover transition-colors",
1000
+ onClick: () => toggleSection(cat.label),
1001
+ children: [
1002
+ /* @__PURE__ */ jsxs("span", { children: [
1003
+ cat.icon,
1004
+ " ",
1005
+ cat.label
1006
+ ] }),
1007
+ /* @__PURE__ */ jsxs("span", { className: "text-ui-fg-muted text-xs", children: [
1008
+ collapsedSections[cat.label] ? "" : "",
1009
+ " ",
1010
+ cat.variables.length
1011
+ ] })
1012
+ ]
1013
+ }
1014
+ ),
1015
+ !collapsedSections[cat.label] && /* @__PURE__ */ jsx("div", { className: "px-3 pb-2 flex flex-wrap gap-1.5", children: cat.variables.map((v, i) => /* @__PURE__ */ jsx(
1016
+ Badge,
1017
+ {
1018
+ color: v.isBlock ? "orange" : "blue",
1019
+ className: "cursor-pointer hover:opacity-80 transition-opacity text-xs",
1020
+ onClick: () => insertVariable(v.name, v.isBlock),
1021
+ children: v.isBlock ? v.name : `{{${v.name}}}`
689
1022
  },
690
- children: v.startsWith("{{") ? v : `{{${v}}}`
691
- },
692
- i
693
- ))
1023
+ `${cat.label}-${i}`
1024
+ )) })
1025
+ ] }, cat.label)) })
694
1026
  ] }),
695
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 16, height: "calc(100vh - 260px)" }, children: [
1027
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 16, height: "calc(100vh - 260px)", padding: 16 }, children: [
696
1028
  /* @__PURE__ */ jsxs("div", { style: { flex: 1, display: "flex", flexDirection: "column", minWidth: 0 }, children: [
697
- /* @__PURE__ */ jsx(Label, { style: { marginBottom: 8 }, children: "Editor HTML + Handlebars" }),
698
- /* @__PURE__ */ jsx("div", { style: { flex: 1, border: "1px solid #e2e8f0", borderRadius: 8, overflow: "hidden" }, children: /* @__PURE__ */ jsx(
1029
+ /* @__PURE__ */ jsx(Label, { className: "mb-2", children: "Editor HTML + Handlebars" }),
1030
+ /* @__PURE__ */ jsx("div", { className: "flex-1 border border-ui-border-base rounded-lg overflow-hidden", children: /* @__PURE__ */ jsx(
699
1031
  CodeMirror,
700
1032
  {
701
1033
  ref: editorRef,
@@ -709,14 +1041,8 @@ const TemplateEditorPage = () => {
709
1041
  ) })
710
1042
  ] }),
711
1043
  /* @__PURE__ */ jsxs("div", { style: { flex: 1, display: "flex", flexDirection: "column", minWidth: 0 }, children: [
712
- /* @__PURE__ */ jsx(Label, { style: { marginBottom: 8 }, children: "Preview en vivo (datos de ejemplo)" }),
713
- /* @__PURE__ */ jsx("div", { style: {
714
- flex: 1,
715
- border: "1px solid #e2e8f0",
716
- borderRadius: 8,
717
- overflow: "auto",
718
- background: "#fff"
719
- }, children: /* @__PURE__ */ jsx(
1044
+ /* @__PURE__ */ jsx(Label, { className: "mb-2", children: "Preview en vivo (datos de ejemplo)" }),
1045
+ /* @__PURE__ */ jsx("div", { className: "flex-1 border border-ui-border-base rounded-lg overflow-auto bg-white", children: /* @__PURE__ */ jsx(
720
1046
  "iframe",
721
1047
  {
722
1048
  srcDoc: previewHtml,
@@ -729,6 +1055,96 @@ const TemplateEditorPage = () => {
729
1055
  ] })
730
1056
  ] });
731
1057
  };
1058
+ const NewTemplatePage = () => {
1059
+ const navigate = useNavigate();
1060
+ const [name, setName] = useState("");
1061
+ const [slug, setSlug] = useState("");
1062
+ const [type, setType] = useState("order_invoice");
1063
+ const createMutation = useMutation({
1064
+ mutationFn: (payload) => sdk.client.fetch("/admin/invoice-templates", {
1065
+ method: "POST",
1066
+ body: payload
1067
+ }),
1068
+ onSuccess: (data) => {
1069
+ toast.success("Plantilla creada");
1070
+ navigate(`/invoice-config/invoice-templates/${data.invoice_template.id}`);
1071
+ },
1072
+ onError: () => {
1073
+ toast.error("Error al crear la plantilla");
1074
+ }
1075
+ });
1076
+ const handleCreate = () => {
1077
+ if (!name || !slug) {
1078
+ toast.error("Nombre y slug son requeridos");
1079
+ return;
1080
+ }
1081
+ createMutation.mutate({
1082
+ name,
1083
+ slug,
1084
+ type,
1085
+ html_content: getDefaultHtml(type)
1086
+ });
1087
+ };
1088
+ return /* @__PURE__ */ jsxs(Container, { children: [
1089
+ /* @__PURE__ */ jsx(Heading, { level: "h1", style: { marginBottom: 24 }, children: "Nueva Plantilla" }),
1090
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: 16, maxWidth: 500 }, children: [
1091
+ /* @__PURE__ */ jsxs("div", { children: [
1092
+ /* @__PURE__ */ jsx(Label, { htmlFor: "name", children: "Nombre" }),
1093
+ /* @__PURE__ */ jsx(Input, { id: "name", value: name, onChange: (e) => setName(e.target.value), placeholder: "Ej: Mi Comprobante" })
1094
+ ] }),
1095
+ /* @__PURE__ */ jsxs("div", { children: [
1096
+ /* @__PURE__ */ jsx(Label, { htmlFor: "slug", children: "Slug (identificador único)" }),
1097
+ /* @__PURE__ */ jsx(
1098
+ Input,
1099
+ {
1100
+ id: "slug",
1101
+ value: slug,
1102
+ onChange: (e) => setSlug(e.target.value.toLowerCase().replace(/[^a-z0-9_]/g, "_")),
1103
+ placeholder: "Ej: my_custom_invoice"
1104
+ }
1105
+ )
1106
+ ] }),
1107
+ /* @__PURE__ */ jsxs("div", { children: [
1108
+ /* @__PURE__ */ jsx(Label, { htmlFor: "type", children: "Tipo de documento" }),
1109
+ /* @__PURE__ */ jsxs(Select, { value: type, onValueChange: setType, children: [
1110
+ /* @__PURE__ */ jsx(Select.Trigger, { children: /* @__PURE__ */ jsx(Select.Value, { placeholder: "Seleccionar tipo" }) }),
1111
+ /* @__PURE__ */ jsxs(Select.Content, { children: [
1112
+ /* @__PURE__ */ jsx(Select.Item, { value: "order_invoice", children: "Comprobante de Pedido" }),
1113
+ /* @__PURE__ */ jsx(Select.Item, { value: "quote_proforma", children: "Cotización Proforma" })
1114
+ ] })
1115
+ ] })
1116
+ ] }),
1117
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 8, marginTop: 16 }, children: [
1118
+ /* @__PURE__ */ jsx(Button, { variant: "secondary", onClick: () => navigate("/invoice-config/invoice-templates"), children: "Cancelar" }),
1119
+ /* @__PURE__ */ jsx(Button, { onClick: handleCreate, isLoading: createMutation.isPending, children: "Crear Plantilla" })
1120
+ ] })
1121
+ ] })
1122
+ ] });
1123
+ };
1124
+ function getDefaultHtml(type) {
1125
+ if (type === "quote_proforma") {
1126
+ return `<!DOCTYPE html>
1127
+ <html>
1128
+ <head><style>body { font-family: Helvetica, sans-serif; }</style></head>
1129
+ <body>
1130
+ <h1>COTIZACIÓN {{quote_number}}</h1>
1131
+ <p>Fecha: {{date_str}}</p>
1132
+ <p>Servicio: {{service_name}}</p>
1133
+ <!-- Personaliza tu plantilla aquí -->
1134
+ </body>
1135
+ </html>`;
1136
+ }
1137
+ return `<!DOCTYPE html>
1138
+ <html>
1139
+ <head><style>body { font-family: Helvetica, sans-serif; }</style></head>
1140
+ <body>
1141
+ <h1>COMPROBANTE {{invoice_id}}</h1>
1142
+ <p>Fecha: {{invoice_date}}</p>
1143
+ <p>Empresa: {{company_name}}</p>
1144
+ <!-- Personaliza tu plantilla aquí -->
1145
+ </body>
1146
+ </html>`;
1147
+ }
732
1148
  const i18nTranslations0 = {};
733
1149
  const widgetModule = { widgets: [
734
1150
  {
@@ -742,17 +1158,29 @@ const routeModule = {
742
1158
  Component: InvoiceConfigPage,
743
1159
  path: "/invoice-config"
744
1160
  },
1161
+ {
1162
+ Component: CompaniesPage,
1163
+ path: "/invoice-config/companies"
1164
+ },
745
1165
  {
746
1166
  Component: InvoiceTemplatesPage,
747
1167
  path: "/invoice-config/invoice-templates"
748
1168
  },
749
1169
  {
750
- Component: NewTemplatePage,
751
- path: "/invoice-config/invoice-templates/new"
1170
+ Component: NewCompanyPage,
1171
+ path: "/invoice-config/companies/new"
1172
+ },
1173
+ {
1174
+ Component: EditCompanyPage,
1175
+ path: "/invoice-config/companies/:id"
752
1176
  },
753
1177
  {
754
1178
  Component: TemplateEditorPage,
755
1179
  path: "/invoice-config/invoice-templates/:id"
1180
+ },
1181
+ {
1182
+ Component: NewTemplatePage,
1183
+ path: "/invoice-config/invoice-templates/new"
756
1184
  }
757
1185
  ]
758
1186
  };