POS: boton Cobrar desde cita (precarga paciente/servicio/doctor) y ticket termico imprimible con reimpresion en Ventas

This commit is contained in:
2026-09-01 22:39:26 +00:00
parent 2710d9d92d
commit f0d7ac4c01
5 changed files with 296 additions and 72 deletions

View File

@@ -1,6 +1,6 @@
import type { FC } from 'react';
import { useEffect, useState, useCallback, useRef } from 'react';
import { Clock, CheckCircle, XCircle, CheckCheck, UserCheck, UserX, Plus, PackageCheck, Sparkles, RotateCcw, LayoutGrid, List, Rows3, CalendarRange, CalendarClock, ChevronLeft, ChevronRight, Ban, Trash2, Phone, Cake } from 'lucide-react';
import { Clock, CheckCircle, XCircle, CheckCheck, UserCheck, UserX, Plus, PackageCheck, Sparkles, RotateCcw, LayoutGrid, List, Rows3, CalendarRange, CalendarClock, ChevronLeft, ChevronRight, Ban, Trash2, Phone, Cake, CreditCard } from 'lucide-react';
import Layout from '../components/Layout';
import { usePatientDrawer } from '../components/PatientDrawer';
import {
@@ -18,7 +18,7 @@ import {
toast,
badgeForAppointmentState,
} from '../components/ui';
import { useSearchParams } from 'react-router-dom';
import { useSearchParams, useNavigate } from 'react-router-dom';
import { odooApi, type Appointment, type Patient, type Service, type Doctor, type Bloqueo } from '../services/odoo';
import { useAuth } from '../lib/auth';
@@ -44,6 +44,7 @@ const QUARTER_TIME_OPTIONS = (() => {
const Agenda: FC = () => {
const [searchParams] = useSearchParams();
const navigate = useNavigate();
const { user } = useAuth();
const { openPatient } = usePatientDrawer();
// Rol médico: agenda restringida a su propio hr.employee (filtro también en servidor)
@@ -2032,6 +2033,25 @@ const Agenda: FC = () => {
<Button size="sm" variant="outline" onClick={() => setEditMode(true)}>
<CalendarClock size={16} className="mr-1.5" /> Reagendar
</Button>
{/* Cobrar a la cita: abre el POS con paciente/servicio/médico precargados.
Solo en estados cobrables (oculto en cancelada/no show). */}
{!['cancelled', 'no_show'].includes(detailApt.state) && (
<Button
size="sm"
variant="outline"
onClick={() => {
const params = new URLSearchParams({
patient_id: String(detailApt.patient_id),
service_id: String(detailApt.service_id),
appointment_id: String(detailApt.id),
});
if (detailApt.doctor_id) params.set('doctor_id', String(detailApt.doctor_id));
navigate(`/pos?${params.toString()}`);
}}
>
<CreditCard size={16} className="mr-1.5" /> Cobrar
</Button>
)}
</div>
</div>
)}