Compare commits

...

35 commits

Author SHA1 Message Date
ale
5b9908e0b5 Agregados toast 2025-05-23 02:18:12 -03:00
ale
f837b7f066 Tirando error cuando se intenta modificar un pedido aprobado 2025-05-23 02:13:09 -03:00
ale
0dba210a6a Funciones para toast y mostrar errores 2025-05-23 02:12:55 -03:00
ale
571b02382e app limpiada 2025-05-23 01:44:39 -03:00
ale
2f071e631d Pseudo routing con migas y dispatch en vez de href 2025-05-23 01:41:16 -03:00
ale
1e830e3cfd Logica de migas movida a ui.js 2025-05-23 01:27:34 -03:00
ale
0381bb0567 Cartel aprobado movido a pedidos body 2025-05-23 01:12:12 -03:00
ale
adabd09ea7 Cambio id 2025-05-23 01:11:31 -03:00
ale
a9ca04811e Usando vuex 2025-05-23 01:02:11 -03:00
ale
5458fae6d9 Renombrado 2025-05-23 01:02:01 -03:00
ale
5023032ac2 Usando vuex para el modal de devoluciones 2025-05-23 00:58:02 -03:00
ale
fb0e13089f Agregado devoluciones-modal 2025-05-23 00:56:27 -03:00
ale
21aa36e3d1 Cambios de nombres, y movida logica de chismosa a store de vuex 2025-05-23 00:37:12 -03:00
ale
f81141d18b Quitado codigo no usado 2025-05-23 00:36:22 -03:00
ale
8f0d715f8c Usando vuex 2025-05-23 00:01:55 -03:00
ale
45dcf643bf Formato 2025-05-22 23:07:07 -03:00
ale
5468b79562 Agregados getters para datos de productos 2025-05-22 23:06:51 -03:00
ale
08a731673b Quitado codigo no usado 2025-05-22 22:12:42 -03:00
ale
94e384c83c Crear pedido setea state, quitado todo lo relativo a sesion, y quitado codigo comentado 2025-05-22 21:46:15 -03:00
ale
a594e8a049 Arreglado parametro 2025-05-22 21:45:34 -03:00
ale
fd055cd7c6 Devolviendo resource tras crear pedido 2025-05-22 21:45:22 -03:00
ale
d4df72afe2 Titulo simplificado 2025-05-22 21:26:08 -03:00
ale
442d35eac8 Agregado main.blade.php con respectiva ruta y web usa main 2025-05-22 21:26:01 -03:00
ale
154e21fae6 Agregados componentes para ordenar el flujo de la aplicación + usandolo en la view + cambios en la store pedido por evitar redireccion 2025-05-22 21:08:06 -03:00
ale
1a8f9eda18 Cambio en nombre de getter 2025-05-22 21:06:14 -03:00
ale
128dd05b9a Agregado metodo, ruta, logica de vuex para obtener rol del usuario logeado 2025-05-22 21:04:17 -03:00
ale
181fbf924f Agregado nombre 2025-05-22 20:25:00 -03:00
ale
8d1eb03ffc Cambio formato y mostrando solo para pedidos 2025-05-22 00:26:08 -03:00
ale
baeff66aaf usando vuex para el resto de los datos 2025-05-22 00:12:34 -03:00
ale
1709468f1f total, productos, y devoluciones_habilitadas tomadas de vuex 2025-05-22 00:05:07 -03:00
ale
b46b56159b formato 2025-05-22 00:01:36 -03:00
ale
b8390c4ac6 Usando pedido de vuex 2025-05-21 23:41:23 -03:00
ale
36af26a647 Agregada logica de sesion 2025-05-21 22:40:53 -03:00
ale
cdf5663b16 Redirección movida a vuex 2025-05-21 22:40:23 -03:00
ale
8fbfa75144 Esperando a que pedido esté definido 2025-05-21 22:33:02 -03:00
33 changed files with 528 additions and 485 deletions

View file

