- Added client_id field to StoreTenantRequest and UpdateTenantRequest for tenant management. - Updated TenantResource to include client_id in the response. - Created migration to establish clients table and link tenants to clients. - Migrated existing tenant integrations to client_integrations table. - Grouped specific tenants under a shared client (OnTicket) in a new migration. - Updated seeders to reflect new client structure and relationships. - Adjusted integration configurations to require client instead of tenant. - Added tests for client integration functionality and ensured existing tests reflect the new client structure.
153 lines
5.8 KiB
PHP
153 lines
5.8 KiB
PHP
<?php
|
|
|
|
namespace App\Domains\Integration\Services;
|
|
|
|
use App\Domains\Client\Models\Client;
|
|
use App\Domains\Purchase\Models\Purchase;
|
|
use App\Domains\Purchase\Models\TelepagosPayment;
|
|
use App\Domains\Purchase\Models\TelepagosQr;
|
|
use App\Domains\Purchase\Services\CheckoutService;
|
|
use Exception;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
class TelepagosWebhookService
|
|
{
|
|
public function __construct(
|
|
private readonly CheckoutService $checkoutService,
|
|
) {}
|
|
|
|
/**
|
|
* Handle the Telepagos webhook notification.
|
|
*
|
|
* @throws Exception
|
|
*/
|
|
public function handleWebhook(Client $client, string $cashinId): void
|
|
{
|
|
$telepagosService = new TelepagosIntegrationService;
|
|
$telepagosService->forClient($client);
|
|
|
|
try {
|
|
$details = $telepagosService->getCashinDetails($cashinId);
|
|
|
|
$qrOrderId = $details['data']['qr_order_id'] ?? $details['qr_order_id'] ?? null;
|
|
$amount = $this->normalizeAmount($details['data']['amount'] ?? $details['amount'] ?? 0);
|
|
$operationId = $details['data']['operation_id'] ?? $details['operation_id'] ?? null;
|
|
|
|
$transferenciaOperationIds = [1, 3, 11];
|
|
$qrOperationIds = [31, 37, 47];
|
|
|
|
$compra = null;
|
|
|
|
if (in_array((int) $operationId, $transferenciaOperationIds, true)) {
|
|
$cuit = $details['data']['buyer']['cuit'] ?? $details['buyer']['cuit'] ?? null;
|
|
|
|
if (! $cuit) {
|
|
Log::warning("Telepagos webhook: CUIT not found for Transferencia cashin {$cashinId}");
|
|
|
|
return;
|
|
}
|
|
|
|
$dni = substr($cuit, 2, -1);
|
|
|
|
$tenantCodes = $client->tenants()->pluck('codigo');
|
|
$purchases = Purchase::whereIn('tenant_codigo', $tenantCodes)
|
|
->where('transfer_payer_dni', $dni)
|
|
->whereIn('status', [
|
|
Purchase::STATUS_CREATED,
|
|
Purchase::STATUS_PENDING_PAYMENT,
|
|
])
|
|
->where('payment_method', 'transfer')
|
|
->where('total', $amount)
|
|
->latest()
|
|
->limit(2)
|
|
->get();
|
|
|
|
$compra = $purchases->count() === 1 ? $purchases->first() : null;
|
|
|
|
if (! $compra) {
|
|
Log::warning("Telepagos webhook: Expected one matching purchase for client {$client->code}, DNI {$dni}, amount {$amount} and cashin {$cashinId}; found {$purchases->count()}");
|
|
|
|
return;
|
|
}
|
|
} elseif (in_array((int) $operationId, $qrOperationIds, true)) {
|
|
if (! $qrOrderId) {
|
|
Log::warning("Telepagos webhook: qr_order_id not found for QR cashin {$cashinId}");
|
|
|
|
return;
|
|
}
|
|
|
|
$telepagosQr = TelepagosQr::where('qr_order_id', $qrOrderId)->first();
|
|
|
|
if (! $telepagosQr) {
|
|
Log::warning("Telepagos webhook: QR {$qrOrderId} not found in database for cashin {$cashinId}");
|
|
|
|
return;
|
|
}
|
|
|
|
$compra = $telepagosQr->compra;
|
|
|
|
if (! $compra) {
|
|
Log::warning("Telepagos webhook: Purchase not found for QR {$qrOrderId}");
|
|
|
|
return;
|
|
}
|
|
|
|
if (! $client->tenants()->where('codigo', $compra->tenant_codigo)->exists()) {
|
|
Log::warning("Telepagos webhook: Purchase {$compra->id} does not belong to client {$client->code}");
|
|
|
|
return;
|
|
}
|
|
|
|
if (! in_array($compra->status, [
|
|
Purchase::STATUS_PENDING_PAYMENT,
|
|
], true)) {
|
|
Log::warning("Telepagos webhook: Purchase {$compra->id} is not awaiting payment confirmation");
|
|
|
|
return;
|
|
}
|
|
|
|
$totalAmount = $this->normalizeAmount($compra->getTotalAmount());
|
|
|
|
if ($amount !== $totalAmount) {
|
|
Log::warning("Telepagos webhook: Amount mismatch. Cashin amount: {$amount}, Purchase amount: {$totalAmount}");
|
|
|
|
return;
|
|
}
|
|
} else {
|
|
Log::warning("Telepagos webhook: Unknown operation_id {$operationId} for cashin {$cashinId}");
|
|
|
|
return;
|
|
}
|
|
|
|
$paymentData = [
|
|
'compra_id' => $compra->id,
|
|
'cuit_buyer' => $details['data']['buyer']['cuit'] ?? $details['buyer']['cuit'] ?? null,
|
|
'cvu_buyer' => $details['data']['buyer']['cvu'] ?? $details['buyer']['cvu'] ?? null,
|
|
'amount' => $amount,
|
|
'concept' => $details['data']['concept'] ?? $details['concept'] ?? null,
|
|
'operation' => $details['data']['operation'] ?? $details['operation'] ?? null,
|
|
'operation_id' => $details['data']['operation_id'] ?? $details['operation_id'] ?? null,
|
|
'transaction_id' => $details['data']['transaction_id'] ?? $details['transaction_id'] ?? null,
|
|
'qr_order_id' => $qrOrderId,
|
|
'link_id' => $details['data']['link_id'] ?? $details['link_id'] ?? null,
|
|
];
|
|
|
|
DB::transaction(function () use ($compra, $paymentData) {
|
|
TelepagosPayment::create($paymentData);
|
|
$this->checkoutService->confirmPaidPurchase($compra);
|
|
});
|
|
|
|
Log::info("Telepagos webhook: Successfully processed cashin {$cashinId} for purchase {$compra->id}");
|
|
} catch (Exception $e) {
|
|
Log::error('Telepagos webhook error: '.$e->getMessage());
|
|
throw $e;
|
|
}
|
|
}
|
|
|
|
protected function normalizeAmount(mixed $amount): string
|
|
{
|
|
return number_format((float) $amount, 2, '.', '');
|
|
}
|
|
}
|