Oleada UX 5: Servicios (duplicar, favoritos y orden para POS, mas vendidos) y Medicos (semana tipo con validacion en agenda, meta mensual con progreso)

This commit is contained in:
2026-09-17 21:28:43 +00:00
parent 9ee3343e22
commit cd945df6a5
10 changed files with 885 additions and 41 deletions

View File

@@ -255,6 +255,8 @@ export interface Service {
color: string;
service_group: string;
is_favorite: boolean;
sequence?: number;
sold_90d?: number | null;
genera_monedero?: boolean;
}
@@ -266,6 +268,11 @@ export interface Doctor {
work_email: string;
commission_pct: number;
staff_type?: 'doctor' | 'cosmetologa';
monthly_goal?: number;
month_total?: number;
horario?: { day_of_week: string; hour_from: number; hour_to: number }[];
tiene_horario?: boolean;
horario_resumen?: string;
patient_count?: number;
recomendaciones_30d?: number;
ventas_30d?: number;
@@ -454,6 +461,13 @@ export interface MySalesResponse {
commission_pct: number;
commission_source?: string;
commission_estimate: number;
monthly_goal?: { goal: number; real: number; pct: number | null; from: string; to: string };
}
export interface HorarioDia {
day_of_week: string;
hour_from: number;
hour_to: number;
}
export interface CashClosing {
@@ -1352,7 +1366,7 @@ export const odooApi = {
},
// Servicios
async getServices(params?: { search?: string; category?: string; page?: number; page_size?: number }): Promise<{ status: string; services: Service[]; total?: number; page?: number; total_pages?: number }> {
async getServices(params?: { search?: string; category?: string; page?: number; page_size?: number; sort?: 'manual' | 'best_sellers' }): Promise<{ status: string; services: Service[]; total?: number; page?: number; total_pages?: number; sort?: string }> {
const { data } = await axios.get(`${ODOO_BASE}/skeen/frontend/v1/services`, { params });
return data;
},
@@ -1372,6 +1386,11 @@ export const odooApi = {
return data;
},
async reorderServices(ids: number[], to?: 'front'): Promise<{ status: string; total: number }> {
const { data } = await axios.post(`${ODOO_BASE}/skeen/frontend/v1/services/reorder`, { ids, ...(to ? { to } : {}) });
return data;
},
async updateService(id: number, service: Partial<Service>): Promise<{ status: string; service: Service }> {
const { data } = await axios.put(`${ODOO_BASE}/skeen/frontend/v1/services/${id}`, service);
return data;
@@ -1383,11 +1402,22 @@ export const odooApi = {
return data;
},
async updateDoctor(id: number, payload: { commission_pct?: number; staff_type?: 'doctor' | 'cosmetologa' }): Promise<{ status: string; doctor: Doctor }> {
async updateDoctor(id: number, payload: { commission_pct?: number; staff_type?: 'doctor' | 'cosmetologa'; monthly_goal?: number }): Promise<{ status: string; doctor: Doctor }> {
const { data } = await axios.put(`${ODOO_BASE}/skeen/frontend/v1/doctors/${id}`, payload);
return data;
},
// Horario semanal del médico (reemplaza la lista completa)
async getDoctorHorario(id: number): Promise<{ status: string; horario: HorarioDia[]; tiene_horario: boolean; horario_resumen: string }> {
const { data } = await axios.get(`${ODOO_BASE}/skeen/frontend/v1/doctors/${id}/horario`);
return data;
},
async setDoctorHorario(id: number, horario: HorarioDia[]): Promise<{ status: string; horario: HorarioDia[]; tiene_horario: boolean; horario_resumen: string }> {
const { data } = await axios.put(`${ODOO_BASE}/skeen/frontend/v1/doctors/${id}/horario`, { horario });
return data;
},
async setDoctorCommission(id: number, commission_pct: number): Promise<{ status: string; doctor: { id: number; name: string; commission_pct: number } }> {
const { data } = await axios.post(`${ODOO_BASE}/skeen/frontend/v1/doctors/${id}/commission`, { commission_pct });
return data;