@ -35,7 +35,7 @@ class SubpedidoController extends Controller
$s->nombre = $validado["nombre"]; $s->nombre = $validado["nombre"];
$s->grupo_de_compra_id = $validado["grupo_de_compra_id"]; $s->grupo_de_compra_id = $validado["grupo_de_compra_id"];
$s->save(); $s->save();
return $s; return $this->show($s);
} }
protected function validateSubpedido(): array protected function validateSubpedido(): array
@ -57,7 +57,7 @@ class SubpedidoController extends Controller
// recibe request, saca producto y cantidad, valida, y pasa a syncProducto en Subpedido // recibe request, saca producto y cantidad, valida, y pasa a syncProducto en Subpedido
public function syncProductos(Subpedido $subpedido) { public function syncProductos(Subpedido $subpedido) {
if ($subpedido->aprobado) if ($subpedido->aprobado)
return new SubpedidoResource($subpedido); abort(400, "No se puede modificar un pedido aprobado.");
$valid = request()->validate([ $valid = request()->validate([
'cantidad' => ['integer','required','min:0'], 'cantidad' => ['integer','required','min:0'],
@ -84,7 +84,8 @@ class SubpedidoController extends Controller
} }
public function syncDevoluciones(Subpedido $subpedido) { public function syncDevoluciones(Subpedido $subpedido) {
if ($subpedido->aprobado) return new SubpedidoResource($subpedido); if ($subpedido->aprobado)
abort(400, "No se puede modificar un pedido aprobado.");
$valid = request()->validate([ $valid = request()->validate([
'total' => 'required|min:0', 'total' => 'required|min:0',

View file

@ -18,7 +18,7 @@ class RouteController extends Controller
switch ($request->user()->role_id) { switch ($request->user()->role_id) {
case $barrio->id: case $barrio->id:
return redirect('/productos'); return redirect('/pedido');
case $admin->id: case $admin->id:
return redirect('/admin'); return redirect('/admin');
case $comision->id: case $comision->id:
@ -27,4 +27,8 @@ class RouteController extends Controller
abort(400, 'Rol de usuario invalido'); abort(400, 'Rol de usuario invalido');
} }
} }
function main(Request $request) {
return view('main');
}
} }

View file

@ -11,12 +11,16 @@ use Illuminate\Support\Facades\Auth;
class UserController extends Controller class UserController extends Controller
{ {
public function rol(Request $request) {
return ["rol" => UserRole::find($request->user()->role_id)->nombre];
}
public function grupoDeCompra(Request $request) public function grupoDeCompra(Request $request)
{ {
$user = Auth::user(); $user = Auth::user();
$result = [ 'grupo_de_compra' => null, ]; $result = [ 'grupo_de_compra' => null, ];
$grupo_de_compra = GrupoDeCompra::find($user->grupo_de_compra_id); $grupo_de_compra = GrupoDeCompra::find($user->grupo_de_compra_id);
switch (UserRole::find($user->role_id)->nombre ?? 'error') { switch (UserRole::findOrFail($user->role_id)->nombre) {
case 'barrio': case 'barrio':
$result['grupo_de_compra'] = new GrupoDeCompraReducido($grupo_de_compra); $result['grupo_de_compra'] = new GrupoDeCompraReducido($grupo_de_compra);
break; break;

99
resources/js/app.js vendored
View file

@ -5,6 +5,7 @@
*/ */
import axios from 'axios'; import axios from 'axios';
import Vue from 'vue'; import Vue from 'vue';
window.Vue = require('vue'); window.Vue = require('vue');
window.Event = new Vue(); window.Event = new Vue();
window.axios = axios; window.axios = axios;
@ -19,19 +20,17 @@ window.bulmaToast = require('bulma-toast');
*/ */
import './components'; import './components';
import store from "./store"; import store from "./store";
/** /**
* Global methods * Global methods
*/ */
Vue.prototype.$settearProducto = function(cantidad, id) { Vue.prototype.$toast = function (mensaje, duration = 2000) {
Event.$emit("sync-subpedido", this.cant, this.producto.id) return window.bulmaToast.toast({
} message: mensaje,
Vue.prototype.$toast = function(mensaje, duration = 2000) { duration: duration,
return window.bulmaToast.toast({ type: 'is-danger',
message: mensaje, position: 'bottom-center',
duration: duration, });
type: 'is-danger',
position: 'bottom-center',
});
} }
/** /**
@ -39,86 +38,8 @@ Vue.prototype.$toast = function(mensaje, duration = 2000) {
* the page. Then, you may begin adding components to this application * the page. Then, you may begin adding components to this application
* or customize the JavaScript scaffolding to fit your unique needs. * or customize the JavaScript scaffolding to fit your unique needs.
*/ */
const app = new Vue({ new Vue({
el: '#root', el: '#root',
store, store,
data() {
return {
gdc: null,
pedido: null,
devoluciones: null,
}
},
computed: {
productos: function() {
return this.pedido.productos
}
},
methods: {
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`)
.then(response => {
this.devoluciones = response.data.devoluciones;
});
}
},
mounted() {
Event.$on('obtener-sesion', () => {
if (!window.location.pathname.startsWith('/admin')) {
axios.get('/subpedidos/obtener_sesion')
.then(response => {
this.gdc = response.data.gdc;
// this.settearDevoluciones();
this.pedido = response.data.subpedido.id;
axios.get('/api/subpedidos/' + this.pedido)
.then(response => {
this.pedido = response.data.data;
Event.$emit("pedido-actualizado");
});
})
}
})
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,
notas: notas,
}).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");
});
});
if (window.location.pathname.startsWith('/productos'))
Event.$emit('obtener-sesion')
},
}); });

View file

@ -0,0 +1,30 @@
<script>
import NavBar from "./comunes/NavBar.vue";
import { mapActions, mapState } from "vuex";
export default {
name: 'Main',
components: { NavBar },
computed: {
...mapState('login',["rol"]),
},
methods: {
...mapActions('login',["getRol"]),
},
async mounted() {
await this.getRol();
},
}
</script>
<template>
<div id="app-main">
<nav-bar></nav-bar>
<pedidos-body v-if="rol === 'barrio'"></pedidos-body>
<admin-body v-if="rol === 'admin_barrio'"></admin-body>
<compras-body v-if="rol === 'comision'"></compras-body>
</div>
</template>
<style scoped>
</style>

View file

@ -1,7 +1,7 @@
<template> <template>
<div v-if="region_elegida !== null" class="block"> <div v-if="region_elegida !== null" class="block">
<div class="field"> <div class="field">
<label class="label" :class="admin ? 'has-text-white' : ''"> <label class="label" :class="adminUrl ? 'has-text-white' : ''">
Seleccioná tu barrio o grupo de compra Seleccioná tu barrio o grupo de compra
</label> </label>
<div class="control"> <div class="control">
@ -35,7 +35,7 @@ export default {
}, },
computed: { computed: {
...mapState('login',["region_elegida","grupos_de_compra","grupo_de_compra_elegido"]), ...mapState('login',["region_elegida","grupos_de_compra","grupo_de_compra_elegido"]),
...mapGetters('login',["admin"]), ...mapGetters('login',["adminUrl"]),
}, },
data() { data() {
return { return {

View file

@ -2,7 +2,7 @@
<div v-if="grupo_de_compra_elegido !== null" class="block"> <div v-if="grupo_de_compra_elegido !== null" class="block">
<div class="field"> <div class="field">
<label class="label" <label class="label"
:class="admin ? 'has-text-white' : ''">{{ mensajes.mensaje }}</label> :class="adminUrl ? 'has-text-white' : ''">{{ mensajes.mensaje }}</label>
<div class="field has-addons"> <div class="field has-addons">
<div class="control"> <div class="control">
<input required class="input" :type="this.passwordType" name="password" :placeholder="mensajes.mensaje"> <input required class="input" :type="this.passwordType" name="password" :placeholder="mensajes.mensaje">
@ -14,7 +14,7 @@
</div> </div>
</div> </div>
<p class="help" <p class="help"
:class="admin ? 'has-text-white' : ''">{{ mensajes.ayuda }}</p> :class="adminUrl ? 'has-text-white' : ''">{{ mensajes.ayuda }}</p>
</div> </div>
<div class="field"> <div class="field">
<div class="control"> <div class="control">
@ -37,7 +37,7 @@ export default {
}, },
computed: { computed: {
...mapState('login',["grupo_de_compra_elegido"]), ...mapState('login',["grupo_de_compra_elegido"]),
...mapGetters('login',["admin","mensajes"]), ...mapGetters('login',["adminUrl","mensajes"]),
}, },
methods: { methods: {
togglePassword() { togglePassword() {

View file

@ -20,10 +20,10 @@ export default {
await this.getRegiones(); await this.getRegiones();
}, },
computed: { computed: {
...mapGetters('login',["admin"]), ...mapGetters('login',["adminUrl"]),
...mapState('login',["grupo_de_compra_elegido"]), ...mapState('login',["grupo_de_compra_elegido"]),
nombre() { nombre() {
return `${this.grupo_de_compra_elegido}${this.admin ? '_admin' : ''}`; return `${this.grupo_de_compra_elegido}${this.adminUrl ? '_admin' : ''}`;
} }
}, },
methods: { methods: {

View file

@ -4,14 +4,15 @@
<a class="navbar-item" href="https://mps.org.uy"> <a class="navbar-item" href="https://mps.org.uy">
<img src="/assets/logoMPS.png" height="28"> <img src="/assets/logoMPS.png" height="28">
</a> </a>
<p class="navbar-item hide-below-1024"> <div class="navbar-item" id="datos-pedido" v-if="pedidoDefinido">
</p> <p class="hide-below-1024">
<p class="navbar-item"> {{ `Núcleo: ${nombre} - Barrio: ${grupo_de_compra}` }}
</p> </p>
</div>
<chismosa-dropdown <chismosa-dropdown
v-if="pedidoDefinido" v-if="pedidoDefinido"
class="hide-above-1023" class="hide-above-1023"
id="mobile"> ariaControls="mobile">
</chismosa-dropdown> </chismosa-dropdown>
<a role="button" class="navbar-burger" :class="{'is-active':burgerActiva}" aria-label="menu" <a role="button" class="navbar-burger" :class="{'is-active':burgerActiva}" aria-label="menu"
aria-expanded="false" data-target="nav-bar" @click="toggleBurger"> aria-expanded="false" data-target="nav-bar" @click="toggleBurger">
@ -34,7 +35,7 @@
<chismosa-dropdown <chismosa-dropdown
v-if="pedidoDefinido" v-if="pedidoDefinido"
class="hide-below-1024" class="hide-below-1024"
id="wide"> ariaControls="wide">
</chismosa-dropdown> </chismosa-dropdown>
<div class="block navbar-item"> <div class="block navbar-item">
<a onclick="event.preventDefault(); document.getElementById('logout-form').submit();" <a onclick="event.preventDefault(); document.getElementById('logout-form').submit();"
@ -50,7 +51,7 @@
<script> <script>
import ChismosaDropdown from '../pedidos/ChismosaDropdown.vue'; import ChismosaDropdown from '../pedidos/ChismosaDropdown.vue';
import { mapActions, mapGetters } from "vuex"; import { mapActions, mapGetters, mapMutations, mapState } from "vuex";
export default { export default {
components: { ChismosaDropdown }, components: { ChismosaDropdown },
@ -61,10 +62,13 @@ export default {
} }
}, },
computed: { computed: {
...mapGetters('pedido',["pedidoDefinido"]), ...mapGetters('pedido', ["pedidoDefinido"]),
...mapState('pedido',["nombre"]),
...mapState('barrio',["grupo_de_compra"]),
}, },
methods: { methods: {
...mapActions('productos', ["filtrarProductos"]), ...mapActions('productos', ["filtrarProductos"]),
...mapMutations('ui',["addMiga"]),
toggleBurger() { toggleBurger() {
this.burgerActiva = !this.burgerActiva this.burgerActiva = !this.burgerActiva
}, },
@ -72,7 +76,7 @@ export default {
if (this.burgerActiva) if (this.burgerActiva)
this.toggleBurger(); this.toggleBurger();
this.filtrarProductos({ filtro: "nombre", valor: this.searchString }); this.filtrarProductos({ filtro: "nombre", valor: this.searchString });
Event.$emit('migas-agregar', { nombre: this.searchString }); this.addMiga({ nombre: this.searchString });
} }
}, },
}; };

View file

@ -1,7 +1,7 @@
<template> <template>
<div class="block"> <div class="block">
<div class="field"> <div class="field">
<label class="label" :class="admin ? 'has-text-white' : ''"> <label class="label" :class="adminUrl ? 'has-text-white' : ''">
Seleccioná tu región Seleccioná tu región
</label> </label>
<div class="control"> <div class="control">
@ -38,7 +38,7 @@ export default {
}, },
computed: { computed: {
...mapState('login',["regiones","region_elegida"]), ...mapState('login',["regiones","region_elegida"]),
...mapGetters('login',["admin"]), ...mapGetters('login',["adminUrl"]),
} }
} }
</script> </script>

View file

@ -1,32 +1,21 @@
<template> <template>
<div class="columns ml-3 mr-3"> <div id="pedidos-body">
<categorias-container :class="chismosaActiva ? 'hide-below-1024' : ''"></categorias-container> <cartel-pedido-aprobado></cartel-pedido-aprobado>
<productos-container :class="chismosaActiva ? 'hide-below-1024' : ''"></productos-container> <pedido-select-section v-if="!pedidoDefinido"></pedido-select-section>
<chismosa v-show="chismosaActiva"></chismosa> <pedido v-else></pedido>
</div> </div>
</template> </template>
<script> <script>
import { mapActions } from "vuex"; import { mapGetters } from "vuex";
import Chismosa from "./Chismosa.vue"; import PedidoSelectSection from "./PedidoSelectSection.vue";
import ProductosContainer from "./ProductosContainer.vue"; import Pedido from "./Pedido.vue";
import CategoriasContainer from "./CategoriasContainer.vue"; import CartelPedidoAprobado from "./CartelPedidoAprobado.vue";
export default { export default {
components: { CategoriasContainer, ProductosContainer, Chismosa }, components: { CartelPedidoAprobado, Pedido, Productos: Pedido, PedidoSelectSection },
data() { computed: {
return { ...mapGetters('pedido',["pedidoDefinido"]),
chismosaActiva: false,
}
},
methods: {
...mapActions('productos',["init"]),
},
async mounted() {
await this.init();
Event.$on('toggle-chismosa', (activa) => {
this.chismosaActiva = activa;
});
}, },
} }
</script> </script>

View file

@ -1,32 +1,19 @@
<template> <template>
<div v-show="aprobado" class="notification is-warning has-text-centered"> <div v-if="aprobado" class="notification is-warning has-text-centered">
Tu pedido fue <strong>aprobado</strong>, por lo que no puede ser modificado Tu pedido fue <strong>aprobado</strong>, por lo que no puede ser modificado
</div> </div>
</template> </template>
<script> <script>
export default { import { mapState } from "vuex";
data() {
return { export default {
aprobado: false, name: 'CartelPedidoAprobado',
} computed: {
}, ...mapState('pedido',["aprobado"]),
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> </script>
<style> <style>
</style> </style>

View file

@ -18,7 +18,7 @@
</template> </template>
<script> <script>
import { mapActions, mapState } from "vuex"; import { mapActions, mapMutations, mapState } from "vuex";
export default { export default {
name: 'CategoriasContainer', name: 'CategoriasContainer',
computed: { computed: {
@ -28,10 +28,11 @@ export default {
} }
}, },
methods: { methods: {
...mapActions('productos', ["seleccionarCategoria"]), ...mapActions('productos',["seleccionarCategoria"]),
...mapMutations('ui',["addMiga"]),
seleccionar(categoria) { seleccionar(categoria) {
this.seleccionarCategoria({ categoria: categoria }); this.seleccionarCategoria({ categoria: categoria });
Event.$emit('migas-agregar', { nombre: categoria }); this.addMiga({ nombre: categoria });
} }
} }
} }

View file

@ -12,20 +12,20 @@
<tfoot> <tfoot>
<tr> <tr>
<th><abbr title="Bonos de Transporte">B. Transporte</abbr></th> <th><abbr title="Bonos de Transporte">B. Transporte</abbr></th>
<th class="has-text-right">{{ cantidad_bonos_transporte }}</th> <th class="has-text-right">{{ cantidad_transporte }}</th>
<th class="has-text-right">{{ total_bonos_transporte }}</th> <th class="has-text-right">{{ total_transporte }}</th>
</tr> </tr>
<tr v-if="this.$root.devoluciones"> <tr v-if="devoluciones_habilitadas">
<th><p>Devoluciones</p></th> <th><p>Devoluciones</p></th>
<td> <td>
<abbr :title="notas_devoluciones">{{ notas_devoluciones_abbr }}</abbr> <abbr :title="devoluciones_notas">{{ notas_abreviadas }}</abbr>
<button @click.capture="modificarDevoluciones()" class="button is-warning is-small"> <button @click.capture="toggleDevoluciones()" class="button is-warning is-small">
<span class="icon"> <span class="icon">
<i class="fas fa-edit"></i> <i class="fas fa-edit"></i>
</span> </span>
</button> </button>
</td> </td>
<th class="has-text-right">-{{ devoluciones }}</th> <th class="has-text-right">-{{ devoluciones_total }}</th>
</tr> </tr>
<tr> <tr>
<th>Total total</th> <th>Total total</th>
@ -45,61 +45,43 @@
</template> </template>
<script> <script>
import ProductoRow from "./ProductoRow.vue"; import ProductoRow from "./ProductoRow.vue";
import { mapMutations, mapState } from "vuex";
export default { export default {
components: {ProductoRow}, components: { ProductoRow },
data() { computed: {
return { ...mapState('barrio',["devoluciones_habilitadas"]),
mostrar_tabla: false, ...mapState('pedido',[
cantidad_bonos_transporte: 0, "productos",
total_bonos_transporte: 0, "total",
devoluciones: 0, "total_transporte",
notas_devoluciones: "", "cantidad_transporte",
notas_devoluciones_abbr: "", "devoluciones_total",
total: 0, "devoluciones_notas",
productos: [], ]),
} notas_abreviadas() {
return this.devoluciones_notas.substring(0, 15) + (this.devoluciones_notas.length > 15 ? "..." : "");
}, },
mounted() { mostrar_tabla() {
Event.$on('pedido-actualizado', this.pedidoActualizado); return this.productos?.length !== 0;
Event.$on('toggle-chismosa', this.pedidoActualizado);
}, },
methods: { },
pedidoActualizado: function() { methods: {
this.mostrar_tabla = this.$root.productos.length > 0; ...mapMutations('ui',["toggleDevoluciones"]),
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.$root.pedido.total;
this.productos = this.$root.productos;
},
modificarDevoluciones: function() {
Event.$emit("modificar-devoluciones");
},
cantidadBonosDeTransporte: function() {
return this.$root.pedido.cantidad_transporte;
},
totalBonosDeTransporte: function() {
return this.$root.pedido.total_transporte
},
},
}
</script> </script>
<style> <style>
.tabla-chismosa { .tabla-chismosa {
width: 100%; width: 100%;
} }
.fixed-right {
position: fixed; .fixed-right {
overflow-y: auto; position: fixed;
max-height: 81vh; overflow-y: auto;
margin-right: 20px; max-height: 81vh;
} margin-right: 20px;
}
</style> </style>

View file

@ -1,7 +1,7 @@
<template> <template>
<div class="dropdown is-right navbar-item" :class="{'is-active':activa}"> <div class="dropdown is-right navbar-item" :class="{'is-active': show_chismosa}">
<div class="dropdown-trigger"> <div class="dropdown-trigger">
<a class="text-a" aria-haspopup="true" :aria-controls="id" @click.capture="toggle"> <a class="text-a" aria-haspopup="true" :aria-controls="ariaControls" @click.capture="toggleChismosa">
<span class="icon is-small mr-1"> <span class="icon is-small mr-1">
<img src="/assets/chismosa.png"> <img src="/assets/chismosa.png">
</span> </span>
@ -13,33 +13,23 @@
<script> <script>
import Chismosa from './Chismosa.vue' import Chismosa from './Chismosa.vue'
import { mapMutations, mapState } from "vuex";
export default { export default {
components: { components: {
Chismosa Chismosa
}, },
props: { props: {
id: { ariaControls: {
type: String, type: String,
required: true required: true
} }
}, },
data() { computed: {
return { ...mapState('pedido',["total"]),
activa: false, ...mapState('ui',["show_chismosa"]),
total: 0,
}
},
mounted() {
Event.$on('pedido-actualizado', this.actualizar);
}, },
methods: { methods: {
toggle() { ...mapMutations('ui',["toggleChismosa"]),
this.activa = !this.activa;
Event.$emit("toggle-chismosa", this.activa);
},
actualizar() {
this.total = this.$root.pedido.total;
},
}, },
} }
</script> </script>

View file

@ -1,67 +1,71 @@
<template> <template>
<div v-bind:class="visible ? 'is-active modal' : 'modal'"> <div :class="show_devoluciones ? 'is-active modal' : 'modal'">
<div class="modal-background"></div> <div class="modal-background"></div>
<div class="modal-card"> <div class="modal-card">
<header class="modal-card-head"> <header class="modal-card-head">
<p class="modal-card-title">Devoluciones</p> <p class="modal-card-title">Devoluciones</p>
<button class="delete" aria-label="close" @click.capture="cerrar"></button> <button class="delete" aria-label="close" @click.capture="toggleDevoluciones()"></button>
</header> </header>
<section class="modal-card-body"> <section class="modal-card-body">
<div class="field has-addons is-centered is-thin-centered"> <div class="field has-addons is-centered is-thin-centered">
<p class="control"> <p class="control">
Total: Total:
<input id="total" class="input" type="number" v-model="total" style="text-align: center"> <input id="totalControl" class="input" type="number" v-model="totalControl"
style="text-align: center">
</p> </p>
</div> </div>
<div class="field has-addons is-centered is-thin-centered"> <div class="field has-addons is-centered is-thin-centered">
<p class="control"> <p class="control">
Notas: Notas:
<input id="notas" class="input" type="text" v-model.text="notas"> <input id="notasControl" class="input" type="text" v-model.text="notasControl">
</p> </p>
</div> </div>
</section> </section>
<footer class="modal-card-foot"> <footer class="modal-card-foot">
<button class="button is-success" @click="modificar">Aceptar</button> <button class="button is-success" @click="modificar">Aceptar</button>
<button class="button" @click.capture="cerrar">Cancelar</button> <button class="button" @click.capture="toggleDevoluciones()">Cancelar</button>
</footer> </footer>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
export default { import { mapActions, mapMutations, mapState } from "vuex";
data() {
return { export default {
visible: false, name: 'DevolucionesModal',
total: 0, data() {
notas: "", return {
} totalControl: 0,
notasControl: "",
}
},
mounted() {
this.actualizar();
},
watch: {
cantidadEnChismosa() {
this.actualizar();
}, },
computed: { notasEnChismosa() {
miga: function() { this.actualizar();
return { }
nombre: "Devoluciones", },
href: "#devoluciones", computed: {
} ...mapState('ui', ["show_devoluciones"]),
}, ...mapState('pedido', ["devoluciones_total", "devoluciones_notas"])
},
methods: {
...mapMutations('ui', ["toggleDevoluciones"]),
...mapActions('pedido', ["modificarDevoluciones"]),
modificar() {
this.modificarDevoluciones({ monto: this.totalControl, notas: this.notasControl });
this.toggleDevoluciones();
}, },
methods: { actualizar() {
cerrar() { this.totalControl = this.devoluciones_total;
this.visible = false; this.notasControl = this.devoluciones_notas;
Event.$emit("migas-pop");
},
modificar() {
Event.$emit('sync-devoluciones', this.total, this.notas);
this.cerrar();
}
}, },
mounted() { },
Event.$on('modificar-devoluciones', () => { }
this.visible = true; </script>
this.total = this.$root.pedido.devoluciones_total;
this.notas = this.$root.pedido.devoluciones_notas;
Event.$emit("migas-agregar", this.miga);
});
},
}
</script>

View file

@ -3,7 +3,7 @@
aria-label="breadcrumbs" v-show="visible"> aria-label="breadcrumbs" v-show="visible">
<ul class="mt-4"> <ul class="mt-4">
<li v-for="(miga, i) in migas" :key="i" :class="{'is-active': i === migaActiva}"> <li v-for="(miga, i) in migas" :key="i" :class="{'is-active': i === migaActiva}">
<a :href="miga.href" v-text="miga.nombre" <a @click="clickMiga({ miga: miga })" v-text="miga.nombre"
:class="{'has-text-danger': i !== migaActiva}"></a> :class="{'has-text-danger': i !== migaActiva}"></a>
</li> </li>
</ul> </ul>
@ -11,39 +11,23 @@
</template> </template>
<script> <script>
import { mapGetters } from "vuex"; import { mapActions, mapGetters, mapState } from "vuex";
export default { export default {
data() { methods: {
return { ...mapActions('productos',["getProductos"]),
initial: [{ nombre: 'Categorías', href: '/productos' }], ...mapActions('ui',["clickMiga"]),
migas: [{ nombre: 'Categorías', href: '/productos' }],
}
}, },
computed: { computed: {
...mapGetters('pedido', ["pedidoDefinido"]), ...mapState('ui',["migas"]),
visible: function () { ...mapGetters('pedido',["pedidoDefinido"]),
visible() {
return this.migas.length > 0 return this.migas.length > 0
}, },
migaActiva: function () { migaActiva() {
return this.migas.length - 1 return this.migas.length - 1
} }
}, },
mounted() {
Event.$on('migas-setear-como-inicio', (miga) => {
this.migas = [];
this.migas.push(miga);
});
Event.$on('migas-agregar', (miga) => {
this.migas.push(miga);
});
Event.$on('migas-reset', () => {
this.migas = this.initial;
});
Event.$on('migas-pop', () => {
this.migas.pop();
});
}
} }
</script> </script>

View file

@ -0,0 +1,36 @@
<script >
import { defineComponent } from "vue";
import { mapActions, mapState } from "vuex";
import SubpedidoSelect from "./SubpedidoSelect.vue";
import CategoriasContainer from "./CategoriasContainer.vue";
import ProductosContainer from "./ProductosContainer.vue";
import Chismosa from "./Chismosa.vue";
import DevolucionesModal from "./DevolucionesModal.vue";
import CartelPedidoAprobado from "./CartelPedidoAprobado.vue";
export default defineComponent({
components: { CartelPedidoAprobado, DevolucionesModal, SubpedidoSelect, CategoriasContainer, ProductosContainer, Chismosa },
computed: {
...mapState('ui',["show_chismosa","show_devoluciones"])
},
methods: {
...mapActions('productos',["init"]),
},
async mounted() {
await this.init();
},
})
</script>
<template>
<div class="columns ml-3 mr-3" v-else>
<categorias-container :class="show_chismosa ? 'hide-below-1024' : ''"></categorias-container>
<productos-container :class="show_chismosa ? 'hide-below-1024' : ''"></productos-container>
<chismosa v-show="show_chismosa"></chismosa>
<devoluciones-modal v-show="show_devoluciones"></devoluciones-modal>
</div>
</template>
<style scoped>
</style>

View file

@ -0,0 +1,26 @@
<script>
import { defineComponent } from "vue";
import SubpedidoSelect from "./SubpedidoSelect.vue";
import { mapGetters } from "vuex";
export default defineComponent({
components: { SubpedidoSelect },
})
</script>
<template>
<section class="section">
<div id="root" class="container">
<h1 class="title">
Pedidos MPS
</h1>
<p class="subtitle">
Bienvenidx a la aplicación de pedidos del <strong>Mercado Popular de Subsistencia</strong>
</p>
<subpedido-select></subpedido-select>
</div>
</section>
</template>
<style scoped>
</style>

View file

@ -7,29 +7,31 @@
</button> </button>
</div> </div>
<div class="control"> <div class="control">
<input id="cantidad" v-model="cantidad" class="input is-small" type="number" style="text-align: center"> <input id="cantidad" v-model="cantidadControl" class="input is-small" type="number"
style="text-align: center">
</div> </div>
<div class="control" @click="incrementar();"> <div class="control" @click="incrementar();">
<button class="button is-small"> <button class="button is-small">
<i class="fa fa-solid fa-plus"></i> <i class="fa fa-solid fa-plus"></i>
</button> </button>
</div> </div>
<button :disabled="disableConfirm()" class="button is-small is-success ml-1" @click="confirmar()"> <button :disabled="!hayCambios" class="button is-small is-success ml-1" @click="confirmar()">
<span class="icon"> <span class="icon">
<i class="fas fa-check"></i> <i class="fas fa-check"></i>
</span> </span>
</button> </button>
<button :disabled="!puedeBorrar()" class="button is-small is-danger ml-1" @click="borrar()"> <button :disabled="!puedeBorrar" class="button is-small is-danger ml-1" @click="borrar()">
<span class="icon"> <span class="icon">
<i class="fas fa-trash-alt"></i> <i class="fas fa-trash-alt"></i>
</span> </span>
</button> </button>
</div> </div>
<div v-if="producto.requiere_notas" v-bind:class="{'has-icons-right': notas_warning_visible}" class="control is-full-width has-icons-left"> <div v-if="requiere_notas" :class="{'has-icons-right': notas_warning_visible}"
class="control is-full-width has-icons-left">
<span class="icon is-small is-left"> <span class="icon is-small is-left">
<i class="fas fa-sticky-note"></i> <i class="fas fa-sticky-note"></i>
</span> </span>
<input v-model="notas" v-bind:class="{'is-danger': notas_warning_visible}" id="notas" class="input" type="text" placeholder="Talle o color" /> <input v-model="notasControl" v-bind:class="{'is-danger': notas_warning_visible}" id="notas" class="input" type="text" placeholder="Talle o color"/>
<span v-if="notas_warning_visible" class="icon is-small is-right"> <span v-if="notas_warning_visible" class="icon is-small is-right">
<i class="fas fa-exclamation-triangle"></i> <i class="fas fa-exclamation-triangle"></i>
</span> </span>
@ -43,98 +45,110 @@
</template> </template>
<script> <script>
export default { import { mapActions, mapGetters } from "vuex";
props: {
producto: Object export default {
props: {
producto_id: {
type: Number,
required: true,
}, },
data() { requiere_notas: {
return { type: Number,
cantidad: this.cantidadEnChismosa(), required: true,
notas: this.notasEnChismosa(), }
notas_warning_visible: false, },
data() {
return {
cantidadControl: 0,
notasControl: '',
notas_warning_visible: false,
}
},
watch: {
cantidadEnChismosa() {
this.actualizar();
},
notasEnChismosa() {
this.actualizar();
}
},
mounted() {
this.actualizar();
},
computed: {
...mapGetters('pedido', ["enChismosa", "cantidad", "notas"]),
cantidadEnChismosa() {
return this.cantidad(this.producto_id);
},
notasEnChismosa() {
return this.notas(this.producto_id);
},
hayCambios() {
return this.cantidadControl !== this.cantidadEnChismosa || this.notasControl !== this.notasEnChismosa;
},
puedeBorrar() {
return this.enChismosa(this.producto_id);
},
faltaNotas() {
return this.requiere_notas && this.cantidadControl > 0 && !this.notasControl;
},
},
methods: {
...mapActions('pedido', ["modificarChismosa"]),
decrementar() {
this.cantidadControl -= 1;
},
incrementar() {
this.cantidadControl += 1;
},
borrar() {
this.cantidadControl = 0;
this.confirmar();
},
async confirmar() {
if (this.faltaNotas) {
this.notas_warning_visible = true;
return;
} }
}, await this.modificarChismosa({
mounted() { producto_id: this.producto_id,
Event.$on('sync-subpedido', (cantidad, productoId, notas) => { cantidad: this.cantidadControl,
if (this.producto.id === productoId) notas: this.notasControl
this.sincronizar(cantidad, notas);
}); });
}, },
methods: { actualizar() {
notasEnChismosa() { this.cantidadControl = this.cantidadEnChismosa;
return this.producto.pivot !== undefined ? this.producto.pivot.notas : ""; this.notasControl = this.notasEnChismosa;
}, },
cantidadEnChismosa() {
return this.producto.pivot !== undefined ? this.producto.pivot.cantidad : 0;
},
decrementar() {
this.cantidad -= 1;
},
incrementar() {
this.cantidad += 1;
},
confirmar() {
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, notas) {
this.notas_warning_visible = false;
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;
},
warningNotas() {
return this.producto.requiere_notas && this.cantidad > 0 && !this.notas;
},
disableConfirm() {
return !this.hayCambios();
},
}
} }
}
</script> </script>
<style> <style>
/* Chrome, Safari, Edge, Opera */ /* Chrome, Safari, Edge, Opera */
input::-webkit-outer-spin-button, input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button { input::-webkit-inner-spin-button {
-webkit-appearance: none; -webkit-appearance: none;
margin: 0; margin: 0;
} }
/* Firefox */ /* Firefox */
input[type=number] { input[type=number] {
appearance: textfield; appearance: textfield;
-moz-appearance: textfield; -moz-appearance: textfield;
} }
.contador {
min-width: 178px;
}
.is-danger { .contador {
background-color: #fca697; min-width: 178px;
} }
.is-danger::placeholder {
color: #fff; .is-danger {
opacity: 1; /* Firefox */ background-color: #fca697;
} }
</style>
.is-danger::placeholder {
color: #fff;
opacity: 1; /* Firefox */
}
</style>

View file

@ -1,53 +1,25 @@
<script> <script>
import ProductoCantidad from "./ProductoCantidad.vue"; import ProductoCantidad from "./ProductoCantidad.vue";
import { mapGetters } from "vuex";
export default { export default {
name: "ProductoCard", name: "ProductoCard",
components: { ProductoCantidad }, components: { ProductoCantidad },
props: { props: {
producto: Object producto: {
type: Object,
required: true
}
}, },
data() { computed: {
return { ...mapGetters('pedido',["enChismosa", "cantidad"]),
cantidad: this.producto.cantidad, fuePedido() {
enChismosa: this.producto.cantidad, return this.enChismosa(this.producto.id);
notas: this.producto.notas, },
} cantidadEnChismosa() {
return this.cantidad(this.producto.id);
}
}, },
mounted() {
Event.$on('sync-subpedido', (cantidad, productoId, notas) => {
if (this.producto.id === productoId)
this.sincronizar(cantidad, notas);
});
},
methods: {
decrementar() {
this.cantidad -= 1;
},
incrementar() {
this.cantidad += 1;
},
confirmar() {
Event.$emit('sync-subpedido', this.cantidad, this.producto.id, this.notas);
},
borrar() {
this.cantidad = 0;
this.confirmar();
},
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 || this.notas !== this.producto.notas;
},
puedeBorrar() {
return this.enChismosa > 0;
},
}
} }
</script> </script>
@ -59,7 +31,7 @@ export default {
<p class="title is-6"> <p class="title is-6">
{{ producto.nombre }} {{ producto.nombre }}
</p> </p>
<span class="subtitle is-7 hidden-from-tablet" v-if="enChismosa">{{ enChismosa }} en chismosa</span> <span class="subtitle is-7 hidden-from-tablet" v-if="fuePedido">{{ cantidadEnChismosa }}</span>
</div> </div>
<div class="column is-one-quarter has-text-right"> <div class="column is-one-quarter has-text-right">
<p class="has-text-weight-bold has-text-primary"> <p class="has-text-weight-bold has-text-primary">
@ -73,13 +45,16 @@ export default {
</div> </div>
<footer class="columns"> <footer class="columns">
<div class="column is-three-quarters"> <div class="column is-three-quarters">
<producto-cantidad :producto="producto"></producto-cantidad> <producto-cantidad
:producto_id="producto.id"
:requiere_notas="producto.requiere_notas">
</producto-cantidad>
</div> </div>
<div class="column"> <div class="column">
<p class="subtitle is-7 is-hidden-mobile" v-if="enChismosa > 0">{{ enChismosa }} en chismosa</p> <p class="subtitle is-7 is-hidden-mobile" v-if="fuePedido">{{ cantidadEnChismosa }} en chismosa</p>
</div> </div>
</footer> </footer>
</div><!-- END BOX --> </div>
</div> </div>
</template> </template>

View file

@ -2,18 +2,25 @@
<tr> <tr>
<td>{{ this.producto.nombre }}</td> <td>{{ this.producto.nombre }}</td>
<td class="has-text-right"> <td class="has-text-right">
<producto-cantidad :producto="producto"></producto-cantidad> <producto-cantidad
:producto_id="producto.id"
:requiere_notas="producto.requiere_notas">
</producto-cantidad>
</td> </td>
<td class="has-text-right">{{ this.producto.pivot.total }}</td> <td class="has-text-right">{{ cantidad(producto.id) }}</td>
</tr> </tr>
</template> </template>
<script> <script>
import ProductoCantidad from "./ProductoCantidad.vue"; import ProductoCantidad from "./ProductoCantidad.vue";
import { mapGetters } from "vuex";
export default { export default {
components: { ProductoCantidad }, components: { ProductoCantidad },
props: { props: {
producto: Object producto: Object
}, },
computed: {
...mapGetters('pedido',["cantidad"]),
},
} }
</script> </script>

View file

@ -1,10 +1,13 @@
<template> <template>
<div v-show="visible" class="column"> <div v-show="visible" class="column">
<div class="columns is-multiline is-mobile"> <div class="columns is-multiline is-mobile">
<producto-card v-for="(producto,i) in this.productos" :key="i" :producto="producto"> <producto-card
</producto-card><!-- END BLOCK COLUMN --> v-for="(producto,i) in this.productos"
</div><!-- END COLUMNS --> :key="i"
</div><!-- END CONTAINER --> :producto="producto">
</producto-card>
</div>
</div>
</template> </template>
<script> <script>
@ -20,8 +23,8 @@ export default {
}, },
miga: function () { miga: function () {
return { return {
nombre: this.valor, nombre: this.filtro.valor,
href: "#" + this.valor href: "#" + this.filtro.valor
} }
} }
}, },

View file

@ -25,7 +25,7 @@
v-text="subpedidoExistente.nombre"></p> v-text="subpedidoExistente.nombre"></p>
</div> </div>
<div class="buttons column is-half-mobile is-one-third-desktop is-one-third-tablet"> <div class="buttons column is-half-mobile is-one-third-desktop is-one-third-tablet">
<button class="button is-danger" @click="elegirSubpedido(subpedidoExistente)">Continuar pedido <button class="button is-danger" @click="elegirPedido({ pedido: subpedidoExistente })">Continuar pedido
</button> </button>
</div> </div>
</div> </div>
@ -37,6 +37,7 @@
import { mapActions, mapMutations, mapState } from "vuex"; import { mapActions, mapMutations, mapState } from "vuex";
export default { export default {
name: 'SubpedidoSelect',
async mounted() { async mounted() {
await this.getGrupoDeCompra(); await this.getGrupoDeCompra();
}, },
@ -55,33 +56,18 @@ export default {
}, },
methods: { methods: {
...mapActions('barrio',["getGrupoDeCompra","getPedidos"]), ...mapActions('barrio',["getGrupoDeCompra","getPedidos"]),
...mapActions('pedido',["crearPedido"]), ...mapActions('pedido',["crearPedido","elegirPedido"]),
...mapMutations('barrio',["setPedidos"]), ...mapMutations('barrio',["setPedidos"]),
onType() { onType() {
if (!this.searchString) { if (!this.searchString) {
this.setPedidos([]); this.setPedidos([]);
return; return;
} }
this.getPedidos(this.searchString); this.getPedidos(this.searchString);
}, },
async submit() { async submit() {
await this.crearPedido({ nombre: this.searchString, grupo_de_compra_id: this.grupo_de_compra_id }); await this.crearPedido({ nombre: this.searchString, grupo_de_compra_id: this.grupo_de_compra_id });
this.guardarSubpedidoEnSesion({ id: this.pedido_id, nombre: this.nombre });
}, },
elegirSubpedido(subpedido) {
//lo guardamos en sesion
this.guardarSubpedidoEnSesion(subpedido);
},
guardarSubpedidoEnSesion(subpedido) {
axios.post("/subpedidos/guardar_sesion", {
subpedido: subpedido,
grupo_de_compra_id: this.grupo_de_compra_id
}).then(_ => {
Event.$emit('obtener-sesion')
window.location.href = 'productos';
});
}
} }
} }
</script> </script>

View file

@ -5,6 +5,7 @@ import login from "./modules/login";
import pedido from "./modules/pedido"; import pedido from "./modules/pedido";
import barrio from "./modules/barrio"; import barrio from "./modules/barrio";
import productos from "./modules/productos"; import productos from "./modules/productos";
import ui from "./modules/ui";
Vue.use(Vuex); Vue.use(Vuex);
@ -15,5 +16,6 @@ export default new Vuex.Store({
pedido, pedido,
barrio, barrio,
productos, productos,
ui,
}, },
}); });

View file

@ -38,9 +38,12 @@ const actions = {
const response = await axios.get('/user/grupo_de_compra'); const response = await axios.get('/user/grupo_de_compra');
commit('setState', response.data); commit('setState', response.data);
}, },
async setAprobacionPedido({ commit }, { pedido_id, aprobacion }){ async setAprobacionPedido({ commit, dispatch }, { pedido_id, aprobacion }){
await axios.post("/api/admin/subpedidos/" + pedido_id + "/aprobacion", { aprobacion: aprobacion }); await axios.post("/api/admin/subpedidos/" + pedido_id + "/aprobacion", { aprobacion: aprobacion });
await actions.getGrupoDeCompra({ commit }); await actions.getGrupoDeCompra({ commit });
dispatch("ui/toast",
{ mensaje: `Pedido ${aprobacion ? '' : 'des' }aprobado con éxito.` },
{ root: true });
}, },
async toggleCaracteristica({ commit }, { caracteristica_id }) { async toggleCaracteristica({ commit }, { caracteristica_id }) {
await axios.post(`/api/grupos-de-compra/${state.grupo_de_compra_id}/${caracteristica_id}`); await axios.post(`/api/grupos-de-compra/${state.grupo_de_compra_id}/${caracteristica_id}`);

View file

@ -5,6 +5,7 @@ const state = {
grupos_de_compra: null, grupos_de_compra: null,
region_elegida: null, region_elegida: null,
grupo_de_compra_elegido: null, grupo_de_compra_elegido: null,
rol: null,
}; };
const mutations = { const mutations = {
@ -18,6 +19,9 @@ const mutations = {
selectGrupoDeCompra(state, { grupo_de_compra }) { selectGrupoDeCompra(state, { grupo_de_compra }) {
state.grupo_de_compra_elegido = grupo_de_compra; state.grupo_de_compra_elegido = grupo_de_compra;
}, },
setRol(state, { rol }) {
state.rol = rol;
},
}; };
const actions = { const actions = {
@ -28,17 +32,21 @@ const actions = {
async selectRegion({ commit }, { region }) { async selectRegion({ commit }, { region }) {
const response = await axios.get("/api/grupos-de-compra"); const response = await axios.get("/api/grupos-de-compra");
commit('setRegionYBarrios', { region: region, grupos_de_compra: response.data[region] }); commit('setRegionYBarrios', { region: region, grupos_de_compra: response.data[region] });
},
async getRol({ commit }) {
const response = await axios.get("/user/rol");
commit('setRol', { rol: response.data.rol });
} }
}; };
const getters = { const getters = {
admin() { adminUrl() {
return window.location.pathname.startsWith('/admin'); return window.location.pathname.startsWith('/admin');
}, },
mensajes() { mensajes() {
return { return {
mensaje: `Contraseña de ${getters.admin() ? 'administración ' : ''}del barrio`, mensaje: `Contraseña de ${getters.adminUrl() ? 'administración ' : ''}del barrio`,
ayuda: `Si no la sabés, consultá a ${getters.admin() ? 'la comisión informática ' : 'tus compañerxs'}.` ayuda: `Si no la sabés, consultá a ${getters.adminUrl() ? 'la comisión informática ' : 'tus compañerxs'}.`
}; };
}, },
}; };

View file

@ -1,3 +1,5 @@
import axios from "axios";
const state = { const state = {
lastFetch: null, lastFetch: null,
pedido_id: null, pedido_id: null,
@ -34,20 +36,52 @@ const actions = {
nombre: nombre, nombre: nombre,
grupo_de_compra_id: grupo_de_compra_id grupo_de_compra_id: grupo_de_compra_id
}); });
commit('setState', response.data);
},
async getPedido({ commit }, pedido_id) {
const response = await axios.get(`/api/subpedidos/${pedido_id}`);
commit('setState', response.data.data); commit('setState', response.data.data);
}, },
async modificarChismosa({ commit }, producto_id, cantidad, notas) {}, async elegirPedido({ commit }, { pedido }) {
async modificarDevoluciones({ commit }, monto, notas) {} const response = await axios.get(`/api/subpedidos/${pedido.id}`);
commit('setState', response.data.data);
},
async modificarChismosa({ commit, dispatch }, { producto_id, cantidad, notas }) {
try {
const response = await axios.post("/api/subpedidos/" + state.pedido_id + "/sync", {
cantidad: cantidad,
producto_id: producto_id,
notas: notas,
});
commit('setState', response.data.data);
dispatch("ui/toast", { mensaje: 'Pedido modificado con éxito' }, { root: true });
} catch (error) {
dispatch("ui/error", { error: error }, { root: true });
}
},
async modificarDevoluciones({ commit, dispatch }, { monto, notas }) {
try {
const response = await axios.post("api/subpedidos/" + state.pedido_id + "/sync_devoluciones", {
total: monto,
notas: notas,
});
commit('setState', response.data.data);
dispatch("ui/toast", { mensaje: 'Devoluciones modificadas con éxito' }, { root: true });
} catch (error) {
dispatch("ui/error", { error: error }, { root: true });
}
},
}; };
const getters = { const getters = {
pedidoDefinido() { pedidoDefinido() {
return state.lastFetch !== null; return state.lastFetch !== null;
}, },
enChismosa() {
return ((producto_id) => state.productos.some(p => p.id === producto_id));
},
cantidad() {
return ((producto_id) => state.productos.find(p => p.id === producto_id)?.pivot.cantidad ?? 0);
},
notas() {
return ((producto_id) => state.productos.find(p => p.id === producto_id)?.pivot.notas ?? "");
}
} }
export default { export default {

48
resources/js/store/modules/ui.js vendored Normal file
View file

@ -0,0 +1,48 @@
import { dropWhile } from "lodash/array";
const state = {
show_chismosa: false,
show_devoluciones: false,
miga_inicial: { nombre: 'Categorias', action: 'productos/getProductos' },
migas: [{ nombre: 'Categorias', action: 'productos/getProductos' }],
};
const mutations = {
toggleChismosa(state) {
state.show_chismosa = !state.show_chismosa;
},
toggleDevoluciones(state) {
state.show_devoluciones = !state.show_devoluciones;
},
addMiga(state, miga) {
state.migas.push(miga);
},
};
const actions = {
clickMiga({ dispatch }, { miga }) {
dispatch(miga.action, null, { root: true });
state.migas = dropWhile(state.migas.reverse(),(m => m.nombre !== miga.nombre)).reverse();
},
toast(_, { mensaje }) {
return window.bulmaToast.toast({
message: mensaje,
duration: 2000,
type: 'is-danger',
position: 'bottom-center',
});
},
error({ dispatch }, { error }) {
const errorMsg = error.response && error.response.data && error.response.data.message
? error.response.data.message
: error.message;
dispatch("toast", { mensaje: errorMsg });
},
};
export default {
namespaced: true,
state,
mutations,
actions,
};

View file

@ -7,7 +7,7 @@
<!-- CSRF Token --> <!-- CSRF Token -->
<meta name="csrf-token" content="{{ csrf_token() }}"> <meta name="csrf-token" content="{{ csrf_token() }}">
<title>{{ session("subpedido_nombre") ? "Pedido de " . session("subpedido_nombre") . " - " . config('app.name', 'Pedidos del MPS') : config('app.name', 'Pedidos del MPS')}}</title> <title>{{ config('app.name', 'Pedidos del MPS') }}</title>
<link rel="icon" type="image/x-icon" href="/assets/favicon.png"> <link rel="icon" type="image/x-icon" href="/assets/favicon.png">
<!-- Fonts --> <!-- Fonts -->
@ -26,7 +26,6 @@
</comunes-nav-bar> </comunes-nav-bar>
<pedidos-nav-migas></pedidos-nav-migas> <pedidos-nav-migas></pedidos-nav-migas>
<main id="main" class="py-4 has-top-padding"> <main id="main" class="py-4 has-top-padding">
<pedidos-cartel-pedido-aprobado></pedidos-cartel-pedido-aprobado>
@yield('content') @yield('content')
</main> </main>
</div> </div>

View file

@ -0,0 +1,8 @@
@extends('layouts.app')
@section('content')
<app-main></app-main>
@endsection
@section('scripts')
@endsection

View file

@ -1,17 +1,7 @@
@extends('layouts.app') @extends('layouts.app')
@section('content') @section('content')
<section class="section"> <app-main></app-main>
<div id="root" class="container">
<h1 class="title">
Pedidos MPS
</h1>
<p class="subtitle">
Bienvenidx a la aplicación de pedidos del <strong>Mercado Popular de Subsistencia</strong>
</p>
<pedidos-subpedido-select></pedidos-subpedido-select>
</div>
</section>
@endsection @endsection
@section('scripts') @section('scripts')

View file

@ -25,13 +25,16 @@ Auth::routes(['register' => false]);
Route::get('/', 'RouteController@home')->name('home'); Route::get('/', 'RouteController@home')->name('home');
Route::middleware(['auth'])->group(function () { Route::middleware(['auth'])->group(function () {
Route::get('/user/rol', 'UserController@rol')->name('user.rol');
Route::get('/user/grupo_de_compra', 'UserController@grupoDeCompra'); Route::get('/user/grupo_de_compra', 'UserController@grupoDeCompra');
}); });
Route::middleware(['auth', 'role:barrio'])->group( function() { Route::middleware(['auth', 'role:barrio'])->group(function() {
Route::get('/pedido', 'RouteController@main')->name('pedido');
Route::get('/productos', 'ProductoController@index')->name('productos.index'); Route::get('/productos', 'ProductoController@index')->name('productos.index');
Route::name('subpedidos.')->prefix("subpedidos")->group( function() { Route::name('subpedidos.')->prefix("subpedidos")->group(function() {
Route::get('/', function() { Route::get('/', function() {
return view('subpedidos_create'); return view('subpedidos_create');
})->name('create'); })->name('create');
@ -68,8 +71,8 @@ Route::middleware(['auth', 'role:barrio'])->group( function() {
Route::get('/admin/login', 'AdminController@show')->name('admin.login'); Route::get('/admin/login', 'AdminController@show')->name('admin.login');
Route::middleware(['auth', 'role:admin_barrio'])->group( function () { Route::middleware(['auth', 'role:admin_barrio'])->group(function () {
Route::get('/admin', 'AdminController@index')->name('admin.pedidos'); Route::get('/admin', 'RouteController@main')->name('admin');
Route::get('/admin/exportar-planillas-a-pdf/{gdc}', 'AdminController@exportarPedidosAPdf'); Route::get('/admin/exportar-planillas-a-pdf/{gdc}', 'AdminController@exportarPedidosAPdf');
@ -81,7 +84,7 @@ Route::middleware(['auth', 'role:admin_barrio'])->group( function () {
Route::get('/compras/login', 'ComprasController@show')->name('compras.login'); Route::get('/compras/login', 'ComprasController@show')->name('compras.login');
Route::middleware(['auth', 'role:comision'])->group( function() { Route::middleware(['auth', 'role:comision'])->group( function() {
Route::get('/compras', 'ComprasController@indexPedidos')->name('compras.pedidos'); Route::get('/compras', 'RouteController@main')->name('compras');
Route::get('/compras/pedidos/descargar', 'ComprasController@descargarPedidos')->name('compras.pedidos.descargar'); Route::get('/compras/pedidos/descargar', 'ComprasController@descargarPedidos')->name('compras.pedidos.descargar');
Route::get('/compras/pedidos/notas', 'ComprasController@descargarNotas')->name('compras.pedidos.descargar'); Route::get('/compras/pedidos/notas', 'ComprasController@descargarNotas')->name('compras.pedidos.descargar');
Route::get('/compras/pedidos/pdf', 'ComprasController@pdf')->name('compras.pedidos.pdf'); Route::get('/compras/pedidos/pdf', 'ComprasController@pdf')->name('compras.pedidos.pdf');