feat(sale): implement event scope for sales, totals, and modifications; add tests for event-based access
This commit is contained in:
@@ -8,12 +8,14 @@ use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class PurchaseRefundSummaryService
|
||||
{
|
||||
public function totalForTenant(Tenant $tenant): string
|
||||
public function totalForTenant(Tenant $tenant, ?int $eventId = null): string
|
||||
{
|
||||
$total = TicketRefund::query()
|
||||
->whereHas(
|
||||
'purchaseItem.purchase',
|
||||
fn (Builder $query): Builder => $query->where('tenant_codigo', $tenant->codigo)
|
||||
fn (Builder $query): Builder => $query
|
||||
->where('tenant_codigo', $tenant->codigo)
|
||||
->when($eventId !== null, fn (Builder $query): Builder => $query->where('event_id', $eventId))
|
||||
)
|
||||
->sum('amount');
|
||||
|
||||
|
||||
@@ -32,10 +32,10 @@ class SaleController extends Controller
|
||||
$tenant = $request->user()->tenant()->firstOrFail();
|
||||
|
||||
return SaleResource::collection(
|
||||
$this->saleService->sales($tenant, $request->validated())
|
||||
$this->saleService->sales($tenant, $request->validated(), $request->user()->event_id)
|
||||
)->additional([
|
||||
'confirmed_sales_total' => $this->saleService->confirmedSalesTotal($tenant),
|
||||
'refunded_total' => $this->saleService->refundedTotal($tenant),
|
||||
'confirmed_sales_total' => $this->saleService->confirmedSalesTotal($tenant, $request->user()->event_id),
|
||||
'refunded_total' => $this->saleService->refundedTotal($tenant, $request->user()->event_id),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ class SaleController extends Controller
|
||||
{
|
||||
$tenant = $request->user()->tenant()->firstOrFail();
|
||||
|
||||
return new SaleDetailResource($this->saleService->detail($tenant, $sale));
|
||||
return new SaleDetailResource($this->saleService->detail($tenant, $sale, $request->user()->event_id));
|
||||
}
|
||||
|
||||
public function tickets(Request $request, int $sale): AnonymousResourceCollection
|
||||
@@ -51,7 +51,7 @@ class SaleController extends Controller
|
||||
$tenant = $request->user()->tenant()->firstOrFail();
|
||||
|
||||
return SaleTicketResource::collection(
|
||||
$this->saleService->tickets($tenant, $sale)
|
||||
$this->saleService->tickets($tenant, $sale, $request->user()->event_id)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -59,14 +59,14 @@ class SaleController extends Controller
|
||||
{
|
||||
$tenant = $request->user()->tenant()->firstOrFail();
|
||||
|
||||
return new SaleResource($this->saleService->confirm($tenant, $sale));
|
||||
return new SaleResource($this->saleService->confirm($tenant, $sale, $request->user()->event_id));
|
||||
}
|
||||
|
||||
public function cancel(Request $request, int $sale): SaleResource
|
||||
{
|
||||
$tenant = $request->user()->tenant()->firstOrFail();
|
||||
|
||||
return new SaleResource($this->saleService->cancel($tenant, $sale));
|
||||
return new SaleResource($this->saleService->cancel($tenant, $sale, $request->user()->event_id));
|
||||
}
|
||||
|
||||
public function modifications(
|
||||
@@ -76,6 +76,7 @@ class SaleController extends Controller
|
||||
$this->saleService->modifications(
|
||||
$request->user()->tenant()->firstOrFail(),
|
||||
$request->validated(),
|
||||
$request->user()->event_id,
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -86,7 +87,7 @@ class SaleController extends Controller
|
||||
|
||||
return $this->salePdfService->downloadSales(
|
||||
$tenant,
|
||||
$this->saleService->salesForExport($tenant, $request->validated()),
|
||||
$this->saleService->salesForExport($tenant, $request->validated(), $request->user()->event_id),
|
||||
$request->validated('timezone'),
|
||||
);
|
||||
}
|
||||
@@ -97,7 +98,7 @@ class SaleController extends Controller
|
||||
|
||||
return $this->salePdfService->downloadModifications(
|
||||
$tenant,
|
||||
$this->saleService->modificationsForExport($tenant, $request->validated()),
|
||||
$this->saleService->modificationsForExport($tenant, $request->validated(), $request->user()->event_id),
|
||||
$request->validated('timezone'),
|
||||
);
|
||||
}
|
||||
@@ -108,7 +109,7 @@ class SaleController extends Controller
|
||||
|
||||
return $this->saleExcelService->downloadSales(
|
||||
$tenant,
|
||||
$this->saleService->salesForExport($tenant, $request->validated()),
|
||||
$this->saleService->salesForExport($tenant, $request->validated(), $request->user()->event_id),
|
||||
$request->validated('timezone'),
|
||||
);
|
||||
}
|
||||
@@ -120,7 +121,7 @@ class SaleController extends Controller
|
||||
|
||||
return $this->saleExcelService->downloadModifications(
|
||||
$tenant,
|
||||
$this->saleService->modificationsForExport($tenant, $request->validated()),
|
||||
$this->saleService->modificationsForExport($tenant, $request->validated(), $request->user()->event_id),
|
||||
$request->validated('timezone'),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
namespace App\Domains\Commerce\Sale\Services;
|
||||
|
||||
use App\Shared\Logging\Models\ValueChange;
|
||||
use App\Domains\Commerce\Purchase\Models\Purchase;
|
||||
use App\Domains\Commerce\Purchase\Services\CheckoutService;
|
||||
use App\Domains\Commerce\Purchase\Services\PurchaseRefundSummaryService;
|
||||
@@ -10,6 +9,7 @@ use App\Domains\Core\Tenant\Models\Tenant;
|
||||
use App\Domains\Ticketing\Ticket\Models\Ticket;
|
||||
use App\Domains\Ticketing\Ticket\Services\TicketPresentationResolver;
|
||||
use App\Domains\Ticketing\Ticket\Services\TicketValidityResolver;
|
||||
use App\Shared\Logging\Models\ValueChange;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Support\Collection;
|
||||
@@ -21,19 +21,18 @@ class AdminAppSaleService
|
||||
protected PurchaseRefundSummaryService $refundSummaryService,
|
||||
) {}
|
||||
|
||||
public function confirmedSalesTotal(Tenant $tenant): string
|
||||
public function confirmedSalesTotal(Tenant $tenant, ?int $eventId = null): string
|
||||
{
|
||||
$total = Purchase::query()
|
||||
->where('tenant_codigo', $tenant->codigo)
|
||||
$total = $this->purchasesQuery($tenant, $eventId)
|
||||
->where('status', Purchase::STATUS_PAID)
|
||||
->sum('total');
|
||||
|
||||
return number_format((float) $total, 2, '.', '');
|
||||
}
|
||||
|
||||
public function refundedTotal(Tenant $tenant): string
|
||||
public function refundedTotal(Tenant $tenant, ?int $eventId = null): string
|
||||
{
|
||||
return $this->refundSummaryService->totalForTenant($tenant);
|
||||
return $this->refundSummaryService->totalForTenant($tenant, $eventId);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -47,43 +46,42 @@ class AdminAppSaleService
|
||||
* } $filters
|
||||
* @return LengthAwarePaginator<Purchase>
|
||||
*/
|
||||
public function sales(Tenant $tenant, array $filters = []): LengthAwarePaginator
|
||||
public function sales(Tenant $tenant, array $filters = [], ?int $eventId = null): LengthAwarePaginator
|
||||
{
|
||||
return $this->salesQuery($tenant, $filters)
|
||||
return $this->salesQuery($tenant, $filters, $eventId)
|
||||
->paginateFromRequest()
|
||||
->withQueryString();
|
||||
}
|
||||
|
||||
public function detail(Tenant $tenant, int $saleId): Purchase
|
||||
public function detail(Tenant $tenant, int $saleId, ?int $eventId = null): Purchase
|
||||
{
|
||||
return Purchase::query()
|
||||
->where('tenant_codigo', $tenant->codigo)
|
||||
return $this->purchasesQuery($tenant, $eventId)
|
||||
->with('items')
|
||||
->findOrFail($saleId);
|
||||
}
|
||||
|
||||
/** @return Collection<int, Ticket> */
|
||||
public function tickets(Tenant $tenant, int $saleId): Collection
|
||||
public function tickets(Tenant $tenant, int $saleId, ?int $eventId = null): Collection
|
||||
{
|
||||
return $this->findForTenant($tenant, $saleId)
|
||||
return $this->findForTenant($tenant, $saleId, $eventId)
|
||||
->tickets()
|
||||
->with([...TicketValidityResolver::RELATIONS, ...TicketPresentationResolver::RELATIONS, 'refund'])
|
||||
->orderBy('id')
|
||||
->get();
|
||||
}
|
||||
|
||||
public function confirm(Tenant $tenant, int $saleId): Purchase
|
||||
public function confirm(Tenant $tenant, int $saleId, ?int $eventId = null): Purchase
|
||||
{
|
||||
$sale = $this->findForTenant($tenant, $saleId);
|
||||
$sale = $this->findForTenant($tenant, $saleId, $eventId);
|
||||
|
||||
return $this->saleForResponse(
|
||||
$this->checkoutService->confirmPaidPurchase($sale)
|
||||
);
|
||||
}
|
||||
|
||||
public function cancel(Tenant $tenant, int $saleId): Purchase
|
||||
public function cancel(Tenant $tenant, int $saleId, ?int $eventId = null): Purchase
|
||||
{
|
||||
$sale = $this->findForTenant($tenant, $saleId);
|
||||
$sale = $this->findForTenant($tenant, $saleId, $eventId);
|
||||
|
||||
return $this->saleForResponse(
|
||||
$this->checkoutService->cancelPurchaseFromAdmin($sale)
|
||||
@@ -94,18 +92,18 @@ class AdminAppSaleService
|
||||
* @param array<string, mixed> $filters
|
||||
* @return Collection<int, Purchase>
|
||||
*/
|
||||
public function salesForExport(Tenant $tenant, array $filters = []): Collection
|
||||
public function salesForExport(Tenant $tenant, array $filters = [], ?int $eventId = null): Collection
|
||||
{
|
||||
return $this->salesQuery($tenant, $filters)->get();
|
||||
return $this->salesQuery($tenant, $filters, $eventId)->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $filters
|
||||
* @return LengthAwarePaginator<ValueChange>
|
||||
*/
|
||||
public function modifications(Tenant $tenant, array $filters = []): LengthAwarePaginator
|
||||
public function modifications(Tenant $tenant, array $filters = [], ?int $eventId = null): LengthAwarePaginator
|
||||
{
|
||||
return $this->modificationsQuery($tenant, $filters)
|
||||
return $this->modificationsQuery($tenant, $filters, $eventId)
|
||||
->paginateFromRequest()
|
||||
->withQueryString();
|
||||
}
|
||||
@@ -114,13 +112,13 @@ class AdminAppSaleService
|
||||
* @param array<string, mixed> $filters
|
||||
* @return Collection<int, ValueChange>
|
||||
*/
|
||||
public function modificationsForExport(Tenant $tenant, array $filters = []): Collection
|
||||
public function modificationsForExport(Tenant $tenant, array $filters = [], ?int $eventId = null): Collection
|
||||
{
|
||||
return $this->modificationsQuery($tenant, $filters)->get();
|
||||
return $this->modificationsQuery($tenant, $filters, $eventId)->get();
|
||||
}
|
||||
|
||||
/** @param array<string, mixed> $filters */
|
||||
protected function salesQuery(Tenant $tenant, array $filters): Builder
|
||||
protected function salesQuery(Tenant $tenant, array $filters, ?int $eventId = null): Builder
|
||||
{
|
||||
$sortColumns = [
|
||||
'id' => 'id',
|
||||
@@ -137,8 +135,7 @@ class AdminAppSaleService
|
||||
? $requestedDirection
|
||||
: 'desc';
|
||||
|
||||
return Purchase::query()
|
||||
->where('tenant_codigo', $tenant->codigo)
|
||||
return $this->purchasesQuery($tenant, $eventId)
|
||||
->when($filters['q'] ?? null, function (Builder $query, string $search): void {
|
||||
$term = trim($search);
|
||||
|
||||
@@ -176,11 +173,18 @@ class AdminAppSaleService
|
||||
* @param array<string, mixed> $filters
|
||||
* @return Builder<ValueChange>
|
||||
*/
|
||||
protected function modificationsQuery(Tenant $tenant, array $filters): Builder
|
||||
protected function modificationsQuery(Tenant $tenant, array $filters, ?int $eventId = null): Builder
|
||||
{
|
||||
return ValueChange::query()
|
||||
->where('tenant_code', $tenant->codigo)
|
||||
->where('trackable_type', (new Purchase)->getMorphClass())
|
||||
->when($eventId !== null, fn (Builder $query): Builder => $query->whereHasMorph(
|
||||
'trackable',
|
||||
[Purchase::class],
|
||||
fn (Builder $sales): Builder => $sales
|
||||
->where('tenant_codigo', $tenant->codigo)
|
||||
->where('event_id', $eventId),
|
||||
))
|
||||
->when($filters['q'] ?? null, function (Builder $query, string $search): void {
|
||||
$term = trim($search);
|
||||
|
||||
@@ -221,11 +225,18 @@ class AdminAppSaleService
|
||||
->orderByDesc('id');
|
||||
}
|
||||
|
||||
protected function findForTenant(Tenant $tenant, int $saleId): Purchase
|
||||
protected function findForTenant(Tenant $tenant, int $saleId, ?int $eventId = null): Purchase
|
||||
{
|
||||
return $this->purchasesQuery($tenant, $eventId)
|
||||
->findOrFail($saleId);
|
||||
}
|
||||
|
||||
/** @return Builder<Purchase> */
|
||||
protected function purchasesQuery(Tenant $tenant, ?int $eventId): Builder
|
||||
{
|
||||
return Purchase::query()
|
||||
->where('tenant_codigo', $tenant->codigo)
|
||||
->findOrFail($saleId);
|
||||
->when($eventId !== null, fn (Builder $query): Builder => $query->where('event_id', $eventId));
|
||||
}
|
||||
|
||||
protected function saleForResponse(Purchase $sale): Purchase
|
||||
|
||||
@@ -29,4 +29,8 @@ Consume compras de `Purchase`, datos del tenant y entradas de `Logging`. No es d
|
||||
|
||||
La consulta paginada y la colección de exportación deben aplicar los mismos filtros para evitar diferencias entre pantalla, PDF y Excel.
|
||||
|
||||
Cuando el usuario autenticado tiene `event_id`, el controlador lo pasa al servicio como alcance obligatorio para ventas, totales, historial y exportaciones. El alcance se combina con el tenant y no se obtiene de los filtros enviados por el cliente. Los administradores sin `event_id` conservan el alcance del tenant.
|
||||
|
||||
El detalle, los tickets de una venta, la confirmación y la cancelación buscan la compra dentro del mismo alcance. Una venta de otro evento o sin evento devuelve 404 para un administrador con `event_id`, antes de ejecutar cualquier acción en `CheckoutService`.
|
||||
|
||||
El historial comparte con ventas los filtros de búsqueda, ID, fecha de venta y estado. En el historial, el estado se evalúa sobre `ValueChange.new_value`: representa el resultado de esa modificación y no el estado actual de la venta.
|
||||
|
||||
183
tests/Feature/Sale/AdminAppSaleEventScopeTest.php
Normal file
183
tests/Feature/Sale/AdminAppSaleEventScopeTest.php
Normal file
@@ -0,0 +1,183 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Sale;
|
||||
|
||||
use App\Domains\Commerce\Purchase\Models\Purchase;
|
||||
use App\Domains\Commerce\Purchase\Services\CheckoutService;
|
||||
use App\Domains\Commerce\Sale\Services\AdminAppSaleExcelService;
|
||||
use App\Domains\Commerce\Sale\Services\AdminAppSalePdfService;
|
||||
use App\Domains\Core\Auth\Models\User;
|
||||
use App\Domains\Core\Authorization\Enums\RoleCode;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Laravel\Sanctum\Sanctum;
|
||||
use Mockery\MockInterface;
|
||||
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||
use Tests\TestCase;
|
||||
|
||||
class AdminAppSaleEventScopeTest extends TestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
// Isolated schema: the full legacy migration chain cannot run on SQLite.
|
||||
Schema::create('tenants', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->string('codigo');
|
||||
});
|
||||
Schema::create('users', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->softDeletes();
|
||||
});
|
||||
Schema::create('compras', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->string('tenant_codigo');
|
||||
$table->unsignedBigInteger('event_id')->nullable();
|
||||
$table->string('nombre_apellido');
|
||||
$table->string('status');
|
||||
$table->decimal('total', 12, 2);
|
||||
$table->timestamps();
|
||||
});
|
||||
Schema::create('compra_items', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('compra_id');
|
||||
$table->integer('cantidad');
|
||||
});
|
||||
Schema::create('tickets', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('source_purchase_item_id');
|
||||
});
|
||||
Schema::create('ticket_refunds', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('purchase_item_id');
|
||||
$table->decimal('amount', 12, 2);
|
||||
});
|
||||
Schema::create('value_changes', function (Blueprint $table): void {
|
||||
$table->id();
|
||||
$table->string('tenant_code');
|
||||
$table->string('trackable_type');
|
||||
$table->unsignedBigInteger('trackable_id');
|
||||
$table->string('attribute');
|
||||
$table->string('old_value');
|
||||
$table->string('new_value');
|
||||
$table->timestamp('changed_at');
|
||||
$table->string('actor_type');
|
||||
$table->unsignedBigInteger('user_id')->nullable();
|
||||
});
|
||||
|
||||
DB::table('tenants')->insert(['codigo' => 'onticket']);
|
||||
foreach ([1 => ['onticket', 10], 2 => ['onticket', 20], 3 => ['onticket', null], 4 => ['other', 10]] as $id => [$tenant, $event]) {
|
||||
DB::table('compras')->insert([
|
||||
'id' => $id,
|
||||
'tenant_codigo' => $tenant,
|
||||
'event_id' => $event,
|
||||
'nombre_apellido' => 'Cliente',
|
||||
'status' => Purchase::STATUS_PAID,
|
||||
'total' => $id * 100,
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
DB::table('compra_items')->insert(['id' => $id, 'compra_id' => $id, 'cantidad' => 1]);
|
||||
DB::table('ticket_refunds')->insert(['purchase_item_id' => $id, 'amount' => $id * 10]);
|
||||
DB::table('value_changes')->insert([
|
||||
'id' => $id,
|
||||
'tenant_code' => $tenant,
|
||||
'trackable_type' => (new Purchase)->getMorphClass(),
|
||||
'trackable_id' => $id,
|
||||
'attribute' => 'status',
|
||||
'old_value' => Purchase::STATUS_PENDING_PAYMENT,
|
||||
'new_value' => Purchase::STATUS_PAID,
|
||||
'changed_at' => now(),
|
||||
'actor_type' => 'system',
|
||||
]);
|
||||
}
|
||||
$this->actingAsAdministrator(10);
|
||||
}
|
||||
|
||||
public function test_list_totals_and_filters_cannot_escape_the_authenticated_event(): void
|
||||
{
|
||||
$this->getJson('/api/v1/adminapp/tenant/sales?event_id=20&q=Cliente')
|
||||
->assertOk()
|
||||
->assertJsonCount(1, 'data')
|
||||
->assertJsonPath('data.0.id', 1)
|
||||
->assertJsonPath('confirmed_sales_total', '100.00')
|
||||
->assertJsonPath('refunded_total', '10.00');
|
||||
$this->getJson('/api/v1/adminapp/tenant/sales?id=2')->assertOk()->assertJsonCount(0, 'data');
|
||||
$this->getJson('/api/v1/adminapp/tenant/sales/modifications?q=Cliente')
|
||||
->assertOk()->assertJsonCount(1, 'data')->assertJsonPath('data.0.sale_id', 1);
|
||||
}
|
||||
|
||||
public function test_unscoped_administrators_keep_access_to_all_sales_in_their_tenant(): void
|
||||
{
|
||||
$this->actingAsAdministrator(null);
|
||||
$this->getJson('/api/v1/adminapp/tenant/sales')->assertOk()->assertJsonCount(3, 'data')
|
||||
->assertJsonPath('confirmed_sales_total', '600.00')->assertJsonPath('refunded_total', '60.00');
|
||||
$this->getJson('/api/v1/adminapp/tenant/sales/modifications')->assertOk()->assertJsonCount(3, 'data');
|
||||
$this->getJson('/api/v1/adminapp/tenant/sales/2')->assertOk();
|
||||
$this->getJson('/api/v1/adminapp/tenant/sales/3')->assertOk();
|
||||
}
|
||||
|
||||
public function test_foreign_and_unassigned_sales_are_inaccessible_before_any_checkout_action(): void
|
||||
{
|
||||
$this->mock(CheckoutService::class, function (MockInterface $mock): void {
|
||||
$mock->shouldNotReceive('confirmPaidPurchase');
|
||||
$mock->shouldNotReceive('cancelPurchaseFromAdmin');
|
||||
});
|
||||
foreach ([2, 3, 4] as $id) {
|
||||
$this->getJson("/api/v1/adminapp/tenant/sales/{$id}")->assertNotFound();
|
||||
$this->getJson("/api/v1/adminapp/tenant/sales/{$id}/tickets")->assertNotFound();
|
||||
$this->postJson("/api/v1/adminapp/tenant/sales/{$id}/confirm", ['event_id' => 20])->assertNotFound();
|
||||
$this->postJson("/api/v1/adminapp/tenant/sales/{$id}/cancel", ['event_id' => 20])->assertNotFound();
|
||||
}
|
||||
$this->assertSame(Purchase::STATUS_PAID, DB::table('compras')->where('id', 2)->value('status'));
|
||||
}
|
||||
|
||||
public function test_own_event_allows_detail_tickets_and_checkout_actions(): void
|
||||
{
|
||||
// Empty snapshots keep this fixture focused on authorization.
|
||||
DB::table('compra_items')->where('compra_id', 1)->delete();
|
||||
$this->mock(CheckoutService::class, function (MockInterface $mock): void {
|
||||
foreach (['confirmPaidPurchase', 'cancelPurchaseFromAdmin'] as $method) {
|
||||
$mock->shouldReceive($method)->once()->withArgs(fn (Purchase $sale): bool => $sale->id === 1)
|
||||
->andReturnUsing(fn (Purchase $sale): Purchase => $sale);
|
||||
}
|
||||
});
|
||||
$this->getJson('/api/v1/adminapp/tenant/sales/1')->assertOk()->assertJsonPath('data.id', 1);
|
||||
$this->getJson('/api/v1/adminapp/tenant/sales/1/tickets')->assertOk();
|
||||
$this->postJson('/api/v1/adminapp/tenant/sales/1/confirm')->assertOk()->assertJsonPath('data.id', 1);
|
||||
$this->postJson('/api/v1/adminapp/tenant/sales/1/cancel')->assertOk()->assertJsonPath('data.id', 1);
|
||||
}
|
||||
|
||||
public function test_pdf_and_excel_exports_only_receive_sales_and_history_for_the_own_event(): void
|
||||
{
|
||||
foreach ([AdminAppSalePdfService::class, AdminAppSaleExcelService::class] as $class) {
|
||||
$this->mock($class, function (MockInterface $mock) use ($class): void {
|
||||
foreach (['downloadSales', 'downloadModifications'] as $method) {
|
||||
$mock->shouldReceive($method)->once()->withArgs(
|
||||
fn ($tenant, Collection $rows, $timezone): bool => $tenant->codigo === 'onticket'
|
||||
&& $rows->pluck('id')->all() === [1] && $timezone === 'UTC'
|
||||
)->andReturn($class === AdminAppSalePdfService::class
|
||||
? response('pdf') : new StreamedResponse(fn () => print ('excel')));
|
||||
}
|
||||
});
|
||||
}
|
||||
foreach (['pdf', 'excel', 'modifications/pdf', 'modifications/excel'] as $path) {
|
||||
$this->getJson("/api/v1/adminapp/tenant/sales/{$path}?timezone=UTC&event_id=20")->assertOk();
|
||||
}
|
||||
}
|
||||
|
||||
private function actingAsAdministrator(?int $eventId): void
|
||||
{
|
||||
$user = new User;
|
||||
$user->setRawAttributes([
|
||||
'id' => 1,
|
||||
'rol_codigo' => RoleCode::AdminApp->value,
|
||||
'tenant_codigo' => 'onticket',
|
||||
'event_id' => $eventId,
|
||||
]);
|
||||
Sanctum::actingAs($user);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user