# Fluxos: Modulo Finance - Cobrancas

---

## 5.1 Criar Cobranca Manual

```
Usuario
  ↓
Finance → Cobrancas → Botao "Nova Cobranca"
  ↓
GET /finance/charges/add/{projectId?}
  ↓
ChargesController@add
  ↓
CoreProject (ativos, com financeClient)
  ↓
View: pages/finance/charges/add
  ↓
Preenche: projeto, descricao, valor, data emissao, vencimento
Pode adicionar cobrancas adicionais (campos dinamicos)
  ↓
POST /finance/charges/store
  ↓
ChargesController@store
  ↓
Validacao: project_id, description, value, issue_date, due_date
  ↓
DB::beginTransaction
  ↓
CoreProject (busca financeClient, latestFinanceProject)
GeneralService::ensureWorkday (se due_on_working_days_only)
FinanceCharge::create (tag='Manual', bill_status='Programado', bill_stage=1)
FinanceCharge::create (adicionais, loop)
  ↓
DB::commit
  ↓
JSON {success, main_charge, additional_charges, redirect}
```

**Tela inicial:** Formulario de nova cobranca
**Acao do usuario:** Seleciona projeto, preenche valores, salva
**Requisicao:** `POST /finance/charges/store`
**Controller:** `ChargesController@store`
**Services:** GeneralService (dia util), FormatHelper, ChargeDescriptionHelper
**Tabelas alteradas:** `finance_charges` (INSERT, 1 principal + N adicionais)
**Tabelas consultadas:** `core_projects`, `finance_clients`, `finance_projects`
**APIs chamadas:** Nenhuma
**Resultado esperado:** Cobranca(s) criada(s) com status "Programado"
**Possiveis erros:**
- Projeto sem cliente faturavel → erro
- Validacao → 422
- DB → rollback

---

## 5.2 Emitir Boleto para Cobranca

```
Usuario
  ↓
Detalhes Cobranca (bill_stage=1) → Botao "Emitir"
  ↓
POST /finance/charges/create/payment/{id}
  ↓
ChargesController@createPayment
  ↓
FinanceCharge, FinanceClient (contatos)
Validacao: bill_stage == 1, sem dados de pagamento, email existe
GeneralService::ensureWorkday
  ↓
AsaasApiController::asaasCreatePayment (cria boleto)
AsaasApiController::asaasCreateInvoice (cria NFS-e)
AsaasApiController::asaasApproveInvoice (aprova NFS-e)
  ↓
FinanceCharge::update
  bill_stage=2, bill_status='Pendente'
  bill_url, bill_pdf_url
  id_payment_asaas, id_nfs, nfs_status, nfs_url
  log (append metadados)
  ↓
JSON {success, redirect}
```

**Tela inicial:** Detalhes da Cobranca
**Acao do usuario:** Clica "Emitir" para gerar boleto e NFS-e
**Requisicao:** `POST /finance/charges/create/payment/{id}`
**Controller:** `ChargesController@createPayment`
**Services:** GeneralService
**Tabelas alteradas:** `finance_charges` (UPDATE: bill_stage, bill_status, URLs, IDs externos)
**APIs chamadas:**
- **Asaas**: createPayment (boleto), createInvoice (NFS-e), approveInvoice
- OU **Iugu**: createPayment (boleto) + **Spedy**: createNFS (NFS-e)
**Resultado esperado:** Boleto emitido, NFS-e gerada, cobranca em status "Pendente"
**Possiveis erros:**
- Cobranca ja emitida (bill_stage != 1) → 403
- Email do contato ausente → erro
- Asaas API falha → erro com log
- NFS-e falha → cobranca parcialmente atualizada (boleto OK, NFS pendente)

---

## 5.3 Cancelar Cobranca (NFS-e + Pagamento)

```
Usuario
  ↓
Detalhes Cobranca → Botao "Cancelar"
  ↓
POST /finance/charges/cancel/nfs-and-payment/{id}
  ↓
ChargesController@cancelNfsAndPayment
  ↓
Validacao: tem id_payment e id_nfs
  ↓
Provider Asaas:
  AsaasApiController::asaasDeletePayment
  AsaasApiController::asaasCancelInvoice
Provider Iugu:
  IuguChargesController::iuguCancelPayment
  SpedyApiController::cancelNFS
  ↓
FinanceCharge::update
  bill_stage=3, bill_status='Cancelado', mail_stage=9
  log (append)
  ↓
JSON {success, redirect}
```

**Tela inicial:** Detalhes da Cobranca
**Acao do usuario:** Cancela cobranca emitida
**Requisicao:** `POST /finance/charges/cancel/nfs-and-payment/{id}`
**Controller:** `ChargesController@cancelNfsAndPayment`
**Tabelas alteradas:** `finance_charges` (bill_stage=3, bill_status='Cancelado')
**APIs chamadas:** Asaas (delete payment, cancel invoice) OU Iugu + Spedy
**Resultado esperado:** Boleto cancelado, NFS-e cancelada, status atualizado
**Possiveis erros:** API externa falha → erro retornado

---

## 5.4 Registrar Pagamento Externo

