Compare commits

...

18 Commits

Author SHA1 Message Date
Rodrigo c1af6909c4 No habilitar sync producto si cantidad es 0 2024-10-08 20:33:20 -03:00
Rodrigo e31c375867 Ajuste visual de notas 2024-10-08 20:28:58 -03:00
Rodrigo 6d10fbc0bf Sincronizar notas de producto 2024-10-08 20:16:25 -03:00
Rodrigo 9fc47513c2 Arreglo para usuarios por defecto 2024-09-19 22:31:58 -03:00
Rodrigo ff332fadc1 Merge branch 'master' into funcion/notas-producto 2024-09-19 21:47:09 -03:00
Rodrigo e106faceda Merge pull request 'nueva-chismosa' (#35) from nueva-chismosa into master
Reviewed-on: #35
2024-09-19 21:42:43 -03:00
Rodrigo 5ef5e93543 Merge remote-tracking branch 'origin/master' into nueva-chismosa 2024-09-19 21:22:24 -03:00
Rodrigo 177ba193de Agregado "requiere notas" a productos con 'PTC' 2024-09-19 20:58:44 -03:00
Rodrigo 52bea8f9b6 Ajustes de medidas en chismosa 2024-09-17 20:13:34 -03:00
Rodrigo d2fde9df83 Revert "Auto sincronziar producto después de 3 segundos"
This reverts commit 80a28f4162.
2024-09-17 19:14:30 -03:00
Rodrigo 80a28f4162 Auto sincronziar producto después de 3 segundos 2024-09-16 20:56:15 -03:00
Rodrigo 1586a1190a Arreglo y ajuste a devoluciones en chismosa 2024-09-16 09:25:37 -03:00
Rodrigo a998f76d44 Arreglo a ProductoCantidad 2024-09-16 09:25:26 -03:00
Rodrigo b845637064 Arreglé todos los errores al inicio 2024-09-15 18:09:23 -03:00
Rodrigo 6fc7021317 ProductoCantidad template WIP 2024-09-15 12:48:34 -03:00
Rodrigo 728c54b3f3 Agregado margen a la chismosa 2024-09-15 11:53:14 -03:00
Rodrigo fbae6770df Cismosa: Ajustes visuales 2024-09-10 22:07:16 -03:00
Rodrigo 69cd306263 Moví la chismosa a la derecha de los productos 2024-09-10 21:31:49 -03:00
18 changed files with 329 additions and 150 deletions

View File

@ -79,7 +79,7 @@ class SubpedidoController extends Controller
$valid = request()->validate([
'cantidad' => 'required|min:0',
'notas' => 'required',
'notas' => 'nullable',
'producto_id' => [
'required',
Rule::in(Producto::all()->pluck('id')),
@ -87,7 +87,11 @@ class SubpedidoController extends Controller
]);
$producto = Producto::find($valid['producto_id']);
$subpedido->syncProducto($producto, $valid['cantidad'], $valid['notas']);
$notas = $valid['notas'];
if ($notas == null) {
$notas = "";
}
$subpedido->syncProducto($producto, $valid['cantidad'], $notas);
return new SubpedidoResource($subpedido);
}

View File

@ -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,
];
}
}

View File

@ -14,8 +14,7 @@ class NotasProducto extends Migration
public function up()
{
Schema::table('producto_subpedido', function (Blueprint $table) {
$table->string('notas');
$table->boolean('requiere-notas');
$table->string('notas')->nullable();
});
}
@ -28,7 +27,6 @@ class NotasProducto extends Migration
{
Schema::table('producto_subpedido', function (Blueprint $table) {
$table->dropColumn('notas');
$table->dropColumn('requiere-notas');
});
}
}

View File

@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class ProductoRequiereNotas extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('productos', function (Blueprint $table) {
$table->boolean('requiere_notas')->default(false);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('productos', function (Blueprint $table) {
$table->dropColumn('requiere_notas');
});
}
}

View File

@ -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",
];
}

View File

@ -13,5 +13,6 @@ class DatabaseSeeder extends Seeder
public function run()
{
$this->call(CanastaSeeder::class);
$this->call(GrupoDeCompraSeeder::class);
}
}

View File

@ -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
];

7
resources/js/app.js vendored
View File

@ -95,6 +95,7 @@ const app = new Vue({
axios.get('/api/subpedidos/' + this.pedido)
.then(response => {
this.pedido = response.data.data;
Event.$emit("pedido-actualizado");
});
} else {
axios.get('/admin/obtener_sesion')
@ -116,21 +117,23 @@ const app = new Vue({
}).then((response) => {
this.pedido = response.data.data
this.$toast('Pedido actualizado exitosamente')
Event.$emit("pedido-actualizado");
});
});
});
// Actualizar monto y notas de devoluciones
Event.$on('sync-devoluciones', (total, 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_devoluciones", {
total: total,
notas: notas,
}).then((response) => {
this.pedido = response.data.data;
this.$toast('Pedido actualizado');
Event.$emit("pedido-actualizado");
});
});

