Clientes API por dominio para los catálogos del SAT, conceptos y emisor. Los catálogos se cachean en un Map del módulo tras la primera carga: son fijos y no cambian durante la sesión. Pantalla de conceptos (/dashboard/fin/conceptos) con tabla, buscador, filtro de activos y alta/edición en diálogo. La clave de producto/servicio se elige con un combobox que consulta el catálogo a partir de 2 caracteres, y el 409 del backend por clave ya asignada se muestra junto al campo. Sección de configuración fiscal (/dashboard/settings/facturacion) con razón social, RFC (misma validación que el backend), régimen fiscal y CP. Si el GET responde 404 se abre en modo alta, no como error; el guardar se deshabilita sin fin.settings.edit. Todo en Svelte 5 con runes. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
52 lines
1.4 KiB
TypeScript
52 lines
1.4 KiB
TypeScript
/**
|
|
* Cliente API — Datos fiscales del emisor (una configuración por empresa).
|
|
*/
|
|
import { api } from '$lib/api';
|
|
import type { SatTaxRegime } from './catalogs';
|
|
|
|
/** RFC de persona moral (3 letras) o física (4 letras) + fecha + homoclave. */
|
|
export const RFC_REGEX = /^[A-ZÑ&]{3,4}\d{6}[A-Z0-9]{3}$/;
|
|
|
|
export interface IssuerSettings {
|
|
id: number;
|
|
tenant_id: number;
|
|
company_id: number;
|
|
legal_name: string;
|
|
rfc: string;
|
|
tax_regime_id: number;
|
|
tax_regime: SatTaxRegime | null;
|
|
zip_code: string | null;
|
|
updated_by: string | null;
|
|
created_at: string;
|
|
updated_at: string;
|
|
}
|
|
|
|
export interface IssuerSettingsInput {
|
|
legal_name: string;
|
|
rfc: string;
|
|
tax_regime_id: number;
|
|
zip_code?: string | null;
|
|
}
|
|
|
|
export const issuerAPI = {
|
|
/**
|
|
* Devuelve `null` cuando la empresa todavía no captura sus datos fiscales: el
|
|
* backend responde 404 y la pantalla debe abrirse en modo alta, no en error.
|
|
*/
|
|
async get(companyId: number): Promise<IssuerSettings | null> {
|
|
const res = await api.get<IssuerSettings>(`/v1/fin/settings/issuer?company_id=${companyId}`);
|
|
if (res.status === 404) return null;
|
|
if (res.error) throw new Error(res.error);
|
|
return res.data!;
|
|
},
|
|
|
|
async save(data: IssuerSettingsInput, companyId: number): Promise<IssuerSettings> {
|
|
const res = await api.put<IssuerSettings>(
|
|
`/v1/fin/settings/issuer?company_id=${companyId}`,
|
|
data
|
|
);
|
|
if (res.error) throw new Error(res.error);
|
|
return res.data!;
|
|
}
|
|
};
|