agenda: dialog pacote saldo realizada — 2 sub-questions claras
Antes (UX confusa): bloco "Gerar cobranca no pacote?" tinha so um Select "Como cobrar?" com options mixadas: - "Enviar link de pagamento (Asaas)" - "Ja recebi - PIX" - "Ja recebi - Dinheiro" - etc User selecionou "Ja recebi - PIX" pensando que era "cobrar via PIX" durante teste C11/A com Andre Green. Resultado: fatura virou paid sem o user ter recebido de verdade. Ambiguidade entre "como cobrar" (header) e "ja recebi" (options). Refactor: espelhar o padrao da avulsa (showRegistrarPagto): 1. Sub-question "A sessao ja foi paga?" radio Sim/Nao (default Nao) 2. Se Nao -> Select "Como vai cobrar?" [Apenas registrar pendente | Enviar link de pagamento (Asaas)] 3. Se Sim -> Select "Como recebeu?" [PIX | Dinheiro | Deposito | Maquininha] (sem prefixo "Ja recebi" — header ja deixa claro) Defaults safer: markPaid=false em ambos contextos (avulsa e pacote) pra evitar marcar paid sem querer. paymentMethod='pending' inicial. Handler em useMelissaAgenda._applyStatusDecisions: pos-processamento agora usa decision.markPaid explicito no caso pacote saldo: - markPaid=true -> record vira paid + payment_method=X - markPaid=false + paymentMethod='link' -> pending + payment_method='asaas' - markPaid=false + paymentMethod='pending' -> pending sem metodo Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -72,8 +72,16 @@ watch(
|
|||||||
consumeSaldo.value = !!props.regraExcecao?.default_consume_on_miss;
|
consumeSaldo.value = !!props.regraExcecao?.default_consume_on_miss;
|
||||||
applyFine.value = _calcInitialFineApply();
|
applyFine.value = _calcInitialFineApply();
|
||||||
fineAmount.value = _calcInitialFineAmount();
|
fineAmount.value = _calcInitialFineAmount();
|
||||||
markPaid.value = true;
|
// Default markPaid:
|
||||||
paymentMethod.value = 'pix';
|
// - Avulsa realizada (showRegistrarPagto): default false (manter pendente)
|
||||||
|
// - Pacote saldo realizada (showCobrancaPacote): default false (gerar pendente)
|
||||||
|
// Em ambos casos o user precisa selecionar ativamente "Sim, já recebi"
|
||||||
|
// pra registrar paid — evita marcar paid sem querer.
|
||||||
|
markPaid.value = false;
|
||||||
|
// paymentMethod default depende do contexto. Inicia 'pending' (que cai
|
||||||
|
// no select de "Como vai cobrar?" quando markPaid=false). Quando user
|
||||||
|
// troca pra "Sim, já recebi", precisa escolher PIX/Dinheiro/etc.
|
||||||
|
paymentMethod.value = 'pending';
|
||||||
generatePackageCharge.value = true;
|
generatePackageCharge.value = true;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -138,12 +146,13 @@ const paymentMethodOptions = [
|
|||||||
{ value: 'deposito', label: 'Depósito' },
|
{ value: 'deposito', label: 'Depósito' },
|
||||||
{ value: 'cartao_maquininha', label: 'Cartão (maquininha)' }
|
{ value: 'cartao_maquininha', label: 'Cartão (maquininha)' }
|
||||||
];
|
];
|
||||||
const paymentMethodOptionsCobranca = [
|
// Opções pra "Como vai cobrar?" quando markPaid=false (sessão pendente
|
||||||
{ value: 'link', label: 'Enviar link de pagamento (Asaas)' },
|
// no pacote saldo). 'pending' = só registra como pendente, terapeuta
|
||||||
{ value: 'pix', label: 'Já recebi — PIX' },
|
// cobra depois pelo /financeiro. 'link' = gera link Asaas e marca
|
||||||
{ value: 'dinheiro', label: 'Já recebi — Dinheiro' },
|
// payment_method='asaas' no record (pós-confirm o handler updata).
|
||||||
{ value: 'deposito', label: 'Já recebi — Depósito' },
|
const paymentMethodOptionsPending = [
|
||||||
{ value: 'cartao_maquininha', label: 'Já recebi — Cartão (maquininha)' }
|
{ value: 'pending', label: 'Apenas registrar como pendente' },
|
||||||
|
{ value: 'link', label: 'Enviar link de pagamento (Asaas)' }
|
||||||
];
|
];
|
||||||
|
|
||||||
const regraResumo = computed(() => {
|
const regraResumo = computed(() => {
|
||||||
@@ -204,11 +213,16 @@ const fineDefaultReason = computed(() => {
|
|||||||
|
|
||||||
// ─── Actions ───────────────────────────────────────────────────────────
|
// ─── Actions ───────────────────────────────────────────────────────────
|
||||||
function onConfirm() {
|
function onConfirm() {
|
||||||
|
// markPaid agora é considerado em DOIS contextos:
|
||||||
|
// 1. Avulsa pendente (showRegistrarPagto): paciente já pagou a cobrança?
|
||||||
|
// 2. Pacote saldo realizado (showCobrancaPacote): já recebeu o valor da sessão?
|
||||||
|
// Em ambos casos: markPaid=true → record vira paid; false → fica pending.
|
||||||
|
const considerMarkPaid = showRegistrarPagto.value || (showCobrancaPacote.value && generatePackageCharge.value);
|
||||||
emit('confirm', {
|
emit('confirm', {
|
||||||
consumeSaldo: showSaldoBlock.value ? consumeSaldo.value : false,
|
consumeSaldo: showSaldoBlock.value ? consumeSaldo.value : false,
|
||||||
applyFine: showFineBlock.value ? applyFine.value : false,
|
applyFine: showFineBlock.value ? applyFine.value : false,
|
||||||
fineAmount: showFineBlock.value && applyFine.value ? Number(fineAmount.value) || 0 : 0,
|
fineAmount: showFineBlock.value && applyFine.value ? Number(fineAmount.value) || 0 : 0,
|
||||||
markPaid: showRegistrarPagto.value ? markPaid.value : false,
|
markPaid: considerMarkPaid ? markPaid.value : false,
|
||||||
paymentMethod: paymentMethod.value,
|
paymentMethod: paymentMethod.value,
|
||||||
generatePackageCharge: showCobrancaPacote.value ? generatePackageCharge.value : false
|
generatePackageCharge: showCobrancaPacote.value ? generatePackageCharge.value : false
|
||||||
});
|
});
|
||||||
@@ -338,11 +352,35 @@ function onCancel() {
|
|||||||
<Checkbox v-model="generatePackageCharge" inputId="asccd-gen-charge" binary />
|
<Checkbox v-model="generatePackageCharge" inputId="asccd-gen-charge" binary />
|
||||||
<label for="asccd-gen-charge" class="cursor-pointer">Gerar cobrança e consumir 1 sessão</label>
|
<label for="asccd-gen-charge" class="cursor-pointer">Gerar cobrança e consumir 1 sessão</label>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="generatePackageCharge" class="asccd-method-row">
|
<!-- Sub-question 1: a sessão já foi paga? (espelha o padrão da avulsa) -->
|
||||||
<label class="asccd-method-label">Como cobrar?</label>
|
<div v-if="generatePackageCharge" class="asccd-radio-group mt-2">
|
||||||
|
<label class="asccd-radio">
|
||||||
|
<input type="radio" :value="false" v-model="markPaid" />
|
||||||
|
<span>Não, gerar como cobrança pendente</span>
|
||||||
|
</label>
|
||||||
|
<label class="asccd-radio">
|
||||||
|
<input type="radio" :value="true" v-model="markPaid" />
|
||||||
|
<span>Sim, já recebi</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<!-- Sub-question 2a: se "Já recebi" → método de recebimento (sem prefixo) -->
|
||||||
|
<div v-if="generatePackageCharge && markPaid" class="asccd-method-row">
|
||||||
|
<label class="asccd-method-label">Como recebeu?</label>
|
||||||
<Select
|
<Select
|
||||||
v-model="paymentMethod"
|
v-model="paymentMethod"
|
||||||
:options="paymentMethodOptionsCobranca"
|
:options="paymentMethodOptions"
|
||||||
|
optionLabel="label"
|
||||||
|
optionValue="value"
|
||||||
|
size="small"
|
||||||
|
class="asccd-method-select"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<!-- Sub-question 2b: se "Pendente" → forma de cobrança (link Asaas vs registrar simples) -->
|
||||||
|
<div v-if="generatePackageCharge && !markPaid" class="asccd-method-row">
|
||||||
|
<label class="asccd-method-label">Como vai cobrar?</label>
|
||||||
|
<Select
|
||||||
|
v-model="paymentMethod"
|
||||||
|
:options="paymentMethodOptionsPending"
|
||||||
optionLabel="label"
|
optionLabel="label"
|
||||||
optionValue="value"
|
optionValue="value"
|
||||||
size="small"
|
size="small"
|
||||||
|
|||||||
@@ -1567,8 +1567,12 @@ function _buildHandlers(deps) {
|
|||||||
toast.add({ severity: 'success', summary: 'Status atualizado', detail: 'Decisões aplicadas.', life: 2500 });
|
toast.add({ severity: 'success', summary: 'Status atualizado', detail: 'Decisões aplicadas.', life: 2500 });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pós: se gerou cobrança via link Asaas, marcar payment_method='asaas'
|
// Pós-processamento do record gerado pelo pacote saldo. Agora o
|
||||||
if (decision.generatePackageCharge && decision.paymentMethod === 'link' && eventoId) {
|
// decision tem markPaid explícito:
|
||||||
|
// - markPaid=true → vira paid + payment_method=PIX/dinheiro/etc
|
||||||
|
// - markPaid=false + paymentMethod='link' → pending + payment_method='asaas'
|
||||||
|
// - markPaid=false + paymentMethod='pending' → pending sem método (default)
|
||||||
|
if (decision.generatePackageCharge && eventoId) {
|
||||||
try {
|
try {
|
||||||
const { data: newRec } = await supabase
|
const { data: newRec } = await supabase
|
||||||
.from('financial_records')
|
.from('financial_records')
|
||||||
@@ -1578,29 +1582,24 @@ function _buildHandlers(deps) {
|
|||||||
.limit(1)
|
.limit(1)
|
||||||
.single();
|
.single();
|
||||||
if (newRec?.id) {
|
if (newRec?.id) {
|
||||||
await supabase.from('financial_records').update({ payment_method: 'asaas', updated_at: new Date().toISOString() }).eq('id', newRec.id);
|
if (decision.markPaid) {
|
||||||
}
|
await supabase
|
||||||
} catch { /* silencioso */ }
|
.from('financial_records')
|
||||||
} else if (decision.generatePackageCharge && decision.paymentMethod !== 'link' && eventoId) {
|
.update({
|
||||||
// Já recebi → marca como paid
|
status: 'paid',
|
||||||
try {
|
paid_at: new Date().toISOString(),
|
||||||
const { data: newRec } = await supabase
|
payment_method: decision.paymentMethod,
|
||||||
.from('financial_records')
|
updated_at: new Date().toISOString()
|
||||||
.select('id')
|
})
|
||||||
.eq('agenda_evento_id', eventoId)
|
.eq('id', newRec.id);
|
||||||
.order('created_at', { ascending: false })
|
} else if (decision.paymentMethod === 'link') {
|
||||||
.limit(1)
|
await supabase
|
||||||
.single();
|
.from('financial_records')
|
||||||
if (newRec?.id) {
|
.update({ payment_method: 'asaas', updated_at: new Date().toISOString() })
|
||||||
await supabase
|
.eq('id', newRec.id);
|
||||||
.from('financial_records')
|
}
|
||||||
.update({
|
// markPaid=false + paymentMethod='pending' → não faz nada
|
||||||
status: 'paid',
|
// (record já criado como pending pelo RPC, sem payment_method)
|
||||||
paid_at: new Date().toISOString(),
|
|
||||||
payment_method: decision.paymentMethod,
|
|
||||||
updated_at: new Date().toISOString()
|
|
||||||
})
|
|
||||||
.eq('id', newRec.id);
|
|
||||||
}
|
}
|
||||||
} catch { /* silencioso */ }
|
} catch { /* silencioso */ }
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user