```
Usuario
  ↓
Detalhes Cobranca → Botao "Pago Externamente"
  ↓
POST /finance/charges/external/paid/{id}
  ↓
ChargesController@externalPaid
  ↓
Validacao: payment_date (nao antes de issue_date)
  ↓
IuguChargesController::iuguExternalPaid OU AsaasApiController::asaasExternalPaid
  ↓
FinanceCharge::update
  paid_at, bill_stage=3, mail_stage=9, bill_status='Pago Externamente'
  log (append com usuario)
  ↓
JSON {success, redirect}
```

**Tela inicial:** Detalhes da Cobranca
**Acao do usuario:** Informa data de pagamento externo
**Requisicao:** `POST /finance/charges/external/paid/{id}`
**Controller:** `ChargesController@externalPaid`
**Tabelas alteradas:** `finance_charges` (paid_at, bill_stage=3, bill_status='Pago Externamente')
**APIs chamadas:** Asaas ou Iugu (marca como pago externamente)
**Resultado esperado:** Cobranca marcada como paga externamente
**Possiveis erros:** Data antes da emissao → erro

---

## 5.5 Emitir Segunda Via

```
Usuario
  ↓
Detalhes Cobranca (bill_stage=2) → Botao "2a Via"
  ↓
GET /finance/charges/extend/{id}
  ↓
View: pages/finance/charges/extend
  ↓
Informa nova data + aplicar multa?
  ↓
POST /finance/charges/extend/second-copy/{id}
  ↓
ChargesController@createSecondCopy
  ↓
FinanceConfig (fine_percentage)
Calcula multa + juros se apply_fines=true
  ↓
Cancela cobranca original (bill_stage=3, bill_status='Cancelado')
Cria nova FinanceCharge (tag='2a Via', is_second_copy=true, parent_charge_id)
  ↓
Provider Asaas:
  asaasDeletePayment (original)
  asaasCreatePayment (nova)
Provider Iugu:
  iuguSegundaVia ou iuguCancel+iuguCreate
  ↓
JSON {success, new_charge_id, redirect}
```

**Tela inicial:** Pagina de extensao
**Acao do usuario:** Define nova data de vencimento e se aplica multa
**Requisicao:** `POST /finance/charges/extend/second-copy/{id}`
**Controller:** `ChargesController@createSecondCopy`
**Tabelas alteradas:**
- `finance_charges` (INSERT nova, UPDATE original para cancelado)
**APIs chamadas:** Asaas (cancel + create) OU Iugu (segunda via ou cancel+create)
**Resultado esperado:** Nova cobranca com valor atualizado (original + multa/juros), original cancelada
**Possiveis erros:**
- bill_stage != 2 → 403
- API falha → erro

---

## 5.6 Calcular Multa (Preview)

```
Usuario
  ↓
Pagina 2a Via → Altera data
  ↓
POST /finance/charges/calculate/fines/{id}
  ↓
ChargesController@calculate_fines_ajax
  ↓
FinanceCharge, FinanceConfig (fine_percentage)
Calcula dias atraso, multa (%), juros (1% a.m.)
  ↓
JSON {calculo detalhado}
```

**Tela inicial:** Pagina de extensao (2a via)
**Acao do usuario:** Seleciona nova data para preview de multa
**Requisicao:** `POST /finance/charges/calculate/fines/{id}` (AJAX)
**Controller:** `ChargesController@calculate_fines_ajax`
**Tabelas consultadas:** `finance_charges`, `finance_config`
**Resultado esperado:** Calculo de multa e juros formatado

---

## 5.7 Cancelar Cobranca Programada

```
Usuario
  ↓
Detalhes Cobranca (bill_stage=1) → Cancelar
  ↓
POST /finance/charges/cancel/appointment/{id}
  ↓
ChargesController@cancelAppointment
  ↓
FinanceCharge::update(bill_stage=3, bill_status='Cancelado', mail_stage=9)
  ↓
JSON {success}
```

**Tela inicial:** Detalhes da Cobranca
**Acao do usuario:** Cancela cobranca ainda nao emitida
**Requisicao:** `POST /finance/charges/cancel/appointment/{id}`
**Controller:** `ChargesController@cancelAppointment`
**Tabelas alteradas:** `finance_charges` (bill_stage=3, bill_status='Cancelado')
**Resultado esperado:** Cobranca cancelada antes de emissao
**Possiveis erros:** bill_stage != 1 ou ja tem dados de pagamento → 403

---

## 5.8 Resetar Notificacao de Cobranca

```
Usuario
  ↓
Detalhes Cobranca → Resetar notificacao
  ↓
POST /finance/charges/reset/notification/{id}
  ↓
ChargesController@resetNotification
  ↓
FinanceCharge::update(summary=0, billing_summary_id=null)
FinanceBillingSummaryBill (remove charge ID de id_payments se existia)
  ↓
JSON {success}
```

**Tela inicial:** Detalhes da Cobranca
**Acao do usuario:** Reseta flag de notificacao para reenvio
**Requisicao:** `POST /finance/charges/reset/notification/{id}`
**Controller:** `ChargesController@resetNotification`
**Tabelas alteradas:** `finance_charges`, `finance_billing_summary_bills`
**Resultado esperado:** Cobranca removida de resumo, pronta para renotificacao