View File

@ -1,10 +1,31 @@
<template>
<div v-show="this.$root.pedido.aprobado" class="notification is-warning has-text-centered">
<div v-show="aprobado" class="notification is-warning has-text-centered">
Tu pedido fue <strong>aprobado</strong>, por lo que no puede ser modificado
</div>
</template>
<script>
export default {
data() {
return {
aprobado: false,
}
},
mounted() {
Event.$on('pedido-actualizado', this.actualizarEstado);
if (this.$root.pedido != null) {
this.actualizarEstado();
}
},
methods: {
pedidoAprobado: function() {
return this.$root.pedido.aprobado;
},
actualizarEstado: function() {
this.aprobado = this.pedidoAprobado();
},
},
}
</script>
<style>

View File

@ -1,5 +1,5 @@
<template>
<div v-show="visible" class="block ml-3 mr-3">
<div v-show="visible" class="column">
<div class="columns is-multiline is-mobile">
<div v-for="(categoria,i) in categorias" :key="i" class="block column is-one-quarter-desktop is-one-third-tablet is-half-mobile">
<div @click.capture="seleccionarCategoria(categoria)" class="card" style="height:100%" >

View File

@ -1,55 +1,83 @@
<template>
<div>
<table v-show="productos.length != 0" class="chismosa-tabla table is-narrow is-striped is-bordered">
<thead>
<tr>
<th>Producto</th>
<th><abbr title="Cantidad">C</abbr></th>
<th><abbr title="Precio Total">$</abbr></th>
<th><abbr title="Eliminar"></abbr></th>
</tr>
</thead>
<tfoot>
<tr>
<th><abbr title="Bonos de Transporte">B. Transporte</abbr></th>
<th class="has-text-right">{{ cantidadBonosDeTransporte }}</th>
<th class="has-text-right">{{ totalBonosDeTransporte }}</th>
<th></th>
</tr>
<tr v-if="this.$root.devoluciones">
<th><p>Devoluciones</p></th>
<td><p :title="this.$root.pedido.devoluciones_notas">...</p></td>
<th class="has-text-right">-{{ this.$root.pedido.devoluciones_total }}</th>
<th>
<button @click.capture="modificarDevoluciones()" class="button is-warning">
<span class="icon">
<i class="fas fa-edit"></i>
</span>
</button>
</th>
</tr>
<tr>
<th>Total total</th>
<th></th>
<th class="has-text-right">{{ total }}</th>
<th></th>
</tr>
</tfoot>
<tbody>
<producto-row v-for="producto in productos" :producto="producto" :key="producto.id"></producto-row>
</tbody>
</table>
<p class="has-text-centered" v-show="productos.length == 0">
Compa, todavía no agregaste nada a la chismosa.
</p>
<div class="column is-one-third">
<div class="fixed-right">
<table v-show="mostrar_tabla" class="table is-striped is-bordered tabla-chismosa is-narrow">
<thead>
<tr>
<th>Producto</th>
<th>Cantidad</th>
<th><abbr title="Precio Total">$</abbr></th>
</tr>
</thead>
<tfoot>
<tr>
<th><abbr title="Bonos de Transporte">B. Transporte</abbr></th>
<th class="has-text-right">{{ cantidad_bonos_transporte }}</th>
<th class="has-text-right">{{ total_bonos_transporte }}</th>
</tr>
<tr v-if="this.$root.devoluciones">
<th><p>Devoluciones</p></th>
<td>
<abbr :title="notas_devoluciones">{{ notas_devoluciones_abbr }}</abbr>
<button @click.capture="modificarDevoluciones()" class="button is-warning is-small">
<span class="icon">
<i class="fas fa-edit"></i>
</span>
</button>
</td>
<th class="has-text-right">-{{ devoluciones }}</th>
</tr>
<tr>
<th>Total total</th>
<th></th>
<th class="has-text-right">{{ total }}</th>
</tr>
</tfoot>
<tbody>
<producto-row v-for="producto in productos" :producto="producto" :key="producto.id"></producto-row>
</tbody>
</table>
<p class="has-text-centered" v-show="!mostrar_tabla">
Compa, todavía no agregaste nada a la chismosa.
</p>
</div>
</div>
</template>
<script>
export default {
computed: {
productos: function() {
return this.$root.productos
data() {
return {
mostrar_tabla: false,
cantidad_bonos_transporte: 0,
total_bonos_transporte: 0,
devoluciones: 0,
notas_devoluciones: "",
notas_devoluciones_abbr: "",
total: 0,
productos: [],
}
},
mounted() {
Event.$on('pedido-actualizado', this.pedidoActualizado);
Event.$on('toggle-chismosa', this.pedidoActualizado);
},
methods: {
pedidoActualizado: function() {
this.mostrar_tabla = this.$root.productos.length > 0;
this.cantidad_bonos_transporte = this.cantidadBonosDeTransporte();
this.total_bonos_transporte = this.totalBonosDeTransporte();
this.devoluciones = this.$root.pedido.devoluciones_total;
this.notas_devoluciones = this.$root.pedido.devoluciones_notas;
this.notas_devoluciones_abbr = this.notas_devoluciones.substring(0, 15);
if (this.notas_devoluciones.length > 15) {
this.notas_devoluciones_abbr += "...";
}
this.total = this.$limpiarInt(this.$root.devoluciones ? this.$root.pedido.total_menos_devoluciones : this.$root.pedido.total);
this.productos = this.$root.productos
},
modificarDevoluciones: function() {
Event.$emit("modificar-devoluciones");
},
cantidadBonosDeTransporte: function() {
return this.$limpiarInt(this.$root.pedido.subtotal_bonos_de_transporte) / 15
@ -57,22 +85,18 @@
totalBonosDeTransporte: function() {
return this.$limpiarInt(this.$root.pedido.subtotal_bonos_de_transporte)
},
total: function() {
return this.$limpiarInt(this.$root.devoluciones ? this.$root.pedido.total_menos_devoluciones : this.$root.pedido.total)
}
},
methods: {
modificarDevoluciones: function() {
Event.$emit("modificar-devoluciones");
},
}
}
</script>
<style>
@media (max-width: 719px) {
.chismosa-tabla {
max-width: 80vw;
.tabla-chismosa {
width: 100%;
}
}
</style>
.fixed-right {
position: fixed;
overflow-y: auto;
max-height: 81vh;
margin-right: 20px;
}
</style>

View File

@ -5,16 +5,9 @@
<span class="icon is-small mr-1">
<img src="/assets/chismosa.png">
</span>
<span v-text="'$' + this.$limpiarInt($root.devoluciones ? $root.pedido.total_menos_devoluciones : $root.pedido.total)"></span>
<span v-text="'$' + total"></span>
</a>
</div>
<div class="dropdown-menu chismosa-menu" :id="id" role="menu">
<div class="dropdown-content">
<div class="dropdown-item">
<chismosa></chismosa>
</div>
</div>
</div>
</div>
</template>
@ -32,33 +25,21 @@ export default {
},
data() {
return {
activa: false
activa: false,
total: 0,
}
},
mounted() {
Event.$on('pedido-actualizado', this.actualizar);
},
methods: {
toggle() {
this.activa = !this.activa
this.activa = !this.activa;
Event.$emit("toggle-chismosa", this.activa);
},
actualizar() {
this.total = this.$limpiarInt(this.$root.devoluciones ? this.$root.pedido.total_menos_devoluciones : this.$root.pedido.total);
},
},
}
</script>
<style>
@media (max-width: 719px) {
.chismosa-menu {
vertical-align: top;
overflow-y: auto;
max-height: 75vh;
max-width: 100vw;
}
}
@media (min-width: 720px) {
.chismosa-menu {
vertical-align: top;
overflow-y: auto;
max-height: 75vh;
}
}
</style>

View File

@ -0,0 +1,31 @@
<template>
<div class="columns ml-3 mr-3">
<categorias-container :class="chismosaActiva ? 'hide-below-1024' : ''"></categorias-container>
<productos-container :class="chismosaActiva ? 'hide-below-1024' : ''"></productos-container>
<chismosa v-show="chismosaActiva"></chismosa>
</div>
</template>
<script>
import Chismosa from './Chismosa.vue';
import ProductosContainer from './ProductosContainer.vue';
import CategoriasContainer from './CategoriasContainer.vue';
export default {
componets: {
Chismosa,
ProductosContainer,
CategoriasContainer,
},
data() {
return {
chismosaActiva: false,
}
},
mounted() {
Event.$on('toggle-chismosa', (activa) => {
this.chismosaActiva = activa;
});
},
}
</script>

View File

@ -0,0 +1,110 @@
<template>
<div>
<div class="field has-addons contador">
<div class="control">
<button class="button is-small" @click.capture="decrementar();">
<i class="fa fa-solid fa-minus"></i>
</button>
</div>
<div class="control">
<input id="cantidad" v-model="cantidad" class="input is-small" type="number" style="text-align: center">
</div>
<div class="control" @click="incrementar();">
<button class="button is-small">
<i class="fa fa-solid fa-plus"></i>
</button>
</div>
<button :disabled="!hayCambios()" class="button is-small is-success ml-1" @click="confirmar()">
<span class="icon">
<i class="fas fa-check"></i>
</span>
</button>
<button :disabled="!puedeBorrar()" class="button is-small is-danger ml-1" @click="borrar()">
<span class="icon">
<i class="fas fa-trash-alt"></i>
</span>
</button>
</div>
<div v-if="producto.requiere_notas" class="field has-addons is-full-width">
<input v-model="notas" class="input" type="text" placeholder="Talle o color" />
</div>
</div>
</template>
<script>
export default {
props: {
producto: Object
},
data() {
return {
cantidad: this.cantidadEnChismosa(),
notas: this.notasEnChismosa(),
}
},
mounted() {
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;
},
incrementar() {
this.cantidad += 1;
},
confirmar() {
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, notas) {
this.notas = notas;
this.cantidad = cantidad;
if (this.producto.pivot !== undefined) {
this.producto.pivot.cantidad = cantidad;
this.producto.pivot.notas = notas;
}
},
hayCambios() {
if (this.cantidad != this.cantidadEnChismosa()) return true;
return this.cantidad > 0 && this.notas != this.notasEnChismosa();
},
puedeBorrar() {
return this.cantidadEnChismosa() > 0;
},
}
}
</script>
<style>
/* Chrome, Safari, Edge, Opera */
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
/* Firefox */
input[type=number] {
appearance: textfield;
-moz-appearance: textfield;
}
.contador {
min-width: 178px;
}
</style>

View File

@ -1,6 +1,11 @@
<script>
import ProductoCantidad from './Producto/ProductoCantidad.vue';
export default {
name: "ProductoCard",
components: {
ProductoCantidad,
},
props: {
producto: Object
},
@ -71,32 +76,7 @@ export default {
</div>
<footer class="columns">
<div class="column is-three-quarters">
<div class="field has-addons">
<div class="control">
<button :disabled="cantidad < 1" class="button is-small" @click.capture="decrementar();">
<i class="fa fa-solid fa-minus"></i>
</button>
</div>
<div class="control">
<input id="cantidad" v-model="cantidad" class="input is-small" type="number" style="text-align: center">
</div>
<div class="control" @click="incrementar();">
<button class="button is-small">
<i class="fa fa-solid fa-plus"></i>
</button>
</div>
<button :disabled="!hayCambios() || cantidad < 0" class="button is-small is-success ml-3" @click="confirmar()">
<span class="icon">
<i class="fas fa-check"></i>
</span>
</button>
<button :disabled="!puedeBorrar()" class="button is-small is-danger ml-3" @click="borrar()">
<span class="icon">
<i class="fas fa-trash-alt"></i>
</span>
</button>
</div>
Notas: <input v-model="notas" />
<producto-cantidad :producto="producto"></producto-cantidad>
</div>
<div class="column">
<p class="subtitle is-7 is-hidden-mobile" v-if="enChismosa !== 0">{{ enChismosa }} en chismosa</p>

View File

@ -1,27 +1,21 @@
<template>
<tr>
<td>{{ this.producto.nombre }}</td>
<td class="has-text-right">{{ this.producto.pivot.cantidad }}</td>
<td class="has-text-right">
<producto-cantidad :producto="producto"></producto-cantidad>
</td>
<td class="has-text-right">{{ Math.ceil(this.producto.pivot.total) }}</td>
<td><button @click.capture="eliminarProducto()" class="button is-danger">
<span class="icon">
<i class="fas fa-trash-alt"></i>
</span>
</button></td>
</tr>
</template>
<script>
export default {
import ProductoCantidad from './Producto/ProductoCantidad.vue';
export default {
components: {
ProductoCantidad,
},
props: {
producto: Object
},
methods: {
seleccionarProducto() {
Event.$emit("producto-seleccionado",this.producto);
},
eliminarProducto() {
Event.$emit("sync-subpedido", 0, this.producto.id);
}
}
}
</script>

View File

@ -1,5 +1,5 @@
<template>
<div v-show="visible" class="block ml-6 mr-6">
<div v-show="visible" class="column">
<div class="columns is-multiline is-mobile">
<producto-card v-for="(producto,i) in productos" :key="i" :producto="producto">
</producto-card><!-- END BLOCK COLUMN -->
@ -38,8 +38,9 @@ export default {
}).then(response => {
this.productos = response.data.data;
this.productos.forEach(p => {
p.cantidad = this.$root.cantidad(p);
p.notas = this.$root.notas(p);
p.pivot = {};
p.pivot.cantidad = this.$root.cantidad(p);
p.pivot.notas = this.$root.notas(p);
});
});
this.visible = true;

View File

@ -1,9 +1,6 @@
@extends('layouts.app')
@section('content')
<chismosa></chismosa>
<categorias-container></categorias-container>
<productos-container></productos-container>
<producto-modal></producto-modal>
<pedido-body></pedido-body>
<devoluciones-modal></devoluciones-modal>
@endsection