diff --git a/app/Console/Commands/AgregarEsBonoAPedidosAprobados.php b/app/Console/Commands/AgregarEsBonoAPedidosAprobados.php new file mode 100644 index 0000000..251b94c --- /dev/null +++ b/app/Console/Commands/AgregarEsBonoAPedidosAprobados.php @@ -0,0 +1,72 @@ + 'Argumento inválido para el parámetro %s. Revise la documentación.' ]; @@ -22,10 +25,10 @@ class Filtro extends Model /** * Apply all existing filters, if available. * - * @param \Illuminate\Database\Eloquent\Builder $builder - * @return \Illuminate\Database\Eloquent\Builder + * @param Builder $builder + * @return Builder */ - public function aplicar(Builder $builder) + public function aplicar(Builder $builder): Builder { $this->builder = $builder; @@ -47,11 +50,11 @@ class Filtro extends Model //Llamar métodos sin argumentos if ($valor === null|| (is_a($valor,'String') && trim($valor)=='')){ $this->$metodo(); continue; } - + //Llamar métodos con argumentos try { $this->$metodo($valor); - } catch (\Throwable $th) { + } catch (Throwable $th) { if (is_a($th,'TypeError') ) { throw new HttpException(400, sprintf($this->MENSAJES_ERROR['ARGUMENTO'],$filtro)); } throw $th; } @@ -63,7 +66,7 @@ class Filtro extends Model //Buscar un término en el nombre public function nombre(String $valor) { - $this->builder->where('nombre', "LIKE", "%" . $valor . "%")->orderByRaw("IF(nombre = '{$valor}',2,IF(nombre LIKE '{$valor}%',1,0)) DESC"); + $this->builder->where('nombre', "LIKE", "%" . $valor . "%")->orderByRaw("IF(nombre = '$valor',2,IF(nombre LIKE '$valor%',1,0)) DESC"); } public function alfabetico(String $order = 'asc') diff --git a/app/Filtros/FiltroDeProducto.php b/app/Filtros/FiltroDeProducto.php index 93672c2..d7e7dc3 100644 --- a/app/Filtros/FiltroDeProducto.php +++ b/app/Filtros/FiltroDeProducto.php @@ -1,7 +1,6 @@ builder->where('categoria', $valor); } -} \ No newline at end of file +} diff --git a/app/Filtros/FiltroDeSubpedido.php b/app/Filtros/FiltroDeSubpedido.php index 6fa8198..c889860 100644 --- a/app/Filtros/FiltroDeSubpedido.php +++ b/app/Filtros/FiltroDeSubpedido.php @@ -2,7 +2,7 @@ namespace App\Filtros; -use Illuminate\Database\Eloquent\Model; +use TypeError; class FiltroDeSubpedido extends Filtro { diff --git a/app/GrupoDeCompra.php b/app/GrupoDeCompra.php index 07b8634..6d56966 100644 --- a/app/GrupoDeCompra.php +++ b/app/GrupoDeCompra.php @@ -2,13 +2,15 @@ namespace App; +use App\Helpers\CsvHelper; +use App\Helpers\PdfHelper; use App\Helpers\TransporteHelper; +use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\Relations\HasMany; +use Illuminate\Support\Collection; use Illuminate\Support\Facades\DB; -use League\Csv\CannotInsertRecord; -use League\Csv\Reader; -use League\Csv\Writer; -use Mpdf\Mpdf; +use Illuminate\Support\Facades\Log; class GrupoDeCompra extends Model { @@ -17,12 +19,12 @@ class GrupoDeCompra extends Model protected $table = 'grupos_de_compra'; protected $hidden = ['password']; - public function subpedidos() + public function subpedidos(): HasMany { - return $this->hasMany('App\Subpedido'); + return $this->hasMany(Subpedido::class); } - public function toggleDevoluciones() + public function toggleDevoluciones(): bool { $this->devoluciones_habilitadas = !$this->devoluciones_habilitadas; $this->save(); @@ -91,25 +93,52 @@ class GrupoDeCompra extends Model return TransporteHelper::totalTransporte($this->totalCentralesQuePaganTransporte()); } - public function cantidadTransporte() + /** + * @return int + * Calcula la cantidad de bonos de transporte del barrio + */ + public function cantidadTransporte(): int { return TransporteHelper::cantidadTransporte($this->totalCentralesQuePaganTransporte()); } - public function exportarPlanillasAPdf() + public function exportarPedidosAPdf() { $subpedidos = $this->pedidosAprobados(); - //generar pdf - $mpdf = new Mpdf(); - foreach ($subpedidos as $subpedido) { - $tabla = $subpedido->generarHTML(); - // agregar la tabla al pdf en una nueva página - $mpdf->WriteHTML($tabla); - $mpdf->AddPage(); + PdfHelper::exportarPedidos($this->nombre . '.pdf', $subpedidos); + } + + function pedidoParaPdf(): array + { + $productos = $this->productosPedidos(true, true); + $pedido = []; + $pedido['productos'] = []; + + $pedido['nombre'] = $this->nombre; + foreach ($productos as $producto) { + $productoParaPdf = []; + $productoParaPdf['pivot'] = []; + $productoParaPdf['nombre'] = $producto->producto_nombre; + $productoParaPdf['pivot']['cantidad'] = $producto->cantidad_pedida; + $productoParaPdf['pivot']['notas'] = false; + $productoParaPdf['bono'] = $producto->producto_es_bono; + + $pedido['productos'][] = $productoParaPdf; } - $filename = $this->nombre . '.pdf'; - // imprimir el pdf - $mpdf->Output($filename, "D"); + + return $pedido; + } + + public function generarHTML() + { + $view = view("pdfgen.pedido_tabla", ["pedido" => $this->pedidoParaPdf()]); + return $view->render(); + } + + public static function exportarPedidosBarrialesAPdf() + { + $barrios = GrupoDeCompra::barriosMenosPrueba()->get(); + PdfHelper::exportarPedidos('pedidos_por_barrio.pdf', $barrios); } static function filaVacia(string $product, int $columns): array @@ -122,7 +151,7 @@ class GrupoDeCompra extends Model } //Asume que los productos están gruadados en orden de fila - public static function obtenerTemplateDeFilasVacias(int $columns) + public static function obtenerTemplateDeFilasVacias(int $columns): array { $productosFilaID = Producto::productosFilaID(); $productosIDNombre = Producto::productosIDNombre(); @@ -135,104 +164,53 @@ class GrupoDeCompra extends Model $template[$fila] = GrupoDeCompra::filaVacia($productosIDNombre[$id], $columns); $num_fila = $fila + 1; } - $template[GrupoDeCompra::obtenerFilaDeBonoTransporte()] = GrupoDeCompra::filaVacia("Bonos de transporte", $columns); + $template[TransporteHelper::filaTransporte()] = GrupoDeCompra::filaVacia("Bonos de transporte", $columns); return $template; } - private static function obtenerFilaDeBonoTransporte() - { - $csv = Reader::createFromPath(resource_path('csv/productos.csv'), 'r'); - $csv->setDelimiter("|"); - $csv->setEnclosure("'"); - $registros = $csv->getRecords(); - - foreach ($registros as $key => $registro) - if ($registro[0] == 'T') return $key; - - throw new Exception('No hay bono de transporte'); - } - - private function totalPedidosSinBonos() - { - $total = 0; - foreach ($this->pedidosAprobados() as $pedido) { - $total += ceil($pedido->totalSinBonos()); - } - return $total; - } - - public function calcularCantidadBDT() - { - $total = 0; - foreach ($this->pedidosAprobados() as $pedido) { - $total += $pedido->totalParaTransporte(); - } - return ceil($total / 500); - } - - public function totalBonosBarriales() - { - $total = 0; - $bonoBarrial = Producto::where('nombre', 'LIKE', '%barrial%')->first(); - if ($bonoBarrial) { - $pedidos = $this->pedidosAprobados(); - foreach ($pedidos as $pedido) { - $bonoPedido = $pedido->productos()->find($bonoBarrial["id"]); - if ($bonoPedido) { - $total += $bonoPedido["pivot"]["total"]; - } - } - } - return $total; - } - public function exportarPedidoEnCSV() { $records = $this->generarColumnaCantidades(); - try { - $writer = Writer::createFromPath(resource_path('csv/exports/' . $this->nombre . '.csv'), 'w'); - $writer->insertAll($records); - } catch (CannotInsertRecord $e) { - var_export($e->getRecords()); - } + + CsvHelper::generarCsv('csv/exports/' . $this->nombre . '.csv', $records); } - public function generarColumnaCantidades() + public function generarColumnaCantidades(): array { - $productos_en_pedido = DB::table('pedidos_aprobados')->where('grupo_de_compra_id', $this->id)->get()->keyBy('producto_id'); + $productos_en_pedido = $this->productosPedidos(); //si no hay pedidos aprobados, salir if ($productos_en_pedido->count() == 0) { - \Log::debug("El grupo de compra " . $this->nombre . " no tiene pedidos aprobados."); + Log::debug("El grupo de compra " . $this->nombre . " no tiene pedidos aprobados."); return []; } $records = $this->obtenerTemplateDeFilasVacias(1); - $productos_id_fila = Producto::productosIdFila(); + $productos_id_fila = Producto::productosIDFila(); foreach ($productos_en_pedido as $id => $producto_pedido) { $fila = $productos_id_fila[$id]; $records[$fila][1] = $producto_pedido->cantidad_pedida; } - $records[$this->obtenerFilaDeBonoTransporte()][1] = $this->calcularCantidadBDT(); + $records[TransporteHelper::filaTransporte()][1] = $this->cantidadTransporte(); return $records; } public function exportarPedidoConNucleosEnCSV() { - $productos_en_pedido = DB::table('pedidos_aprobados')->where('grupo_de_compra_id', $this->id)->get()->keyBy('producto_id'); + $productos_en_pedido = $this->productosPedidos(); // si no hay pedidos aprobados, salir if ($productos_en_pedido->count() == 0) { - \Log::debug("El grupo de compra " . $this->nombre . " no tiene pedidos aprobados."); + Log::debug("El grupo de compra " . $this->nombre . " no tiene pedidos aprobados."); return; } $pedidos = $this->pedidosAprobados(); // Generar tabla vacía con una columna por núcleo $records = $this->obtenerTemplateDeFilasVacias($pedidos->count()); - $productos_id_fila = Producto::productosIdFila(); + $productos_id_fila = Producto::productosIDFila(); foreach ($productos_en_pedido as $id => $producto_pedido) { $fila = $productos_id_fila[$id]; @@ -251,13 +229,7 @@ class GrupoDeCompra extends Model } array_splice($records, 0, 0, array($nucleos)); - // Guardar en un archivo .csv - try { - $writer = Writer::createFromPath(resource_path('csv/exports/' . $this->nombre . '-completo.csv'), 'w'); - $writer->insertAll($records); - } catch (CannotInsertRecord $e) { - var_export($e->getRecords()); - } + CsvHelper::generarCsv('csv/exports/' . $this->nombre . '-completo.csv', $records); } public function agregarCantidad($pedido, $id, array $records, $fila, int $i): array @@ -269,52 +241,40 @@ class GrupoDeCompra extends Model return array($records, $i, $cantidad); } - static public function totalesParaTransportePorBarrio() { - return DB::table('grupos_de_compra') - ->leftJoin('subpedidos', 'grupos_de_compra.id', '=', 'subpedidos.grupo_de_compra_id') - ->leftJoin('producto_subpedido', 'subpedidos.id', '=', 'producto_subpedido.subpedido_id') - ->leftJoin('productos', 'producto_subpedido.producto_id', '=', 'productos.id') - ->where(function ($query) { - $query->whereNull('productos.categoria') - ->orWhere('productos.categoria', 'not like', '%SUBSIDIADO%'); - }) - ->where(function ($query) { - $query->whereNull('productos.bono') - ->orWhere('productos.bono', 0); - }) - ->where(function ($query) { - $query->whereNull('subpedidos.aprobado') - ->orWhere('subpedidos.aprobado', 1); - }) - ->select( - 'grupos_de_compra.id as id', - 'grupos_de_compra.nombre as barrio', - DB::raw('COALESCE(SUM(producto_subpedido.cantidad * productos.precio), 0) as total') - ) - ->groupBy('grupos_de_compra.id') - ->get(); + public static function barriosMenosPrueba(): Builder + { + return self::where('nombre', '<>', 'PRUEBA') + ->orderBy('region') + ->orderBy('nombre'); } + public static function transportePorBarrio(): array + { + $result = []; + $barrios = GrupoDeCompra::barriosMenosPrueba()->get(); - static public function planillaTransporte() { - $totalesPorBarrio = self::totalesParaTransportePorBarrio(); - $barrios = []; - $bonosDeTransporte = []; - - foreach ($totalesPorBarrio as $totalBarrio) { - $barrios[] = $totalBarrio->barrio; - $bonosDeTransporte[] = ceil($totalBarrio->total / 500); + foreach ($barrios as $barrio) { + $result[] = $barrio->cantidadTransporte(); } - $planilla = []; - $planilla[] = array_merge(['Barrio'], $barrios); - $planilla[] = array_merge(['Cant. bonos de transporte'], $bonosDeTransporte); + return $result; + } - try { - $writer = Writer::createFromPath(resource_path('csv/exports/transporte-por-barrio.csv'), 'w'); - $writer->insertAll($planilla); - } catch (CannotInsertRecord $e) { - var_export($e->getRecords()); - } + /** + * @return Collection + */ + public function productosPedidos($excluirBarriales = false, $excluirBonos = false): Collection + { + $query = DB::table('pedidos_aprobados') + ->where('grupo_de_compra_id', $this->id); + + if ($excluirBarriales) + $query = $query->where('producto_nombre','NOT LIKE','%barrial%'); + if ($excluirBonos) + $query = $query->where('producto_es_bono',false); + + return $query + ->get() + ->keyBy('producto_id'); } } diff --git a/app/Helpers/CanastaHelper.php b/app/Helpers/CanastaHelper.php index ce37cf7..9d3edcf 100644 --- a/app/Helpers/CanastaHelper.php +++ b/app/Helpers/CanastaHelper.php @@ -9,14 +9,15 @@ use DatabaseSeeder; use Illuminate\Support\Arr; use Illuminate\Support\Facades\DB; use Illuminate\Support\Str; -use League\Csv\Reader; + class CanastaHelper { - const FILA_HEADER = "Tipo"; - const ULTIMA_FILA = "TOTAL"; + const TIPO = "Tipo"; + const TOTAL = "TOTAL"; const ARCHIVO_SUBIDO = 'Archivo subido'; const CANASTA_CARGADA = 'Canasta cargada'; + const TIPOS_BONO = ["B", "F", "BE"]; public static function guardarCanasta($data, $path): string { $nombre = $data->getClientOriginalName(); @@ -31,53 +32,43 @@ class CanastaHelper public static function cargarCanasta($archivo) { self::limpiarTablas(); - $csv = Reader::createFromPath(resource_path($archivo), 'r'); - $csv->setDelimiter("|"); - $iHeader = self::obtenerIndiceDeHeader($csv); - $csv->setHeaderOffset($iHeader); - $registros = $csv->getRecords(); - + $registros = CsvHelper::getRecords($archivo); $toInsert = []; $categoria = ''; - foreach($registros as $i => $registro){ - //filas que están arriba del header - if ($i <= $iHeader){ - continue; - } - //finalizar - if ($registro[self::FILA_HEADER] == self::ULTIMA_FILA) { + foreach($registros as $i => $registro) { + // finalizar + if ($registro[self::TIPO] == self::TOTAL) break; - } - //filas que no tienen tipo - if (!Arr::has($registro,self::FILA_HEADER)|| trim($registro[self::FILA_HEADER]) == ''){ + // saltear filas que no tienen tipo + if (self::noTieneTipo($registro)) { var_dump("no hay tipo en la fila " . $i); continue; } - //saltear bono de transporte - if ($registro[self::FILA_HEADER] == "T"){ + // saltear bono de transporte + if ($registro[self::TIPO] == "T"){ continue; } - //obtener categoria + // obtener categoria si no hay producto if ($registro['Producto'] == '') { - //es la pregunta de la copa? - if (Str::contains($registro[self::FILA_HEADER],"¿")) { continue; } - $categoria = $registro[self::FILA_HEADER]; + // no es la pregunta de la copa? + if (!Str::contains($registro[self::TIPO],"¿")) + $categoria = $registro[self::TIPO]; continue; } - //completar producto + // completar producto $toInsert[] = [ 'fila' => $i, 'categoria' => $categoria, - 'nombre' => trim(str_replace('*', ' ',$registro['Producto'])), + 'nombre' => trim(str_replace('*', '',$registro['Producto'])), 'precio' => $registro['Precio'], 'proveedor_id' => self::obtenerProveedor($registro['Producto']), - 'bono' => $registro[self::FILA_HEADER] == "B", - 'requiere_notas'=> $registro[self::FILA_HEADER] =="PTC", + 'bono' => in_array($registro[self::TIPO], self::TIPOS_BONO), + 'requiere_notas'=> $registro[self::TIPO] =="PTC", ]; } @@ -90,18 +81,6 @@ class CanastaHelper self::log($archivo, self::CANASTA_CARGADA); } - private static function obtenerIndiceDeHeader($csv){ - $registros = $csv->getRecords(); - $iheader = 0; - foreach ($registros as $i => $registro){ - if (strtolower($registro[0]) == strtolower(self::FILA_HEADER)) { - $iheader = $i; - break; - } - } - return $iheader; - } - private static function obtenerProveedor($nombre) { $result = null; if (Str::contains($nombre,"*")){ @@ -137,7 +116,14 @@ class CanastaHelper private static function agregarBonoBarrial() { - $categoria = Producto::all()->pluck('categoria')->unique()->flatten()->first(function ($c) { return Str::contains($c, 'BONO'); }); + $categoria = Producto::all() + ->pluck('categoria') + ->unique() + ->flatten() + ->first(function ($c) { + return Str::contains($c, 'BONO'); + }); + DB::table('productos')->insert([ 'fila' => 420, 'nombre' => "Bono barrial", @@ -148,4 +134,13 @@ class CanastaHelper 'requiere_notas'=> false, ]); } + + /** + * @param $registro + * @return bool + */ + public static function noTieneTipo($registro): bool + { + return !Arr::has($registro, self::TIPO) || trim($registro[self::TIPO]) == ''; + } } diff --git a/app/Helpers/CsvHelper.php b/app/Helpers/CsvHelper.php new file mode 100644 index 0000000..95f2cfd --- /dev/null +++ b/app/Helpers/CsvHelper.php @@ -0,0 +1,40 @@ +setDelimiter("|"); + $csv->setEnclosure("'"); + $csv->setHeaderOffset(0); + return $csv->getRecords(); + } catch (InvalidArgument|Exception $e) { + Log::error($e->getMessage()); + return null; + } + } + + public static function generarCsv($filePath, $contenido, $headers = null): void + { + try { + $writer = Writer::createFromPath(resource_path($filePath), 'w'); + if ($headers) { + $writer->insertOne($headers); + } + $writer->insertAll($contenido); + } catch (CannotInsertRecord $e) { + Log::error($e->getMessage(), $e->getTrace()); + } + } +} diff --git a/app/Helpers/PdfHelper.php b/app/Helpers/PdfHelper.php new file mode 100644 index 0000000..b13ae35 --- /dev/null +++ b/app/Helpers/PdfHelper.php @@ -0,0 +1,29 @@ +generarHTML(); + $mpdf->WriteHTML($html); + $mpdf->AddPage(); + } + + $mpdf->Output($filepath, 'D'); + } +} diff --git a/app/Helpers/TransporteHelper.php b/app/Helpers/TransporteHelper.php index 8bfc3de..49ec37f 100644 --- a/app/Helpers/TransporteHelper.php +++ b/app/Helpers/TransporteHelper.php @@ -2,6 +2,9 @@ namespace App\Helpers; +use App\CanastaLog; +use Illuminate\Support\Facades\Log; + class TransporteHelper { const COSTO_TRANSPORTE = 15; @@ -16,4 +19,20 @@ class TransporteHelper { return self::cantidadTransporte($monto) * self::COSTO_TRANSPORTE; } + + public static function filaTransporte() + { + $ultimaCanasta = CanastaLog::where('descripcion', CanastaHelper::CANASTA_CARGADA) + ->orderBy('created_at', 'desc') + ->pluck('path') + ->first(); + + $registros = CsvHelper::getRecords($ultimaCanasta); + + foreach ($registros as $key => $registro) + if ($registro[CanastaHelper::TIPO] == 'T') return $key; + + Log::error('No hay fila de tipo T en la planilla: ' . $ultimaCanasta); + return null; + } } diff --git a/app/Http/Controllers/AdminController.php b/app/Http/Controllers/AdminController.php index 2b87532..44165ac 100644 --- a/app/Http/Controllers/AdminController.php +++ b/app/Http/Controllers/AdminController.php @@ -3,8 +3,7 @@ namespace App\Http\Controllers; use App\GrupoDeCompra; -use Illuminate\Http\Request; -use Response; +use Symfony\Component\HttpFoundation\BinaryFileResponse; class AdminController extends Controller { @@ -17,17 +16,19 @@ class AdminController extends Controller return view('auth/admin_subpedidos'); } - public function exportarPlanillasAPdf(GrupoDeCompra $gdc) { - return $gdc->exportarPlanillasAPdf(); + public function exportarPedidosAPdf(GrupoDeCompra $gdc) { + $gdc->exportarPedidosAPdf(); } - public function exportarPedidoACSV(GrupoDeCompra $gdc) { + public function exportarPedidoACSV(GrupoDeCompra $gdc): BinaryFileResponse + { $gdc->exportarPedidoEnCSV(); $file = resource_path('csv/exports/'.$gdc->nombre.'.csv'); return response()->download($file); } - public function exportarPedidoConNucleosACSV(GrupoDeCompra $gdc) { + public function exportarPedidoConNucleosACSV(GrupoDeCompra $gdc): BinaryFileResponse + { $gdc->exportarPedidoConNucleosEnCSV(); $file = resource_path('csv/exports/'.$gdc->nombre.'-completo.csv'); return response()->download($file); diff --git a/app/Http/Controllers/Api/ProductoController.php b/app/Http/Controllers/Api/ProductoController.php index 57f27fd..ed66c1f 100644 --- a/app/Http/Controllers/Api/ProductoController.php +++ b/app/Http/Controllers/Api/ProductoController.php @@ -10,24 +10,11 @@ use App\Producto; class ProductoController extends Controller { - /** - * Mostrar una lista de productos. - * - * @param App\Filtros\FiltroDeProducto $filtros - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Http\Response - */ public function index(FiltroDeProducto $filtros, Request $request) { return ProductoResource::collection(Producto::filtrar($filtros)->paginate(Producto::getPaginar($request))); } - /** - * Display the specified resource. - * - * @param \App\Producto $producto - * @return \Illuminate\Http\Response - */ public function show(Producto $producto) { return new ProductoResource($producto); diff --git a/app/Http/Controllers/Api/SubpedidoController.php b/app/Http/Controllers/Api/SubpedidoController.php index 4bd090a..d17d571 100644 --- a/app/Http/Controllers/Api/SubpedidoController.php +++ b/app/Http/Controllers/Api/SubpedidoController.php @@ -15,13 +15,6 @@ use Symfony\Component\HttpKernel\Exception\HttpException; class SubpedidoController extends Controller { - /** - * Mostrar una lista de productos. - * - * @param App\Filtros\FiltroDeSubpedido $filtros - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Http\Response - */ public function index(FiltroDeSubpedido $filtros, Request $request) { return Subpedido::filtrar($filtros)->get(); @@ -32,12 +25,6 @@ class SubpedidoController extends Controller return SubpedidoResource::collection(Subpedido::filtrar($filtros)->get()); } - /** - * Store a newly created resource in storage. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Http\Response - */ public function store(Request $request) { $validado = $this->validateSubpedido(); @@ -51,7 +38,8 @@ class SubpedidoController extends Controller return $s; } - protected function validateSubpedido(){ + protected function validateSubpedido(): array + { return request()->validate([ 'nombre' => 'required|max:255', 'grupo_de_compra_id' => [ @@ -61,12 +49,6 @@ class SubpedidoController extends Controller ]); } - /** - * Display the specified resource. - * - * @param \App\Subpedido $subpedido - * @return \Illuminate\Http\Response - */ public function show(Subpedido $subpedido) { return new SubpedidoResource($subpedido); diff --git a/app/Http/Controllers/ComprasController.php b/app/Http/Controllers/ComprasController.php index 92be64e..2aef574 100644 --- a/app/Http/Controllers/ComprasController.php +++ b/app/Http/Controllers/ComprasController.php @@ -5,7 +5,9 @@ namespace App\Http\Controllers; use App\GrupoDeCompra; use App\Helpers\CanastaHelper; use App\Producto; +use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; +use Symfony\Component\HttpFoundation\BinaryFileResponse; class ComprasController { @@ -15,22 +17,22 @@ class ComprasController return view('compras_pedidos'); } - public function descargarPedidos() { + public function descargarPedidos(): BinaryFileResponse + { Producto::planillaTotales(); $file = resource_path('csv/exports/pedidos-por-barrio.csv'); return response()->download($file); } - public function descargarNotas() { + public function descargarNotas(): BinaryFileResponse + { Producto::planillaNotas(); $file = resource_path('csv/exports/notas-por-barrio.csv'); return response()->download($file); } - public function descargarTransporte() { - GrupoDeCompra::planillaTransporte(); - $file = resource_path('csv/exports/transporte-por-barrio.csv'); - return response()->download($file); + public function pdf() { + GrupoDeCompra::exportarPedidosBarrialesAPdf(); } public function show() @@ -38,7 +40,7 @@ class ComprasController return view('auth/compras_login'); } - public function cargarCanasta(Request $request) + public function cargarCanasta(Request $request): JsonResponse { $request->validate([ 'data' => 'required|file|mimes:csv,txt|max:2048', @@ -49,10 +51,11 @@ class ComprasController return response()->json([ 'message' => 'Canasta cargada exitosamente', - ], 200); + ]); } - public function descargarCanastaEjemplo() { + public function descargarCanastaEjemplo(): BinaryFileResponse + { $file = resource_path('csv/productos.csv'); return response()->download($file); } diff --git a/app/Http/Controllers/ProductoController.php b/app/Http/Controllers/ProductoController.php index c7577d6..99391d8 100644 --- a/app/Http/Controllers/ProductoController.php +++ b/app/Http/Controllers/ProductoController.php @@ -2,8 +2,6 @@ namespace App\Http\Controllers; -use Illuminate\Http\Request; - class ProductoController extends Controller { /** @@ -16,11 +14,6 @@ class ProductoController extends Controller $this->middleware(['auth','subpedido']); } - /** - * Show the application dashboard. - * - * @return \Illuminate\Contracts\Support\Renderable - */ public function index() { return view('productos'); diff --git a/app/Http/Middleware/Admin.php b/app/Http/Middleware/Admin.php index 6eed291..df3fdb1 100644 --- a/app/Http/Middleware/Admin.php +++ b/app/Http/Middleware/Admin.php @@ -3,18 +3,12 @@ namespace App\Http\Middleware; use Closure; -use Auth; +use Illuminate\Support\Facades\Auth; +use Illuminate\Http\Request; class Admin { - /** - * Handle an incoming request. - * - * @param \Illuminate\Http\Request $request - * @param \Closure $next - * @return mixed - */ - public function handle($request, Closure $next) + public function handle(Request $request, Closure $next) { $user = Auth::user(); if ($user->is_admin) { diff --git a/app/Http/Middleware/Subpedido.php b/app/Http/Middleware/Subpedido.php index 66e8051..3319847 100644 --- a/app/Http/Middleware/Subpedido.php +++ b/app/Http/Middleware/Subpedido.php @@ -3,17 +3,18 @@ namespace App\Http\Middleware; use Closure; +use Illuminate\Http\Request; class Subpedido { /** * Handle an incoming request. * - * @param \Illuminate\Http\Request $request - * @param \Closure $next + * @param Request $request + * @param Closure $next * @return mixed */ - public function handle($request, Closure $next) + public function handle(Request $request, Closure $next) { if (!session('subpedido_nombre') || !session('subpedido_id')) { return redirect()->route('subpedidos.create'); diff --git a/app/Http/Resources/GrupoDeCompraResource.php b/app/Http/Resources/GrupoDeCompraResource.php index 3ff9cce..58a025b 100644 --- a/app/Http/Resources/GrupoDeCompraResource.php +++ b/app/Http/Resources/GrupoDeCompraResource.php @@ -2,6 +2,7 @@ namespace App\Http\Resources; +use Illuminate\Http\Request; use Illuminate\Http\Resources\Json\JsonResource; class GrupoDeCompraResource extends JsonResource @@ -9,10 +10,10 @@ class GrupoDeCompraResource extends JsonResource /** * Transform the resource into an array. * - * @param \Illuminate\Http\Request $request + * @param Request $request * @return array */ - public function toArray($request) + public function toArray($request): array { return [ 'id' => $this->id, @@ -23,8 +24,8 @@ class GrupoDeCompraResource extends JsonResource 'total_barrial' => number_format($this->totalBarrial(),2), 'total_devoluciones' => number_format($this->totalDevoluciones(),2), 'total_a_transferir' => number_format($this->totalATransferir(),2), - 'total_transporte' => number_format($this->totalTransporte(),0), - 'cantidad_transporte' => number_format($this->cantidadTransporte(),0), + 'total_transporte' => number_format($this->totalTransporte()), + 'cantidad_transporte' => number_format($this->cantidadTransporte()), ]; } } diff --git a/app/Http/Resources/ProductoResource.php b/app/Http/Resources/ProductoResource.php index 4040989..677af54 100644 --- a/app/Http/Resources/ProductoResource.php +++ b/app/Http/Resources/ProductoResource.php @@ -2,6 +2,7 @@ namespace App\Http\Resources; +use Illuminate\Http\Request; use Illuminate\Http\Resources\Json\JsonResource; class ProductoResource extends JsonResource @@ -9,10 +10,10 @@ class ProductoResource extends JsonResource /** * Transform the resource into an array. * - * @param \Illuminate\Http\Request $request + * @param Request $request * @return array */ - public function toArray($request) + public function toArray($request): array { return [ 'id' => $this->id, diff --git a/app/Http/Resources/SubpedidoResource.php b/app/Http/Resources/SubpedidoResource.php index d0da61f..98fd733 100644 --- a/app/Http/Resources/SubpedidoResource.php +++ b/app/Http/Resources/SubpedidoResource.php @@ -2,6 +2,7 @@ namespace App\Http\Resources; +use Illuminate\Http\Request; use Illuminate\Http\Resources\Json\JsonResource; class SubpedidoResource extends JsonResource @@ -9,10 +10,10 @@ class SubpedidoResource extends JsonResource /** * Transform the resource into an array. * - * @param \Illuminate\Http\Request $request + * @param Request $request * @return array */ - public function toArray($request) + public function toArray($request): array { return [ 'id' => $this->id, @@ -21,8 +22,8 @@ class SubpedidoResource extends JsonResource 'productos' => $this->productos, 'aprobado' => (bool) $this->aprobado, 'total' => number_format($this->total(),2), - 'total_transporte' => number_format($this->totalTransporte(),0), - 'cantidad_transporte' => number_format($this->cantidadTransporte(),0), + 'total_transporte' => number_format($this->totalTransporte()), + 'cantidad_transporte' => number_format($this->cantidadTransporte()), 'total_sin_devoluciones' => number_format($this->totalSinDevoluciones(),2), 'devoluciones_total' => number_format($this->devoluciones_total,2), 'devoluciones_notas' => $this->devoluciones_notas diff --git a/app/Producto.php b/app/Producto.php index 1d002a6..9b412c3 100644 --- a/app/Producto.php +++ b/app/Producto.php @@ -3,65 +3,61 @@ namespace App; use App\Filtros\FiltroDeProducto; +use App\Helpers\CsvHelper; +use App\Helpers\TransporteHelper; +use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\Relations\BelongsTo; +use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Http\Request; +use Illuminate\Support\Collection; use Illuminate\Support\Facades\DB; -use Illuminate\Support\Str; -use League\Csv\CannotInsertRecord; -use League\Csv\Reader; -use League\Csv\Writer; class Producto extends Model { public $timestamps = false; protected $fillable = ["nombre", "precio", "presentacion", "stock", "categoria"]; - static $paginarPorDefecto = 10; + static int $paginarPorDefecto = 10; - public function subpedidos() + public function subpedidos(): BelongsToMany { return $this->belongsToMany('App\Subpedido', 'productos_subpedidos')->withPivot(["cantidad", "notas"]); } - public function proveedor() + public function proveedor(): BelongsTo { return $this->belongsTo('App\Proveedor'); } - public function pagaTransporte() - { - return !($this->bono || Str::contains($this->categoria, 'SUBSIDIADO')); - } - //Este método permite que se apliquen los filtros al hacer una request (por ejemplo, de búsqueda) - public function scopeFiltrar($query, FiltroDeProducto $filtros) + public function scopeFiltrar($query, FiltroDeProducto $filtros): Builder { return $filtros->aplicar($query); } - public static function getPaginar(Request $request) + public static function getPaginar(Request $request): int { return $request->has('paginar') && intval($request->input('paginar')) ? intval($request->input('paginar')) : self::$paginarPorDefecto; } public static function productosFilaID() { - return Producto::pluck('id', 'fila',)->all(); + return Producto::pluck('id', 'fila')->all(); } public static function productosIDFila() { - return Producto::pluck('fila', 'id',)->all(); + return Producto::pluck('fila', 'id')->all(); } public static function productosIDNombre() { - return Producto::pluck('nombre', 'id',)->all(); + return Producto::pluck('nombre', 'id')->all(); } - static public function cantidadesPorBarrio() + static public function cantidadesPorBarrio(): Collection { - $barrios = DB::table('grupos_de_compra') - ->where('nombre', '<>', 'PRUEBA') + $barrios = GrupoDeCompra::barriosMenosPrueba() ->pluck('id', 'nombre'); $columnasBarrios = $barrios->map(function ($id, $nombre) { @@ -82,22 +78,28 @@ class Producto extends Model ->get(); } - static public function planillaTotales() { + static public function planillaTotales() + { $headers = ['Producto']; - $barrios = DB::table('grupos_de_compra') - ->where('nombre', '<>', 'PRUEBA') + $barrios = GrupoDeCompra::barriosMenosPrueba() ->pluck('nombre')->toArray(); $headers = array_merge($headers, $barrios); $cantidadesPorBarrio = self::cantidadesPorBarrio(); + $transportePorBarrio = GrupoDeCompra::transportePorBarrio(); $planilla = []; $ultimaFila = 1; + $filaTransporte = TransporteHelper::filaTransporte(); foreach ($cantidadesPorBarrio as $productoCantidades) { $fila = $productoCantidades->fila; while ($fila - $ultimaFila > 1) { $ultimaFila++; - $planilla[$ultimaFila] = ['---']; + if ($ultimaFila == $filaTransporte) { + $planilla[$ultimaFila] = ['Bono de transporte']; + } else { + $planilla[$ultimaFila] = ['---']; + } } $planilla[$fila] = [$productoCantidades->producto]; foreach ($barrios as $barrio) { @@ -106,16 +108,14 @@ class Producto extends Model $ultimaFila = $fila; } - try { - $writer = Writer::createFromPath(resource_path('csv/exports/pedidos-por-barrio.csv'), 'w'); - $writer->insertOne($headers); - $writer->insertAll($planilla); - } catch (CannotInsertRecord $e) { - var_export($e->getRecords()); + foreach ($transportePorBarrio as $key => $cantidad) { + $planilla[$filaTransporte][] = $cantidad; } + + CsvHelper::generarCsv('csv/exports/pedidos-por-barrio.csv', $planilla, $headers); } - public static function notasPorBarrio(): \Illuminate\Support\Collection + public static function notasPorBarrio(): Collection { return DB::table('productos') ->join('producto_subpedido', 'productos.id', '=', 'producto_subpedido.producto_id') @@ -133,8 +133,7 @@ class Producto extends Model static public function planillaNotas() { $headers = ['Producto']; - $barrios = DB::table('grupos_de_compra') - ->where('nombre', '<>', 'PRUEBA') + $barrios = GrupoDeCompra::barriosMenosPrueba() ->pluck('nombre')->toArray(); $headers = array_merge($headers, $barrios); @@ -150,12 +149,6 @@ class Producto extends Model $planilla[] = $fila; } - try { - $writer = Writer::createFromPath(resource_path('csv/exports/notas-por-barrio.csv'), 'w'); - $writer->insertOne($headers); - $writer->insertAll($planilla); - } catch (CannotInsertRecord $e) { - var_export($e->getRecords()); - } + CsvHelper::generarCsv('csv/exports/notas-por-barrio.csv', $planilla, $headers); } } diff --git a/app/Proveedor.php b/app/Proveedor.php index 20af175..07dbc40 100644 --- a/app/Proveedor.php +++ b/app/Proveedor.php @@ -3,14 +3,15 @@ namespace App; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\Relations\HasMany; class Proveedor extends Model { public $timestamps = false; protected $fillable = [ "nombre","direccion","telefono","correo","comentario" ]; protected $table = 'proveedores'; - - public function productos() + + public function productos(): HasMany { return $this->hasMany('App\Producto'); } diff --git a/app/Subpedido.php b/app/Subpedido.php index f99dfdd..0370020 100644 --- a/app/Subpedido.php +++ b/app/Subpedido.php @@ -3,43 +3,33 @@ namespace App; use App\Helpers\TransporteHelper; +use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\Relations\BelongsTo; +use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Support\Facades\DB; -use Log; use App\Filtros\FiltroDeSubpedido; class Subpedido extends Model { - const COSTO_TRANSPORTE = 15; public $timestamps = false; - protected $fillable = ['grupo_de_compra_id', 'aprobado', 'nombre', 'devoluciones_total', 'devoluciones_notas']; + protected $fillable = ['grupo_de_compra_id', 'aprobado', 'nombre', 'devoluciones_total', 'devoluciones_notas']; - public function productos() - { - return $this->belongsToMany('App\Producto')->withPivot(["cantidad","total", "notas"]); - } + public function productos(): BelongsToMany + { + return $this->belongsToMany('App\Producto')->withPivot(["cantidad", "total", "notas"]); + } - //Bonos del MPS, Sororo, etc. NO devuelve bonos de transporte - private function bonos() - { - return $this->productos()->where('bono',1); - } + public function grupoDeCompra(): BelongsTo + { + return $this->belongsTo('App\GrupoDeCompra'); + } - public function productosSinBonos() - { - return $this->productos()->where('bono',false); - } - - public function grupoDeCompra() - { - return $this->belongsTo('App\GrupoDeCompra'); - } - - //Permite que se apliquen los filtros al hacer una request (por ejemplo, de búsqueda) - public function scopeFiltrar($query, FiltroDeSubpedido $filtros) - { - return $filtros->aplicar($query); - } + // Permite que se apliquen los filtros al hacer una request (por ejemplo, de búsqueda) + public function scopeFiltrar($query, FiltroDeSubpedido $filtros): Builder + { + return $filtros->aplicar($query); + } public function total() { @@ -102,36 +92,40 @@ class Subpedido extends Model return TransporteHelper::cantidadTransporte($this->totalCentralesQuePaganTransporte()); } - //Actualiza el pedido, agregando o quitando del subpedido según sea necesario. Debe ser llamado desde el controlador de subpedidos, luego de validar que los parámetros $producto y $cantidad son correctos. También calcula el subtotal por producto. - public function syncProducto(Producto $producto, Int $cantidad, string $notas) { - if ($cantidad){ - //si la cantidad es 1 o más se agrega el producto o actualiza la cantidad - $this->productos()->syncWithoutDetaching([ - $producto->id => [ - 'cantidad' => $cantidad, - 'total' => $cantidad * $producto->precio, - 'notas' => $notas, - ] - ]); + //Actualiza el pedido, agregando o quitando del subpedido según sea necesario. Debe ser llamado desde el controlador de subpedidos, luego de validar que los parámetros $producto y $cantidad son correctos. También calcula el subtotal por producto. + public function syncProducto(Producto $producto, int $cantidad, string $notas) + { + if ($cantidad) { + //si la cantidad es 1 o más se agrega el producto o actualiza la cantidad + $this->productos()->syncWithoutDetaching([ + $producto->id => [ + 'cantidad' => $cantidad, + 'total' => $cantidad * $producto->precio, + 'notas' => $notas, + ] + ]); } else { //si la cantidad es 0, se elimina el producto del subpedido $this->productos()->detach($producto->id); } - } + } - public function toggleAprobacion(bool $aprobacion) { - $this->aprobado = $aprobacion; - $this->save(); - } + public function toggleAprobacion(bool $aprobacion) + { + $this->aprobado = $aprobacion; + $this->save(); + } - public function generarHTML() { - $view = view("pdfgen.subpedido_tabla", ["subpedido" => $this]); - return $view->render(); - } + public function generarHTML() + { + $view = view("pdfgen.pedido_tabla", ["pedido" => $this]); + return $view->render(); + } - public function syncDevoluciones(float $total, string $notas) { - $this->devoluciones_total = $total; - $this->devoluciones_notas = $notas; - $this->save(); - } + public function syncDevoluciones(float $total, string $notas) + { + $this->devoluciones_total = $total; + $this->devoluciones_notas = $notas; + $this->save(); + } } diff --git a/app/User.php b/app/User.php index 9d9c786..5f45a74 100644 --- a/app/User.php +++ b/app/User.php @@ -2,7 +2,7 @@ namespace App; -use Illuminate\Contracts\Auth\MustVerifyEmail; +use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; @@ -38,7 +38,7 @@ class User extends Authenticatable ]; - public function grupoDeCompra() + public function grupoDeCompra(): BelongsTo { return $this->belongsTo('App\GrupoDeCompra'); } diff --git a/database/factories/UserFactory.php b/database/factories/UserFactory.php index 741edea..2955bd8 100644 --- a/database/factories/UserFactory.php +++ b/database/factories/UserFactory.php @@ -1,9 +1,10 @@ setDelimiter("|"); - $csv->setEnclosure("'"); - $csv->setHeaderOffset(0); - $registros = $csv->getRecords(); + $registros = CsvHelperAlias::getRecords('csv/barrios.csv'); $gdcToInsert = []; $usersToInsert = []; diff --git a/resources/js/components/compras/Body.vue b/resources/js/components/compras/Body.vue index 8bcf794..8225e77 100644 --- a/resources/js/components/compras/Body.vue +++ b/resources/js/components/compras/Body.vue @@ -20,10 +20,9 @@ La planilla de la canasta tiene que tener el siguiente formato para que la aplicación la lea correctamente:
- {{ $producto->nombre }}
- @if($producto->pivot->notas)
- Talle/Color: {{ $producto->pivot->notas }} + {{ $producto['nombre'] }} + @if($producto['pivot']['notas']) + Talle/Color: {{ $producto['pivot']['notas'] }} @endif |
- {{ $producto->pivot->cantidad }} + {{ $producto['pivot']['cantidad'] }} |