102 lines
2.6 KiB
TypeScript
102 lines
2.6 KiB
TypeScript
import { serve } from "https://deno.land/std@0.168.0/http/server.ts";
|
|
import { mydb } from "../../lib/mySupabase.ts";
|
|
import { corsHeaders, jsonResponse, errorResponse } from "../../lib/utils.ts";
|
|
import { validateAuth, hasPermission } from "../../lib/auth.ts";
|
|
|
|
/**
|
|
* POST /appointments/no-show
|
|
* Marcar consulta como no-show (paciente não compareceu)
|
|
*
|
|
* Body:
|
|
* {
|
|
* appointment_id: uuid,
|
|
* reason?: string,
|
|
* automatic_detection?: boolean
|
|
* }
|
|
*
|
|
* Returns:
|
|
* {
|
|
* success: boolean,
|
|
* appointment_id: uuid,
|
|
* penalty_applied: boolean,
|
|
* message: string
|
|
* }
|
|
*/
|
|
|
|
serve(async (req) => {
|
|
if (req.method === "OPTIONS") {
|
|
return new Response("ok", { headers: corsHeaders() });
|
|
}
|
|
|
|
try {
|
|
const auth = await validateAuth(req);
|
|
if (!auth) {
|
|
return errorResponse("Não autorizado", 401);
|
|
}
|
|
|
|
if (req.method !== "POST") {
|
|
return errorResponse("Method not allowed", 405);
|
|
}
|
|
|
|
const body = await req.json();
|
|
const { appointment_id, reason, automatic_detection } = body;
|
|
|
|
// Apenas staff ou sistema pode marcar no-show
|
|
if (
|
|
!hasPermission(auth.role, ["admin", "secretary", "doctor"]) &&
|
|
!automatic_detection
|
|
) {
|
|
return errorResponse("Sem permissão", 403);
|
|
}
|
|
|
|
// Registrar no-show
|
|
const noShowRes = await mydb
|
|
.from("no_show_tracking")
|
|
.insert({
|
|
appointment_id,
|
|
patient_id: null, // Será preenchido na query
|
|
doctor_id: null,
|
|
marked_at: new Date().toISOString(),
|
|
reason,
|
|
automatic_detection: automatic_detection || false,
|
|
})
|
|
.select();
|
|
|
|
if (noShowRes.error) {
|
|
return errorResponse(noShowRes.error.message);
|
|
}
|
|
|
|
// Aplicar penalidade se necessário
|
|
let penaltyApplied = false;
|
|
// TODO: Implementar lógica de penalidade (reduzir pontos gamificação, etc)
|
|
|
|
// Registrar em patient_journey
|
|
await mydb.from("patient_journey").insert({
|
|
patient_id: null,
|
|
event_type: "no_show",
|
|
event_data: { appointment_id, reason },
|
|
points_earned: -5, // Penalidade de pontos
|
|
});
|
|
|
|
// Audit log
|
|
await mydb.from("audit_log").insert({
|
|
user_id: automatic_detection ? null : auth.userId,
|
|
action: "mark_no_show",
|
|
target_type: "appointment",
|
|
target_id: appointment_id,
|
|
payload: { reason, automatic: automatic_detection },
|
|
});
|
|
|
|
return jsonResponse({
|
|
success: true,
|
|
appointment_id,
|
|
penalty_applied: penaltyApplied,
|
|
message: "Consulta marcada como no-show",
|
|
});
|
|
} catch (error: unknown) {
|
|
console.error("[no-show]", error);
|
|
const err = error as Error;
|
|
return errorResponse(err.message, 500);
|
|
}
|
|
});
|