Preficicação, Convenio, Ajustes Agenda, Configurações Excessões

This commit is contained in:
Leonardo
2026-03-13 16:03:08 -03:00
parent f4b185ae17
commit 06fb369beb
30 changed files with 24851 additions and 307 deletions
@@ -0,0 +1,118 @@
// src/features/agenda/composables/usePatientDiscounts.js
//
// CRUD completo sobre a tabela public.patient_discounts.
//
// Interface pública:
// discounts ref([]) lista de descontos do owner
// loading ref(false)
// error ref('')
//
// load(ownerId) carrega todos os registros do owner
// save(payload) cria ou atualiza (id presente = update)
// remove(id) soft-delete (active = false)
// loadActive(ownerId, patientId) desconto ativo vigente para um paciente
import { ref } from 'vue'
import { supabase } from '@/lib/supabase/client'
export function usePatientDiscounts () {
const discounts = ref([])
const loading = ref(false)
const error = ref('')
// ── Carregar todos os descontos do owner ─────────────────────────────
async function load (ownerId) {
if (!ownerId) return
loading.value = true
error.value = ''
try {
const { data, error: err } = await supabase
.from('patient_discounts')
.select('*')
.eq('owner_id', ownerId)
.order('created_at', { ascending: false })
if (err) throw err
discounts.value = data || []
} catch (e) {
error.value = e?.message || 'Falha ao carregar descontos.'
discounts.value = []
} finally {
loading.value = false
}
}
// ── Criar ou atualizar um desconto ───────────────────────────────────
// payload deve conter: { owner_id, tenant_id, patient_id, discount_pct, discount_flat, ... }
// Se payload.id estiver presente, faz UPDATE; caso contrário, INSERT.
async function save (payload) {
error.value = ''
try {
if (payload.id) {
const { id, owner_id, tenant_id, ...fields } = payload
const { error: err } = await supabase
.from('patient_discounts')
.update(fields)
.eq('id', id)
.eq('owner_id', owner_id)
if (err) throw err
} else {
const { error: err } = await supabase
.from('patient_discounts')
.insert(payload)
if (err) throw err
}
} catch (e) {
error.value = e?.message || 'Falha ao salvar desconto.'
throw e
}
}
// ── Soft-delete: marca active = false ───────────────────────────────
async function remove (id) {
error.value = ''
try {
const { error: err } = await supabase
.from('patient_discounts')
.update({ active: false })
.eq('id', id)
if (err) throw err
discounts.value = discounts.value.filter(d => d.id !== id)
} catch (e) {
error.value = e?.message || 'Falha ao desativar desconto.'
throw e
}
}
// ── Desconto ativo vigente para um paciente específico ───────────────
// Retorna o primeiro registro que satisfaz:
// active = true
// active_from IS NULL OR active_from <= now()
// active_to IS NULL OR active_to >= now()
// Ordenado por created_at DESC (mais recente tem precedência).
async function loadActive (ownerId, patientId) {
if (!ownerId || !patientId) return null
try {
const now = new Date().toISOString()
const { data, error: err } = await supabase
.from('patient_discounts')
.select('*')
.eq('owner_id', ownerId)
.eq('patient_id', patientId)
.eq('active', true)
.or(`active_from.is.null,active_from.lte.${now}`)
.or(`active_to.is.null,active_to.gte.${now}`)
.order('created_at', { ascending: false })
.limit(1)
.maybeSingle()
if (err) throw err
return data || null
} catch (e) {
console.warn('[usePatientDiscounts] loadActive error:', e?.message)
return null
}
}
return { discounts, loading, error, load, save, remove, loadActive }
}