diff --git a/app/GrupoDeCompra.php b/app/GrupoDeCompra.php index 98207f6..31cdfb0 100644 --- a/app/GrupoDeCompra.php +++ b/app/GrupoDeCompra.php @@ -233,10 +233,36 @@ class GrupoDeCompra extends Model // Guardar en un archivo .csv try { - $writer = Writer::createFromPath(resource_path('csv/exports/total-pedidos.csv'), 'w'); - $writer->insertAll($planilla); + $writer = Writer::createFromPath(resource_path('csv/exports/total-pedidos.csv'), 'w'); + $writer->insertAll($planilla); } catch (CannotInsertRecord $e) { - var_export($e->getRecords()); + var_export($e->getRecords()); + } + } + + public static function exportarProductosConNotasEnCSV() { + $gdcs = GrupoDeCompra::all(); + foreach ($gdcs as $i => $gdc) { + $productos_en_pedido = DB::table('pedidos_aprobados')->where('grupo_de_compra_id', $gdc->id)->get()->keyBy('producto_id'); + $pedidos = $gdc->pedidosAprobados(); + foreach ($productos_en_pedido as $id => $producto_pedido) { + foreach ($pedidos as $pedido) { + $producto = $pedido->productos()->find($id); + if ($producto != null && $producto->requiere_notas) { + $planilla[$i+1][0] = $gdc->nombre; + $planilla[$i+1][1] = $producto->nombre; + $planilla[$i+1][2] = $producto->pivot->cantidad; + $planilla[$i+1][3] = $producto->pivot->notas; + } + } + } + } + // Guardar en un archivo .csv + try { + $writer = Writer::createFromPath(resource_path('csv/exports/pedidos-notas.csv'), 'w'); + $writer->insertAll($planilla); + } catch (CannotInsertRecord $e) { + var_export($e->getRecords()); } } } diff --git a/app/Http/Controllers/Api/SubpedidoController.php b/app/Http/Controllers/Api/SubpedidoController.php index 00c9302..7f57cab 100644 --- a/app/Http/Controllers/Api/SubpedidoController.php +++ b/app/Http/Controllers/Api/SubpedidoController.php @@ -79,6 +79,7 @@ class SubpedidoController extends Controller $valid = request()->validate([ 'cantidad' => 'required|min:0', + 'notas' => 'nullable', 'producto_id' => [ 'required', Rule::in(Producto::all()->pluck('id')), @@ -86,7 +87,11 @@ class SubpedidoController extends Controller ]); $producto = Producto::find($valid['producto_id']); - $subpedido->syncProducto($producto, $valid['cantidad']); + $notas = $valid['notas']; + if ($notas == null) { + $notas = ""; + } + $subpedido->syncProducto($producto, $valid['cantidad'], $notas); return new SubpedidoResource($subpedido); } diff --git a/app/Http/Controllers/ComprasController.php b/app/Http/Controllers/ComprasController.php index 5c7e3d1..e39eeda 100644 --- a/app/Http/Controllers/ComprasController.php +++ b/app/Http/Controllers/ComprasController.php @@ -15,6 +15,12 @@ class ComprasController $file = resource_path('csv/exports/total-pedidos.csv'); return response()->download($file); } + + public function descargarNotas() { + GrupoDeCompra::exportarProductosConNotasEnCSV(); + $file = resource_path('csv/exports/pedidos-notas.csv'); + return response()->download($file); + } public function show() { diff --git a/app/Http/Resources/ProductoResource.php b/app/Http/Resources/ProductoResource.php index 5177696..4040989 100644 --- a/app/Http/Resources/ProductoResource.php +++ b/app/Http/Resources/ProductoResource.php @@ -25,7 +25,8 @@ class ProductoResource extends JsonResource 'imagen' => optional($this->poster)->url(), 'descripcion' => $this->descripcion, 'apto_veganxs' => $this->apto_veganxs, - 'apto_celiacxs' => $this->apto_celiacxs + 'apto_celiacxs' => $this->apto_celiacxs, + 'requiere_notas' => $this->requiere_notas, ]; } } diff --git a/app/Producto.php b/app/Producto.php index f3fb6b4..1a70545 100644 --- a/app/Producto.php +++ b/app/Producto.php @@ -15,7 +15,7 @@ class Producto extends Model public function subpedidos() { - return $this->belongsToMany('App\Subpedido','productos_subpedidos')->withPivot(["cantidad"]); + return $this->belongsToMany('App\Subpedido','productos_subpedidos')->withPivot(["cantidad", "notas"]); } public function proveedor() diff --git a/app/Subpedido.php b/app/Subpedido.php index 136716f..62eccb1 100644 --- a/app/Subpedido.php +++ b/app/Subpedido.php @@ -15,7 +15,7 @@ class Subpedido extends Model public function productos() { - return $this->belongsToMany('App\Producto')->withPivot(["cantidad","total"]); + return $this->belongsToMany('App\Producto')->withPivot(["cantidad","total", "notas"]); } //Bonos del MPS, Sororo, etc. NO devuelve bonos de transporte @@ -84,13 +84,14 @@ class Subpedido extends Model } //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) { + 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 + 'total' => $cantidad * $producto->precio, + 'notas' => $notas, ] ]); } else { diff --git a/database/migrations/2024_09_17_234635_notas_producto.php b/database/migrations/2024_09_17_234635_notas_producto.php new file mode 100644 index 0000000..898db8d --- /dev/null +++ b/database/migrations/2024_09_17_234635_notas_producto.php @@ -0,0 +1,32 @@ +string('notas')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('producto_subpedido', function (Blueprint $table) { + $table->dropColumn('notas'); + }); + } +} diff --git a/database/migrations/2024_09_19_230732_producto_requiere_notas.php b/database/migrations/2024_09_19_230732_producto_requiere_notas.php new file mode 100644 index 0000000..065fff4 --- /dev/null +++ b/database/migrations/2024_09_19_230732_producto_requiere_notas.php @@ -0,0 +1,32 @@ +boolean('requiere_notas')->default(false); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('productos', function (Blueprint $table) { + $table->dropColumn('requiere_notas'); + }); + } +} diff --git a/database/seeds/CanastaSeeder.php b/database/seeds/CanastaSeeder.php index f9a5756..0edc5b5 100644 --- a/database/seeds/CanastaSeeder.php +++ b/database/seeds/CanastaSeeder.php @@ -61,7 +61,8 @@ class CanastaSeeder extends Seeder 'nombre' => trim(str_replace('*', ' ',$registro['Producto'])), 'precio' => $registro['Precio'], 'proveedor_id' => $this->obtenerProveedor($registro['Producto']), - 'bono' => $registro[$this::FILA_HEADER] == "B" + 'bono' => $registro[$this::FILA_HEADER] == "B", + 'requiere_notas'=> $registro[$this::FILA_HEADER] =="PTC", ]; } diff --git a/database/seeds/DatabaseSeeder.php b/database/seeds/DatabaseSeeder.php index b71ca5a..abc15ac 100644 --- a/database/seeds/DatabaseSeeder.php +++ b/database/seeds/DatabaseSeeder.php @@ -13,5 +13,6 @@ class DatabaseSeeder extends Seeder public function run() { $this->call(CanastaSeeder::class); + $this->call(GrupoDeCompraSeeder::class); } } diff --git a/database/seeds/GrupoDeCompraSeeder.php b/database/seeds/GrupoDeCompraSeeder.php index 89a0982..6c634da 100644 --- a/database/seeds/GrupoDeCompraSeeder.php +++ b/database/seeds/GrupoDeCompraSeeder.php @@ -31,14 +31,14 @@ class GrupoDeCompraSeeder extends Seeder $usersToInsert[] = [ 'name' => $registro['barrio'], - 'password' => Hash::make($registro['barrio']), + 'password' => Hash::make("asd"), "is_admin" => 0, 'grupo_de_compra_id' => $key ]; $usersToInsert[] = [ 'name' => $registro['barrio'] . "_admin", - 'password' => Hash::make($registro['barrio'] . "admin"), + 'password' => Hash::make("asd"), "is_admin" => 1, 'grupo_de_compra_id' => $key ]; diff --git a/resources/js/app.js b/resources/js/app.js index e08d2a7..d61ca56 100644 --- a/resources/js/app.js +++ b/resources/js/app.js @@ -70,6 +70,10 @@ const app = new Vue({ cantidad(producto) { let pedido = this.productos.some(p => p.id == producto.id) return pedido ? this.productos.find(p => p.id == producto.id).pivot.cantidad : 0 + }, + notas(producto) { + let pedido = this.productos.some(p => p.id == producto.id); + return pedido ? this.productos.find(p => p.id == producto.id).pivot.notas : ""; }, settearDevoluciones() { axios.get(`/api/grupos-de-compra/${this.gdc}/devoluciones`) @@ -99,14 +103,15 @@ const app = new Vue({ } }) }) - Event.$on('sync-subpedido', (cantidad, id) => { + Event.$on('sync-subpedido', (cantidad, id, notas) => { if (this.pedido.aprobado) { this.$toast('No se puede modificar un pedido ya aprobado', 2000); return; } axios.post("/api/subpedidos/" + this.pedido.id + "/sync", { cantidad: cantidad, - producto_id: id + producto_id: id, + notas: notas, }).then((response) => { this.pedido = response.data.data this.$toast('Pedido actualizado exitosamente') diff --git a/resources/js/components/compras/Body.vue b/resources/js/components/compras/Body.vue index 6b0a468..07c3786 100644 --- a/resources/js/components/compras/Body.vue +++ b/resources/js/components/compras/Body.vue @@ -11,6 +11,16 @@

