refactor(backend): reorganize domains into Core, Commerce, Ticketing and Shared
This commit is contained in:
252
app/Domains/Commerce/Sale/Services/AdminAppSaleService.php
Normal file
252
app/Domains/Commerce/Sale/Services/AdminAppSaleService.php
Normal file
@@ -0,0 +1,252 @@
|
||||
<?php
|
||||
|
||||
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;
|
||||
use App\Domains\Ticket\Services\TicketValidityResolver;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class AdminAppSaleService
|
||||
{
|
||||
public function __construct(
|
||||
protected CheckoutService $checkoutService,
|
||||
protected PurchaseRefundSummaryService $refundSummaryService,
|
||||
) {}
|
||||
|
||||
public function confirmedSalesTotal(Tenant $tenant): string
|
||||
{
|
||||
$total = Purchase::query()
|
||||
->where('tenant_codigo', $tenant->codigo)
|
||||
->where('status', Purchase::STATUS_PAID)
|
||||
->sum('total');
|
||||
|
||||
return number_format((float) $total, 2, '.', '');
|
||||
}
|
||||
|
||||
public function refundedTotal(Tenant $tenant): string
|
||||
{
|
||||
return $this->refundSummaryService->totalForTenant($tenant);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array{
|
||||
* q?: string|null,
|
||||
* id?: int|null,
|
||||
* sale_date?: string|null,
|
||||
* status?: string|null,
|
||||
* sort_by?: string,
|
||||
* sort_direction?: string
|
||||
* } $filters
|
||||
* @return LengthAwarePaginator<Purchase>
|
||||
*/
|
||||
public function sales(Tenant $tenant, array $filters = []): LengthAwarePaginator
|
||||
{
|
||||
return $this->salesQuery($tenant, $filters)
|
||||
->paginateFromRequest()
|
||||
->withQueryString();
|
||||
}
|
||||
|
||||
public function detail(Tenant $tenant, int $saleId): Purchase
|
||||
{
|
||||
return Purchase::query()
|
||||
->where('tenant_codigo', $tenant->codigo)
|
||||
->with('items')
|
||||
->findOrFail($saleId);
|
||||
}
|
||||
|
||||
/** @return Collection<int, Ticket> */
|
||||
public function tickets(Tenant $tenant, int $saleId): Collection
|
||||
{
|
||||
return $this->findForTenant($tenant, $saleId)
|
||||
->tickets()
|
||||
->with([...TicketValidityResolver::RELATIONS, ...TicketPresentationResolver::RELATIONS, 'refund'])
|
||||
->orderBy('id')
|
||||
->get();
|
||||
}
|
||||
|
||||
public function confirm(Tenant $tenant, int $saleId): Purchase
|
||||
{
|
||||
$sale = $this->findForTenant($tenant, $saleId);
|
||||
|
||||
return $this->saleForResponse(
|
||||
$this->checkoutService->confirmPaidPurchase($sale)
|
||||
);
|
||||
}
|
||||
|
||||
public function cancel(Tenant $tenant, int $saleId): Purchase
|
||||
{
|
||||
$sale = $this->findForTenant($tenant, $saleId);
|
||||
|
||||
return $this->saleForResponse(
|
||||
$this->checkoutService->cancelPurchaseFromAdmin($sale)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $filters
|
||||
* @return Collection<int, Purchase>
|
||||
*/
|
||||
public function salesForExport(Tenant $tenant, array $filters = []): Collection
|
||||
{
|
||||
return $this->salesQuery($tenant, $filters)->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $filters
|
||||
* @return LengthAwarePaginator<ValueChange>
|
||||
*/
|
||||
public function modifications(Tenant $tenant, array $filters = []): LengthAwarePaginator
|
||||
{
|
||||
return $this->modificationsQuery($tenant, $filters)
|
||||
->paginateFromRequest()
|
||||
->withQueryString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $filters
|
||||
* @return Collection<int, ValueChange>
|
||||
*/
|
||||
public function modificationsForExport(Tenant $tenant, array $filters = []): Collection
|
||||
{
|
||||
return $this->modificationsQuery($tenant, $filters)->get();
|
||||
}
|
||||
|
||||
/** @param array<string, mixed> $filters */
|
||||
protected function salesQuery(Tenant $tenant, array $filters): Builder
|
||||
{
|
||||
$sortColumns = [
|
||||
'id' => 'id',
|
||||
'date' => 'created_at',
|
||||
'customer_name' => 'nombre_apellido',
|
||||
'quantity' => 'quantity',
|
||||
'status' => 'status',
|
||||
'total' => 'total',
|
||||
];
|
||||
$requestedSort = $filters['sort_by'] ?? 'date';
|
||||
$sortBy = array_key_exists($requestedSort, $sortColumns) ? $requestedSort : 'date';
|
||||
$requestedDirection = $filters['sort_direction'] ?? 'desc';
|
||||
$sortDirection = in_array($requestedDirection, ['asc', 'desc'], true)
|
||||
? $requestedDirection
|
||||
: 'desc';
|
||||
|
||||
return Purchase::query()
|
||||
->where('tenant_codigo', $tenant->codigo)
|
||||
->when($filters['q'] ?? null, function (Builder $query, string $search): void {
|
||||
$term = trim($search);
|
||||
|
||||
$query->where(function (Builder $query) use ($term): void {
|
||||
$query
|
||||
->where('id', 'like', "%{$term}%")
|
||||
->orWhere('nombre_apellido', 'like', "%{$term}%")
|
||||
->orWhere('created_at', 'like', "%{$term}%");
|
||||
});
|
||||
})
|
||||
->when($filters['id'] ?? null, fn (Builder $query, int $id): Builder => $query->whereKey($id))
|
||||
->when(
|
||||
$filters['sale_date'] ?? null,
|
||||
fn (Builder $query, string $date): Builder => $query->whereDate('created_at', $date)
|
||||
)
|
||||
->when(
|
||||
$filters['status'] ?? null,
|
||||
fn (Builder $query, string $status): Builder => $query->whereIn(
|
||||
'status',
|
||||
Purchase::realStatusesForAdminStatus($status),
|
||||
)
|
||||
)
|
||||
->select('compras.*')
|
||||
->selectRaw(
|
||||
'(SELECT COALESCE(SUM(purchase_items.cantidad), 0) '
|
||||
.'FROM compra_items AS purchase_items '
|
||||
.'WHERE purchase_items.compra_id = compras.id) AS quantity',
|
||||
)
|
||||
->withCount('tickets')
|
||||
->orderBy($sortColumns[$sortBy], $sortDirection)
|
||||
->when($sortBy !== 'id', fn (Builder $query): Builder => $query->orderByDesc('id'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $filters
|
||||
* @return Builder<ValueChange>
|
||||
*/
|
||||
protected function modificationsQuery(Tenant $tenant, array $filters): Builder
|
||||
{
|
||||
return ValueChange::query()
|
||||
->where('tenant_code', $tenant->codigo)
|
||||
->where('trackable_type', (new Purchase)->getMorphClass())
|
||||
->when($filters['q'] ?? null, function (Builder $query, string $search): void {
|
||||
$term = trim($search);
|
||||
|
||||
$query->where(function (Builder $query) use ($term): void {
|
||||
$query
|
||||
->where('trackable_id', 'like', "%{$term}%")
|
||||
->orWhereHasMorph(
|
||||
'trackable',
|
||||
[Purchase::class],
|
||||
function (Builder $sales) use ($term): void {
|
||||
$sales
|
||||
->where('nombre_apellido', 'like', "%{$term}%")
|
||||
->orWhere('created_at', 'like', "%{$term}%");
|
||||
},
|
||||
);
|
||||
});
|
||||
})
|
||||
->when(
|
||||
$filters['id'] ?? null,
|
||||
fn (Builder $query, int $id): Builder => $query->where('trackable_id', $id)
|
||||
)
|
||||
->when(
|
||||
$filters['sale_date'] ?? null,
|
||||
fn (Builder $query, string $date): Builder => $query->whereHasMorph(
|
||||
'trackable',
|
||||
[Purchase::class],
|
||||
fn (Builder $sales): Builder => $sales->whereDate('created_at', $date),
|
||||
)
|
||||
)
|
||||
->when(
|
||||
$filters['status'] ?? null,
|
||||
fn (Builder $query, string $status): Builder => $query
|
||||
->where('attribute', 'status')
|
||||
->whereIn('new_value', Purchase::realStatusesForAdminStatus($status))
|
||||
)
|
||||
->with(['trackable', 'user'])
|
||||
->orderByDesc('changed_at')
|
||||
->orderByDesc('id');
|
||||
}
|
||||
|
||||
protected function findForTenant(Tenant $tenant, int $saleId): Purchase
|
||||
{
|
||||
return Purchase::query()
|
||||
->where('tenant_codigo', $tenant->codigo)
|
||||
->findOrFail($saleId);
|
||||
}
|
||||
|
||||
protected function saleForResponse(Purchase $sale): Purchase
|
||||
{
|
||||
/** @var Purchase */
|
||||
return Purchase::query()
|
||||
->select('compras.*')
|
||||
->selectRaw($this->quantityExpression())
|
||||
->withCount('tickets')
|
||||
->findOrFail($sale->getKey());
|
||||
}
|
||||
|
||||
protected function quantityExpression(): string
|
||||
{
|
||||
return <<<'SQL'
|
||||
COALESCE(
|
||||
(SELECT SUM(compra_items.cantidad)
|
||||
FROM compra_items
|
||||
WHERE compra_items.compra_id = compras.id),
|
||||
0
|
||||
) AS quantity
|
||||
SQL;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user