diff --git a/app/Http/Controllers/App/ReportController.php b/app/Http/Controllers/App/ReportController.php index 7b5b044..561d7a6 100644 --- a/app/Http/Controllers/App/ReportController.php +++ b/app/Http/Controllers/App/ReportController.php @@ -15,22 +15,22 @@ public function __construct( /** * Obtener el producto más vendido - * - * @param Request $request - * @return \Illuminate\Http\JsonResponse */ public function topSellingProduct(Request $request) { $request->validate([ + 'include_stock_value' => ['nullable', 'boolean'], 'from_date' => ['nullable', 'date_format:Y-m-d'], 'to_date' => ['nullable', 'date_format:Y-m-d', 'after_or_equal:from_date', 'required_with:from_date'], ], [ + 'include_stock_value.boolean' => 'El parámetro de valor de stock debe ser verdadero o falso.', 'from_date.date_format' => 'La fecha inicial debe tener el formato Y-m-d (ejemplo: 2025-01-01).', 'to_date.date_format' => 'La fecha final debe tener el formato Y-m-d (ejemplo: 2025-01-31).', 'to_date.after_or_equal' => 'La fecha final debe ser igual o posterior a la fecha inicial.', 'to_date.required_with' => 'La fecha final es obligatoria cuando se proporciona fecha inicial.', ]); + try { $product = $this->reportService->getTopSellingProduct( fromDate: $request->input('from_date'), @@ -57,25 +57,27 @@ public function topSellingProduct(Request $request) /** * Obtener productos sin movimiento - * - * @param Request $request - * @return \Illuminate\Http\JsonResponse */ public function productsWithoutMovement(Request $request) { $request->validate([ - 'days_threshold' => ['nullable', 'integer', 'min:1'], 'include_stock_value' => ['nullable', 'boolean'], + 'from_date' => ['required', 'date_format:Y-m-d'], + 'to_date' => ['required', 'date_format:Y-m-d', 'after_or_equal:from_date'], ], [ - 'days_threshold.integer' => 'El umbral de días debe ser un número entero.', - 'days_threshold.min' => 'El umbral de días debe ser al menos 1.', 'include_stock_value.boolean' => 'El parámetro de valor de stock debe ser verdadero o falso.', + 'from_date.required' => 'La fecha inicial es obligatoria.', + 'from_date.date_format' => 'La fecha inicial debe tener el formato Y-m-d (ejemplo: 2025-01-01).', + 'to_date.required' => 'La fecha final es obligatoria.', + 'to_date.date_format' => 'La fecha final debe tener el formato Y-m-d (ejemplo: 2025-01-31).', + 'to_date.after_or_equal' => 'La fecha final debe ser igual o posterior a la fecha inicial.', ]); try { $products = $this->reportService->getProductsWithoutMovement( - daysThreshold: (int)($request->input('days_threshold', 30)), - includeStockValue: (bool)($request->input('include_stock_value', true)) + includeStockValue: (bool)($request->input('include_stock_value', true)), + fromDate: $request->input('from_date'), + toDate: $request->input('to_date') ); return ApiResponse::OK->response([ diff --git a/app/Services/ReportService.php b/app/Services/ReportService.php index c11ec65..37cb3b4 100644 --- a/app/Services/ReportService.php +++ b/app/Services/ReportService.php @@ -56,13 +56,14 @@ public function getTopSellingProduct(?string $fromDate = null, ?string $toDate = * @param bool $includeStockValue Incluir valor del inventario (default: true) * @return array Lista de productos sin ventas */ - public function getProductsWithoutMovement(int $daysThreshold = 30, bool $includeStockValue = true): array + public function getProductsWithoutMovement(bool $includeStockValue = true, ?string $fromDate = null, ?string $toDate = null): array { // Obtener IDs de productos que SÍ tienen ventas $inventoriesWithSales = SaleDetail::query() ->join('sales', 'sale_details.sale_id', '=', 'sales.id') ->where('sales.status', 'completed') ->whereNull('sales.deleted_at') + ->whereBetween(DB::raw('DATE(sales.created_at)'), [$fromDate, $toDate]) ->distinct() ->pluck('sale_details.inventory_id') ->toArray(); @@ -76,7 +77,6 @@ public function getProductsWithoutMovement(int $daysThreshold = 30, bool $includ inventories.stock, categories.name as category_name, inventories.created_at as date_added, - DATEDIFF(NOW(), inventories.created_at) as days_without_movement, prices.retail_price '); @@ -93,7 +93,6 @@ public function getProductsWithoutMovement(int $daysThreshold = 30, bool $includ ->where('inventories.is_active', true) ->whereNull('inventories.deleted_at') ->whereNotIn('inventories.id', $inventoriesWithSales) - ->havingRaw('DATEDIFF(NOW(), inventories.created_at) >= ?', [$daysThreshold]) ->orderBy('inventories.created_at') ->get() ->toArray();