+
+

+ + + + + Descargar planilla de notas + +

+
diff --git a/resources/js/components/pedidos/ProductoCantidad.vue b/resources/js/components/pedidos/ProductoCantidad.vue index 93ec5cd..49d5799 100644 --- a/resources/js/components/pedidos/ProductoCantidad.vue +++ b/resources/js/components/pedidos/ProductoCantidad.vue @@ -1,28 +1,44 @@ @@ -33,21 +49,24 @@ }, data() { return { - cantidad: this.producto.cantidad, - enChismosa: this.producto.cantidad, + cantidad: this.cantidadEnChismosa(), + notas: this.notasEnChismosa(), + notas_warning_visible: false, } }, mounted() { - if (this.producto.pivot !== undefined) { - this.cantidad = this.producto.pivot.cantidad; - this.enChismosa = this.cantidad; - } - Event.$on('sync-subpedido', (cantidad,productoId) => { - if (this.producto.id === productoId) - this.sincronizar(cantidad); + Event.$on('sync-subpedido', (cantidad, productoId, notas) => { + if (this.producto.id === productoId) + this.sincronizar(cantidad, notas); }); }, methods: { + notasEnChismosa() { + return this.producto.pivot !== undefined ? this.producto.pivot.notas : ""; + }, + cantidadEnChismosa() { + return this.producto.pivot !== undefined ? this.producto.pivot.cantidad : 0; + }, decrementar() { this.cantidad -= 1; }, @@ -55,26 +74,39 @@ this.cantidad += 1; }, confirmar() { - Event.$emit('sync-subpedido', this.cantidad, this.producto.id); + if (this.warningNotas()) { + this.notas_warning_visible = true; + return; + } + console.log("Emit sync " + this.cantidad + " " + this.notas); + Event.$emit('sync-subpedido', this.cantidad, this.producto.id, this.notas); }, borrar() { this.cantidad = 0; this.confirmar(); }, - sincronizar(cantidad) { + sincronizar(cantidad, notas) { + this.notas_warning_visible = false; + this.notas = notas; this.cantidad = cantidad; - if (this.producto.pivot != null) { + if (this.producto.pivot !== undefined) { this.producto.pivot.cantidad = cantidad; - } else { - this.producto.cantidad = cantidad; + this.producto.pivot.notas = notas; } - this.enChismosa = cantidad; }, hayCambios() { - return this.cantidad != this.enChismosa; + if (this.cantidad != this.cantidadEnChismosa()) return true; + + return this.cantidad > 0 && this.notas != this.notasEnChismosa(); }, puedeBorrar() { - return this.enChismosa > 0; + return this.cantidadEnChismosa() > 0; + }, + warningNotas() { + return this.producto.requiere_notas && this.cantidad > 0 && !this.notas; + }, + disableConfirm() { + return !this.hayCambios(); }, } } @@ -97,4 +129,12 @@ .contador { min-width: 178px; } + + .is-danger { + background-color: #fca697; + } + .is-danger::placeholder { + color: #fff; + opacity: 1; /* Firefox */ + } \ No newline at end of file diff --git a/resources/js/components/pedidos/ProductoCard.vue b/resources/js/components/pedidos/ProductoCard.vue index 320a9fd..cabdd5f 100644 --- a/resources/js/components/pedidos/ProductoCard.vue +++ b/resources/js/components/pedidos/ProductoCard.vue @@ -8,12 +8,13 @@ export default { return { cantidad: this.producto.cantidad, enChismosa: this.producto.cantidad, + notas: this.producto.notas, } }, mounted() { - Event.$on('sync-subpedido', (cantidad,productoId) => { + Event.$on('sync-subpedido', (cantidad, productoId, notas) => { if (this.producto.id === productoId) - this.sincronizar(cantidad); + this.sincronizar(cantidad, notas); }); }, methods: { @@ -24,19 +25,21 @@ export default { this.cantidad += 1; }, confirmar() { - Event.$emit('sync-subpedido', this.cantidad, this.producto.id); + Event.$emit('sync-subpedido', this.cantidad, this.producto.id, this.notas); }, borrar() { this.cantidad = 0; this.confirmar(); }, - sincronizar(cantidad) { + sincronizar(cantidad, notas) { this.cantidad = cantidad; this.producto.cantidad = cantidad; this.enChismosa = cantidad; + this.notas = notas; + this.producto.notas = notas; }, hayCambios() { - return this.cantidad != this.enChismosa; + return this.cantidad != this.enChismosa || this.notas != this.producto.notas; }, puedeBorrar() { return this.enChismosa > 0; diff --git a/resources/js/components/pedidos/ProductosContainer.vue b/resources/js/components/pedidos/ProductosContainer.vue index 0979855..3719d7d 100644 --- a/resources/js/components/pedidos/ProductosContainer.vue +++ b/resources/js/components/pedidos/ProductosContainer.vue @@ -34,7 +34,11 @@ export default { params: this.params(filtro,valor) }).then(response => { this.productos = response.data.data; - this.productos.forEach(p => p.cantidad = this.$root.cantidad(p)) + this.productos.forEach(p => { + p.pivot = {}; + p.pivot.cantidad = this.$root.cantidad(p); + p.pivot.notas = this.$root.notas(p); + }); }); this.visible = true; Event.$emit("migas-agregar",this.miga); diff --git a/resources/views/pdfgen/subpedido_tabla.blade.php b/resources/views/pdfgen/subpedido_tabla.blade.php index 41e1173..981d0ba 100644 --- a/resources/views/pdfgen/subpedido_tabla.blade.php +++ b/resources/views/pdfgen/subpedido_tabla.blade.php @@ -27,9 +27,13 @@ @foreach($subpedido->productos as $producto) @if(!$producto->bono) + {{ $producto->nombre }} + @if($producto->pivot->notas) +
Talle/Color: {{ $producto->pivot->notas }} + @endif {{ $producto->pivot->cantidad }} diff --git a/routes/web.php b/routes/web.php index c2b0ea0..baaa801 100644 --- a/routes/web.php +++ b/routes/web.php @@ -81,4 +81,5 @@ Route::get('/compras', 'ComprasController@show')->name('compras_login.show'); Route::middleware(['compras'])->group( function() { Route::get('/compras/pedidos', 'ComprasController@indexPedidos')->name('compras.pedidos'); Route::get('/compras/pedidos/descargar', 'ComprasController@descargarPedidos')->name('compras.pedidos.descargar'); + Route::get('/compras/pedidos/notas', 'ComprasController@descargarNotas')->name('compras.pedidos.descargar'); });