fase 1 productizacion: capa de configuracion (glosario multi-giro, sucursales y categorias configurables, ajustes de clinica por instancia, colores de marca, horarios, URLs de pago dinamicas) + script de provisioning de instancia nueva con datos demo + frontend consumiendo la config
This commit is contained in:
@@ -905,6 +905,9 @@ export interface ClinicBrand {
|
||||
logo_claro: string; // fondos oscuros (login SKEEN, sidebar)
|
||||
logo_oscuro: string; // fondos claros (tema HomeNest)
|
||||
pie: string; // línea del pie (login / documentos)
|
||||
url_publica?: string; // URL pública de la instancia (opcional)
|
||||
// Colores de marca (opcional). Vacíos = se usa el color del tema activo.
|
||||
colores?: { primario?: string; acento?: string };
|
||||
}
|
||||
|
||||
export const BRAND_DEFAULT: ClinicBrand = {
|
||||
@@ -914,6 +917,80 @@ export const BRAND_DEFAULT: ClinicBrand = {
|
||||
pie: 'SKEEN Derma Experts · Playas de Rosarito, B.C.',
|
||||
};
|
||||
|
||||
// ---- Glosario / terminología white-label ----
|
||||
export const GLOSSARY_KEYS = [
|
||||
'patient_singular', 'patient_plural',
|
||||
'appointment_singular', 'appointment_plural',
|
||||
'visit_singular', 'visit_plural',
|
||||
'record_singular', 'record_plural',
|
||||
'doctor_singular', 'doctor_plural',
|
||||
'staff_singular', 'staff_plural',
|
||||
'branch_singular', 'branch_plural',
|
||||
'room_singular', 'room_plural',
|
||||
'service_singular', 'service_plural',
|
||||
'package_singular', 'package_plural',
|
||||
'prescription_singular', 'prescription_plural',
|
||||
'treatment_singular', 'treatment_plural',
|
||||
] as const;
|
||||
|
||||
export type GlossaryKey = typeof GLOSSARY_KEYS[number];
|
||||
export type GlossaryTerms = Record<GlossaryKey, string>;
|
||||
export interface GlossaryPack { code: string; name: string; }
|
||||
|
||||
// ---- Sucursales ----
|
||||
export interface Sucursal {
|
||||
id: number;
|
||||
code: string;
|
||||
name: string;
|
||||
sequence: number;
|
||||
active: boolean;
|
||||
is_default: boolean;
|
||||
address: string;
|
||||
phone: string;
|
||||
notes: string;
|
||||
}
|
||||
|
||||
// ---- Categorías de servicio ----
|
||||
export interface ServiceCategory {
|
||||
id: number;
|
||||
code: string;
|
||||
name: string;
|
||||
sequence: number;
|
||||
active: boolean;
|
||||
is_system: boolean;
|
||||
}
|
||||
|
||||
// ---- Ajustes de la clínica ----
|
||||
export interface ClinicSettings {
|
||||
nombre: string;
|
||||
telefono: string;
|
||||
email: string;
|
||||
direccion: string;
|
||||
web: string;
|
||||
rfc: string;
|
||||
horario_apertura: string;
|
||||
horario_cierre: string;
|
||||
zona_horaria: string;
|
||||
url_publica: string;
|
||||
moneda_base: string;
|
||||
nota_ticket: string;
|
||||
}
|
||||
|
||||
export const CLINIC_SETTINGS_DEFAULT: ClinicSettings = {
|
||||
nombre: BRAND_DEFAULT.nombre,
|
||||
telefono: '',
|
||||
email: '',
|
||||
direccion: '',
|
||||
web: '',
|
||||
rfc: '',
|
||||
horario_apertura: '08:00',
|
||||
horario_cierre: '19:00',
|
||||
zona_horaria: 'America/Tijuana',
|
||||
url_publica: '',
|
||||
moneda_base: 'MXN',
|
||||
nota_ticket: '',
|
||||
};
|
||||
|
||||
export interface FrontendUser {
|
||||
id: number;
|
||||
login: string;
|
||||
@@ -1397,6 +1474,79 @@ export const odooApi = {
|
||||
return data;
|
||||
},
|
||||
|
||||
// ---- Glosario / terminología ----
|
||||
async getGlosario(): Promise<{ status: string; pack: string; terms: GlossaryTerms; message?: string }> {
|
||||
const { data } = await axios.get(`${ODOO_BASE}/skeen/frontend/v1/glosario`);
|
||||
return data;
|
||||
},
|
||||
|
||||
async getGlosarioPacks(): Promise<{ status: string; packs: GlossaryPack[]; message?: string }> {
|
||||
const { data } = await axios.get(`${ODOO_BASE}/skeen/frontend/v1/glosario/packs`);
|
||||
return data;
|
||||
},
|
||||
|
||||
async putGlosario(payload: { pack?: string; overrides?: Partial<GlossaryTerms>; motivo?: string }): Promise<{ status: string; pack: string; terms: GlossaryTerms; message?: string }> {
|
||||
const { data } = await axios.put(`${ODOO_BASE}/skeen/frontend/v1/glosario`, payload);
|
||||
return data;
|
||||
},
|
||||
|
||||
// ---- Sucursales ----
|
||||
async getSucursales(opts?: { includeInactive?: boolean }): Promise<{ status: string; sucursales: Sucursal[]; total: number; message?: string }> {
|
||||
const { data } = await axios.get(`${ODOO_BASE}/skeen/frontend/v1/sucursales`, {
|
||||
params: opts?.includeInactive ? { include_inactive: 1 } : undefined,
|
||||
});
|
||||
return data;
|
||||
},
|
||||
|
||||
async createSucursal(payload: Partial<Sucursal>): Promise<{ status: string; sucursal: Sucursal; message?: string }> {
|
||||
const { data } = await axios.post(`${ODOO_BASE}/skeen/frontend/v1/sucursales`, payload);
|
||||
return data;
|
||||
},
|
||||
|
||||
async updateSucursal(id: number, payload: Partial<Sucursal>): Promise<{ status: string; sucursal: Sucursal; message?: string }> {
|
||||
const { data } = await axios.put(`${ODOO_BASE}/skeen/frontend/v1/sucursales/${id}`, payload);
|
||||
return data;
|
||||
},
|
||||
|
||||
async deleteSucursal(id: number): Promise<{ status: string; sucursal: Sucursal; en_uso: number; message: string }> {
|
||||
const { data } = await axios.delete(`${ODOO_BASE}/skeen/frontend/v1/sucursales/${id}`);
|
||||
return data;
|
||||
},
|
||||
|
||||
// ---- Categorías de servicio ----
|
||||
async getServiceCategories(opts?: { includeInactive?: boolean }): Promise<{ status: string; categories: ServiceCategory[]; total: number; message?: string }> {
|
||||
const { data } = await axios.get(`${ODOO_BASE}/skeen/frontend/v1/service-categories`, {
|
||||
params: opts?.includeInactive ? { include_inactive: 1 } : undefined,
|
||||
});
|
||||
return data;
|
||||
},
|
||||
|
||||
async createServiceCategory(payload: { name: string; code?: string; sequence?: number; active?: boolean }): Promise<{ status: string; category: ServiceCategory; message?: string }> {
|
||||
const { data } = await axios.post(`${ODOO_BASE}/skeen/frontend/v1/service-categories`, payload);
|
||||
return data;
|
||||
},
|
||||
|
||||
async updateServiceCategory(id: number, payload: { name?: string; code?: string; sequence?: number; active?: boolean }): Promise<{ status: string; category: ServiceCategory; message?: string }> {
|
||||
const { data } = await axios.put(`${ODOO_BASE}/skeen/frontend/v1/service-categories/${id}`, payload);
|
||||
return data;
|
||||
},
|
||||
|
||||
async deleteServiceCategory(id: number): Promise<{ status: string; category?: ServiceCategory; en_uso?: number; message?: string }> {
|
||||
const { data } = await axios.delete(`${ODOO_BASE}/skeen/frontend/v1/service-categories/${id}`);
|
||||
return data;
|
||||
},
|
||||
|
||||
// ---- Ajustes de la clínica ----
|
||||
async getClinicSettings(): Promise<{ status: string; settings: ClinicSettings; message?: string }> {
|
||||
const { data } = await axios.get(`${ODOO_BASE}/skeen/frontend/v1/clinic-settings`);
|
||||
return data;
|
||||
},
|
||||
|
||||
async putClinicSettings(settings: Partial<ClinicSettings> & { motivo?: string }): Promise<{ status: string; settings: ClinicSettings; message?: string }> {
|
||||
const { data } = await axios.put(`${ODOO_BASE}/skeen/frontend/v1/clinic-settings`, settings);
|
||||
return data;
|
||||
},
|
||||
|
||||
async updateRolePermissions(matrix: Record<string, FrontendRole[]>): Promise<{ status: string; matrix: Record<string, FrontendRole[]>; message?: string }> {
|
||||
const { data } = await axios.put(`${ODOO_BASE}/skeen/frontend/v1/roles/permissions`, { matrix });
|
||||
return data;
|
||||
@@ -1430,7 +1580,7 @@ export const odooApi = {
|
||||
return data;
|
||||
},
|
||||
|
||||
async createQuickAppointment(payload: { name: string; phone: string; date: string; time: number; doctor_id?: number; notes?: string; duration?: number }): Promise<{ status: string; appointment: Appointment; patient: Patient; patient_created: boolean; message?: string }> {
|
||||
async createQuickAppointment(payload: { name: string; phone: string; date: string; time: number; doctor_id?: number; notes?: string; duration?: number; branch?: string }): Promise<{ status: string; appointment: Appointment; patient: Patient; patient_created: boolean; message?: string }> {
|
||||
const { data } = await axios.post(`${ODOO_BASE}/skeen/frontend/v1/appointments/quick`, payload);
|
||||
return data;
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user