Files
agenciapsilmno/src/features/financeiro/composables/useFinancialExceptions.js
T
Leonardo fbfb95648e M4: financeiro foundation — services + composables paralelo
Modulo 4 da Fase 1. 9 arquivos novos em features/financeiro/:
4 services (_tenantGuards, financialSelects, financialRecords
Repository, financialExceptionsRepository, billingContractsRepository)
+ 4 composables (useFinancialRecords, useFinancialExceptions,
useBillingContracts, useBillingOrchestrator). Old composables ainda
em paralelo — Fase C (cutover) bloqueada pelas decisoes #2/#3/#6
de billing (memoria agenda_billing_decisoes).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 04:20:23 -03:00

91 lines
2.6 KiB
JavaScript

/*
|--------------------------------------------------------------------------
| Agência PSI
|--------------------------------------------------------------------------
| Arquivo: src/features/financeiro/composables/useFinancialExceptions.js
|
| Cache de regras de exceção financeira POR INSTÂNCIA do composable.
| Substitui o _exceptionsCache módulo-level do useAgendaFinanceiro.js
| (que vazava entre instâncias — audit baseline alta).
|
| Cache TTL: vive enquanto o composable existir. Chamar invalidate()
| ao trocar tenant.
|--------------------------------------------------------------------------
*/
import { ref } from 'vue';
import {
getRule,
listAll,
upsertRule,
calcChargeAmount
} from '@/features/financeiro/services/financialExceptionsRepository';
export function useFinancialExceptions() {
const rules = ref([]);
const loading = ref(false);
const error = ref('');
// Cache local — chave: `${tenantId}:${exceptionType}`
const _cache = new Map();
async function getRuleCached(exceptionType, { tenantId } = {}) {
const key = `${tenantId || 'active'}:${exceptionType}`;
if (_cache.has(key)) return _cache.get(key);
try {
const rule = await getRule(exceptionType, { tenantId });
_cache.set(key, rule);
return rule;
} catch (e) {
error.value = e?.message || 'Falha ao carregar regra de exceção.';
return null;
}
}
async function loadAll(opts = {}) {
loading.value = true;
error.value = '';
try {
rules.value = await listAll(opts);
} catch (e) {
error.value = e?.message || 'Falha ao carregar regras.';
rules.value = [];
} finally {
loading.value = false;
}
}
async function upsert(payload) {
loading.value = true;
error.value = '';
try {
const updated = await upsertRule(payload);
const idx = rules.value.findIndex((r) => r.id === updated.id);
if (idx >= 0) rules.value[idx] = updated;
else rules.value = [...rules.value, updated];
invalidate();
return updated;
} catch (e) {
error.value = e?.message || 'Falha ao salvar regra.';
throw e;
} finally {
loading.value = false;
}
}
function invalidate() {
_cache.clear();
}
return {
rules,
loading,
error,
getRuleCached,
loadAll,
upsert,
invalidate,
// re-export utilitário (puro, não state)
calcChargeAmount
};
}