NETBien.backend/app/Http/Controllers/Netbien/CashCloseController.php
juan.zapata af8749abcd WIP (#1)
Co-authored-by: Juan Felipe Zapata Moreno <zapata_pipe@hotmail.com>
Reviewed-on: #1
2025-11-10 22:45:59 +00:00

297 lines
11 KiB
PHP

<?php
namespace App\Http\Controllers\Netbien;
use App\Http\Controllers\Controller;
use App\Models\CashClose;
use App\Models\Sale;
use App\Models\SaleItem;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Notsoweb\ApiResponse\Enums\ApiResponse;
use phpseclib3\Crypt\RC2;
/**
*
*/
class CashCloseController extends Controller
{
public function index(Request $request)
{
$query = CashClose::with('user:id,name')->withCount('sales');
if ($request->has('status')) {
$query->where('status', $request->status);
}
if ($request->has('date')) {
$query->whereDate('close_date', $request->date);
}
$cashCloses = $query->orderBy('id', 'asc')
->paginate(config('app.pagination'));
return ApiResponse::OK->response([
'cash_closes' => $cashCloses,
]);
}
public function closeCashClose(Request $request)
{
$request->validate([
'exit' => 'sometimes|numeric|min:0',
]);
$cashClose = CashClose::open()->first();
if (!$cashClose) {
return ApiResponse::NOT_FOUND->response([
'message' => 'No hay un corte de caja abierto para cerrar.',
]);
}
$totalSales = Sale::where('cash_close_id', $cashClose->id)->sum('total_amount');
$paymentMethods = Sale::where('cash_close_id', $cashClose->id)
->select('payment_method', DB::raw('SUM(total_amount) as total'))
->groupBy('payment_method')
->pluck('total', 'payment_method');
$exit = $request->input('exit', 0);
$cashClose->update([
'closed_at' => now(),
'income' => $totalSales,
'exit' => $exit,
'income_cash' => $paymentMethods->get('cash', 0),
'income_card' => $paymentMethods->get('card', 0),
'income_transfer' => $paymentMethods->get('transfer', 0),
'status' => 'closed',
]);
$balanceFinal = $cashClose->initial_balance + $totalSales - $exit;
return ApiResponse::OK->response([
'message' => 'Corte de caja cerrado exitosamente.',
'cash_close' => $cashClose->fresh('user'),
'resumen' => [
'periodo' => [
'apertura' => $cashClose->opened_at,
'cierre' => $cashClose->closed_at,
],
'totales' => [
'fondo_inicial' => $cashClose->initial_balance,
'total_ventas' => $totalSales,
'efectivo' => $paymentMethods->get('cash', 0),
'tarjeta' => $paymentMethods->get('card', 0),
'transferencia' => $paymentMethods->get('transfer', 0),
'egresos' => $exit,
'balance_final' => $balanceFinal,
],
],
]);
}
public function report(Request $request)
{
$request->validate([
'start_date' => 'nullable|date',
'end_date' => 'nullable|date|after_or_equal:start_date',
]);
$query = CashClose::with('user:id,name')->withCount('sales');
if ($request->has('start_date') && $request->has('end_date')) {
$query->whereBetween('close_date', [$request->start_date, $request->end_date]);
} elseif ($request->has('start_date')) {
$query->whereDate('close_date', '>=', $request->start_date);
} elseif ($request->has('end_date')) {
$query->whereDate('close_date', '<=', $request->end_date);
} else {
$query->closed()->orderBy('id', 'desc')->limit(1);
}
// Información del corte de caja
$cashCloses = $query->orderBy('id', 'desc')->get();
if ($cashCloses->isEmpty()) {
return ApiResponse::NOT_FOUND->response([
'message' => 'No se encontraron cortes de caja en el rango de fechas especificado.',
]);
}
$cashCloseIds = $cashCloses->pluck('id')->toArray();
// Estadísticas por paquete (Total de Paquetes Vendidos por Tipo)
$packageStats = DB::table('sale_items')
->join('sales', 'sale_items.sale_id', '=', 'sales.id')
->join('packages', 'sale_items.package_id', '=', 'packages.id')
->whereIn('sales.cash_close_id', $cashCloseIds)
->select(
'packages.name as paquete',
DB::raw('COUNT(*) as total_vendidos'),
DB::raw('SUM(packages.price) as total_ingresos')
)
->groupBy('packages.id', 'packages.name')
->get();
// Estadísticas por duración (Total de Ventas por Duración)
$durationStats = DB::table('sale_items')
->join('sales', 'sale_items.sale_id', '=', 'sales.id')
->join('packages', 'sale_items.package_id', '=', 'packages.id')
->whereIn('sales.cash_close_id', $cashCloseIds)
->select(
'packages.period as duracion_dias',
DB::raw('COUNT(DISTINCT sales.id) as total_ventas')
)
->groupBy('packages.period')
->orderBy('packages.period', 'asc')
->get();
// Reporte detallado de ventas
$detailedSales = SaleItem::whereHas('sale', function ($query) use ($cashCloseIds) {
$query->whereIn('cash_close_id', $cashCloseIds);
})
->with([
'sale.client:id,name,paternal,maternal',
'sale:id,client_id,payment_method',
'simCard:id,iccid,msisdn',
'package:id,name,price'
])
->orderBy('id', 'asc')
->paginate(config('app.pagination'))
->through(function ($item) {
return [
'nombre_comprador' => $item->sale->client->full_name,
'id_sim' => $item->simCard->iccid,
'numero_asignado' => $item->simCard->msisdn,
'paquete' => $item->package->name,
'costo' => $item->package->price,
'medio_pago' => $item->sale->payment_method
];
});
$totalIncome = $cashCloses->sum('income');
$totalExit = $cashCloses->sum('exit');
$totalCash = $cashCloses->sum('income_cash');
$totalCard = $cashCloses->sum('income_card');
$totalTransfer = $cashCloses->sum('income_transfer');
$balanceFinal = $cashCloses->sum('initial_balance') + $totalIncome - $totalExit;
return ApiResponse::OK->response([
'cash_closes' => $cashCloses,
'periodo' => [
'inicio' => $cashCloses->last()?->opened_at,
'fin' => $cashCloses->first()?->closed_at,
],
'resumen_financiero' => [
'total_ventas' => $totalIncome,
'efectivo' => $totalCash,
'tarjeta' => $totalCard,
'transferencia' => $totalTransfer,
'egresos' => $totalExit,
'balance_final' => $balanceFinal,
],
'ventas_paquete' => $packageStats,
'ventas_duracion' => $durationStats,
'ventas_detalladas' => $detailedSales,
]);
}
public function exportReport(Request $request)
{
$request->validate([
'start_date' => 'nullable|date',
'end_date' => 'nullable|date|after_or_equal:start_date',
]);
$query = CashClose::with('user:id,name')->withCount('sales');
if ($request->has('start_date') && $request->has('end_date')) {
$query->whereBetween('close_at', [$request->start_date, $request->end_date]);
} elseif ($request->has('start_date')) {
$query->whereDate('close_at', '>=', $request->start_date);
} elseif ($request->has('end_date')) {
$query->whereDate('close_at', '<=', $request->end_date);
} else {
$query->closed()->orderBy('id', 'desc')->limit(1);
}
$cashCloses = $query->orderBy('id', 'desc')->get();
if ($cashCloses->isEmpty()) {
return ApiResponse::NOT_FOUND->response([
'message' => 'No se encontraron cortes de caja en el rango de fechas especificado.',
]);
}
$cashCloseIds = $cashCloses->pluck('id')->toArray();
// Obtener ventas detalladas
$detailedSales = SaleItem::whereHas('sale', function ($query) use ($cashCloseIds) {
$query->whereIn('cash_close_id', $cashCloseIds);
})
->with([
'sale.client:id,name,paternal,maternal',
'sale:id,client_id,payment_method',
'simCard:id,iccid,msisdn',
'package:id,name,price'
])
->orderBy('id', 'asc')
->get();
// Calcular totales
$totalIncome = $cashCloses->sum('income');
$totalExit = $cashCloses->sum('exit');
$totalCash = $cashCloses->sum('income_cash');
$totalCard = $cashCloses->sum('income_card');
$totalTransfer = $cashCloses->sum('income_transfer');
// Crear el CSV
$filename = 'reporte_corte_caja_' . date('Y-m-d_His') . '.csv';
$headers = [
'Content-Type' => 'text/csv; charset=UTF-8',
'Content-Disposition' => 'attachment; filename="' . $filename . '"',
];
$callback = function () use ($cashCloses, $detailedSales, $totalIncome, $totalExit, $totalCash, $totalCard, $totalTransfer) {
$file = fopen('php://output', 'w');
fprintf($file, chr(0xEF) . chr(0xBB) . chr(0xBF));
// RESUMEN FINANCIERO
fputcsv($file, ['RESUMEN FINANCIERO', '']);
fputcsv($file, ['Periodo Inicio', $cashCloses->last()?->opened_at]);
fputcsv($file, ['Periodo Fin', $cashCloses->first()?->closed_at]);
fputcsv($file, ['Total Ventas', number_format($totalIncome, 2)]);
fputcsv($file, ['Efectivo', number_format($totalCash, 2)]);
fputcsv($file, ['Tarjeta', number_format($totalCard, 2)]);
fputcsv($file, ['Transferencia', number_format($totalTransfer, 2)]);
fputcsv($file, ['Egresos', number_format($totalExit, 2)]);
fputcsv($file, []);
// VENTAS DETALLADAS
fputcsv($file, ['VENTAS DETALLADAS']);
fputcsv($file, ['Nombre Comprador', 'ID SIM', 'Número Asignado', 'Paquete', 'Costo', 'Medio de Pago']);
foreach ($detailedSales as $item) {
fputcsv($file, [
$item->sale->client->full_name,
"'" . $item->simCard->iccid . "'",
"'" . $item->simCard->msisdn . "'",
$item->package->name,
number_format($item->package->price, 2),
ucfirst($item->sale->payment_method)
]);
}
fclose($file);
};
return response()->stream($callback, 200, $headers);
}
}