From 4f7ede10723dca04a527b0c91456d2f4f6458f7c Mon Sep 17 00:00:00 2001 From: ncoronel Date: Fri, 11 Sep 2026 16:23:23 -0300 Subject: [PATCH] feat(purchase,sale,ticket): expose refunded total summary in admin sales and tickets --- .../Services/PurchaseRefundSummaryService.php | 22 ++++++++++ .../Controllers/AdminApp/SaleController.php | 1 + .../Sale/Services/AdminAppSaleService.php | 7 +++ .../AdminApp/AdminAppTicketCollection.php | 6 ++- .../Ticket/Services/AdminAppTicketResult.php | 1 + .../Ticket/Services/AdminAppTicketService.php | 3 ++ .../Sale/AdminAppSaleControllerTest.php | 5 ++- .../Ticket/AdminAppTicketControllerTest.php | 43 ++++++++++++++++++- 8 files changed, 84 insertions(+), 4 deletions(-) create mode 100644 app/Domains/Purchase/Services/PurchaseRefundSummaryService.php diff --git a/app/Domains/Purchase/Services/PurchaseRefundSummaryService.php b/app/Domains/Purchase/Services/PurchaseRefundSummaryService.php new file mode 100644 index 0000000..9546810 --- /dev/null +++ b/app/Domains/Purchase/Services/PurchaseRefundSummaryService.php @@ -0,0 +1,22 @@ +whereHas( + 'purchase', + fn (Builder $query): Builder => $query->where('tenant_codigo', $tenant->codigo) + ) + ->sum('refunded_amount'); + + return number_format((float) $total, 2, '.', ''); + } +} diff --git a/app/Domains/Sale/Controllers/AdminApp/SaleController.php b/app/Domains/Sale/Controllers/AdminApp/SaleController.php index 383f700..71fe5f6 100644 --- a/app/Domains/Sale/Controllers/AdminApp/SaleController.php +++ b/app/Domains/Sale/Controllers/AdminApp/SaleController.php @@ -35,6 +35,7 @@ class SaleController extends Controller $this->saleService->sales($tenant, $request->validated()) )->additional([ 'confirmed_sales_total' => $this->saleService->confirmedSalesTotal($tenant), + 'refunded_total' => $this->saleService->refundedTotal($tenant), ]); } diff --git a/app/Domains/Sale/Services/AdminAppSaleService.php b/app/Domains/Sale/Services/AdminAppSaleService.php index eecd5fc..d329a96 100644 --- a/app/Domains/Sale/Services/AdminAppSaleService.php +++ b/app/Domains/Sale/Services/AdminAppSaleService.php @@ -5,6 +5,7 @@ namespace App\Domains\Sale\Services; use App\Domains\Logging\Models\ValueChange; use App\Domains\Purchase\Models\Purchase; use App\Domains\Purchase\Services\CheckoutService; +use App\Domains\Purchase\Services\PurchaseRefundSummaryService; use App\Domains\Tenant\Models\Tenant; use App\Domains\Ticket\Models\Ticket; use App\Domains\Ticket\Services\TicketPresentationResolver; @@ -17,6 +18,7 @@ class AdminAppSaleService { public function __construct( protected CheckoutService $checkoutService, + protected PurchaseRefundSummaryService $refundSummaryService, ) {} public function confirmedSalesTotal(Tenant $tenant): string @@ -29,6 +31,11 @@ class AdminAppSaleService return number_format((float) $total, 2, '.', ''); } + public function refundedTotal(Tenant $tenant): string + { + return $this->refundSummaryService->totalForTenant($tenant); + } + /** * @param array{ * q?: string|null, diff --git a/app/Domains/Ticket/Resources/AdminApp/AdminAppTicketCollection.php b/app/Domains/Ticket/Resources/AdminApp/AdminAppTicketCollection.php index 3af312c..3b7c0e6 100644 --- a/app/Domains/Ticket/Resources/AdminApp/AdminAppTicketCollection.php +++ b/app/Domains/Ticket/Resources/AdminApp/AdminAppTicketCollection.php @@ -15,20 +15,24 @@ class AdminAppTicketCollection extends ResourceCollection private readonly int $totalTickets; + private readonly string $refundedTotal; + public function __construct(AdminAppTicketResult $result) { parent::__construct($result->tickets); $this->scannedTickets = $result->scannedTickets; $this->totalTickets = $result->totalTickets; + $this->refundedTotal = $result->refundedTotal; } - /** @return array{scanned_tickets: int, total_tickets: int} */ + /** @return array{scanned_tickets: int, total_tickets: int, refunded_total: string} */ public function with(Request $request): array { return [ 'scanned_tickets' => $this->scannedTickets, 'total_tickets' => $this->totalTickets, + 'refunded_total' => $this->refundedTotal, ]; } } diff --git a/app/Domains/Ticket/Services/AdminAppTicketResult.php b/app/Domains/Ticket/Services/AdminAppTicketResult.php index e9f65f4..bce92bc 100644 --- a/app/Domains/Ticket/Services/AdminAppTicketResult.php +++ b/app/Domains/Ticket/Services/AdminAppTicketResult.php @@ -12,5 +12,6 @@ final readonly class AdminAppTicketResult public LengthAwarePaginator $tickets, public int $scannedTickets, public int $totalTickets, + public string $refundedTotal, ) {} } diff --git a/app/Domains/Ticket/Services/AdminAppTicketService.php b/app/Domains/Ticket/Services/AdminAppTicketService.php index 46a1cde..64eb532 100644 --- a/app/Domains/Ticket/Services/AdminAppTicketService.php +++ b/app/Domains/Ticket/Services/AdminAppTicketService.php @@ -4,6 +4,7 @@ namespace App\Domains\Ticket\Services; use App\Domains\Auth\Models\User; use App\Domains\Purchase\Models\PurchaseItem; +use App\Domains\Purchase\Services\PurchaseRefundSummaryService; use App\Domains\Tenant\Models\Tenant; use App\Domains\Ticket\Models\Ticket; use Illuminate\Database\Eloquent\Builder; @@ -27,6 +28,7 @@ class AdminAppTicketService public function __construct( private readonly AdminAppTicketColumnService $columnService, private readonly AdminAppTicketRowService $rowService, + private readonly PurchaseRefundSummaryService $refundSummaryService, ) {} /** @@ -68,6 +70,7 @@ class AdminAppTicketService tickets: $tickets, scannedTickets: $scannedTickets, totalTickets: $totalTickets, + refundedTotal: $this->refundSummaryService->totalForTenant($tenant), ); } diff --git a/tests/Feature/Sale/AdminAppSaleControllerTest.php b/tests/Feature/Sale/AdminAppSaleControllerTest.php index cb74909..81b21e9 100644 --- a/tests/Feature/Sale/AdminAppSaleControllerTest.php +++ b/tests/Feature/Sale/AdminAppSaleControllerTest.php @@ -163,6 +163,7 @@ class AdminAppSaleControllerTest extends TestCase 'cantidad' => 3, 'precio_unitario' => '10000.00', 'total' => '30000.00', + 'refunded_amount' => '1250.00', ]); $pendingCart = Cart::query()->create([ @@ -203,6 +204,7 @@ class AdminAppSaleControllerTest extends TestCase 'cantidad' => 2, 'precio_unitario' => '10000.00', 'total' => '20000.00', + 'refunded_amount' => '2500.00', ]); $supersededPurchase = Purchase::query()->create([ @@ -237,7 +239,8 @@ class AdminAppSaleControllerTest extends TestCase ->assertJsonPath('data.2.status_label', 'Confirmado') ->assertJsonPath('data.3.id', $supersededPurchase->id) ->assertJsonPath('data.3.admin_status', Purchase::ADMIN_STATUS_CANCELLED) - ->assertJsonPath('data.3.status_label', 'Anulado'); + ->assertJsonPath('data.3.status_label', 'Anulado') + ->assertJsonPath('refunded_total', '3750.00'); $this->getJson('/api/v1/adminapp/tenant/sales?status='.Purchase::STATUS_SUPERSEDED) ->assertUnprocessable(); diff --git a/tests/Feature/Ticket/AdminAppTicketControllerTest.php b/tests/Feature/Ticket/AdminAppTicketControllerTest.php index a933388..1887e4e 100644 --- a/tests/Feature/Ticket/AdminAppTicketControllerTest.php +++ b/tests/Feature/Ticket/AdminAppTicketControllerTest.php @@ -541,17 +541,56 @@ class AdminAppTicketControllerTest extends TestCase $this->createTicket($tenant, $admin)->update(['disabled_at' => now()]); $this->createTicket($otherTenant, $otherUser)->update(['used_at' => now()]); + $catalogItem = CatalogItem::query()->create([ + 'tenant_code' => $tenant->codigo, + 'slug' => 'refund-summary-item', + 'nombre' => 'Entrada', + 'precio' => '1000.00', + ]); + $purchase = Purchase::query()->create([ + 'tenant_codigo' => $tenant->codigo, + 'status' => Purchase::STATUS_PAID, + 'total' => '1000.00', + ]); + PurchaseItem::query()->create([ + 'compra_id' => $purchase->id, + 'source_catalog_item_id' => $catalogItem->id, + 'nombre' => 'Entrada', + 'item_nombre' => 'Entrada', + 'cantidad' => 1, + 'precio_unitario' => '1000.00', + 'total' => '1000.00', + 'refunded_amount' => '250.00', + ]); + $otherPurchase = Purchase::query()->create([ + 'tenant_codigo' => $otherTenant->codigo, + 'status' => Purchase::STATUS_PAID, + 'total' => '2000.00', + ]); + PurchaseItem::query()->create([ + 'compra_id' => $otherPurchase->id, + 'source_catalog_item_id' => $catalogItem->id, + 'nombre' => 'Otra entrada', + 'item_nombre' => 'Otra entrada', + 'cantidad' => 1, + 'precio_unitario' => '2000.00', + 'total' => '2000.00', + 'refunded_amount' => '2000.00', + ]); + $this->getJson('/api/v1/adminapp/tenant/tickets?q=does-not-match') ->assertOk() ->assertJsonCount(0, 'data') ->assertJsonPath('scanned_tickets', 0) - ->assertJsonPath('total_tickets', 0); + ->assertJsonPath('total_tickets', 0) + ->assertJsonPath('refunded_total', '250.00'); $this->getJson('/api/v1/adminapp/tenant/tickets') ->assertOk() ->assertJsonCount(5, 'data') ->assertJsonPath('scanned_tickets', 1) - ->assertJsonPath('total_tickets', 2); + ->assertJsonPath('total_tickets', 2) + ->assertJsonPath('refunded_total', '250.00'); } public function test_it_returns_structured_variant_properties(): void