|
@@ -2,8 +2,10 @@
|
|
|
|
|
|
|
|
namespace App\Jobs;
|
|
namespace App\Jobs;
|
|
|
|
|
|
|
|
|
|
+use App\Enums\NotificationType;
|
|
|
use App\Enums\ReceivableStatus;
|
|
use App\Enums\ReceivableStatus;
|
|
|
use App\Models\FranchiseeAccountReceive;
|
|
use App\Models\FranchiseeAccountReceive;
|
|
|
|
|
+use App\Services\NotificationService;
|
|
|
use Illuminate\Bus\Queueable;
|
|
use Illuminate\Bus\Queueable;
|
|
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
|
|
use Illuminate\Foundation\Bus\Dispatchable;
|
|
use Illuminate\Foundation\Bus\Dispatchable;
|
|
@@ -16,11 +18,11 @@ class ProcessAsaasWebhookJob implements ShouldQueue
|
|
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
|
|
|
|
|
|
|
private const EVENT_STATUS_MAP = [
|
|
private const EVENT_STATUS_MAP = [
|
|
|
- 'PAYMENT_RECEIVED' => ReceivableStatus::PAID,
|
|
|
|
|
|
|
+ 'PAYMENT_RECEIVED' => ReceivableStatus::PAID,
|
|
|
'PAYMENT_CONFIRMED' => ReceivableStatus::PAID,
|
|
'PAYMENT_CONFIRMED' => ReceivableStatus::PAID,
|
|
|
- 'PAYMENT_OVERDUE' => ReceivableStatus::OVERDUE,
|
|
|
|
|
- 'PAYMENT_DELETED' => ReceivableStatus::CANCELLED,
|
|
|
|
|
- 'PAYMENT_REFUNDED' => ReceivableStatus::CANCELLED,
|
|
|
|
|
|
|
+ 'PAYMENT_OVERDUE' => ReceivableStatus::OVERDUE,
|
|
|
|
|
+ 'PAYMENT_DELETED' => ReceivableStatus::CANCELLED,
|
|
|
|
|
+ 'PAYMENT_REFUNDED' => ReceivableStatus::CANCELLED,
|
|
|
];
|
|
];
|
|
|
|
|
|
|
|
public array $payload;
|
|
public array $payload;
|
|
@@ -30,29 +32,32 @@ public function __construct(array $payload)
|
|
|
$this->payload = $payload;
|
|
$this->payload = $payload;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- public function handle(): void
|
|
|
|
|
|
|
+ public function handle(NotificationService $notifications): void
|
|
|
{
|
|
{
|
|
|
- $event = $this->payload['event'] ?? null;
|
|
|
|
|
|
|
+ $event = $this->payload['event'] ?? null;
|
|
|
$payment = $this->payload['payment'] ?? [];
|
|
$payment = $this->payload['payment'] ?? [];
|
|
|
|
|
|
|
|
- if (!$event || empty($payment)) {
|
|
|
|
|
|
|
+ if (! $event || empty($payment)) {
|
|
|
Log::warning('Asaas Webhook Job: payload incompleto', $this->payload);
|
|
Log::warning('Asaas Webhook Job: payload incompleto', $this->payload);
|
|
|
|
|
+
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
$newStatus = self::EVENT_STATUS_MAP[$event] ?? null;
|
|
$newStatus = self::EVENT_STATUS_MAP[$event] ?? null;
|
|
|
|
|
|
|
|
- if (!$newStatus) {
|
|
|
|
|
|
|
+ if (! $newStatus) {
|
|
|
Log::info("Asaas Webhook Job: evento '{$event}' ignorado (não mapeado).");
|
|
Log::info("Asaas Webhook Job: evento '{$event}' ignorado (não mapeado).");
|
|
|
|
|
+
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
$externalReference = $payment['externalReference'] ?? null;
|
|
$externalReference = $payment['externalReference'] ?? null;
|
|
|
- $asaasId = $payment['id'] ?? null;
|
|
|
|
|
|
|
+ $asaasId = $payment['id'] ?? null;
|
|
|
|
|
|
|
|
// Cobrança de aluno (parcela) cobrada pela conta Asaas PRÓPRIA da unidade.
|
|
// Cobrança de aluno (parcela) cobrada pela conta Asaas PRÓPRIA da unidade.
|
|
|
if ($externalReference && str_starts_with($externalReference, 'STU_')) {
|
|
if ($externalReference && str_starts_with($externalReference, 'STU_')) {
|
|
|
$this->handleStudentInstallment($externalReference, $payment, $event, $newStatus);
|
|
$this->handleStudentInstallment($externalReference, $payment, $event, $newStatus);
|
|
|
|
|
+
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -74,7 +79,7 @@ public function handle(): void
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Fallback por asaas_id caso externalReference venha nulo
|
|
// Fallback por asaas_id caso externalReference venha nulo
|
|
|
- if (!$receive && $asaasId) {
|
|
|
|
|
|
|
+ if (! $receive && $asaasId) {
|
|
|
$receive = FranchiseeAccountReceive::where('asaas_id', $asaasId)->first();
|
|
$receive = FranchiseeAccountReceive::where('asaas_id', $asaasId)->first();
|
|
|
|
|
|
|
|
if ($receive) {
|
|
if ($receive) {
|
|
@@ -82,12 +87,13 @@ public function handle(): void
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (!$receive) {
|
|
|
|
|
- Log::warning("Asaas Webhook Job: registro não encontrado", [
|
|
|
|
|
|
|
+ if (! $receive) {
|
|
|
|
|
+ Log::warning('Asaas Webhook Job: registro não encontrado', [
|
|
|
'externalReference' => $externalReference,
|
|
'externalReference' => $externalReference,
|
|
|
'asaas_id' => $asaasId,
|
|
'asaas_id' => $asaasId,
|
|
|
'event' => $event,
|
|
'event' => $event,
|
|
|
]);
|
|
]);
|
|
|
|
|
+
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -98,17 +104,18 @@ public function handle(): void
|
|
|
// Idempotência
|
|
// Idempotência
|
|
|
if ($currentStatus === ReceivableStatus::PAID->value && $newStatusValue === ReceivableStatus::PAID->value) {
|
|
if ($currentStatus === ReceivableStatus::PAID->value && $newStatusValue === ReceivableStatus::PAID->value) {
|
|
|
Log::info("Asaas Webhook Job: registro {$type} #{$receive->id} já está pago. Ignorando duplicata.");
|
|
Log::info("Asaas Webhook Job: registro {$type} #{$receive->id} já está pago. Ignorando duplicata.");
|
|
|
|
|
+
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
$updateData = [
|
|
$updateData = [
|
|
|
- 'status' => $newStatusValue,
|
|
|
|
|
|
|
+ 'status' => $newStatusValue,
|
|
|
'asaas_status' => $payment['status'] ?? $event,
|
|
'asaas_status' => $payment['status'] ?? $event,
|
|
|
];
|
|
];
|
|
|
|
|
|
|
|
if ($newStatusValue === ReceivableStatus::PAID->value) {
|
|
if ($newStatusValue === ReceivableStatus::PAID->value) {
|
|
|
$updateData['payment_date'] = $payment['paymentDate'] ?? $payment['confirmedDate'] ?? now();
|
|
$updateData['payment_date'] = $payment['paymentDate'] ?? $payment['confirmedDate'] ?? now();
|
|
|
- $updateData['paid_value'] = $payment['value'] ?? $receive->value;
|
|
|
|
|
|
|
+ $updateData['paid_value'] = $payment['value'] ?? $receive->value;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
$receive->update($updateData);
|
|
$receive->update($updateData);
|
|
@@ -123,13 +130,28 @@ public function handle(): void
|
|
|
|
|
|
|
|
if ($payable) {
|
|
if ($payable) {
|
|
|
$payable->update([
|
|
$payable->update([
|
|
|
- 'status' => 'paid',
|
|
|
|
|
- 'paid_value' => $payable->value,
|
|
|
|
|
|
|
+ 'status' => 'paid',
|
|
|
|
|
+ 'paid_value' => $payable->value,
|
|
|
'payment_date' => $updateData['payment_date'] ?? now(),
|
|
'payment_date' => $updateData['payment_date'] ?? now(),
|
|
|
]);
|
|
]);
|
|
|
|
|
|
|
|
Log::info("Asaas Webhook Job: Conta a Pagar da unidade #{$payable->id} baixada automaticamente (TBR pago).");
|
|
Log::info("Asaas Webhook Job: Conta a Pagar da unidade #{$payable->id} baixada automaticamente (TBR pago).");
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ if ($receive->unit_id) {
|
|
|
|
|
+ $notifications->dispatch([
|
|
|
|
|
+ 'origin_table' => 'franchisee_account_receives',
|
|
|
|
|
+ 'origin_id' => $receive->id,
|
|
|
|
|
+ 'unit_id' => $receive->unit_id,
|
|
|
|
|
+ 'type' => NotificationType::PAYMENT_CREDITED->value,
|
|
|
|
|
+ 'title' => 'Pagamento confirmado',
|
|
|
|
|
+ 'message' => "Sua cobrança {$receive->history} foi devidamente creditada e consta como paga.",
|
|
|
|
|
+ 'url' => '/financial/accounts-payable',
|
|
|
|
|
+ 'action_text' => 'Ver Contas a Pagar',
|
|
|
|
|
+ 'priority' => 'normal',
|
|
|
|
|
+ 'recipient_user_ids' => $notifications->unitUserIds($receive->unit_id),
|
|
|
|
|
+ ]);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
Log::info("Asaas Webhook Job: {$type} #{$receive->id} atualizado para '{$newStatusValue}'", [
|
|
Log::info("Asaas Webhook Job: {$type} #{$receive->id} atualizado para '{$newStatusValue}'", [
|
|
@@ -147,18 +169,19 @@ private function handleStudentInstallment(string $externalReference, array $paym
|
|
|
|
|
|
|
|
$installment = \App\Models\StudentContractInstallment::find($id);
|
|
$installment = \App\Models\StudentContractInstallment::find($id);
|
|
|
|
|
|
|
|
- if (!$installment) {
|
|
|
|
|
|
|
+ if (! $installment) {
|
|
|
Log::warning("Asaas Webhook Job: parcela {$externalReference} não encontrada.", [
|
|
Log::warning("Asaas Webhook Job: parcela {$externalReference} não encontrada.", [
|
|
|
'event' => $event,
|
|
'event' => $event,
|
|
|
'asaas_id' => $payment['id'] ?? null,
|
|
'asaas_id' => $payment['id'] ?? null,
|
|
|
]);
|
|
]);
|
|
|
|
|
+
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Mapeia o status do recebível para o vocabulário das parcelas.
|
|
// Mapeia o status do recebível para o vocabulário das parcelas.
|
|
|
$statusMap = [
|
|
$statusMap = [
|
|
|
- ReceivableStatus::PAID->value => 'paid',
|
|
|
|
|
- ReceivableStatus::OVERDUE->value => 'overdue',
|
|
|
|
|
|
|
+ ReceivableStatus::PAID->value => 'paid',
|
|
|
|
|
+ ReceivableStatus::OVERDUE->value => 'overdue',
|
|
|
ReceivableStatus::CANCELLED->value => 'cancelled',
|
|
ReceivableStatus::CANCELLED->value => 'cancelled',
|
|
|
];
|
|
];
|
|
|
$installmentStatus = $statusMap[$newStatus->value] ?? $installment->status;
|
|
$installmentStatus = $statusMap[$newStatus->value] ?? $installment->status;
|
|
@@ -166,17 +189,18 @@ private function handleStudentInstallment(string $externalReference, array $paym
|
|
|
// Idempotência: já pago e continua pago → ignora duplicata.
|
|
// Idempotência: já pago e continua pago → ignora duplicata.
|
|
|
if ($installment->status === 'paid' && $installmentStatus === 'paid') {
|
|
if ($installment->status === 'paid' && $installmentStatus === 'paid') {
|
|
|
Log::info("Asaas Webhook Job: parcela #{$installment->id} já paga. Ignorando duplicata.");
|
|
Log::info("Asaas Webhook Job: parcela #{$installment->id} já paga. Ignorando duplicata.");
|
|
|
|
|
+
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
$update = [
|
|
$update = [
|
|
|
- 'status' => $installmentStatus,
|
|
|
|
|
|
|
+ 'status' => $installmentStatus,
|
|
|
'asaas_status' => $payment['status'] ?? $event,
|
|
'asaas_status' => $payment['status'] ?? $event,
|
|
|
];
|
|
];
|
|
|
|
|
|
|
|
if ($installmentStatus === 'paid') {
|
|
if ($installmentStatus === 'paid') {
|
|
|
$update['payment_date'] = $payment['paymentDate'] ?? $payment['confirmedDate'] ?? now();
|
|
$update['payment_date'] = $payment['paymentDate'] ?? $payment['confirmedDate'] ?? now();
|
|
|
- $update['paid_value'] = $payment['value'] ?? $installment->value;
|
|
|
|
|
|
|
+ $update['paid_value'] = $payment['value'] ?? $installment->value;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
$installment->update($update);
|
|
$installment->update($update);
|