Compare commits

..

399 commits

Author SHA1 Message Date
7eb7dd04d7 Merge pull request 'refactor/totales' (#41) from refactor/totales into master
Reviewed-on: nathalie/pedi2#41
2025-04-13 23:22:08 -03:00
ale
45757f0ae1 Agregado redondeo 2025-03-18 23:01:03 -03:00
ale
45e8a189cf Cambios para usar nuevos resources (pedidos, gdc) 2025-03-18 19:58:49 -03:00
ale
fd2c1b2970 Cambios para usar nuevo resource de gdc + arreglo plancha con timeout para sincornizar datos 2025-03-18 19:58:19 -03:00
ale
2587c759fb Reestablecida ruta para devoluciones 2025-03-18 19:55:54 -03:00
ale
2a1394a5c4 Cambio por nuevo resource de pedido 2025-03-18 19:45:16 -03:00
ale
56eb59ddeb Arreglos en resource 2025-03-18 19:45:06 -03:00
ale
354079519a Quitado argumento innecesario 2025-03-18 19:39:06 -03:00
ale
2ca91addb0 Agregado total devoluciones y devoluciones habilitadas a resource + metodo para total devoluciones 2025-03-18 19:34:02 -03:00
ale
c46073ed06 Cambio de endpoints individuales a resource 2025-03-17 18:35:12 -03:00
ale
df0b66bf65 Agregados resource y controller en api 2025-03-17 18:11:50 -03:00
ale
641eb6a4d3 Nuevos metodos de totales 2025-03-17 18:11:36 -03:00
ale
e598e1496b Agregado helper para transporte + limpieza 2025-03-17 17:28:54 -03:00
ale
085d72b4f8 Actualizado a nuevo resource 2025-03-17 17:15:08 -03:00
ale
c54a0b361f Cambios en totales 2025-03-17 17:02:49 -03:00
ale
2a5c215f40 Restando devoluciones al total 2025-03-17 17:01:59 -03:00
ale
584cebb902 Agregadas nuevas funciones para calcular total de pedidos 2025-03-17 16:49:43 -03:00
d4bffd1df8 Merge pull request 'funcion/actualizar-canasta-desde-compras' (#39) from funcion/actualizar-canasta-desde-compras into master
Reviewed-on: nathalie/pedi2#39
2024-12-27 19:32:15 -03:00
ale
94c2baff07 Arreglado nombre de campo 2024-12-24 15:02:46 -03:00
ale
7b36aa0b0c Arreglado error en FilaCaracteristica.vue 2024-12-23 18:54:49 -03:00
ale
5feb2ff22f Cambios nombre columna 2024-12-23 15:58:33 -03:00
ale
d0ffcda226 Cambios nombre columna 2024-12-23 15:58:14 -03:00
ale
1f2ab91bd3 Cambios nombre columna 2024-12-23 15:57:18 -03:00
ale
184b53cfc8 Cambios minimos 2024-12-23 00:09:39 -03:00
ale
345be9c688 Cambio mensaje 2024-12-22 23:41:25 -03:00
ale
30eb822201 Limpieza de tablas previa a cargar + bono barrial 2024-12-22 10:28:05 -03:00
ale
76f2af2ef9 Cambio mensaje 2024-12-22 09:43:57 -03:00
ale
9f93a17053 Cambio mensaje 2024-12-22 01:54:04 -03:00
ale
83016d38b0 Agregado instructivo para planilla de canasta 2024-12-22 01:51:53 -03:00
ale
cc734866c5 Agregada logica para logs de carga de canastas 2024-12-21 15:48:06 -03:00
ale
c31b808f05 Agregada tabla para log de carga de canastas 2024-12-21 15:16:10 -03:00
ale
95a9a404d2 Manejo de archivos movido a helper y limpieza 2024-12-21 15:08:35 -03:00
ale
57b8d6bcce Agregada logica para cargar canasta 2024-12-21 14:57:03 -03:00
ale
ac4d5895be Logica de trabajo con CSV y carga movida a CanastaHelper.php 2024-12-21 14:56:53 -03:00
ale
131bf33a73 Agregada ruta y logica para cargar canastas 2024-12-21 14:37:38 -03:00
ale
5a4b933f11 Agregado csv input para canasta 2024-12-21 14:17:47 -03:00
ale
bea8de2c8c Siempre habilitado 2024-12-21 13:56:45 -03:00
ale
92782be7f6 Descargas movidas a dropdown 2024-12-21 13:48:40 -03:00
ale
22cbac14f1 Pestañas para body de compras 2024-12-21 13:29:14 -03:00
ale
bddaf223e4 tab-secciones movida a comunes 2024-12-21 13:21:39 -03:00
ale
4b2ed9f90e Generalizacion de tab-secciones 2024-12-21 13:20:34 -03:00
cad8dffbcf Merge pull request 'funcion/arreglar-planilla-totales' (#38) from funcion/arreglar-planilla-totales into master
Reviewed-on: nathalie/pedi2#38
2024-12-21 11:06:23 -03:00
ale
c4eb4563d5 Arreglado nombre de archivo 2024-12-09 21:13:51 -03:00
ale
cef38cf69c Borrada funcion innecesaria 2024-12-09 20:59:34 -03:00
ale
8a0f8fbe13 Hueco para transporte 2024-12-09 20:58:56 -03:00
ale
9abeb98239 Cambiado a left join para tener todos los productos 2024-12-09 20:52:51 -03:00
ale
fab7695e6c Agregado boton para planilla de transporte 2024-12-09 13:03:32 -03:00
ale
2486826dba Agregada ruta y método de controlador para planilla de transporte 2024-12-09 12:59:59 -03:00
ale
1b82700db3 Limpieza 2024-12-09 12:57:53 -03:00
ale
635cecedb7 Quitados comentarios 2024-12-09 12:56:47 -03:00
ale
5c97fc9e70 Cambiado para tener todos los barrios, incluso los que tienen 0 bonos de transporte 2024-12-09 12:52:41 -03:00
ale
8e885c18d8 Planilla de transporte 2024-12-09 12:35:32 -03:00
ale
b5d23c6740 Formato 2024-12-09 12:35:11 -03:00
ale
f778a4f24e Planilla de notas + ignorar barrio PRUEBA 2024-12-09 12:33:42 -03:00
ale
acc21091f9 Merge remote-tracking branch 'origin/funcion/arreglar-planilla-totales' into funcion/arreglar-planilla-totales
# Conflicts:
#	app/Producto.php
2024-12-09 07:20:56 -03:00
ale
ec10bdca92 Cambio en controller para usar metodo de producto 2024-12-09 07:20:28 -03:00
ale
f84e1f2954 Nueva logica para planilla de notas, a partir de producto 2024-12-09 07:18:02 -03:00
ale
df05b31b86 Eliminado método viejo 2024-12-09 07:01:37 -03:00
ale
1b16669512 Cambio de método en ruta de descarga de pedidos 2024-12-09 07:01:37 -03:00
ale
d170f9e46e Agregada funcion que genera planilla de totales por barrio 2024-12-09 07:01:37 -03:00
ale
f5f9838fc3 Agregada funcion que genera tabla de totales por producto 2024-12-09 07:01:37 -03:00
ale
c58f24d2d0 Hotfix: arreglada validacion de cantidad + cartelito de 'en chismosa' 2024-12-06 20:15:57 -03:00
Nat
e75fcc562a canasta diciembre 2024 2024-12-02 14:47:49 -03:00
ale
6dae6afe95 Eliminado método viejo 2024-11-25 21:46:40 -03:00
ale
1c5b8ecb29 Cambio de método en ruta de descarga de pedidos 2024-11-25 21:45:09 -03:00
ale
00b41afa5a Agregada funcion que genera planilla de totales por barrio 2024-11-25 21:44:03 -03:00
ale
1324898483 Agregada funcion que genera tabla de totales por producto 2024-11-25 17:20:04 -03:00
ba22988026 Merge pull request 'funcion: notas de producto' (#36) from funcion/notas-producto into master
Reviewed-on: nathalie/pedi2#36
2024-11-12 22:08:36 -03:00
ale
9c9b1dc6cb Merge branch 'refs/heads/master' into funcion/notas-producto 2024-11-12 21:48:48 -03:00
ale
73f02dfff0 Canasta 107 - fix2 2024-11-05 12:07:45 -03:00
ale
bbb57e1d7f Canasta 107 - fix 2024-11-05 11:07:23 -03:00
ale
2996cf4100 Merge remote-tracking branch 'origin/master' 2024-11-05 10:48:39 -03:00
ale
97ec11331b Canasta 107 2024-11-05 10:48:22 -03:00
ale
8c9a0ee4c1 Actualizado package-lock.json 2024-11-05 10:46:38 -03:00
ale
01d5abdd99 Arreglado error en migración 2024-11-05 10:45:50 -03:00
Rodrigo
f9e55b38a5 Merge branch 'master' into funcion/notas-producto 2024-10-18 19:10:20 -03:00
Rodrigo
3ad9500f23 Alerta de notas sale sólo después de intentar de confirmar 2024-10-16 22:32:16 -03:00
Rodrigo
538cc84e10 Desactivar agregar producto si requiere notas y están vacías 2024-10-16 21:56:05 -03:00
4e7e46f92d Merge pull request 'Filtrado de barrios para usar solo los que tienen pedidos aprobados + agregada cantidad de bonos de transporte a planilla de totales de barrios' (#37) from funcion/planilla-pedidos-total into master
Reviewed-on: nathalie/pedi2#37
Reviewed-by: Rodrigo <rodrigopdm@protonmail.com>
2024-10-15 21:46:42 -03:00
ale
61e756f9e5 Filtrado de barrios para usar solo los que tienen pedidos aprobados + agregada cantidad de bonos de transporte a planilla de totales de barrios 2024-10-15 21:37:22 -03:00
Rodrigo
be945b0eee Agregué las notas al PDF para el armado del barrio 2024-10-15 20:56:37 -03:00
Rodrigo
b5f4443836 Boton para descargar notas en pag de compras 2024-10-15 20:44:28 -03:00
ale
c53e342f54 Hotfix: quitado animate de bulma-toast 2024-10-08 21:08:50 -03:00
ale
ff213bd90d Canasta 106 2024-10-08 20:45:01 -03:00
Rodrigo
1e443ea2ca Merge branch 'master' into funcion/notas-producto 2024-10-08 20:36:16 -03:00
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
96eea84997 Merge pull request 'funcion/planilla-pedidos-total' (#33) from funcion/planilla-pedidos-total into master
Reviewed-on: nathalie/pedi2#33
2024-10-08 20:07:56 -03:00
ale
10273e2159 Arreglos post-merge 2024-10-08 20:07:03 -03:00
ale
0b55fa8109 Merge branch 'refs/heads/master' into funcion/planilla-pedidos-total
# Conflicts:
#	resources/js/components/pedidos/Chismosa.vue
#	resources/js/components/pedidos/ChismosaDropdown.vue
#	resources/views/productos.blade.php
2024-10-08 19:43:04 -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
e106faceda Merge pull request 'nueva-chismosa' (#35) from nueva-chismosa into master
Reviewed-on: nathalie/pedi2#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
ale
88e3532418 Arreglado metodo para generar csv con totales de todos los barrios 2024-09-17 21:48:44 -03:00
ale
07289b01e9 Arreglado metodo que al final sí era usado 2024-09-17 21:45:28 -03:00
ale
5c1fa931eb Arreglo tags 2024-09-17 21:42:55 -03:00
Rodrigo
82f5862063 Mostrar notas en pedido 2024-09-17 21:28:08 -03:00
Rodrigo
7eeeae6a1e Agregar notas a la base de datos 2024-09-17 21:27:58 -03:00
ale
744b867af3 Agregado body de compras y cambios en rutas 2024-09-17 20:41:50 -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
ale
917e3e1df3 Ajustes de refactor 2024-09-14 16:25:57 -03:00
ale
517b95f14f Merge branch 'refs/heads/refactor/componentes-vue' into funcion/planilla-pedidos-total
# Conflicts:
#	resources/js/components/admin/Body.vue
#	resources/js/components/pedidos/ProductoModal.vue
2024-09-14 16:12:09 -03:00
ale
2337ad9a37 Login de compras funcionando 2024-09-14 13:37:06 -03:00
ale
99f327445e Merge branch 'refs/heads/master' into funcion/planilla-pedidos-total 2024-09-14 12:45:14 -03:00
b4ca119f9a Merge pull request 'hotfix/negativos-chismosa' (#34) from hotfix/negativos-chismosa into master
Reviewed-on: nathalie/pedi2#34
2024-09-14 11:17:13 -03:00
ale
9d9ebd75b5 Borrado boton inutil de chismosa 2024-09-14 11:06:09 -03:00
ale
b79548624f Botón '-' no baja de 0 + no se puede confirmar con cantidad menor a 0 2024-09-14 11:03:55 -03:00
Rodrigo
fbae6770df Cismosa: Ajustes visuales 2024-09-10 22:07:16 -03:00
ale
5f565a3f5a Pantalla de login con textfields + agregado caso de usuario de compras a LoginController.php 2024-09-10 22:07:11 -03:00
Rodrigo
69cd306263 Moví la chismosa a la derecha de los productos 2024-09-10 21:31:49 -03:00
ale
bf3f697299 Agregadas rutas con middleware y pantalla de login vacia 2024-09-10 21:11:22 -03:00
ale
53691f6a30 Arreglado middleware compras 2024-09-10 21:03:01 -03:00
ale
9259248caf Middleware de compras andando 2024-09-10 20:23:49 -03:00
ale
9f6f36e2e6 Merge branch 'refs/heads/master' into funcion/planilla-pedidos-total 2024-09-10 19:50:42 -03:00
ale
1204a80b3c Canasta 105: fix provisorio castañas con precio anterior 2024-09-09 01:43:08 -03:00
ale
b9702a736e Canasta 105 2024-09-09 01:33:20 -03:00
ale
4283eae3be hotfix: margenes en admin body 2024-09-09 01:28:13 -03:00
28f2b3b498 Merge pull request 'funcion/nueva-lista-de-productos' (#32) from funcion/nueva-lista-de-productos into master
Reviewed-on: nathalie/pedi2#32
2024-09-09 01:18:58 -03:00
ale
079b21af04 Cambio margenes 2024-09-09 01:17:08 -03:00
ale
ffd4570d44 Cambio lugar de iconos y mensaje de chismosa 2024-09-09 01:09:23 -03:00
ale
82ad4dd910 Arreglado ancho de columnas 2024-09-09 00:14:29 -03:00
e334234c9f Merge pull request 'funcion/producto-paga-transporte' (#31) from funcion/producto-paga-transporte into master
Reviewed-on: nathalie/pedi2#31
Reviewed-by: Rodrigo <rodrigopdm@protonmail.com>
2024-09-07 10:53:01 -03:00
ale
3340de941b Revert "Mejoras en cálculo de cantidad de bonos de transporte"
This reverts commit 3770d728c3.
2024-09-05 17:11:53 -03:00
ale
3770d728c3 Mejoras en cálculo de cantidad de bonos de transporte 2024-09-05 13:52:31 -03:00
ale
c86eb97cb9 Cambio lógica de pago de transporte 2024-09-05 13:34:33 -03:00
ale
d91d46c589 Seeding simplificado 2024-09-04 15:41:35 -03:00
ale
449579a768 Merge branch 'refs/heads/master' into funcion/planilla-pedidos-total
# Conflicts:
#	app/GrupoDeCompra.php
2024-09-01 13:11:53 -03:00
bb29e34b1b Merge pull request 'funcion/nueva-lista-de-productos' (#29) from funcion/nueva-lista-de-productos into master
Reviewed-on: nathalie/pedi2#29
2024-09-01 12:58:37 -03:00
Rodrigo
078e29a01f Desactivar botones de producto cuando no hacen nada 2024-08-31 23:03:09 -03:00
ale
189342d785 Refactor de componentes de pantalla de pedidos 2024-08-30 01:34:03 -03:00
ale
003cb86ec0 Refactor de componentes de pantalla de admin 2024-08-30 01:33:47 -03:00
ale
12b77de018 Refactor de componentes de pantallas de login 2024-08-30 01:14:30 -03:00
ale
5453b1158f Cambio en logica de registro automatico de componentes 2024-08-30 01:13:06 -03:00
ale
18ede25c16 Cambios de estilo 2024-08-30 00:10:50 -03:00
ale
6d58524823 Arreglado problema de márgenes 2024-08-29 23:01:31 -03:00
ale
2a57fdc1e9 Solo actualiza el producto que cambia 2024-08-29 22:54:05 -03:00
ale
ddd8d57d2b ProductosContainer.vue usa ProductoCard.vue 2024-08-29 22:51:46 -03:00
ale
781ef8a7a1 ProductoModal.vue reemplazado por ProductoCard.vue 2024-08-29 22:51:13 -03:00
ale
43f2a1e928 eliminados parametros innecesarios y evento vacío que tiraba error 2024-08-29 22:50:53 -03:00
ale
97139905cc actualizado gitignore 2024-08-29 21:46:07 -03:00
ale
438071eea3 formato 2024-08-29 21:43:24 -03:00
ale
937e7ec16c Agregado input para cantidad con botones, todavia sin logica 2024-08-29 21:43:13 -03:00
ale
9d96010752 package-lock.json 2024-08-29 21:16:09 -03:00
ale
4e7c1232b0 Agregada public/mix-manifest.json 2024-08-29 21:15:22 -03:00
ale
9b06839798 Cambio public por public/js y public/css 2024-08-29 20:54:06 -03:00
ale
4a59b8e146 Cambio public por public/js y public/css 2024-08-29 20:53:59 -03:00
Rodrigo
39e1eaddcf Poner cantidad 0 saca el producto de la chismosa 2024-08-27 23:32:38 -03:00
Rodrigo
5ca11324a0 Modal de producto ajustado 2024-08-27 23:27:18 -03:00
Rodrigo
758c425f91 Las cards de productos ahora son boxes en lista 2024-08-27 22:51:31 -03:00
ale
2d7a90f6b2 Agregado middleware para comision compras + columna en tabla users 2024-08-27 21:21:10 -03:00
11d18ad4a5 Merge pull request 'funcion/devoluciones' (#28) from funcion/devoluciones into master
Reviewed-on: nathalie/pedi2#28
Reviewed-by: Rodrigo <rodrigopdm@protonmail.com>
2024-08-27 21:18:15 -03:00
ale
2beda0bf5b ComprasController + hice estáticos algunos métodos + primeros pasos hacia total de pedidos de los barrios 2024-08-27 20:57:11 -03:00
ale
48e1a04bae Borrado método no usado 2024-08-27 20:56:27 -03:00
ale
f0f05f8361 Borrado controller no usado 2024-08-27 20:56:20 -03:00
ale
800fed2097 Agregada ruta para obtener total de pedidos 2024-08-27 19:53:57 -03:00
Rodrigo
203b70e2ef Agregar paso de instalar dependencias de npm a README 2024-08-20 21:17:29 -03:00
Rodrigo
bf703489fd Actualizar total bonos barriales en admin 2024-08-20 21:15:22 -03:00
ale
c57fd0436d canasta 104 arreglo 2024-08-06 22:57:12 -03:00
ale
d04650facf debugeo 2024-08-06 22:53:28 -03:00
ale
4ee91ed5a0 canasta 104 2024-08-06 22:36:45 -03:00
ale
32d84879c7 cambio visual notas de devoluciones 2024-07-17 17:25:41 -03:00
ale
6f1b4581ce cambio en cuenta de bonos barriales 2024-07-17 17:25:19 -03:00
ale
0659f67e84 cambio en validacion 2024-07-17 17:25:08 -03:00
ale
42f0cc11d4 cambios de visibilidad en la tabla de totales en funcion de si devoluciones está activada o no 2024-07-17 16:46:31 -03:00
ale
05d13008fb cambio validacion de devoluciones 2024-07-17 16:26:16 -03:00
ale
5921767654 arreglos en las cuentas 2024-07-11 19:55:14 -03:00
ale
475d2a6cd9 cambio a pagado 2024-07-11 19:54:56 -03:00
ale
9781d63a60 agregado id de grupo de compra a la cookie para poder (des)habilitar devoluciones 2024-07-11 19:00:31 -03:00
ale
057170118d cambio segun si devoluciones esta activa 2024-07-11 18:59:47 -03:00
ale
0c79d3b002 agregada tabla de caracteristicas con switch para togglearlas 2024-07-11 18:34:45 -03:00
ale
105335a773 no renderiza si no estan habilitadas las devoluciones 2024-07-11 18:34:20 -03:00
ale
749940233d cambio nombre seccion 2024-07-11 18:33:56 -03:00
ale
d9e8264cd0 cambio nombre seccion 2024-07-11 18:33:45 -03:00
ale
9babf1975f borrado log viejo 2024-07-11 18:32:52 -03:00
ale
716d1ca6fa Cambio de logica de obtener sesion + variable para habilitar devoluciones 2024-07-11 18:32:42 -03:00
ale
388beba5cc Cambio de where a find para obtener directamente por id + arreglo acceso a propiedad 2024-07-11 18:31:59 -03:00
ale
75b7507bbe Agregada metodo para togglear devoluciones + ruta de api 2024-07-11 17:03:19 -03:00
ale
9e7eb89014 Agregada pestaña para caracteristicas 2024-07-11 16:32:25 -03:00
ale
808980d77e Ignorando public 2024-07-11 16:25:38 -03:00
ale
66984043bc Merge branch 'master' into funcion/devoluciones 2024-07-10 19:05:28 -03:00
ale
05f2777a49 fix version php 2024-07-10 19:03:05 -03:00
ale
725a599b6a Canasta 103 2024-07-08 21:01:30 -03:00
ale
1c5cabb253 Canasta 103 2024-06-03 15:12:45 -03:00
ale
31dadcc10b Canasta 101 - 2do intento 2024-05-06 20:46:44 -03:00
ale
70755ba0a2 Canasta 101 2024-05-06 20:27:36 -03:00
ale
8fc1a3b256 Cambios de tipo para parseo 2024-04-08 21:00:33 -03:00
ale
814295e8ee Cambio por el csv correcto 2024-04-08 20:58:38 -03:00
nathalie
fefd052a8e Revert "Cambio en cuenta de bonos de transporte"
This reverts commit 43b0b04859.
2024-04-08 15:31:13 -03:00
nathalie
ab7e44fd85 Revert "cambio logica bdt"
This reverts commit e9321678e2.
2024-04-08 15:31:00 -03:00
ale
b66c2fe19d Agregado nombre de columna 2024-04-08 15:15:35 -03:00
ale
9cf4a117df Merge branch 'master' of https://git.mps.org.uy/nathalie/pedi2 2024-04-08 15:06:26 -03:00
ale
0b427e4796 Canasta 100 2024-04-08 15:05:18 -03:00
85238695c7 Merge pull request 'Cambio en cuenta de bonos de transporte' (#27) from funcion/fix-bonos-de-transporte into master
Reviewed-on: nathalie/pedi2#27
2024-04-06 16:48:06 -03:00
ale
e9321678e2 cambio logica bdt 2024-03-18 20:12:08 -03:00
ale
43b0b04859 Cambio en cuenta de bonos de transporte 2024-03-17 17:12:21 -03:00
5036c2baa9 Actualizar 'README.md' 2024-03-17 16:46:20 -03:00
ale
b19556fd39 Cambio seeder bonos 2024-03-11 15:34:25 -03:00
ale
35b0533664 Canasta 99 2024-03-11 15:34:09 -03:00
ale
16e5075825 canasta 98 2024-02-12 21:42:43 -03:00
Ale
0665770972 canasta 96 2023-12-06 08:44:08 -03:00
1ccfbe11a7 Merge pull request 'Sacado total de bonos de chismosa' (#26) from funcion/sacar-total-bonos-de-chismosa into funcion/devoluciones
Reviewed-on: nathalie/pedi2#26
2023-11-25 13:40:28 -03:00
Ale
4376586a23 agregado campo y ruta para togglear devoluciones 2023-11-12 20:13:17 -03:00
Ale
d16a8de5ac Sacado total de bonos de chismosa 2023-11-12 11:48:47 -03:00
Ale
10f4fefb0c Total sin devoluciones en la barra 2023-11-12 11:47:01 -03:00
Ale
f3ee5ea7d9 Agregado mouseover con notas de la devolucion 2023-11-12 11:46:16 -03:00
Ale
5b2c489f2d Columnas a su propia migracion 2023-11-12 11:26:29 -03:00
Ale
e7100121d4 Merge branch 'master' into funcion/devoluciones 2023-11-12 09:54:56 -03:00
Ale
e0a64d3653 Canasta 95 2023-11-06 16:14:51 -03:00
Ale
fe2d8608cb Pequeños ajustes 2023-11-06 14:03:43 -03:00
Ale
e7c90a4899 Cambio de nombre para hacer compatible con docker-compose.yml 2023-11-06 14:00:43 -03:00
Ale
0a51ccba2a USERID agregada 2023-11-06 13:58:48 -03:00
Ale
988bf266e8 canasta 94 2023-10-10 19:49:17 -03:00
Rodrigo
3941dc0fd2 Mostrar devoluciones en admin 2023-10-05 12:58:03 -03:00
Rodrigo
1a8448ca45 Merge branch 'master' into funcion/devoluciones 2023-10-05 12:00:02 -03:00
9954dbd66a Merge pull request 'Mejoras varias a la pantalla de admini' (#24) from funcion/mejoras-admin into master
Reviewed-on: nathalie/pedi2#24
2023-10-05 11:59:15 -03:00
Rodrigo
14361a858e Devoluciones: modelo y sync
Lo agregué a la base de datos y se sincroniza con un modal
que se abre desde la chismosa
2023-10-04 23:36:03 -03:00
Ale
8f8733cb7b Mejoras varias a la pantalla de admini 2023-10-04 22:37:59 -03:00
aab05541b2 Merge pull request 'Exportar tabla de compras con todos los nucleos a CSV' (#20) from exportar-tabla-compras into master
Reviewed-on: nathalie/pedi2#20
2023-09-18 19:07:34 -03:00
Rodrigo
5b6fd933e3 Agregado botón de descarga de planilla completa
Modificado orden y textos para claridad
2023-09-17 17:22:50 -03:00
Ale
9634f51054 Alineación de texto en tabla de bonos 2023-09-10 17:07:41 -03:00
Ale
80fbbd510d Merge branch 'master' of https://git.mps.org.uy/nathalie/pedi2 2023-09-09 13:33:12 -03:00
Ale
c278e0a7a5 Cambios de formato de numeros 2023-09-09 13:32:49 -03:00
f55ac3a4ff Merge pull request 'Agregado versionado al build' (#23) from funcion/versionado into master
Reviewed-on: nathalie/pedi2#23
2023-09-05 19:00:33 -03:00
Rodrigo
e1aa6e2f68 Agregado versionado al build 2023-09-05 18:47:09 -03:00
Ale
71b4c1c38d Canasta 93: faltaban precios de copas solidarias 2023-09-05 13:12:55 -03:00
Ale
a7a1f69c5a Merge branch 'master' of https://git.mps.org.uy/nathalie/pedi2 2023-09-05 13:02:50 -03:00
Ale
3a894f2965 Canasta 93 2023-09-05 13:02:27 -03:00
381909fb7e Merge pull request 'Refactor del cartel pera que aparezca en todas las pantallas' (#22) from funcion/cartelito-pedido-aprobado into master
Reviewed-on: nathalie/pedi2#22
2023-09-05 12:35:55 -03:00
Ale
17cc127f2e Refactor del cartel pera que aparezca en todas las pantallas 2023-09-05 10:08:36 -03:00
9991337b87 Merge pull request 'Modal de producto muestra cantidad pedida' (#19) from refactor/cantidades-producto into master
Reviewed-on: nathalie/pedi2#19
2023-09-04 21:22:25 -03:00
b58261bbf0 Merge pull request 'No sincronizar subpedidos aprobados' (#21) from funcion/congelar-pedidos-aprobados into master
Reviewed-on: nathalie/pedi2#21
2023-09-04 20:33:09 -03:00
Rodrigo
b09d284a1d Agregado notificación de pedido aprobado 2023-09-04 20:32:16 -03:00
Ale
5a4a1ff391 El toast ahora dura 2s 2023-09-04 18:20:31 -03:00
Ale
72b3d1e4af Merge branch 'master' of https://git.mps.org.uy/nathalie/pedi2 2023-08-07 17:23:03 -03:00
Ale
ca3af75b5a Canasta 92 2023-08-07 17:22:38 -03:00
Rodrigo
f50d4b975d Agregado toast que avisa si el pedido fue aprobado 2023-07-11 21:33:33 -03:00
Rodrigo
bf3b888e71 No sincronizar subpedidos aprobados 2023-07-10 21:29:25 -03:00
Ale
cadd9de7a0 dependencia cross-env 2023-07-06 23:25:05 -03:00
Rodrigo
ccdba6efd4 Merge branch 'master' of ssh://git.mps.org.uy:4422/nathalie/pedi2 2023-07-06 10:39:42 -03:00
dc339fb025 Merge branch 'master' into exportar-tabla-compras 2023-07-06 10:35:30 -03:00
Rodrigo
962d6ec58a Exportar pedido con nucleos a CSV 2023-07-06 00:18:52 -03:00
Rodrigo
8d3f686fa1 Crear view 'pedidos_aprobados' en migraciones 2023-07-05 23:30:38 -03:00
Rodrigo
148f0e5244 Crear view 'pedidos_aprobados' en migraciones 2023-07-05 23:25:36 -03:00
Ale
129d52d6d6 canasta 91 2023-07-04 20:12:36 -03:00
Ale
22e4253ea9 Ahora si, cantidad en modal y en tarjeta 2023-06-17 15:54:18 -03:00
Ale
121dfa4c49 Modal de producto muestra cantidad pedida 2023-06-10 19:20:25 -03:00
nathalie
9bf68050a7 merged from server 2023-06-07 22:21:21 -03:00
nathalie
615c9427b9 merge from server 2023-06-07 22:20:36 -03:00
023cef2bf3 Merge pull request 'refactor/chismosa' (#18) from refactor/chismosa into master
Reviewed-on: nathalie/pedi2#18
2023-06-07 22:04:36 -03:00
2426638414 Merge pull request 'funcion/buscar-productos' (#17) from funcion/buscar-productos into master
Reviewed-on: nathalie/pedi2#17
2023-06-07 22:03:48 -03:00
d18de9e4c0 Merge pull request 'Rework de la tabla de bonos y cambios en total de tabla de pedidos' (#16) from funcion/cambio-admin-bonos into master
Reviewed-on: nathalie/pedi2#16
2023-06-07 22:03:18 -03:00
Ale
6f2721a0f2 canasta 90 2023-06-07 20:41:47 -03:00
Ale
70aaadd901 refactor de chismosa 2023-05-27 20:08:55 -03:00
Ale
daa998c89e cambio de nombre de evento 2023-05-27 15:38:56 -03:00
Ale
c2ce43d295 buscar productos funcionando 2023-05-27 15:33:08 -03:00
Ale
d19c83289d busqueda funcionando, migas rotas 2023-05-27 14:23:52 -03:00
Ale
2eac2a9554 refactors varios para sacar responsabilidades a la nav bar 2023-05-27 11:20:38 -03:00
Ale
599d55b684 cambios en la nav bar y barra de búsqueda 2023-05-24 22:00:04 -03:00
Ale
ea6596a5b4 Rework de la tabla de bonos y cambios en total de tabla de pedidos 2023-05-24 15:01:31 -03:00
nathalie
3203f48f76 Merge branch 'master' of https://git.mps.org.uy/nathalie/pedi2 2023-05-10 12:15:04 -03:00
Ale
4acc2b0605 Canasta 89 2023-05-10 11:35:24 -03:00
nathalie
55a94cb05b Merge branch 'master' of https://git.mps.org.uy/nathalie/pedi2 2023-04-10 16:16:10 -03:00
Ale
ddb09d56e7 Arreglo de | que deberian ser , 2023-04-10 16:13:29 -03:00
nathalie
835cb14042 Merge branch 'master' of https://git.mps.org.uy/nathalie/pedi2 2023-04-10 16:07:35 -03:00
Ale
474e6871e3 Canasta 88 2023-04-10 15:53:42 -03:00
nathalie
13a445ef64 Merge branch 'master' of https://git.mps.org.uy/nathalie/pedi2
Arreglado bug de bonos de ollas
2023-03-20 21:29:12 -03:00
nathalie
ee7cdc8d10 Config 2023-03-20 21:27:25 -03:00
Ale
e712d3265f deshecho cambio en docker-compose.yml 2023-03-20 21:11:13 -03:00
Ale
11ec71cd7e Merge branch 'fix/csv-bonos-ollas' 2023-03-20 21:06:42 -03:00
7b94e05d0a Merge pull request 'Sacados bonos de pdfs por estar la tabla de bonos en admin' (#15) from adminUI into master
Reviewed-on: nathalie/pedi2#15
2023-03-20 21:06:15 -03:00
Ale
bc8e6cad10 Arreglado error por el que no aparecia el bono de ollas en la template 2023-03-20 20:59:59 -03:00
nathalie
9e55955970 Merge branch 'master' of https://git.mps.org.uy/nathalie/pedi2 2023-03-08 15:35:57 -03:00
Ale
334da613fa Canasta 87 2023-03-07 17:07:44 -03:00
Ale
1593a84b34 Merge branch 'master' of https://git.mps.org.uy/nathalie/pedi2 2023-03-07 16:25:20 -03:00
nathalie
a340647df4 Merge branch 'master' of https://git.mps.org.uy/nathalie/pedi2 2023-01-11 08:15:28 -03:00
nat
c8054a5272 canasta 85 - fix 2023-01-11 08:14:35 -03:00
nathalie
b56d82fff1 Merge branch 'master' of https://git.mps.org.uy/nathalie/pedi2 2023-01-11 07:55:08 -03:00
nat
9e1ea6299d canasta 85 2023-01-11 07:46:24 -03:00
nathalie
78a5e8ad61 Merge branch 'master' of https://git.mps.org.uy/nathalie/pedi2 2022-12-07 06:26:08 -03:00
nat
e61ad02dc2 Canasta 84 dic 2022 2022-12-06 20:51:45 -03:00
Ale
bb122c5e39 Sacados bonos de pdds por estar la tabla de bonos en admin 2022-11-14 11:51:03 -03:00
Ale
2b68c2ea8d Revert "Planillas en pdf sin bonos por haber agregado la pantalla de bonos"
This reverts commit d52382c1dc.
2022-11-14 11:49:34 -03:00
Ale
d52382c1dc Planillas en pdf sin bonos por haber agregado la pantalla de bonos 2022-11-14 11:48:46 -03:00
nathalie
f9f72cf830 Merge branch 'master' of https://git.mps.org.uy/nathalie/pedi2 2022-11-13 21:40:47 -03:00
eea1f2c3a2 Merge pull request 'adminUI' (#14) from adminUI into master
Reviewed-on: nathalie/pedi2#14
2022-11-13 21:22:13 -03:00
aa70fa1c8d Merge pull request 'Fix-ExportarPedido' (#13) from Fix-ExportarPedido into master
Reviewed-on: nathalie/pedi2#13
2022-11-13 21:22:01 -03:00
Ale
896baf18dd Agregados bonos de transporte y cambio de estilo 2022-11-13 18:01:01 -03:00
Ale
1a961c0732 pestaña de pedidos y de bonos en la pantalla de admin 2022-11-13 17:34:33 -03:00
Ale
6005cc01b7 Agregada tabla de bonos a la pantalla de admin 2022-11-13 17:00:24 -03:00
Ale
323b77f6dc Pequeño refactor y cambio de nombre de componentes de admin pedidos 2022-11-12 21:16:35 -03:00
Ale
f572b5a6bc Merge branch 'Fix-ExportarPedido' into adminUI 2022-11-12 20:23:28 -03:00
Ale
733e13ff66 Agregado dropdown con opciones para descargar pedido y renombre de componentes 2022-11-12 20:20:13 -03:00
Ale
f8484959d6 Las planillas se descargan automáticamente y tienen el nombre del barrio 2022-11-12 18:53:06 -03:00
Ale
cf82e1e21e Solo se generan pdfs de pedidos aprobados. Los pdfs ahora incluyen bonos 2022-11-12 18:44:22 -03:00
Ale
b76f114ab0 Merge branch 'master' into adminUI 2022-11-10 22:12:29 -03:00
nathalie
1b519ca440 Merge branch 'master' of https://git.mps.org.uy/nathalie/pedi2 2022-11-08 15:56:50 -03:00
nat
f67232f55c Deshabilita botones de eportar pedido barrial e imprimir planillas cuando no hay subpedidos aprobados 2022-11-08 15:55:49 -03:00
nathalie
426052ba09 Merge branch 'master' of https://git.mps.org.uy/nathalie/pedi2 2022-11-08 14:34:17 -03:00
nat
85f0a5a06b Canasta 83 2022-11-08 14:28:44 -03:00
cf77fc5e61 Merge pull request 'mostrar-password' (#12) from mostrar-password into master
Reviewed-on: nathalie/pedi2#12
2022-11-04 16:16:08 -03:00
Ale
3e426d088d Agregado boton para mostrar contraseña en login de admin 2022-10-24 22:40:30 -03:00
Ale
4da7ff2431 Agregado nombre a Login.vue 2022-10-24 22:39:55 -03:00
Ale
4906d2bb4d Arreglado error de booleanos pasados como string y warning de keys 2022-10-24 22:39:23 -03:00
Ale
69b244d074 Agregado botón para mostrar la contraseña en el login del barrio 2022-10-24 22:22:20 -03:00
Ale
155a86975c Cambio de boton a switch y estilos 2022-10-21 19:17:52 -03:00
Ale
5c134989d2 El csv del pedido incluye los bonos de transporte 2022-10-14 19:14:24 -03:00
Ale
3f34483fd5 Agregado middleware autorizacion admin 2022-10-14 17:36:49 -03:00
nathalie
e0d5bc5739 Merge branch 'master' of https://git.mps.org.uy/nathalie/pedi2 2022-10-04 12:51:08 -03:00
nat
f4d269721a productos y barrios canasta 82 2022-10-04 12:49:36 -03:00
a88e7ffb87 Merge pull request 'exportar csv de pedidos' (#11) from exportar-planilla-de-pedido into master
Reviewed-on: nathalie/pedi2#11
2022-10-04 12:25:49 -03:00
nat
60e8725ac3 exportar csv de pedidos 2022-10-01 15:29:31 -03:00
Ale
c0dd9c1124 Merge branch 'master' into adminUI 2022-09-21 10:06:15 -03:00
Ale
8284b793d3 bash script de comandos para levantar la pagina al desarrollar 2022-09-21 10:02:44 -03:00
be4ea4906a Merge pull request 'Import de productos a partir de la planilla de compras con numero de filas' (#10) from importar-productos into master
Reviewed-on: nathalie/pedi2#10
2022-09-19 02:21:07 -03:00
nat
f0a1a68144 exportar todas las planillas en un formato apto para copiar y pegar a la planilla de compras 2022-09-19 02:18:39 -03:00
nat
098b23b864 Import de productos a partir de la planilla de compras con numero de filas 2022-09-11 02:51:38 -03:00
nathalie
cdb8522f65 Merge branch 'master' of https://git.mps.org.uy/nathalie/pedi2 2022-09-07 08:15:47 -03:00
b1f1444a0c Merge pull request 'exportar-planillas' (#9) from exportar-planillas into master
Reviewed-on: nathalie/pedi2#9
2022-09-06 21:48:10 -03:00
Ale
4939dbbd83 Se pueden exportar las planillas de un barrio a pdf 2022-09-06 21:43:56 -03:00
Ale
25d5830462 esto debería estar en gitignore jeje 2022-09-06 21:39:09 -03:00
Ale
ac13e0a3f2 agregado mpdf 2022-09-06 21:38:52 -03:00
Ale
1aa112aac2 funciones para exportar planillas 2022-09-06 21:38:01 -03:00
nathalie
7468ca9086 Merge branch 'master' of https://git.mps.org.uy/nathalie/pedi2 2022-09-05 23:21:12 -03:00
nat
11cd073a51 canasta 81 2022-09-05 23:20:21 -03:00
nathalie
50cdbe57e8 Merge branch 'master' of https://git.mps.org.uy/nathalie/pedi2 2022-09-05 23:12:50 -03:00
nat
a3a4ecdd33 canasta 81 2022-09-05 23:06:19 -03:00
nathalie
6a00c6db22 Merge branch 'master' of https://git.mps.org.uy/nathalie/pedi2 2022-08-09 23:15:07 -03:00
nat
401c0e888f canasta 80 2022-08-09 23:13:46 -03:00
nathalie
75401556aa Merge branch 'master' of https://git.mps.org.uy/nathalie/pedi2 2022-07-06 18:39:34 -03:00
nat
53a203b067 Productos canasta 79 2022-07-06 18:39:05 -03:00
nathalie
33d59073e3 Merge branch 'master' of https://git.mps.org.uy/nathalie/pedi2 2022-07-06 17:30:54 -03:00
c06a3ed38c Merge pull request 'ajuste-tabla-admin' (#7) from ajuste-tabla-admin into master
Reviewed-on: nathalie/pedi2#7
2022-07-06 17:17:53 -03:00
eda9d5ce6c Merge pull request 'adminUI' (#6) from adminUI into master
Reviewed-on: nathalie/pedi2#6
2022-07-06 17:16:47 -03:00
rodrigo
4160f72615 Cambios de estilo 2022-06-28 19:24:15 -03:00
rodrigo
498c550a15 Ajuste para arreglar layout de admin
Saqué dos clases que estaban haciendo conflicto
2022-06-28 19:16:07 -03:00
nathalie
b733100269 Merge branch 'master' of https://git.mps.org.uy/nathalie/pedi2 2022-06-11 11:09:06 -03:00
nat
8502fb72d9 Endpoint regenera vistas 2022-06-11 10:49:39 -03:00
Ale
0d5551406a Arreglado bug de totales con coma 2022-06-09 20:09:18 -03:00
nat
72bbaac9a6 Merge branch 'master' of https://git.mps.org.uy/nathalie/pedi2 2022-06-09 15:48:16 -03:00
nat
ee916afdfd Readme 2022-06-09 15:47:29 -03:00
Ale
ece866a3ec Arreglado bug que mostraba los pedidos de todos los barrios en la pantalla de admin de cualquier barrio 2022-06-09 10:34:28 -03:00
Ale
77bdccdf86 Suma el total de los pedidos aprobados 2022-06-08 23:33:33 -03:00
nathalie
c8768665e0 Merge branch 'master' of https://git.mps.org.uy/nathalie/pedi2 2022-06-08 22:39:47 -03:00
f2dee0359f Merge pull request 'adminUI' (#5) from adminUI into master
Reviewed-on: nathalie/pedi2#5
2022-06-08 22:29:28 -03:00
Ale
5b18461bd9 la pantalla de admin se comunica correctamente con la bd 2022-06-08 22:19:44 -03:00
Ale
b0f25de000 lista de subpedidos del barrio loggeado 2022-06-08 20:32:50 -03:00
nathalie
509ceaeefe Merge branch 'master' of https://git.mps.org.uy/nathalie/pedi2 2022-06-08 20:15:09 -03:00
nat
bcb1e1b2c8 productos canasta 78 2022-06-08 20:14:20 -03:00
nat
aa416b7ee4 install npm through dockerfile 2022-06-08 19:32:20 -03:00
nathalie
9e554b0a65 Merge branch 'master' of https://git.mps.org.uy/nathalie/pedi2 2022-06-08 18:31:42 -03:00
nat
b2e84204ce puerto db expuesto 2022-06-08 18:26:38 -03:00
Ale
dd1b66bd06 pantalla de login de admin de barrio y botoncito pa acceder 2022-06-08 15:18:14 -03:00
nat
8d5e780f94 refactor 2022-05-25 19:03:29 -03:00
dce0620365 Merge pull request 'Actualizar docker-compose.yml para optimizarlo para puesta en produccion.' (#4) from felix/pedi2:master into master
Reviewed-on: nathalie/pedi2#4
2022-05-21 19:34:17 -03:00
323ab09238 Modifico web.php para que sirva todo el contenido en https cuando esta en produccion 2022-05-19 15:30:11 -03:00
3a2ffde0ab Actualizar docker-compose.yml para optimizarlo para puesta en produccion. 2022-05-19 14:53:42 -03:00
Felix
a9bb6df711 arreglos del docker-compose.yml referentes al deploy en prod 2022-05-19 14:46:30 -03:00
nat
0410e844b1 Docker version 2022-05-18 18:25:51 -03:00
nat
2d302d0116 Arreglado bug de chismosa 2022-05-18 18:17:38 -03:00
nat
e4a08f5aed Chismosa scrollablre 2022-05-18 17:46:47 -03:00
nat
70235970ab comenzamos 2022-05-04 16:50:22 -03:00
nat
67aadf157f Merge branch 'lista-chismosa' 2022-05-04 16:24:43 -03:00
nat
54e515cb7a toast muestra que el pedido fue actualizado 2022-05-04 16:20:27 -03:00
nat
c82fdeee96 el boton de crear solo se muestra si es posible crear un pedido con ese nombre. en lugar de desabilitar el boton, se oculta 2022-05-04 15:46:43 -03:00
nat
34e4fd6bb5 texto de chismosa vacia 2022-05-04 15:37:32 -03:00
nat
9fb5275007 Barra de navegacion y de migas se mantienen fijas 2022-05-04 15:19:41 -03:00
nat
667d7dbddb Endpoint crea vista transpuesta en la que los productos son las filas y los barrios son las columnas 2022-04-19 17:24:59 -03:00
nat
f7f06cfa3a Mostrar apto para veganes y celiques. Reacomodar iconos de nacional y ecosolidaria 2022-04-11 23:40:41 -03:00
nat
1779f573ec Borrar producto de chismosa 2022-04-11 23:02:54 -03:00
nat
fba73636de Editar producto en chismossa 2022-04-11 22:53:26 -03:00
nat
3814022411 favicon 2022-04-11 22:17:10 -03:00
nat
53b998f1e5 Estilos de botones de editar y borrar en la chismosa 2022-04-07 16:56:58 -03:00
Ale
86d2c0e9f6 Se ven los productos en una tabla al clickear en la chismosa 2022-03-31 17:48:08 -03:00
Ale
8b4e07d66e Cantidades no validas ahora incluyen números no enteros además de negativos 2022-03-31 15:03:39 -03:00
Ale
420387cdb7 Boton de agregar a la chismosa desabilitado para cantidades no validas 2022-03-31 14:43:15 -03:00
763fd3f646 Merge pull request 'endpoint devuelve lista de productos en el subpedido, con su cantidad y subtotal' (#3) from lista-chismosa into master
Reviewed-on: nathalie/pedi2#3
2022-03-24 16:30:07 -03:00
Ale
7975528317 Actualiza subpedido al agregar/quitar productos 2022-03-24 16:26:38 -03:00
nat
89c9a85204 endpoint devuelve lista de productos en el subpedido, con su cantidad y subtotal 2022-03-16 23:56:51 -03:00
Ale
2f397c88d4 Agregados botones para cantidad en el modal de agregar producto 2022-02-28 13:08:03 -03:00
nat
3bf776b6f7 Merge branch 'master' of https://git.mps.org.uy/nathalie/pedi2 into precio-total-subpedido 2022-02-24 19:12:10 -03:00
nat
0ec99a8cf5 ver dinero total del pedido en la barra de navegacion (total de chismosa) 2022-02-24 19:10:06 -03:00
nat
6f532eaf05 ver dinero total del pedido en la barra de navegacion (total de chismosa) 2022-02-24 19:07:58 -03:00
bc7b7e2f22 Merge pull request 'Endpoint devuelve subpedido con totales' (#2) from precio-total-subpedido into master
Reviewed-on: nathalie/pedi2#2
2022-02-23 19:54:47 -03:00
nat
b700239e18 Endpoint devuelve subpedido con totales 2022-02-23 19:52:52 -03:00
0200160aa8 Merge pull request 'seleccionar-subpedido-existente' (#1) from seleccionar-subpedido-existente into master
Reviewed-on: nathalie/pedi2#1
2022-02-22 19:20:18 -03:00
nat
39cc35341f Elegir pedido existente 2022-02-22 19:18:02 -03:00
nat
d17bc70c45 boton de crear nuevo subpedido se desabilita 2022-02-22 18:52:12 -03:00
nat
48871e3f88 UI 2022-02-22 16:15:13 -03:00
nat
546b901a05 Frontend de crear Subpedido muestra las coincidencias de tu barrio únicamente 2022-02-22 11:44:52 -03:00
104 changed files with 30831 additions and 1737 deletions

9
.directory Normal file
View file

@ -0,0 +1,9 @@
[Dolphin]
HeaderColumnWidths=372,72,103
SortRole=modificationtime
Timestamp=2022,6,1,16,36,48
Version=4
ViewMode=1
[Settings]
HiddenFilesShown=true

BIN
.docker-compose.yml.swp Normal file

Binary file not shown.

View file

@ -6,9 +6,11 @@ APP_URL=http://localhost
LOG_CHANNEL=stack LOG_CHANNEL=stack
USERID=
DB_CONNECTION=mysql DB_CONNECTION=mysql
DB_HOST=db DB_HOST=db
DB_PORT=3306 DB_PORT_EXPOSED=3306
DB_DATABASE=pedi2 DB_DATABASE=pedi2
DB_USERNAME=pedi2 DB_USERNAME=pedi2
DB_PASSWORD=pedi2 DB_PASSWORD=pedi2
@ -48,3 +50,4 @@ MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
WEB_CLIENT_EMAIL=informaticamps@buzon.uy WEB_CLIENT_EMAIL=informaticamps@buzon.uy
WEB_CLIENT_NAME=web WEB_CLIENT_NAME=web
WEB_CLIENT_PASS=pass WEB_CLIENT_PASS=pass
NGINX_PORT=8000

6
.gitignore vendored
View file

@ -10,3 +10,9 @@ Homestead.json
Homestead.yaml Homestead.yaml
npm-debug.log npm-debug.log
yarn-error.log yarn-error.log
.idea
/resources/csv/exports/*.csv
/resources/csv/canastas/*.csv
/public/css/
/public/js/
/public/mix-manifest.json

View file

@ -12,7 +12,8 @@ RUN apt-get update && apt-get install -y \
libonig-dev \ libonig-dev \
libxml2-dev \ libxml2-dev \
zip \ zip \
unzip unzip \
npm
# Clear cache # Clear cache
RUN apt-get clean && rm -rf /var/lib/apt/lists/* RUN apt-get clean && rm -rf /var/lib/apt/lists/*

View file

@ -1,6 +1,6 @@
# Pedi2 # Pedi2
Aplicación de compras del Mercado Popular de Subsistencia. Aplicación de pedidos del Mercado Popular de Subsistencia.
Pedi2 está hecha en Laravel 7 y utiliza laravel7-docker de dyarleniber. Pedi2 está hecha en Laravel 7 y utiliza laravel7-docker de dyarleniber.
@ -17,41 +17,39 @@ Se utilizan los siguientes servicios, separadamente:
## Instalación ## Instalación
1. Una vez descargado el proyecto, hacé una copia del archivo `.env.example` que se encuentra en la raíz del proyecto y nombrala `.env`. Seteá los valores correctos - específicamente, para las variables, `APP_URL`, `DB_USERNAME` y `DB_PASSWORD`. Prestá atención a que `DB_HOST` sea el nombre del servicio que corre MySQL (por defecto `DB_HOST=db`). 1. Una vez descargado el proyecto, hacé una copia del archivo `.env.example` que se encuentra en la raíz del proyecto y nombrala `.env`. Seteá los valores correctos - específicamente, para las variables, `APP_URL`, `DB_USERNAME` y `DB_PASSWORD`. Prestá atención a que `DB_HOST` sea el nombre del servicio que corre MySQL (por defecto `DB_HOST=db`).
2. Construí la imagen de la app 2. Levantá los contenedores, construyendo la imagen de la app primero
```bash ```bash
docker-compose build app docker-compose up -d --build
```
3. Cuando termine, levantá los contenedores:
```bash
docker-compose up -d
``` ```
El ambiente ahora está andando, pero necesitamos ejecutar un par de comandos para terminar la instalación de Laravel. Podemos usar `docker-compose exec [nombre-del-servicio]` previo a un comando para ejecutarlo dentro del contenedor. El ambiente ahora está andando, pero necesitamos ejecutar un par de comandos para terminar la instalación de Laravel. Podemos usar `docker-compose exec [nombre-del-servicio]` previo a un comando para ejecutarlo dentro del contenedor.
4. Terminá de instalar las dependencias de la app, según fueron definidas en `composer.json`. 3. Terminá de instalar las dependencias de la app, según fueron definidas en `composer.json`.
```bash ```bash
docker-compose exec app composer update docker-compose exec app composer install
``` ```
5. Generá una clave de aplicación. Esta clave se usa para encriptar datos sensibles. 4. Generá una clave de aplicación. Esta clave se usa para encriptar datos sensibles.
```bash ```bash
docker-compose exec app php artisan key:generate docker-compose exec app php artisan key:generate
``` ```
6. Corré las migraciones y seeders de Laravel 5. Corré las migraciones y seeders de Laravel
```bash ```bash
docker-compose exec app php artisan migrate --seed docker-compose exec app php artisan migrate:fresh --seed
``` ```
7. Copia el token que se imprime al correr los seeders. Lo necesitamos para autenticar las llamadas que hagamos desde nuestro cliente web 6. Copia el token que se imprime al correr los seeders. Lo necesitamos para autenticar las llamadas que hagamos desde nuestro cliente web
7. Instala las dependencias de npm
```bash
docker-compose exec app npm install
```
Ahora la aplicación está corriendo y la podés ver en el puerto 8000 de tu dominio o IP. En caso de que estés en tu máquina local, la vas a ver accediendo a `http://localhost:8000` desde tu navegador. Ahora la aplicación está corriendo y la podés ver en el puerto 8000 de tu dominio o IP. En caso de que estés en tu máquina local, la vas a ver accediendo a `http://localhost:8000` desde tu navegador.
@ -61,6 +59,11 @@ Podés usar el comando `logs` para ver los logs generados por tus servicios:
docker-compose logs nginx docker-compose logs nginx
``` ```
8. Ejecuta npm para compilar el js y css
```bash
docker-compose exec app npm run prod
```
## Services description ## Services description
### Dockerfile ### Dockerfile

11
app/CanastaLog.php Normal file
View file

@ -0,0 +1,11 @@
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class CanastaLog extends Model
{
protected $fillable = ["path", "descripcion"];
protected $table = "carga_de_canastas";
}

View file

@ -0,0 +1,62 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
class CrearPedidosAprobadosViewCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'view:CrearPedidosAprobadosView';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Crea view "pedidos_aprobados"';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
DB::statement("
CREATE OR REPLACE VIEW pedidos_aprobados
AS
SELECT
g.id as grupo_de_compra_id,
g.nombre as grupo_de_compra_nombre,
g.region as grupo_de_compra_region,
pr.id AS producto_id,
pr.nombre as producto_nombre,
pr.precio as producto_precio,
SUM(ps.cantidad) as cantidad_pedida,
pr.precio*SUM(ps.cantidad) as total_por_producto
FROM grupos_de_compra g
JOIN subpedidos s ON (s.grupo_de_compra_id = g.id AND s.aprobado=1)
JOIN producto_subpedido ps ON (ps.subpedido_id = s.id)
JOIN productos pr ON (pr.id = ps.producto_id)
GROUP BY
g.id, g.nombre, pr.id, pr.nombre
;");
return 0;
}
}

View file

@ -2,17 +2,319 @@
namespace App; namespace App;
use App\Helpers\TransporteHelper;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;
use League\Csv\CannotInsertRecord;
use League\Csv\Reader;
use League\Csv\Writer;
use Mpdf\Mpdf;
class GrupoDeCompra extends Model class GrupoDeCompra extends Model
{ {
public $timestamps = false; public $timestamps = false;
protected $fillable = [ "nombre","region","telefono","correo","referente_finanzas","cantidad_de_nucleos"]; protected $fillable = ["nombre", "region", "telefono", "correo", "referente_finanzas", "cantidad_de_nucleos", "fila", "devoluciones_habilitadas"];
protected $table = 'grupos_de_compra'; protected $table = 'grupos_de_compra';
protected $hidden = ['password']; protected $hidden = ['password'];
public function subpedidos() { public function subpedidos()
{
return $this->hasMany('App\Subpedido'); return $this->hasMany('App\Subpedido');
} }
public function toggleDevoluciones()
{
$this->devoluciones_habilitadas = !$this->devoluciones_habilitadas;
$this->save();
return $this->devoluciones_habilitadas;
}
public function pedidosAprobados()
{
return $this->subpedidos->where('aprobado', 1);
}
public function totalARecaudar()
{
$total = 0;
foreach ($this->pedidosAprobados() as $subpedido) {
$total = $total + $subpedido->total();
}
return $total;
}
public function totalBarrial()
{
$total = 0;
foreach ($this->pedidosAprobados() as $subpedido) {
$total = $total + $subpedido->totalBarrial();
}
return $total;
}
public function totalDevoluciones()
{
$total = 0;
foreach ($this->pedidosAprobados() as $subpedido) {
$total = $total + $subpedido->devoluciones_total;
}
return $total;
}
public function totalATransferir()
{
return $this->totalCentralesQueNoPaganTransporte()
+ $this->totalCentralesQuePaganTransporte()
+ $this->totalTransporte();
}
public function totalCentralesQueNoPaganTransporte()
{
$total = 0;
foreach ($this->pedidosAprobados() as $subpedido) {
$total = $total + $subpedido->totalCentralesQueNoPaganTransporte();
}
return $total;
}
public function totalCentralesQuePaganTransporte()
{
$total = 0;
foreach ($this->pedidosAprobados() as $subpedido) {
$total = $total + $subpedido->totalCentralesQuePaganTransporte();
}
return $total;
}
public function totalTransporte()
{
return TransporteHelper::totalTransporte($this->totalCentralesQuePaganTransporte());
}
public function cantidadTransporte()
{
return TransporteHelper::cantidadTransporte($this->totalCentralesQuePaganTransporte());
}
public function exportarPlanillasAPdf()
{
$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();
}
$filename = $this->nombre . '.pdf';
// imprimir el pdf
$mpdf->Output($filename, "D");
}
static function filaVacia(string $product, int $columns): array
{
$fila = [$product];
for ($i = 1; $i <= $columns; $i++) {
$fila[$i] = "0";
}
return $fila;
}
//Asume que los productos están gruadados en orden de fila
public static function obtenerTemplateDeFilasVacias(int $columns)
{
$productosFilaID = Producto::productosFilaID();
$productosIDNombre = Producto::productosIDNombre();
$num_fila = 1;
$template = [];
foreach ($productosFilaID as $fila => $id) {
for ($i = $num_fila; $i < $fila; $i++) {
$template[$i] = GrupoDeCompra::filaVacia("", $columns);
}
$template[$fila] = GrupoDeCompra::filaVacia($productosIDNombre[$id], $columns);
$num_fila = $fila + 1;
}
$template[GrupoDeCompra::obtenerFilaDeBonoTransporte()] = 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());
}
}
public function generarColumnaCantidades()
{
$productos_en_pedido = DB::table('pedidos_aprobados')->where('grupo_de_compra_id', $this->id)->get()->keyBy('producto_id');
//si no hay pedidos aprobados, salir
if ($productos_en_pedido->count() == 0) {
\Log::debug("El grupo de compra " . $this->nombre . " no tiene pedidos aprobados.");
return [];
}
$records = $this->obtenerTemplateDeFilasVacias(1);
$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();
return $records;
}
public function exportarPedidoConNucleosEnCSV()
{
$productos_en_pedido = DB::table('pedidos_aprobados')->where('grupo_de_compra_id', $this->id)->get()->keyBy('producto_id');
// si no hay pedidos aprobados, salir
if ($productos_en_pedido->count() == 0) {
\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();
foreach ($productos_en_pedido as $id => $producto_pedido) {
$fila = $productos_id_fila[$id];
$i = 1;
// Poner cantidad de cada producto para cada núcleo
foreach ($pedidos as $pedido) {
list($records, $i, $_) = $this->agregarCantidad($pedido, $id, $records, $fila, $i);
}
}
// Insertar lista de núcleos en la primera fila
$nucleos = [""];
$i = 1;
foreach ($pedidos as $pedido) {
$nucleos[$i] = $pedido->nombre;
$i++;
}
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());
}
}
public function agregarCantidad($pedido, $id, array $records, $fila, int $i): array
{
$producto = $pedido->productos()->find($id);
$cantidad = $producto == NULL ? 0 : $producto->pivot->cantidad;
$records[$fila][$i] = $cantidad;
$i++;
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();
}
static public function planillaTransporte() {
$totalesPorBarrio = self::totalesParaTransportePorBarrio();
$barrios = [];
$bonosDeTransporte = [];
foreach ($totalesPorBarrio as $totalBarrio) {
$barrios[] = $totalBarrio->barrio;
$bonosDeTransporte[] = ceil($totalBarrio->total / 500);
}
$planilla = [];
$planilla[] = array_merge(['Barrio'], $barrios);
$planilla[] = array_merge(['Cant. bonos de transporte'], $bonosDeTransporte);
try {
$writer = Writer::createFromPath(resource_path('csv/exports/transporte-por-barrio.csv'), 'w');
$writer->insertAll($planilla);
} catch (CannotInsertRecord $e) {
var_export($e->getRecords());
}
}
} }

View file

@ -0,0 +1,151 @@
<?php
namespace App\Helpers;
use App\Producto;
use App\Proveedor;
use App\CanastaLog;
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 ARCHIVO_SUBIDO = 'Archivo subido';
const CANASTA_CARGADA = 'Canasta cargada';
public static function guardarCanasta($data, $path): string {
$nombre = $data->getClientOriginalName();
$data->move(resource_path($path), $nombre);
self::log($path . $nombre, self::ARCHIVO_SUBIDO);
return $nombre;
}
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();
$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) {
break;
}
//filas que no tienen tipo
if (!Arr::has($registro,self::FILA_HEADER)|| trim($registro[self::FILA_HEADER]) == ''){
var_dump("no hay tipo en la fila " . $i);
continue;
}
//saltear bono de transporte
if ($registro[self::FILA_HEADER] == "T"){
continue;
}
//obtener categoria
if ($registro['Producto'] == '') {
//es la pregunta de la copa?
if (Str::contains($registro[self::FILA_HEADER],"¿")) { continue; }
$categoria = $registro[self::FILA_HEADER];
continue;
}
//completar producto
$toInsert[] = [
'fila' => $i,
'categoria' => $categoria,
'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",
];
}
foreach (array_chunk($toInsert,DatabaseSeeder::CHUNK_SIZE) as $chunk) {
DB::table('productos')->insert($chunk);
}
self::agregarBonoBarrial();
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,"*")){
$result = Proveedor::firstOrCreate([
'nombre' => 'Proveedor de economía solidaria',
'economia_solidaria' => 1,
'nacional' => 1
])->id;
}
return $result;
}
/**
* @param $path
* @param $descripcion
* @return void
*/
private static function log($path, $descripcion): void
{
$log = new CanastaLog([
'path' => $path,
'descripcion' => $descripcion,
]);
$log->save();
}
private static function limpiarTablas()
{
DB::delete('delete from producto_subpedido');
DB::delete('delete from productos');
DB::delete('delete from subpedidos');
}
private static function agregarBonoBarrial()
{
$categoria = Producto::all()->pluck('categoria')->unique()->flatten()->first(function ($c) { return Str::contains($c, 'BONO'); });
DB::table('productos')->insert([
'fila' => 420,
'nombre' => "Bono barrial",
'precio' => 20,
'categoria' => $categoria,
'bono' => 1,
'proveedor_id' => null,
'requiere_notas'=> false,
]);
}
}

View file

@ -0,0 +1,19 @@
<?php
namespace App\Helpers;
class TransporteHelper
{
const COSTO_TRANSPORTE = 15;
const MONTO_TRANSPORTE = 500;
public static function cantidadTransporte($monto)
{
return ceil($monto / self::MONTO_TRANSPORTE);
}
public static function totalTransporte($monto)
{
return self::cantidadTransporte($monto) * self::COSTO_TRANSPORTE;
}
}

View file

@ -2,9 +2,34 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use App\GrupoDeCompra;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Response;
class AdminController extends Controller class AdminController extends Controller
{ {
// public function show()
{
return view('auth/admin_login');
}
public function index() {
return view('auth/admin_subpedidos');
}
public function exportarPlanillasAPdf(GrupoDeCompra $gdc) {
return $gdc->exportarPlanillasAPdf();
}
public function exportarPedidoACSV(GrupoDeCompra $gdc) {
$gdc->exportarPedidoEnCSV();
$file = resource_path('csv/exports/'.$gdc->nombre.'.csv');
return response()->download($file);
}
public function exportarPedidoConNucleosACSV(GrupoDeCompra $gdc) {
$gdc->exportarPedidoConNucleosEnCSV();
$file = resource_path('csv/exports/'.$gdc->nombre.'-completo.csv');
return response()->download($file);
}
} }

View file

@ -0,0 +1,19 @@
<?php
namespace App\Http\Controllers\Api;
use App\GrupoDeCompra;
use App\Http\Controllers\Controller;
use App\Http\Resources\GrupoDeCompraResource;
class GrupoDeCompraController extends Controller
{
public function index()
{
return GrupoDeCompraResource::collection(GrupoDeCompra::all());
}
public function show(GrupoDeCompra $grupoDeCompra)
{
return new GrupoDeCompraResource($grupoDeCompra);
}
}

View file

@ -3,11 +3,12 @@
namespace App\Http\Controllers\Api; namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Producto;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use App\Filtros\FiltroDeSubpedido; use App\Filtros\FiltroDeSubpedido;
use App\Subpedido; use App\Subpedido;
use App\GrupoDeCompra; use App\GrupoDeCompra;
use App\Producto; use App\Http\Resources\SubpedidoResource;
use Illuminate\Validation\Rule; use Illuminate\Validation\Rule;
use Symfony\Component\HttpKernel\Exception\HttpException; use Symfony\Component\HttpKernel\Exception\HttpException;
@ -26,8 +27,13 @@ class SubpedidoController extends Controller
return Subpedido::filtrar($filtros)->get(); return Subpedido::filtrar($filtros)->get();
} }
public function indexResources(FiltroDeSubpedido $filtros, Request $request)
{
return SubpedidoResource::collection(Subpedido::filtrar($filtros)->get());
}
/** /**
* Guardar un nuevo registro en el almacenamiento. * Store a newly created resource in storage.
* *
* @param \Illuminate\Http\Request $request * @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response * @return \Illuminate\Http\Response
@ -45,28 +51,6 @@ class SubpedidoController extends Controller
return $s; return $s;
} }
/**
* Agregar un producto a un subpedido.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function updateProducto(Subpedido $subpedido, Producto $producto, Request $request)
{
$validado = $this->validateActualizacionDeProducto();
$cantidad = $validado['cantidad'];
if ($cantidad){
//si la cantidad es 1 o más se agrega el producto o actualiza la cantidad
$subpedido->productos()->syncWithoutDetaching([$producto->id => ['cantidad' => $cantidad]]);
} else {
//si la cantidad es 0, se elimina el producto del subpedido
$subpedido->productos()->detach($producto->id);
}
return response('Producto ' . $producto->nombre . ' actualizado en subpedido de ' . $subpedido->nombre . ' (cantidad ' . $cantidad . ')', 200);
}
protected function validateSubpedido(){ protected function validateSubpedido(){
return request()->validate([ return request()->validate([
'nombre' => 'required|max:255', 'nombre' => 'required|max:255',
@ -77,9 +61,55 @@ class SubpedidoController extends Controller
]); ]);
} }
protected function validateActualizacionDeProducto(){ /**
return request()->validate([ * Display the specified resource.
'cantidad' => 'required|min:0' *
* @param \App\Subpedido $subpedido
* @return \Illuminate\Http\Response
*/
public function show(Subpedido $subpedido)
{
return new SubpedidoResource($subpedido);
}
// recibe request, saca producto y cantidad, valida, y pasa a syncProducto en Subpedido
public function syncProductos(Subpedido $subpedido) {
if ($subpedido->aprobado)
return new SubpedidoResource($subpedido);
$valid = request()->validate([
'cantidad' => ['integer','required','min:0'],
'notas' => 'nullable',
'producto_id' => [
'required',
Rule::in(Producto::all()->pluck('id')),
]
]); ]);
$producto = Producto::find($valid['producto_id']);
$notas = $valid['notas'];
$cantidad = $valid['cantidad'];
$subpedido->syncProducto($producto, $cantidad, $notas ?? "");
return new SubpedidoResource($subpedido);
}
public function toggleAprobacion(Subpedido $subpedido) {
$valid = request()->validate([
'aprobacion' => 'required | boolean'
]);
$subpedido->toggleAprobacion($valid['aprobacion']);
return new SubpedidoResource($subpedido);
}
public function syncDevoluciones(Subpedido $subpedido) {
if ($subpedido->aprobado) return new SubpedidoResource($subpedido);
$valid = request()->validate([
'total' => 'required|min:0',
'notas' => 'min:0'
]);
$subpedido->syncDevoluciones($valid['total'], $valid['notas'] ?? "");
return new SubpedidoResource($subpedido);
} }
} }

View file

@ -5,6 +5,7 @@ namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider; use App\Providers\RouteServiceProvider;
use Illuminate\Foundation\Auth\AuthenticatesUsers; use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
class LoginController extends Controller class LoginController extends Controller
@ -28,6 +29,18 @@ class LoginController extends Controller
*/ */
protected $redirectTo = RouteServiceProvider::HOME; protected $redirectTo = RouteServiceProvider::HOME;
protected function authenticated(Request $request, $user)
{
if ($user->is_compras) {
return redirect('compras/pedidos');
} else if ($user->is_admin) {
session(['admin_gdc' => $user->grupo_de_compra_id]);
return redirect('admin/pedidos');
} else {
return redirect('/');
}
}
/** /**
* Create a new controller instance. * Create a new controller instance.
* *

View file

@ -0,0 +1,59 @@
<?php
namespace App\Http\Controllers;
use App\GrupoDeCompra;
use App\Helpers\CanastaHelper;
use App\Producto;
use Illuminate\Http\Request;
class ComprasController
{
const CANASTAS_PATH = 'csv/canastas/';
public function indexPedidos() {
return view('compras_pedidos');
}
public function descargarPedidos() {
Producto::planillaTotales();
$file = resource_path('csv/exports/pedidos-por-barrio.csv');
return response()->download($file);
}
public function descargarNotas() {
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 show()
{
return view('auth/compras_login');
}
public function cargarCanasta(Request $request)
{
$request->validate([
'data' => 'required|file|mimes:csv,txt|max:2048',
]);
$nombre = CanastaHelper::guardarCanasta($request->file('data'), self::CANASTAS_PATH);
CanastaHelper::cargarCanasta(self::CANASTAS_PATH . $nombre);
return response()->json([
'message' => 'Canasta cargada exitosamente',
], 200);
}
public function descargarCanastaEjemplo() {
$file = resource_path('csv/productos.csv');
return response()->download($file);
}
}

View file

@ -56,6 +56,8 @@ class Kernel extends HttpKernel
*/ */
protected $routeMiddleware = [ protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class, 'auth' => \App\Http\Middleware\Authenticate::class,
'admin' => \App\Http\Middleware\Admin::class,
'compras' => \App\Http\Middleware\Compras::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class, 'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class, 'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,

View file

@ -0,0 +1,26 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Auth;
class Admin
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
$user = Auth::user();
if ($user->is_admin) {
return $next($request);
} else {
return response('Necesitás ser admin para hacer esto', 403);
}
}
}

View file

@ -0,0 +1,29 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class Compras
{
/**
* Handle an incoming request.
*
* @param Request $request
* @param Closure $next
* @return mixed
*/
public function handle(Request $request, Closure $next)
{
if (!Auth::check())
return redirect()->route('compras_login.show');
if (Auth::user()->is_compras) {
return $next($request);
} else {
return response('Necesitás ser de comisión compras para hacer esto', 403);
}
}
}

View file

@ -0,0 +1,30 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class GrupoDeCompraResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'nombre' => $this->nombre,
'devoluciones_habilitadas' => $this->devoluciones_habilitadas,
'pedidos' => SubpedidoResource::collection($this->subpedidos),
'total_a_recaudar' => number_format($this->totalARecaudar(),2),
'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),
];
}
}

View file

@ -25,7 +25,8 @@ class ProductoResource extends JsonResource
'imagen' => optional($this->poster)->url(), 'imagen' => optional($this->poster)->url(),
'descripcion' => $this->descripcion, 'descripcion' => $this->descripcion,
'apto_veganxs' => $this->apto_veganxs, 'apto_veganxs' => $this->apto_veganxs,
'apto_celiacxs' => $this->apto_celiacxs 'apto_celiacxs' => $this->apto_celiacxs,
'requiere_notas' => $this->requiere_notas,
]; ];
} }
} }

View file

@ -0,0 +1,31 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class SubpedidoResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'nombre' => $this->nombre,
'grupo_de_compra' => $this->grupoDeCompra,
'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_sin_devoluciones' => number_format($this->totalSinDevoluciones(),2),
'devoluciones_total' => number_format($this->devoluciones_total,2),
'devoluciones_notas' => $this->devoluciones_notas
];
}
}

View file

@ -2,19 +2,24 @@
namespace App; namespace App;
use App\Filtros\FiltroDeProducto;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use App\Filtros\FiltroDeProducto; 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 class Producto extends Model
{ {
public $timestamps = false; public $timestamps = false;
protected $fillable = [ "nombre", "precio", "presentacion", "stock", "categoria" ]; protected $fillable = ["nombre", "precio", "presentacion", "stock", "categoria"];
static $paginarPorDefecto = 10; static $paginarPorDefecto = 10;
public function subpedidos() 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() public function proveedor()
@ -22,6 +27,11 @@ class Producto extends Model
return $this->belongsTo('App\Proveedor'); 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) //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)
{ {
@ -33,4 +43,119 @@ class Producto extends Model
return $request->has('paginar') && intval($request->input('paginar')) ? intval($request->input('paginar')) : self::$paginarPorDefecto; return $request->has('paginar') && intval($request->input('paginar')) ? intval($request->input('paginar')) : self::$paginarPorDefecto;
} }
public static function productosFilaID()
{
return Producto::pluck('id', 'fila',)->all();
}
public static function productosIDFila()
{
return Producto::pluck('fila', 'id',)->all();
}
public static function productosIDNombre()
{
return Producto::pluck('nombre', 'id',)->all();
}
static public function cantidadesPorBarrio()
{
$barrios = DB::table('grupos_de_compra')
->where('nombre', '<>', 'PRUEBA')
->pluck('id', 'nombre');
$columnasBarrios = $barrios->map(function ($id, $nombre) {
return DB::raw("SUM(CASE WHEN subpedidos.grupo_de_compra_id = $id AND subpedidos.aprobado = 1 THEN producto_subpedido.cantidad ELSE 0 END) as `$nombre`");
})->toArray();
return DB::table('productos')
->where('productos.nombre', 'not like', '%barrial%')
->leftJoin('producto_subpedido', 'productos.id', '=', 'producto_subpedido.producto_id')
->leftJoin('subpedidos', 'subpedidos.id', '=', 'producto_subpedido.subpedido_id')
->select(array_merge(
['productos.fila as fila'],
['productos.nombre as producto'],
$columnasBarrios
))
->groupBy('productos.fila', 'productos.id', 'productos.nombre')
->orderBy('productos.fila')
->get();
}
static public function planillaTotales() {
$headers = ['Producto'];
$barrios = DB::table('grupos_de_compra')
->where('nombre', '<>', 'PRUEBA')
->pluck('nombre')->toArray();
$headers = array_merge($headers, $barrios);
$cantidadesPorBarrio = self::cantidadesPorBarrio();
$planilla = [];
$ultimaFila = 1;
foreach ($cantidadesPorBarrio as $productoCantidades) {
$fila = $productoCantidades->fila;
while ($fila - $ultimaFila > 1) {
$ultimaFila++;
$planilla[$ultimaFila] = ['---'];
}
$planilla[$fila] = [$productoCantidades->producto];
foreach ($barrios as $barrio) {
$planilla[$fila][] = $productoCantidades->$barrio ?? 0;
}
$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());
}
}
public static function notasPorBarrio(): \Illuminate\Support\Collection
{
return DB::table('productos')
->join('producto_subpedido', 'productos.id', '=', 'producto_subpedido.producto_id')
->join('subpedidos', 'producto_subpedido.subpedido_id', '=', 'subpedidos.id')
->join('grupos_de_compra', 'subpedidos.grupo_de_compra_id', '=', 'grupos_de_compra.id')
->where('productos.requiere_notas', 1)
->select(
'productos.nombre as producto',
'grupos_de_compra.nombre as barrio',
'producto_subpedido.notas'
)
->get()
->groupBy('producto');
}
static public function planillaNotas() {
$headers = ['Producto'];
$barrios = DB::table('grupos_de_compra')
->where('nombre', '<>', 'PRUEBA')
->pluck('nombre')->toArray();
$headers = array_merge($headers, $barrios);
$notasPorBarrio = self::notasPorBarrio();
$planilla = [];
foreach ($notasPorBarrio as $producto => $notasGrupo) {
$fila = [$producto];
foreach ($barrios as $barrio) {
$notas = $notasGrupo->where('barrio', $barrio)->pluck('notas')->implode('; ');
$fila[] = $notas ?: '';
}
$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());
}
}
} }

View file

@ -2,7 +2,7 @@
namespace App; namespace App;
use League\Csv\Reader; use App\Helpers\TransporteHelper;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Log; use Log;
@ -10,12 +10,24 @@ use App\Filtros\FiltroDeSubpedido;
class Subpedido extends Model class Subpedido extends Model
{ {
const COSTO_TRANSPORTE = 15;
public $timestamps = false; public $timestamps = false;
protected $fillable = ['grupo_de_compra_id', 'aprobado', 'nombre']; protected $fillable = ['grupo_de_compra_id', 'aprobado', 'nombre', 'devoluciones_total', 'devoluciones_notas'];
public function productos() public function productos()
{ {
return $this->belongsToMany('App\Producto')->withPivot(["cantidad"]); 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 productosSinBonos()
{
return $this->productos()->where('bono',false);
} }
public function grupoDeCompra() public function grupoDeCompra()
@ -23,10 +35,103 @@ class Subpedido extends Model
return $this->belongsTo('App\GrupoDeCompra'); return $this->belongsTo('App\GrupoDeCompra');
} }
//Este método permite que se apliquen los filtros al hacer una request (por ejemplo, de búsqueda) //Permite que se apliquen los filtros al hacer una request (por ejemplo, de búsqueda)
public function scopeFiltrar($query, FiltroDeSubpedido $filtros) public function scopeFiltrar($query, FiltroDeSubpedido $filtros)
{ {
return $filtros->aplicar($query); return $filtros->aplicar($query);
} }
public function total()
{
return $this->totalSinDevoluciones() - $this->devoluciones_total;
}
public function totalSinDevoluciones()
{
return $this->totalBarrial() + $this->totalCentral();
}
public function totalBarrial()
{
return DB::table('producto_subpedido')
->join('productos', 'producto_subpedido.producto_id', '=', 'productos.id')
->where('producto_subpedido.subpedido_id', $this->id)
->where('productos.nombre', 'like', '%barrial%')
->selectRaw('SUM(productos.precio * producto_subpedido.cantidad) as total')
->value('total');
}
public function totalCentral()
{
return $this->totalCentralesQueNoPaganTransporte() + $this->totalCentralesQuePaganTransporte() + $this->totalTransporte();
}
public function totalCentralesQueNoPaganTransporte()
{
return DB::table('producto_subpedido')
->join('productos', 'producto_subpedido.producto_id', '=', 'productos.id')
->where('producto_subpedido.subpedido_id', $this->id)
->where('productos.nombre', 'not like', '%barrial%')
->where(function ($query) {
$query->where('productos.categoria', 'like', '%SUBSIDIADO%')
->orWhere('productos.bono', true);
})
->selectRaw('SUM(productos.precio * producto_subpedido.cantidad) as total')
->value('total');
}
public function totalCentralesQuePaganTransporte()
{
return DB::table('producto_subpedido')
->join('productos', 'producto_subpedido.producto_id', '=', 'productos.id')
->where('producto_subpedido.subpedido_id', $this->id)
->where('productos.nombre', 'not like', '%barrial%')
->where('productos.bono', false)
->where('productos.categoria', 'not like', '%SUBSIDIADO%')
->selectRaw('SUM(productos.precio * producto_subpedido.cantidad) as total')
->value('total');
}
public function totalTransporte()
{
return TransporteHelper::totalTransporte($this->totalCentralesQuePaganTransporte());
}
public function cantidadTransporte()
{
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,
]
]);
} 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 generarHTML() {
$view = view("pdfgen.subpedido_tabla", ["subpedido" => $this]);
return $view->render();
}
public function syncDevoluciones(float $total, string $notas) {
$this->devoluciones_total = $total;
$this->devoluciones_notas = $notas;
$this->save();
}
} }

View file

@ -8,7 +8,7 @@
], ],
"license": "MIT", "license": "MIT",
"require": { "require": {
"php": "^7.2.5|^8.0", "php": "^7.4",
"fideloper/proxy": "^4.4", "fideloper/proxy": "^4.4",
"fruitcake/laravel-cors": "^2.0", "fruitcake/laravel-cors": "^2.0",
"guzzlehttp/guzzle": "^6.3.1|^7.0.1", "guzzlehttp/guzzle": "^6.3.1|^7.0.1",
@ -16,7 +16,9 @@
"laravel/sanctum": "^2.13", "laravel/sanctum": "^2.13",
"laravel/tinker": "^2.5", "laravel/tinker": "^2.5",
"laravel/ui": "*", "laravel/ui": "*",
"league/csv": "^9.8" "league/csv": "^9.8",
"mpdf/mpdf": "^8.1",
"prexview/prexview": "^1.1"
}, },
"require-dev": { "require-dev": {
"facade/ignition": "^2.0", "facade/ignition": "^2.0",
@ -52,13 +54,13 @@
"scripts": { "scripts": {
"post-autoload-dump": [ "post-autoload-dump": [
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump", "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
"@php artisan package:discover --ansi" "@php7.4 artisan package:discover --ansi"
], ],
"post-root-package-install": [ "post-root-package-install": [
"@php -r \"file_exists('.env') || copy('.env.example', '.env');\"" "@php7.4 -r \"file_exists('.env') || copy('.env.example', '.env');\""
], ],
"post-create-project-cmd": [ "post-create-project-cmd": [
"@php artisan key:generate --ansi" "@php7.4 artisan key:generate --ansi"
] ]
} }
} }

1860
composer.lock generated

File diff suppressed because it is too large Load diff

View file

@ -19,6 +19,8 @@ class CreateUsersTable extends Migration
$table->string('email')->unique()->nullable(); $table->string('email')->unique()->nullable();
$table->timestamp('email_verified_at')->nullable(); $table->timestamp('email_verified_at')->nullable();
$table->foreignId('grupo_de_compra_id')->nullable(); $table->foreignId('grupo_de_compra_id')->nullable();
$table->boolean('is_admin');
$table->unique(['name', 'is_admin']);
$table->string('password'); $table->string('password');
$table->rememberToken(); $table->rememberToken();
$table->timestamps(); $table->timestamps();

View file

@ -17,7 +17,7 @@ class CreateSubpedidosTable extends Migration
$table->id(); $table->id();
$table->string('nombre'); $table->string('nombre');
$table->foreignId('grupo_de_compra_id'); $table->foreignId('grupo_de_compra_id');
$table->boolean('aprobado')->nullable(); $table->boolean('aprobado')->default(false);
$table->timestamps(); $table->timestamps();
}); });

View file

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

View file

@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AgregarColumnaTotalATablaDeProductoSubpedido extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('producto_subpedido', function (Blueprint $table) {
$table->double('total',10,2)->after('cantidad')->default(0);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('producto_subpedido', function (Blueprint $table) {
$table->dropColumn('total');
});
}
}

View file

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

View file

@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CallCrearPedidosAprobados extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Artisan::call("view:CrearPedidosAprobadosView");
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
//
}
}

View file

@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class DevolucionesPedido extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('subpedidos', function (Blueprint $table) {
$table->double('devoluciones_total', 10, 2)->default(0);
$table->string('devoluciones_notas')->default("");
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('subpedidos', function (Blueprint $table) {
$table->dropColumn('devoluciones_total');
$table->dropColumn('devoluciones_notas');
});
}
}

View file

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

View file

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

View file

@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class NotasProducto extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('producto_subpedido', function (Blueprint $table) {
$table->string('notas')->nullable();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('producto_subpedido', function (Blueprint $table) {
$table->dropColumn('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

@ -0,0 +1,33 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CrearCargaDeCanastas extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('carga_de_canastas', function (Blueprint $table) {
$table->id();
$table->string('path');
$table->string('descripcion');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('carga_de_canastas');
}
}

View file

@ -0,0 +1,19 @@
<?php
use App\Helpers\CanastaHelper;
use Illuminate\Database\Seeder;
class CanastaSeeder extends Seeder
{
const ARCHIVO_DEFAULT = 'csv/productos.csv';
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
CanastaHelper::cargarCanasta(self::ARCHIVO_DEFAULT);
}
}

View file

@ -12,7 +12,7 @@ class DatabaseSeeder extends Seeder
*/ */
public function run() public function run()
{ {
$this->call(CanastaSeeder::class);
$this->call(GrupoDeCompraSeeder::class); $this->call(GrupoDeCompraSeeder::class);
$this->call(ProductoSeeder::class);
} }
} }

View file

@ -31,7 +31,15 @@ class GrupoDeCompraSeeder extends Seeder
$usersToInsert[] = [ $usersToInsert[] = [
'name' => $registro['barrio'], '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("asd"),
"is_admin" => 1,
'grupo_de_compra_id' => $key 'grupo_de_compra_id' => $key
]; ];
} }

View file

@ -1,39 +0,0 @@
<?php
use Illuminate\Database\Seeder;
use League\Csv\Reader;
use App\Proveedor;
class ProductoSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
$csv = Reader::createFromPath(resource_path('csv/productos.csv'), 'r');
$csv->setDelimiter("|");
$csv->setEnclosure("'");
$csv->setHeaderOffset(0);
$registros = $csv->getRecords();
$toInsert = [];
foreach($registros as $registro){
$toInsert[] = [
'categoria' => $registro['categoria'],
'nombre' => $registro['producto'],
'precio' => $registro['precio'],
'proveedor_id' => isset($registro['proveedor']) ? Proveedor::firstOrCreate([
'nombre' => $registro['proveedor']
])->id : null
];
}
foreach (array_chunk($toInsert,DatabaseSeeder::CHUNK_SIZE) as $chunk)
{
DB::table('productos')->insert($chunk);
}
}
}

2
dev-start Executable file
View file

@ -0,0 +1,2 @@
#!/usr/bin/bash
docker-compose up -d && docker-compose exec app npm run watch

View file

@ -1,14 +1,14 @@
version: "3.7" version: "3.3"
services: services:
app: app:
build: build:
args: args:
user: www user: www
uid: 1000 uid: ${USERID}
context: ./ context: ./
dockerfile: Dockerfile dockerfile: Dockerfile
image: laravel-image image: laravel-image
container_name: laravel-app container_name: pedi2-app
restart: unless-stopped restart: unless-stopped
working_dir: /var/www/ working_dir: /var/www/
volumes: volumes:
@ -19,10 +19,8 @@ services:
db: db:
image: mysql:5.7 image: mysql:5.7
container_name: laravel-db container_name: pedi2-db
restart: unless-stopped restart: unless-stopped
ports:
- "3306:3306"
environment: environment:
MYSQL_DATABASE: ${DB_DATABASE} MYSQL_DATABASE: ${DB_DATABASE}
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD} MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
@ -36,13 +34,15 @@ services:
- dbdata:/var/lib/mysql - dbdata:/var/lib/mysql
networks: networks:
- app-network - app-network
ports:
- ${DB_PORT_EXPOSED}:3306
nginx: nginx:
image: nginx:alpine image: nginx:alpine
container_name: laravel-nginx container_name: pedi2-nginx
restart: unless-stopped restart: unless-stopped
ports: ports:
- 8000:80 - ${NGINX_PORT}:80
volumes: volumes:
- ./:/var/www - ./:/var/www
- ./nginx/conf.d/:/etc/nginx/conf.d/ - ./nginx/conf.d/:/etc/nginx/conf.d/

25435
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -10,9 +10,9 @@
"production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --config=node_modules/laravel-mix/setup/webpack.config.js" "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --config=node_modules/laravel-mix/setup/webpack.config.js"
}, },
"devDependencies": { "devDependencies": {
"axios": "^0.19", "axios": "^0.19.2",
"bootstrap": "^4.0.0", "bootstrap": "^4.0.0",
"cross-env": "^7.0", "cross-env": "^7.0.3",
"jquery": "^3.2", "jquery": "^3.2",
"laravel-mix": "^5.0.1", "laravel-mix": "^5.0.1",
"lodash": "^4.17.19", "lodash": "^4.17.19",
@ -22,5 +22,11 @@
"sass-loader": "^8.0.0", "sass-loader": "^8.0.0",
"vue": "^2.5.17", "vue": "^2.5.17",
"vue-template-compiler": "^2.6.10" "vue-template-compiler": "^2.6.10"
},
"dependencies": {
"animate.css": "^4.1.1",
"bulma": "^0.9.4",
"bulma-switch": "^2.0.4",
"bulma-toast": "^2.4.1"
} }
} }

BIN
public/assets/chismosa.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
public/assets/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

8
public/css/app.css vendored
View file

@ -1,8 +0,0 @@
p.navbar-item:empty {
display: none;
}
.breadcrumb a {
color: #cc0f35;
}

View file

@ -1,4 +0,0 @@
figure.image.icono {
float: right;
margin: 4px;
}

73
public/js/app.js vendored
View file

@ -1,73 +0,0 @@
window.Event = new Vue();
Vue.component('nav-bar', {
template: `
<nav class="navbar is-danger" role="navigation" aria-label="main navigation">
<div class="navbar-brand">
<a class="navbar-item" href="https://mps.org.uy">
<img src="/assets/logoMPS.png" height="28">
</a>
<p style="margin:0 auto" class="navbar-item"><slot name="subpedido"></slot></p>
<a role="button" class="navbar-burger" :class="{'is-active':isActive}" aria-label="menu" aria-expanded="false" data-target="navbarBasicExample" @click="toggleState">
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
</div>
<div id="navbarBasicExample" class="navbar-menu" :class="{'is-active':isActive}">
<div class="navbar-start has-text-right-mobile">
<!-- Styles nombre del barrio-->
<p class="navbar-item"><slot name="gdc"></slot></p>
<a class="navbar-item"
onclick="event.preventDefault();
document.getElementById('logout-form').submit();">
Cerrar sesión
</a>
<slot name="logout-form"></slot>
</div>
</div>
</nav>`,
data() {
return {
isActive: false
}
},
methods: {
toggleState() {
this.isActive = !this.isActive;
}
}
});
Vue.component('nav-migas', {
data() {
return {
migas: []
}
},
computed: {
visible: function() {
return this.migas.length > 0
}
},
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 = [];
});
Event.$on('migas-pop', () => {
this.migas.pop();
});
}
});
new Vue({
el: '#app'
});

114
public/js/login.js vendored
View file

@ -1,114 +0,0 @@
window.Event = new Vue();
Vue.component('region-select', {
template: `
<div class="block">
<div class="field">
<label class="label">Seleccioná tu región</label>
<div class="control">
<div class="select">
<select @change="onRegionSelected" v-model="region">
<option :disabled="isDefaultDisabled==1" value=null>Seleccionar</option>
<option v-for="region in regiones" v-text="region" :name="region"></option>
</select>
</div>
</div>
</div>
</div>`,
data() {
return {
regiones: [],
isDefaultDisabled: 0,
region: null
}
},
mounted() {
axios.get("/api/regiones").then(response => this.regiones = response.data);
},
methods: {
onRegionSelected() {
this.isDefaultDisabled = 1;
Event.$emit("region-seleccionada",this.region);
}
}
});
Vue.component('barrio-select', {
template: `
<div v-show="visible" class="block">
<div class="field">
<label class="label">Seleccioná tu barrio o grupo de compra</label>
<div class="control">
<div class="select">
<select @change="onGDCSelected" v-model="gdc" name="name">
<option :disabled="isDefaultDisabled==1" value=null>Seleccionar</option>
<option v-for="gdc in gdcs" v-text="gdc.nombre" :name="gdc.nombre"></option>
</select>
</div>
</div>
</div>
</div>`,
data() {
return {
visible: false,
region: null,
gdcs: [],
isDefaultDisabled: 0,
gdc: null
}
},
mounted() {
Event.$on('region-seleccionada', (region)=> {
this.region = region;
this.fillGDC(region);
this.visible = true;
});
},
methods : {
fillGDC(region) {
axios.get("/api/grupos-de-compra").then(response => {
this.gdcs = response.data[this.region];
});
},
onGDCSelected() {
this.isDefaultDisabled = 1;
Event.$emit("gdc-seleccionado",this.gdc);
}
}
});
Vue.component('login', {
template: `
<div v-show="visible" class="block">
<div class="field">
<label class="label">Contraseña del barrio</label>
<p class="control">
<input required class="input" type="password" name="password" placeholder="Contraseña del barrio">
</p>
<p class="help">Si no la sabés, consultá a tus compañerxs.</p>
</div>
<div class="field">
<div class="control">
<input type="submit" class="button is-success" value="Ingresar">
</input>
</div>
</div>
</div>`,
data() {
return {
visible: false,
gdc: null
}
},
mounted() {
Event.$on('gdc-seleccionado', (gdc) => {
this.gdc = gdc;
this.visible = true;
});
}
});
new Vue({
el: '#root'
});

171
public/js/productos.js vendored
View file

@ -1,171 +0,0 @@
Vue.component('categorias-container', {
template: `
<div v-show="visible" class="container">
<div class="columns is-multiline is-mobile">
<div v-for="catego in categorias" class="block column is-one-quarter-desktop is-one-third-tablet is-half-mobile">
<div @click.capture="seleccionarCategoria(catego)" class="card" style="height:100%" >
<div class="card-content">
<div class="media">
<div class="media-content" style="overflow:hidden">
<p class="title is-6" v-text="catego"></p>
</div>
</div>
</div>
</div><!-- END CARD -->
</div><!-- END BLOCK COLUMN -->
</div><!-- END COLUMNS -->
</div><!-- END CONTAINER -->`,
data() {
return {
categorias: null,
visible: true,
miga: {
nombre: "Categorías",
href: "/productos"
}
}
},
mounted() {
axios.get("/api/categorias").then(response => {
this.categorias = response.data;
});
Event.$emit("migas-setear-como-inicio",this.miga);
},
methods: {
seleccionarCategoria(categoria) {
this.visible = false;
Event.$emit("categoria-seleccionada",categoria);
}
}
});
Vue.component('productos-container', {
template: `
<div v-show="visible" class="container">
<div class="columns is-multiline is-mobile">
<div v-for="producto in productos" class="block column is-one-quarter-desktop is-one-third-tablet is-half-mobile">
<div @click.capture="seleccionarProducto(producto)" class="card" style="height:100%">
<div class="card-image">
<figure class="image is-4by3">
<img v-bind:src="producto.imagen ? producto.imagen : 'https://bulma.io/images/placeholders/1280x960.png'">
</figure>
<figure v-show="producto.nacional" class="image icono is-32x32">
<img src="/assets/uruguay.png">
</figure>
<figure v-show="producto.economia_solidaria" class="image icono is-32x32">
<img src="/assets/solidaria.png">
</figure>
</div>
<div class="card-content">
<div class="media">
<div class="media-content">
<p class="title is-6" v-text="producto.nombre"></p>
<p class="subtitle is-7" v-text="producto.proveedor"></p>
<p class="subtitle is-7">$<span v-text="producto.precio"></span></p>
</div>
</div>
</div>
</div><!-- END CARD -->
</div><!-- END BLOCK COLUMN -->
</div><!-- END COLUMNS -->
</div><!-- END CONTAINER -->`,
data() {
return {
productos: [],
visible: false,
categoria: null,
paginar: 150
}
},
computed: {
miga: function(){
return {
nombre: this.categoria,
href: "#" + this.categoria
}
}
},
mounted() {
Event.$on('categoria-seleccionada', (categoria) => {
this.categoria = categoria;
axios.get("/api/productos", {
params: {
categoria: this.categoria,
paginar: this.paginar
}
}).then(response => {
this.productos = response.data.data;
});
this.visible = true;
Event.$emit("migas-agregar",this.miga);
});
},
methods: {
seleccionarProducto(producto) {
Event.$emit("producto-seleccionado",producto);
}
}
});
Vue.component('producto-container', {
template: `
<div v-bind:class="visible ? 'is-active modal' : 'modal'">
<div class="modal-background"></div>
<div class="modal-card">
<header class="modal-card-head">
<p class="modal-card-title" v-text="producto.nombre"></p>
<button class="delete" aria-label="close" @click.capture="cerrar"></button>
</header>
<section class="modal-card-body">
<div class="card-image">
<figure class="image is-4by3">
<img v-bind:src="producto.imagen ? producto.imagen : 'https://bulma.io/images/placeholders/1280x960.png'">
</figure>
<figure v-show="producto.nacional" class="image icono is-32x32">
<img src="/assets/uruguay.png">
</figure>
<figure v-show="producto.economia_solidaria" class="image icono is-32x32">
<img src="/assets/solidaria.png">
</figure>
</div>
<div class="media-content">
<p class="title is-4" v-text="producto.proveedor"></p>
<p class="subtitle is-4">$<span v-text="producto.precio"></span></p>
<p class="subtitle is-5"><span v-text="producto.descripcion"></span></p>
</div>
</section>
<footer class="modal-card-foot">
<button class="button is-success">Agregar a la chismosa</button>
<button class="button" @click.capture="cerrar">Cancelar</button>
</footer>
</div>
</div>`,
data() {
return {
producto: null,
visible: false
}
},
computed: {
miga: function(){
return {
nombre: this.producto.nombre,
href: "#" + this.producto.nombre
}
}
},
methods: {
cerrar() {
this.visible = false;
Event.$emit("migas-pop");
}
},
mounted() {
Event.$on('producto-seleccionado', (producto) => {
this.producto = producto;
this.visible = true;
Event.$emit("migas-agregar",this.miga);
});
}
});

View file

@ -1,33 +0,0 @@
Vue.component('subpedido-select', {
data() {
return {
subpedido: null,
subpedidosExistentes: []
}
},
props: ["gdcid"],
mounted() {
console.log("ready");
},
methods: {
onType() {
axios.get("/api/subpedidos?nombre=" + this.subpedido).then(response => {
this.subpedidosExistentes = response.data
});
},
submit() {
axios.post("/api/subpedidos", {
nombre: this.subpedido,
grupo_de_compra_id: this.gdcid
}).then(response => {
//se creo el subpedido, guardamos el subpedido en sesion
axios.post("/subpedidos/guardar_sesion", {
subpedido: response.data
}).then(response => {
window.location.href = 'productos';
});
});
}
}
});

View file

@ -1,45 +1,4 @@
barrio|region|referente|telefono|correo barrio|region|referente|telefono|correo
BUCEO|ESTE||| ENTREVERO|SUR|||
MALVIN NORTE|ESTE|||
PINAR|ESTE|||
UNION|ESTE|||
SANTO DOMINGO|NORTE|||
21 DE FEBRERO|NORTE|||
PIEDRAS BLANCAS|NORTE|||
BELLA ITALIA|NORTE|||
JARDINES|NORTE|||
LA SOCIALISTA|NORTE|||
VILLA GARCIA|NORTE|||
LAS ACACIAS|NORTE|||
MANGA|NORTE|||
CERRITO|OESTE|||
LEZICA|OESTE|||
PEÑAROL|OESTE|||
LAS PIEDRAS|OESTE|||
A.C.T.E.O|OESTE|||
NUEVO PARIS|OESTE|||
SANTA CATALINA|OESTE|||
BELVEDERE|OESTE|||
BATLLE BERRES|OESTE|||
CERRO PTI|OESTE|||
COLECTIVO UTU LAVALLEJA|OESTE|||
FOGONES|OESTE|||
LAVALLEJA|OESTE|||
REJUNTE|OESTE|||
CAPURRO|OESTE|||
PARQUE RODO|SUR|||
REDUCTO|SUR|||
AGUADA|SUR|||
CASA DEL VECINO|SUR|||
CIUDAD VIEJA|SUR|||
COOP EJIDO|SUR|||
COVIREUS|SUR|||
LA BLANQUEADA|SUR|||
NITEP|SUR|||
LA CURVA|SUR|||
PANADERIA VIDAL|SUR|||
SUA|SUR|||
TRES CRUCES|SUR||| TRES CRUCES|SUR|||
VILLA ESPAÑOLA|SUR||| PRUEBA|SIN REGION|||
AUDA|OTRA|||
SINTEP|OTRA|||
1 barrio region referente telefono correo
2 BUCEO ENTREVERO ESTE SUR
MALVIN NORTE ESTE
PINAR ESTE
UNION ESTE
SANTO DOMINGO NORTE
21 DE FEBRERO NORTE
PIEDRAS BLANCAS NORTE
BELLA ITALIA NORTE
JARDINES NORTE
LA SOCIALISTA NORTE
VILLA GARCIA NORTE
LAS ACACIAS NORTE
MANGA NORTE
CERRITO OESTE
LEZICA OESTE
PEÑAROL OESTE
LAS PIEDRAS OESTE
A.C.T.E.O OESTE
NUEVO PARIS OESTE
SANTA CATALINA OESTE
BELVEDERE OESTE
BATLLE BERRES OESTE
CERRO PTI OESTE
COLECTIVO UTU LAVALLEJA OESTE
FOGONES OESTE
LAVALLEJA OESTE
REJUNTE OESTE
CAPURRO OESTE
PARQUE RODO SUR
REDUCTO SUR
AGUADA SUR
CASA DEL VECINO SUR
CIUDAD VIEJA SUR
COOP EJIDO SUR
COVIREUS SUR
LA BLANQUEADA SUR
NITEP SUR
LA CURVA SUR
PANADERIA VIDAL SUR
SUA SUR
3 TRES CRUCES SUR
4 VILLA ESPAÑOLA PRUEBA SUR SIN REGION
AUDA OTRA
SINTEP OTRA

View file

@ -1,359 +1,381 @@
categoria|producto|precio|proveedor Tipo|Producto|Precio
ALIMENTOS NO PERECEDEROS|Yerba Compuesta La Herboristería 1kg |140.3| ALIMENTOS NO PERECEDEROS||
ALIMENTOS NO PERECEDEROS|Yerba Yusa tradicional 1kg |121.8| P|Yerba Compuesta La Herboristería 1kg|157.63
ALIMENTOS NO PERECEDEROS|Yerba Yusa tradicional 500grs|65| P|Yerba Yusa tradicional 1kg|148.00
ALIMENTOS NO PERECEDEROS|Yerba Sara tradicional 1kg|129.7| P|Yerba Yusa tradicional 500grs|81.00
ALIMENTOS NO PERECEDEROS|Yerba Sara suave 1kg|132.2| P|Yerba Sara tradicional 1kg (Sin TACC)|139.40
ALIMENTOS NO PERECEDEROS|Yerba Kiero mate 500grs|72.5| P|Yerba Sara suave 1kg (Sin TACC)|139.40
ALIMENTOS NO PERECEDEROS|*Harina Santa Unión 000 1kg|27.3|Santa Unión P|*Harina Santa Unión 000 1kg|33.11
ALIMENTOS NO PERECEDEROS|*Harina Santa Unión 0000 1kg|34.8|Santa Unión P|*Harina Santa Unión 0000 1kg|38.70
ALIMENTOS NO PERECEDEROS|*Harina de trigo integral Pasaná 1 kg|65|Pasaná P|*Harina de arroz Pasaná 1 kg (Puede contener gluten)|90.00
ALIMENTOS NO PERECEDEROS|*Harina de arroz Pasaná 1 kg |65|Pasaná P|*Harina de Garbanzos Pasaná 1 kg (Puede contener gluten)|140.00
ALIMENTOS NO PERECEDEROS|*Harina de Garbanzos Pasaná 1 kg |140|Pasaná P|*Mezcla para faina Pasaná 1 kg (Puede contener gluten)|160.00
ALIMENTOS NO PERECEDEROS|*Mezcla para faina Pasaná 1 kg |150|Pasaná P|*Fécula de Mandioca Pasaná 1 kg (Puede contener gluten)|140.00
ALIMENTOS NO PERECEDEROS|*Fécula de Mandioca Pasaná 1 kg |85|Pasaná P|Fécula de Mandioca Hornex 800g (Sin TACC)|125.00
ALIMENTOS NO PERECEDEROS|Tres Harinas 500grs. |85| P|Tres Harinas Hornex 800grs (Sin TAAC)|129.00
ALIMENTOS NO PERECEDEROS|*Harina Santa Unión 000 Bolsa 25kg|560.6|Santa Unión P|*Harina Santa Unión 000 Bolsa 25kg|602.86
ALIMENTOS NO PERECEDEROS|*Polenta Santa Unión 450gr|15.4|Santa Unión P|*Polenta Santa Unión 450gr|16.34
ALIMENTOS NO PERECEDEROS|*Mezcla de Fainá Santa Unión 5kg|294.8|Santa Unión P|*Mezcla de Fainá Santa Unión 5kg|431.29
ALIMENTOS NO PERECEDEROS|*Fideos Caorsi Tirabuzón 1kg|59|Caorsi P|*Harina de trigo intergal orgánica "La linda sauceña"|97.00
ALIMENTOS NO PERECEDEROS|*Fideos Caorsi Tallarín 1kg|69|Caorsi P|*Fideos Caorsi Tirabuzón 1kg|73.00
ALIMENTOS NO PERECEDEROS|*Fideos Caorsi Moñita 1kg|69|Caorsi P|*Fideos Caorsi Tallarín 1kg|81.00
ALIMENTOS NO PERECEDEROS|*Fideos Caorsi para sopa 1kg|59|Caorsi P|*Fideos Caorsi Moñita 1kg|81.00
ALIMENTOS NO PERECEDEROS|*Fideos Caorsi para sopa 5kg|268|Caorsi P|*Fideos Caorsi Tirabuzón 5kg|353.00
ALIMENTOS NO PERECEDEROS|*Fideos Caorsi Tirabuzón 5kg|268|Caorsi P|Arroz Blue Patna 1kg|50.02
ALIMENTOS NO PERECEDEROS|Arroz Blue Patna 1kg|40.2| P|Arroz Shiva 1kg|35.65
ALIMENTOS NO PERECEDEROS|Arroz Shiva 1kg|27| P|*Arroz integral 1kg|72.00
ALIMENTOS NO PERECEDEROS|Arroz integral 1kg |55| P|*Arroz integral 3kg|204.00
ALIMENTOS NO PERECEDEROS|Arroz integral 3kg|155| P|Aceite Condesa de Soja 900 cc.|59.80
ALIMENTOS NO PERECEDEROS|Aceite Condesa de Soja 900 cc.|84| P|Aceite Uruguay de Girasol 900 cc.|81.70
ALIMENTOS NO PERECEDEROS|Aceite Uruguay de Girasol 900 cc.|108| P|Aceite Optimo canola 900 cc.|75.00
ALIMENTOS NO PERECEDEROS|Aceite Optimo canola 900 cc.|82.4| P|Vinagre Uruguay 900ml|61.60
ALIMENTOS NO PERECEDEROS|*Aceite de oliva 500 ml. |195| P|*Salsa de soja La Posta 250 ml.|120.00
ALIMENTOS NO PERECEDEROS|Vinagre Uruguay 900ml|77.9| P|*Aceitunas verdes sin carozo en frasco La Posta 500 gr.|220.00
ALIMENTOS NO PERECEDEROS|Aceite de Oliva Cuatro Piedras 3 lt|1090| P|*Aceitunas negras sin carozo en frasco La Posta 500 gr.|240.00
ALIMENTOS NO PERECEDEROS|*Salsa de soja La Posta 250 ml. |95| P|Lata de atún Golden Fish desmenuzado al aceite 170g|33.35
ALIMENTOS NO PERECEDEROS|*Aceitunas verdes sin carozo en frasco La Posta 500 gr. |180|La Posta P|Lata de arvejas Campero 300g|18.28
ALIMENTOS NO PERECEDEROS|*Aceitunas negras sin carozo en frasco frasco La Posta 500 gr. |180|La Posta P|Lata de choclo Cosecha 300g|32.29
ALIMENTOS NO PERECEDEROS|Lata atún Golden Fish desmenuzado al aceite 170g|31.1| P|Lata de jardinera Cosecha|30.34
ALIMENTOS NO PERECEDEROS|Lata de arvejas Campero 300g|18.3| P|Lata de porotos negros Cosecha|37.06
ALIMENTOS NO PERECEDEROS|Lata de choclo Cosecha 300g|22| P|Lata de porotos de frutilla Cosecha|37.06
ALIMENTOS NO PERECEDEROS|Lata de jardinera Cosecha|25| P|Lata de duraznos en almíbar Campero|73.07
ALIMENTOS NO PERECEDEROS|Lata de porotos negros Cosecha|31.1| P|Mayonesa Uruguay 500g|81.40
ALIMENTOS NO PERECEDEROS|Lata de porotos de frutilla Cosecha|31.1| P|Azúcar Bella Unión 1kg|44.90
ALIMENTOS NO PERECEDEROS|Lata de duraznos en almíbar Campero |66.6| P|Azúcar Mascabo 500g|102.00
ALIMENTOS NO PERECEDEROS|Mayonesa Uruguay 500g|77.9| P|Azúcar impalpable Hornex 200 gr|39.00
ALIMENTOS NO PERECEDEROS|Azúcar Azucarlito 25kg|1007.5| P|Almidón de maíz Hornex 1Kg|89.00
ALIMENTOS NO PERECEDEROS|Azúcar Bella Unión 1kg|39.8| P|Almidón de maíz Ilu wayra 1Kg|75.00
ALIMENTOS NO PERECEDEROS|Azúcar impalpable Hornex 200 gr|31| P|Polvo de Hornear Hornex 100 g + 20 g|38.00
ALIMENTOS NO PERECEDEROS|Azúcar impalpable Hornex 1kg|104| P|*Esencia de vainilla La Posta 100ml|100.00
ALIMENTOS NO PERECEDEROS|Almidón de maíz Hornex 1Kg|64.5| P|*Bicarbonato de sodio La Posta 250 gr|60.00
ALIMENTOS NO PERECEDEROS|Polvo de Hornear Hornex 1 kg|122| P|Grasa Uruguay 400grs|45.80
ALIMENTOS NO PERECEDEROS|Polvo de Hornear Hornex 100 g + 20 g|27.9| P|Levadura seca Hornex 125g|120.00
ALIMENTOS NO PERECEDEROS|*Esencia de vainilla La Posta 100ml|80| P|Café Sorocabana glaseado p/máquina 500 grs|396.00
ALIMENTOS NO PERECEDEROS|Grasa Uruguay 400grs|50| P|Café Sorocabana natural p/máquina 500 grs|557.00
ALIMENTOS NO PERECEDEROS|Levadura seca Hornex 125g|85.5| P|Café soluble Saint bollón 170 gr|232.50
ALIMENTOS NO PERECEDEROS|Café Sorocabana glaseado p/máquina 500 grs|232.8| P|Té Negro en hebras 90gr hornimans|41.12
ALIMENTOS NO PERECEDEROS|Café Sorocabana natural p/máquina 500 grs |315.8| P|Galletas de arroz SIN SAL Natural Rice 120 gr (Sin TACC)|39.00
ALIMENTOS NO PERECEDEROS|Café Saint 170 gr Instantaneo|185.3| P|Galletas de arroz comunes Natural Rice 120 gr (Sin TACC)|39.00
ALIMENTOS NO PERECEDEROS|Té Negro en hebras 90gr hornimans|30.7| P|Leche en polvo entera 250 g|105.00
ALIMENTOS NO PERECEDEROS|Galletas de arroz comunes Natural Rice 120 gr|34| P|Leche en polvo entera 1kg|315.00
ALIMENTOS NO PERECEDEROS|* Leche en polvo 250grs|65| P|* Coco rallado 200gr|72.00
ALIMENTOS NO PERECEDEROS|* Leche en polvo 1kg|220| P|* Coco rallado 1kg|246.00
ALIMENTOS NO PERECEDEROS|* Coco rallado 200gr|70| P|Cocoa Hornex 200gr|55.00
ALIMENTOS NO PERECEDEROS|* Coco rallado 1kg|275| P|Postre de chocolate Hornex 8 porciones|44.00
ALIMENTOS NO PERECEDEROS|Cocoa Hornex 200gr|43| P|Postre LIGHT de vainilla Hornex 8 porciones (aprobado por ADU)|68.00
ALIMENTOS NO PERECEDEROS|Postre de chocolate Hornex 8 porciones|36.5| P|Flan de vainilla Hornex 8 porciones|44.00
ALIMENTOS NO PERECEDEROS|Prostre LIGHT de vainilla Hornex 8 porciones (aprobado por ADU)|57| P|Gelatina de frutilla Hornex 8 porciones|44.00
ALIMENTOS NO PERECEDEROS|Flan de vainilla Hornex 8 porciones|36.5| P|Bizcochuelo de vainilla SIN GLUTEN 500gr Hornex|180.00
ALIMENTOS NO PERECEDEROS|Gelatina de frutilla Hornex 8 porciones|36.5| P|Pizza SIN GLUTEN 320gr Hornex|170.00
ALIMENTOS NO PERECEDEROS|Bizcochuelo de vainilla SIN GLUTEN 500gr Hornex|142| P|Pulpa de Tomate De Ley 1lt (S-G)|50.43
ALIMENTOS NO PERECEDEROS|Pizza SIN GLUTEN 320gr Hornex|137| P|Pure de papa instantaneo De Ley 125g|24.73
ALIMENTOS NO PERECEDEROS|Pulpa de Tomate De Ley 1lt|43.5| P|*Sal fina sin fluor Polenteados 500g|36.00
ALIMENTOS NO PERECEDEROS|Pure de papa instantaneo De Ley 125g|21.3| P|*Sal gruesa sin fluor Polenteados 500g|36.00
ALIMENTOS NO PERECEDEROS|*Sal fina sin fluor Polenteados 500g|27| P|*Sal Rosa 250gr |80.00
ALIMENTOS NO PERECEDEROS|*Sal gruesa sin fluor Polenteados 500g|27| P|*Salsa de tomate casera (puro tomate) 1 lt - (S-G) - azucar agregada: 1g/L - sal agregada: 0,25g/L|85.00
ALIMENTOS NO PERECEDEROS|*Salsa de tomate casera (puro tomate) 1 lt|65| P|*Barras de cereales (maní, sésamo, lino, girasol, avena, copos de arroz, copos de máiz, azúcar rubia y miel) - Pack x2|80.00
ALIMENTOS NO PERECEDEROS|*Barras de cereales (maní, sésamo, lino, girasol, avena, copos de arroz, copos de máiz, azúcar rubia y miel) - Pack x2 |65| P|*Barras de cereales bañadas en chocolate (maní, sésamo, lino, girasol, avena, copos de arroz, copos de máiz, azúcar rubia y miel) - Pack x2|90.00
ALIMENTOS NO PERECEDEROS|*Barras de cereales bañadas en chocolate (maní, sésamo, lino, girasol, avena, copos de arroz, copos de máiz, azúcar rubia y miel) - Pack x2|75| P|*Granola artesanal 500 gr Ing: copos ,avena,miel, vainilla,coco rallado, chia,girasol,sésamo, lino,maní, almendras, castañas de caju, nueces, chips de chocolate.|250.00
ALIMENTOS NO PERECEDEROS|*Granola artesanal 500 gr Ing: copos ,avena,miel, vainilla,coco rallado, chia,girasol,sésamo, lino,maní, almendras, castañas de caju, nueces, chips de chocolate.|210| P|*Granola simple (avena+ girasol+ pasaUva) 1kg|171.00
ALIMENTOS NO PERECEDEROS|*Granola simple (avena+ girasol+ pasaUva) 1kg|160| P|*Copos de maíz azucarados 500g|112.00
ALIMENTOS NO PERECEDEROS|*Copos de maíz azucarados 500g|89| P|*Copos de maíz naturales 500g|112.00
ALIMENTOS NO PERECEDEROS|*Copos de maíz naturales 500g|89| P|*Crema untable de maní 330 gr, envase de vidrio |225.00
ALIMENTOS NO PERECEDEROS|*Crema untable de maní 250gr|89| P|*Tableta artesanal chocolate semiamargo con frutos secos 100g |130.00
ALIMENTOS NO PERECEDEROS|*Galletas de coco, avena y maní 400gr|100| P|*Tableta artesanal chocolate semiamargo con pasas 100g |130.00
ALIMENTOS NO PERECEDEROS|*Budin Panitep con cobertura de chocolate con almendras, maní, nueces y pasas 250grs|160| P|*Tableta artesanal chocolate blanco con frutos secos 100g |130.00
ALIMENTOS NO PERECEDEROS|*Budin Panitep con cobertura de almíbar y coco con almendras, maní, nueces y pasas 250grs|140| P|*Tableta artesanal chocolate blanco con pasas 100g |130.00
ALIMENTOS NO PERECEDEROS|*Budin Panitep de naranja 250grs|140| P|Alfajor de chocolate negro 80 g (S-G) |48.00
ALIMENTOS NO PERECEDEROS|*Chia 1/4 kg |65| P|Galletitas dulces de chispas de chocolate y avena 150 g (S-G)|116.00
ALIMENTOS NO PERECEDEROS|*Girasol 1/2 kg |85| P|Crackers saladas de sésamo girasol y chía 180 g (S-G)|116.00
ALIMENTOS NO PERECEDEROS|*Lino 1/4 kg |30| P|*Lino 1/4 kg|42.00
ALIMENTOS NO PERECEDEROS|*Sésamo 1/4 kg |55| P|*Chía 1/4 kg|80.00
ALIMENTOS NO PERECEDEROS|*Quinoa 1 kg |200| P|*Girasol 1/2 kg|140.00
ALIMENTOS NO PERECEDEROS|*Dátiles con carozo 500 gr|180| P|*Sésamo 1/4 kg|65.00
ALIMENTOS NO PERECEDEROS|*Cacao en polvo 250 grs |100| P|*Quinoa 1 kg|210.00
ALIMENTOS NO PERECEDEROS|*Almendra pelada (sin tostar) Polenteados 100g|80|Polenteados P|*Dátiles con carozo 500 gr|240.00
ALIMENTOS NO PERECEDEROS|*Pasas de Uva Polenteados 250 gr|69|Polenteados P|*Cacao en polvo 250 grs (S-A)|125.00
ALIMENTOS NO PERECEDEROS|*Nueces Polenteados 100g|79|Polenteados P|*Almendra pelada (sin tostar) Polenteados 100g|93.00
ALIMENTOS NO PERECEDEROS|*Castañas tostadas SIN sal 100grs|76|Polenteados P|*Pasas de Uva Polenteados 500 gr|149.00
ALIMENTOS NO PERECEDEROS|*Avena laminada instantánea Polenteados 500g|49|Polenteados P|*Nueces Polenteados 100g|89.00
ALIMENTOS NO PERECEDEROS|*Pan de molde Gigor Lacteado 550g|55|Gigor P|*Castañas tostadas SIN sal 100grs|81.00
ALIMENTOS NO PERECEDEROS|*Pan de molde Gigor Integral 550g|55|Gigor P|*Avena laminada instantánea Polenteados 500g|69.00
ALIMENTOS NO PERECEDEROS|*Galleta Malteada La Socialista 350g|56|La Socialista P|*Pan de molde Gory Lacteado 550g|64.00
ALIMENTOS NO PERECEDEROS|*Galleta Malteada c/semillas (sésamo, chia, lino) La Socialista 380gr |74|La Socialista P|*Pan de molde Integral Gory 550g|64.00
ALIMENTOS NO PERECEDEROS|*Galleta Cara Sucia La Socialista 350g|63|La Socialista P|*Galleta Malteada La Socialista 350g|84.00
ALIMENTOS NO PERECEDEROS|*Grisines La Socialista 350g|67|La Socialista P|*Galleta Malteada c/semillas (sésamo, chia, lino) La Socialista 380gr|103.00
ALIMENTOS NO PERECEDEROS|*Mezcla para panqueques La Socialista 2 x 250g|56|La Socialista P|*Galleta Cara Sucia La Socialista 350g|92.00
ALIMENTOS NO PERECEDEROS|*Mezcla para salsa blanca La Socialista 2 x 50g|46|La Socialista P|*Grisines La Socialista 350g|96.00
ALIMENTOS NO PERECEDEROS|*Maní pelado frito y salado Polenteados 500g|89|Polenteados P|*Maní pelado frito y salado Polenteados 500g|103.00
ALIMENTOS NO PERECEDEROS|*Maní pelado sin sal Polenteados 500g|89|Polenteados P|*Maní pelado sin sal Polenteados 500g|103.00
ALIMENTOS NO PERECEDEROS|*Garbanzo Polenteados 1kg|79|Polenteados P|*Garbanzo Polenteados 1kg|109.00
ALIMENTOS NO PERECEDEROS|*Lentejas Polenteados 1kg|96|Polenteados P|* Maiz para pop 500grs|54.00
ALIMENTOS NO PERECEDEROS|*Porotos negros Polenteados 1kg|86|Polenteados P|*Lentejas Polenteados 1kg|125.00
ALIMENTOS NO PERECEDEROS|*Porotos de manteca Polenteados 1kg |105|Polenteados P|*Porotos negros Polenteados 1kg|125.00
ALIMENTOS NO PERECEDEROS|*Proteína de SOJA texturizada 1kg |125| P|*Porotos de manteca Polenteados 1kg|149.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Tallarines frescos de yema Pastas Colon 1kg|155|Pastas Colón P|*Porotos mung 1kg |150.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Tallarines frescos de espinaca Pastas Colon 1kg|165|Pastas Colón P|*Arvejas 1kg |120.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Tallarines frescos de morrón Pastas Colon 1kg|165|Pastas Colón P|*Proteína de SOJA texturizada 1kg|139.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Salsa pomarola 300gr ex trabajadores de La Spezia|90| P|*Semillas Zapallo 100g.|60.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Fetuccine integral de zanahoria, apto veganos 1kg|190| CONDIMENTOS, PERECEDEROS Y BEBIDAS||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Romanitos rellenos jamón y queso ex trabajadores de La Spezia 1kg|490| P|*Tallarines frescos de yema Pastas Colon 1kg|175.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Romanitos vegetarianos ex trabajadores de La Spezia 1kg|490| P|*Tallarines frescos de espinaca Pastas Colon 1kg|185.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Sorrentinos jamón y queso 1Kg ex trabajadores de La Spezia|450| P|*Tallarines frescos de morrón Pastas Colon 1kg|190.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Sorrentinos Ricota y Nuez 1kg ex Trabajadores de La Spezia|450| P|*Prepizza 28cm ex trabajadores de La Spezia|90.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Raviolón vegetariano 1Kg ex trabajadores de La Spezia|450| P|*Milanesas de carne 1kg|395.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Raviolón Caprese 1kg ex Trabajadores de La Spezia|450| P|*Milanesas de pollo 1kg|370.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Prepizza de 28cm ex trabajadores de La Spezia|85| P|*Empanada de pollo x 6|265.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Milanesas de carne empanadas 1kg|365| P|*Empanada de carne x 6|265.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Milanesas de pollo empanadas 1kg|365| P|*Pan rallado 1kg|75.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Milanesas de seitan x6 |300| P|*Pan rallado saborizado 1Kg|95.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Hamburguesas parrilleras de soja no transgénica, sal, harina de avena y adobo sin picante x6|300| P|*Pimienta blanca 30g|20.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Jamón vegano (gluten de trigo, salsa de tomate, sabor ahumado, sal) horma 250 g|200| P|*Orégano 25g|20.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Hummus 200cc |140| P|*Pimentón 30g|20.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Pate de zanahoria 200cc |140| P|*Adobo 30g|20.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Pan rallado 1kg|55| P|*Ajo y Perejil 30g|20.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Pan rallado saborizado 1Kg|75| P|*Clavo de olor 15g|20.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Pimienta blanca 30g|20| P|*Tomillo 25g|20.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Orégano 25g|20| P|*PACK "A" Curry / Nuez moscada / Ajo en polvo / Condimento verde / Comino|100.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Pimentón 30g|20| P|*PACK "B" Pimienta Negra polvo / Sal de ajo / Aji molido / Canela en polvo / Condimento para arroz|100.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Adobo 30g|20| P|*PACK "C" Cebolla en polvo / Pimienta blanca en grano / Pimienta negra en grano / Ajo en escamas / Especias surtidas|100.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Ajo y Perejil 30g|20| P|*Pimentón 250grs|110.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*PACK "A" Curry, nuez moscada, ajo polvo, condimento verde, comino|80| P|*Orégano 250g|115.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*PACK "B" Pimienta Negra polvo / sal de ajo, aji molido, canela polvo y chimichurry|80| P|*Nuez moscada entera 2 unidades|28.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*PACK "C" Cebolla en escamas, tomillo, clavo de olor, pimienta blanca en grano, ajo en escamas|80| P|*Canela en rama 10g|25.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Pimentón 250grs |75| P|*Cúrcuma 20g|25.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Orégano 250g|85| P|*Pack "Mix sabores"- Paprika, Albahaca, Mostaza en polvo.|65.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Nuez moscada entera 2 unidades |21| P|*Pack "Pal mate"- Boldo, Cedron, Marcela.|120.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Canela en rama 10g|21| P|*Pack "Relax"- Tilo, Malva, Té rojo.|120.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Cúrcuma 20g |21| P|*Pack "Power" - Ginseng, Carqueja, Ginkgo biloba.|120.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Pack "Sabores exoticos" - Paprika, fenogreco y cardamomo|57| P|Atado de perejil|50.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|'''''''*Pack "Pa''''''''l mate" - Manzanilla, cedrón y carqueja'''''''|105| P|Mix de hierbas (ciboullete, tomillo, laurel y pasto lim[on)|50.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|Pack "Medicinas de monte" - Tilo, malva y marcela|105| P|Atado de romero|50.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Pack "Té helado light" - Té rojo, stevia y lemon grass|105| P|Fernet 760 ml|405.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|Vino Santero Marselán 1 lt.|198| P|Vino Santero Marselán 1 lt.|235.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|Vino Tannat-Cabernet Paso del Roble 1 lt.|90| P|Frizzante de Maracuyá|246.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|Vino Rosado dulce Paso del Roble 1 lt.|90| P|Frizzante de Frutos del bosque|246.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|Frizzante de Maracuyá|205| P|*Cerveza artesanal APA Press 1L|170.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|Frizzante de Frutos del bosque|205| P|* Cerveza artesanal IPA Press 1L |180.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Cerveza artesanal Sudaka Blonde 500cc|100| P|*Cerveza artesanal Negra Press 1L|180.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Cerveza artesanal Sudaka Scottish 500cc|100| P|* Cerveza artesanal Rubia Lager 1L |160.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Cerveza artesanal Punto Rojo Red Ipa 500cc|100| P|Jugo en polvo "Juguito" sabores surtidos|8.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Cerveza artesanal Punto Rojo Negra 500cc|100| P|Jugo Big C 200ml sabores surtidos|16.84
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Cerveza artesanal APA Guillotina 1L|180| P|*Refresco U Naranja 2lt|94.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|Fernet artesanal 780 ml|370| P|*Refresco U Mandarina 2lt|94.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|Jugo en polvo "Juguito" sabores surtidos|8.06| P|*Refresco U Pomelo 2lt|94.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|Jugo Big C 200ml sabores surtidos|13.14| P|*Refresco U Limonada 2lt|94.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Refresco U Naranja 2lt|82| P|*Agua 6 lts|98.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Refresco U Mandarina 2lt|82| P|*Queso Muzzarella 1/2 kg Unidad Cooperaria|172.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Refresco U Pomelo 2lt|82| P|*Queso Magro s/sal 1/2 kg Unidad Cooperaria|191.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Refresco U Limonada 2lt|82| P|*Queso Magro c/sal 1/2 kg Unidad Cooperaria|191.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Agua 6 lts|84| P|*Queso Danbo 1/2 kg Unidad Cooperaria|188.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Queso Muzzarella 1/2 kg Unidad Cooperaria|130| P|*Queso Sbrinz 1/2 kg Unidad Cooperaria|287.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Queso Magro s/sal 1/2 kg Unidad Cooperaria|147.5| P|*Queso Colonia 1/2 Kg Unidad Cooperaria|197.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Queso Magro c/sal 1/2 kg Uniddad Cooperaria|147.5| P|*Queso parrillero 350g Unidad Cooperaria|177.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Queso Danbo 1/2 kg Unidad Cooperaria|137.5| P|*Queso semiduro 500grs (envasado al vacío) Productores Ismael Cortinas|258.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Queso Sbrinz 1/2 kg Unidad Cooperaria|170| P|*Queso cuartirolo horma 1kg envasado al vacío|375.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Queso Colonia 1/2 Kg Unidad Cooperaria|160| P|*Queso rallado 200grs|155.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Queso parrillero 350g Unidad Cooperaria|165| P|*Dulce de Leche 1 Kg Unidad Cooperaria|269.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Queso de mandioca en horma 400 gr|200| P|*Morrones en vinagre 330 gr|230.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Queso saborizado con ciboulette 600grs (envasado al vacío)|230| P|*Berenjenas en vinagre 330 gr|230.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Queso saborizado con albahaca 600grs (envasado al vacío)|230| P|*Mermelada de morrones 250 gr|230.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Queso saborizado con orégano 500grs (envasado al vacío)|250| P|*Mermelada de frutilla, 450 grs.|145.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Queso semiduro 500grs (envasado al vacío) Productores Ismael Cortinas|195| P|*Mermelada de durazno, 450 grs.|133.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Queso cuartirolo horma 1kg envasado al vacío|270| P|*Mermelada de ciruela, 450 grs.|133.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Queso rallado 100grs|63| P|*Mermelada de higo, 450 grs.|133.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Queso rallado 200grs|120| P|*Mermelada de zapallo, 450 grs.|133.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Dulce de Leche 1 Kg Unidad Cooperaria|165| P|*Mermelada de naranja, 450 grs.|134.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Dulce de leche de coco 360 gr|300| P|*Mermelada de arándanos, 450 grs.|159.50
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Morrones en vinagre 330 gr|140| P|*Dulce de membrillo, 900grs|123.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Berenjenas en vinagre 330 gr|140| P|*Dulce de batata con chocolate 1kg|154.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Mermelada de morrones 250 gr|140| P|*Dulce de zapallo 1kg|139.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Mermelada de frutilla, 450 grs. |123| P|*Dulce de higo 1kg|134.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Mermelada de durazno, 450 grs.|110| P|*Miel artesanal 500g|130.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Mermelada de ciruela, 450 grs. |115| P|*Miel artesanal 1 kg|240.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Mermelada de higo, 450 grs. |110| P|*Canasta de frutas y verduras "34 Sur Productos Orgánicos"|630.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Mermelada de zapallo, 450 grs.|110| ARTÍCULOS PERSONALES Y DE LIMPIEZA||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Mermelada de naranja, 450 grs. |115| P|Preservativos Prime ultrafinos x3|89.70
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Mermelada de arándanos, 450 grs. |145| P|Preservativos Kamasutra x3|34.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Dulce de membrillo, 900grs |105| P|Tabaco Cerrito|125.67
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Dulce de batata con chocolate 1kg|115| P|Hojilla JOB x30|28.36
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Dulce de zapallo 1kg|115| P|Shampoo Suave 930ml|123.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|'''''''*Dulce de higo 1kg'''|115| P|Acondicionador Suave 930ml|123.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|Miel artesanal 1 kg|210| P|Jabón de tocador IO, 80gs|16.60
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Canasta de frutas y verduras "34 Sur Productos Orgánicos"|630| P|Cepillo dental kolynos máster. |28.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Romero 25grs, El Ombú PTIc|45| P|Pasta Dental kolynos 180 grs. |49.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Apio 25grs, El Ombú PTIc|45| P|Pastillas para mosquitos Fuyi x 12|98.30
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Menta 25grs, El Ombú PTIc|45| P|*Pack x3 jabones glicerina vegetal Natura|380.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Melissa 25grs, El Ombú Ptic|45| P|*Shampoo artesanal pelo seco 250ml Natura|250.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Albahaca limón, El Ombú Ptic|45| P|*Desodorante ecológico apto veganos Natura|190.00
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Llanten 25grs, El Ombú PTIc|45| P|*Shampoo artesanal pelo graso 250ml Natura|250.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Preservativos Prudence clasico x3|59.09| P|*Barrita quita manchas 75 gr Natura|100.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Tabaco Cerrito|99| P|*Aromatizador ambiental fragancia floral de varilla Natura, 100ml |345.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Hojilla JOB x30 |22| P|*Aromatizador ambiental fragancia cítrica de varilla Natura, 100ml |345.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Shampoo Ainé Cuidado Total 500cc|230| P|*Talco pédico Natura, 200gr|235.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Shampoo Ainé Brillo Extremo 500cc|230| P|*Repelente Natura, 125ml|245.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Acondicionador Ainé Cuidado Total 500cc |230| P|*Shampoo pediculosis, envase 250 ml|320.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Acondicionador Ainé Brillo Extremo 500cc |230| P|*Jabón en polvo Bonsai 800g|95.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Acondicionador Ainé Dos Minutos 500cc |230| P|*Jabón en polvo Bonsai 5kg|550.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Shampoo Suave 930ml |144.09| P|*Suavizante Bonsai 1lt|80.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Acondicionador Suave 930ml |144.09| P|*Jabon liquido para lavarropas 900 cc Bonsai|85.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Jabón de tocador IO, 80gs |12| P|*Jabon liquido para lavarropas 3 lts Bonsai|270.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Cepillo dental Introdento (medio)|29.74| P|*Jabon liquido de Manos 500 cc Bonsai|60.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Pasta Dental Introdento menta 102 grs. |36.72| P|*Perfumador de telas 250 cc Bonsai|120.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Loción repelente de mosquitos, 200 ml|210| P|*Limpiador desengarsante para cocinas y baños aroma cítrico 1 litro (no es para cañerías)|120.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Pack x3 jabones glicerina vegetal Natura|330| P|*Limpiador cremoso 650 cc *|120.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Desodorante ecológico apto veganos Natura|160| P|*Entrebichitos - MEN 2lts. (graseras, pozos, cañerías, plantas)|180.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Pasta Dental Libre de Flúor Natura|165| P|*Entrebichitos - MEN Limpieza 1lt (suelos, mesadas, paredes, combate hongos, bacterias y virus)|100.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Shampoo artesanal pelo graso 250ml Natura|235| P|*Entrebichitos - Pastilla grasera|80.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Shampoo artesanal pelo seco 250ml Natura|230| P|*Hipoclorito El Resistente 1800cc|76.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Shampoo sólido cabello seco y normal 50gr |340| P|*Limpiador perfumado El Resistente (perfumol) 1800cc|76.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Protector solar factor 65, 200 ml. NUEVO!!|550| P|*Detergente El Resistente 500ml|51.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Shampoo sólido cabello graso 50gr |355| P|*KIT El Resistente (Hip./Perf./Det.)|188.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Acondicionador sólido 50gr |350| P|Jabon en barra Primor x1|29.36
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Cepillo dental de bambú 97% biodegradable (niños y adultos)|165| P|Rejilla de cocina 40 x 27.5 Tacuabé (ex Paylana) cm|36.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Talco pédico 200gr |205| P|Trapo de piso 53 x 53 Tacuabé (ex Paylana)|36.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Bálsamo labial Herencias de aquelarre (protege y repara) |180| P|Esponja de cocina|26.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Detergente ecológico grupo Flores Silvestres 500 grs|90| P|Esponja de acero inoxidable|29.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Jabón en polvo Bonsai 800g|70|Bonsai P|Repasador de algodón 43 x 65 cm|53.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Jabón en polvo Bonsai 5kg|350|Bonsai P|Franela 34 x 34|37.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Suavizante Bonsai 1lt|70|Bonsai P|Escoba|116.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Jabon liquido para lavarropas 900 cc Bonsai|80|Bonsai P|Pala con mango|99.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Jabon liquido para lavarropas 3 lts Bonsai|220|Bonsai P|Balde 9 Lts|109.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Jabon liquido de Manos 500 cc Bonsai|50|Bonsai P|Bolsa de residuos 50x55 30 unidades|63.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Perfumador de telas 250 cc Bonsai|100|Bonsai P|Lampazo|119.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Limpiador desengarsante para cocinas y baños aroma cítrico 1 litro (no es para cañerías)|90|Bonsai P|Rollitos de aluminio Griselda x12|38.30
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Entrebichitos - MEN 2lts. (graseras, pozos, cañerías, plantas)|180|Entrebichitos P|rollitos de aluminio jaspe x6|30.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Entrebichitos - MEN Limpieza 1lt (suelos, mesadas, paredes, combate hongos, bacterias y virus)|100|Entrebichitos P|*Vela de apagón|8.40
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Entrebichitos - Pastilla grasera|80|Entrebichitos P|*Vela de citronela 1 mecha|132.80
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Hipoclorito El Resistente 1800cc|66|El Resistente P|Toallita de bebé BabySec ultra 50un|83.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Limpiador perfumado El Resistente (perfumol) 1800cc|66|El Resistente P|Papel Higienico: Higienol Texturado x4|42.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Detergente El Resistente 500ml|43|El Resistente P|Papel de Cocina Sussex extra x 2 -120 paños-|72.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*KIT El Resistente (Hip./Perf./Det.)|161|El Resistente P|Pañales Babysec ULTRA (Celeste) XXG 24 unidades |448.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Jabon bulldog packx2|66.24| P|Pañales Babysec ULTRA (Celeste) XG 24 unidades|448.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Rejilla de cocina 40 x 27.5 Tacuabé (ex Paylana) cm|22| P|Pañales Babysec ULTRA (Celeste) G 30 unidades|448.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Trapo de piso 55 x 55 Tacuabé (ex Paylana)|35| P|Pañales Babysec ULTRA (Celeste) M 36 unidades|448.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Esponja de cocina|22| P|Pañales Babysec ULTRA (Celeste) P 36 unidades|448.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Esponja de acero inoxidable|23| P|Pañales Babysec PREMIUM (Violeta) XXG 48 unidades|790.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Repasador de algodón 43 x 65 cm|39| P|Pañales Babysec PREMIUM (Violeta) XG 48 unidades|790.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Franela 34 x 34|30| P|Pañales Babysec PREMIUM (Violeta) G 60 unidades|790.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Escoba|97| P|Pañales Babysec PREMIUM (Violeta) M 68 unidades|790.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Pala con mango|89| P|Pañales para Adultes INCOPROTECT TALLE M|579.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Balde 9 Lts |99| P|Pañales para Adultes INCOPROTECT TALLE G |617.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Bolsa de residuos 50x55 30 unidades |49| P|Pañales para Adultes INCOPROTECT TALLE EXTRA G |743.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Lampazo |99| TEXTIL||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Guantes de latex talle M|80.1| PTC|*Calza licra de algodon talle S|900.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Rollitos de alumnio x6 |27.3| PTC|*Calza licra de algodon talle M|900.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Vela de apagón|8.37| PTC|*Calza licra de algodon talle L|900.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Vela de citronela 1 mecha|122.2| PTC|*Calza licra de algodon talle XL|900.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Pastillas para mosquitos Sapolio 12 unidades |52.61| PTC|*Biker licra de algodón - Talle S |650.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Pañales Babysec ULTRA XXG 24 unidades|312| PTC|*Biker licra de algodón - Talle M |650.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Pañales Babysec ULTRA XG 24 unidades|312| PTC|*Biker licra de algodón - Talle L |650.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Pañales Babysec ULTRA G 30 unidades|312| PTC|*Biker licra de algodón - Talle XL |650.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Pañales Babysec ULTRA M 36 unidades|312| PTC|*Biker licra de algodón - Talle 0 |350.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Pañales Babysec ULTRA P 36 unidades|312| PTC|*Biker licra de algodón - Talle 2 |350.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Toallita de bebé BabySec ultra 50un|67| PTC|*Biker licra de algodón - Talle 4 |350.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Papel Higienico: Higienol Texturado x4|47| PTC|*Biker licra de algodón - Talle 6 |400.00
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Papel de Cocina Sussex extra x 2 -120 paños-|57| PTC|*Biker licra de algodón - Talle 8 |400.00
TEXTIL|*Calza licra de algodon talle S|750| PTC|*Biker licra de algodón - Talle 10 |400.00
TEXTIL|*Calza licra de algodon talle M|750| PTC|*Biker licra de algodón - Talle 12 |500.00
TEXTIL|*Calza licra de algodon talle L|750| PTC|*Biker licra de algodón - Talle 14 |500.00
TEXTIL|*Calza licra de algodon talle XL|750| PTC|*Biker licra de algodón - Talle 16 |500.00
TEXTIL|*Calza licra de algodon talle 0|300| P|*Conjunto primera muda 100% algodón (pack de pelele, bata y gorrito en bolsa de lienzo) color a elección sujeto a disponibilidad de tela|600.00
TEXTIL|*Calza licra de algodon talle 2 |300| PTC|*Calza licra de algodon talle 0|350.00
TEXTIL|*Calza licra de algodon talle 4|300| PTC|*Calza licra de algodon talle 2|350.00
TEXTIL|*Calza licra de algodon talle 6 |300| PTC|*Calza licra de algodon talle 4|350.00
TEXTIL|*Calza licra de algodon talle 8 |300| PTC|*Calza licra de algodon talle 6|450.00
TEXTIL|*Calza licra de algodon talle 10|300| PTC|*Calza licra de algodon talle 8|450.00
TEXTIL|*Calza licra de algodon talle 12|300| PTC|*Calza licra de algodon talle 10|450.00
TEXTIL|*Calza licra de algodon talle 14 |350| PTC|*Calza licra de algodon talle 12|550.00
TEXTIL|*Calza licra de algodon talle 16 |350| PTC|*Calza licra de algodon talle 14|550.00
TEXTIL|*Campera deportiva - Talle 0|350| PTC|*Calza licra de algodon talle 16|550.00
TEXTIL|*Campera deportiva - Talle 2|350| PTC|*Campera deportiva - Talle 0|400.00
TEXTIL|*Campera deportiva - Talle 4|350| PTC|*Campera deportiva - Talle 2|400.00
TEXTIL|*Campera deportiva - Talle 6|400| PTC|*Campera deportiva - Talle 4|400.00
TEXTIL|*Campera deportiva - Talle 8|400| PTC|*Campera deportiva - Talle 6|450.00
TEXTIL|*Campera deportiva - Talle 10|400| PTC|*Campera deportiva - Talle 8|450.00
TEXTIL|*Campera deportiva - Talle 12|450| PTC|*Campera deportiva - Talle 10|450.00
TEXTIL|*Campera deportiva - Talle 14|450| PTC|*Campera deportiva - Talle 12|500.00
TEXTIL|*Campera deportiva - Talle 16|450| PTC|*Campera deportiva - Talle 14|500.00
TEXTIL|*Pantalón deportivo - Talle 0|250| PTC|*Campera deportiva - Talle 16|500.00
TEXTIL|*Pantalón deportivo - Talle 2|250| PTC|*Pantalón deportivo - Talle 0|300.00
TEXTIL|*Pantalón deportivo - Talle 4|250| PTC|*Pantalón deportivo - Talle 2|300.00
TEXTIL|*Pantalón deportivo - Talle 6|300| PTC|*Pantalón deportivo - Talle 4|300.00
TEXTIL|*Pantalón deportivo - Talle 8|300| PTC|*Pantalón deportivo - Talle 6|350.00
TEXTIL|*Pantalón deportivo - Talle 10|300| PTC|*Pantalón deportivo - Talle 8|350.00
TEXTIL|*Pantalón deportivo - Talle 12|350| PTC|*Pantalón deportivo - Talle 10|350.00
TEXTIL|*Pantalón deportivo - Talle 14|350| PTC|*Pantalón deportivo - Talle 12|400.00
TEXTIL|*Pantalón deportivo - Talle 16|350| PTC|*Pantalón deportivo - Talle 14|400.00
TEXTIL|*Babucha deportiva en algodón - Talle 4|500| PTC|*Pantalón deportivo - Talle 16|400.00
TEXTIL|*Babucha deportiva en algodón - Talle 6|500| PTC|*Buzo deportivo de verano para adultes - Talle S |1000.00
TEXTIL|*Babucha deportiva en algodón - Talle 8 |500| PTC|*Buzo deportivo de verano para adultes - Talle M |1000.00
TEXTIL|*Babucha deportiva en algodón - Talle 10 |600| PTC|*Buzo deportivo de verano para adultes - Talle L |1000.00
TEXTIL|*Babucha deportiva en algodón - Talle 12 |600| PTC|*Buzo deportivo de verano para adultes - Talle XL |1000.00
TEXTIL|*Babucha deportiva en algodón - Talle 14 |600| PTC|*Pantalón deportivo de verano para adultes - Talle S |900.00
TEXTIL|*Babucha deportiva en algodón - Talle 16 |600| PTC|*Pantalón deportivo de verano para adultes - Talle M |900.00
TEXTIL|*Babucha deportiva en algodón - Talle 18 |600| PTC|*Pantalón deportivo de verano para adultes - Talle L |900.00
TEXTIL|*Pantalón deportivo liso de algodón - Talle S|850| PTC|*Pantalón deportivo de verano para adultes - Talle XL |900.00
TEXTIL|*Pantalón deportivo liso de algodón - Talle M|850| P|*Juego de sábanas de algodón 1 plaza|1300.00
TEXTIL|*Pantalón deportivo liso de algodón - Talle L|850| P|*Juego de sábanas de algodón 2 plazas (para sommier)|1500.00
TEXTIL|*Pantalón deportivo liso de algodón - Talle XL |850| P|*Materas de Lona.|450.00
TEXTIL|*Canguro deportivo liso con capucha de algodón - TalleS |1000| P|*Sábana sola con elástico, 2 plazas (para sommier)|950.00
TEXTIL|*Canguro deportivo liso con capucha de algodón - Talle M |1000| P|*Juego de toallón y toalla de algodón|900.00
TEXTIL|*Canguro deportivo liso con capucha de algodón - Talle L |1000| P|*Toallón|750.00
TEXTIL|*Canguro deportivo liso con capucha de algodón - Talle XL|1000| P|*Toalla de mano|350.00
TEXTIL|*Túnica niñe con cinto en espalda y tajo detrás- talles 6 a 16|480| P|*Turbante toalla|450.00
TEXTIL|*Túnica niñe con martingala, festón y pinzas talles 6 a 16|480| P|*Juego de Sábanas de poliéster 1 plaza |850.00
TEXTIL|*Pintor verde - talles 2 a 8|300| P|*Juego de sábanas de poliéster 2 plazas |1000.00
TEXTIL|*Pintor azul - talles 2 a 8|300| MADRES Y FAMILIARES||
TEXTIL|*Pintor rojo - talles 2 a 8|300| PTC|Camiseta EDICION ESPECIAL - talles S al XXL|450.00
TEXTIL|*Pintor amarillo - talles 2 a 8|300| PTC|Canguros Madres y Familiares |950.00
TEXTIL|*Túnicas adulto - talles 1 a 5|1100| P|Pack 1: 1 pin redondo + 1 lapicera + 1 Pañuelo + Pegotines y marcalibros|150.00
TEXTIL|*Moña escolar satinada|50| P|Pack 2: 1 Pin redondo + 1 Lapicera + Pegotines y marcalibros|100.00
TEXTIL|*Juego de sábanas de algodón 1 plaza|1000| P|Pack 3: 1 Llavero + 1 Lapicera|100.00
TEXTIL|*Juego de sábanas de algodón 2 plazas (para sommier) |1200| P|Libro "Desaparecidos"|50.00
TEXTIL|*Sábana sola sin elástico, 2 plazas (para sommier) |700| ARTÍCULOS DE LA COORDINADORA POR PALESTINA||
TEXTIL|*Sábana sola con elástico, 2 plazas (para sommier) |700| B|Bono colaboración|20.00
TEXTIL|*Juego de toallón y toalla de algodón |650| P|Remera talle S - Palestina|450.00
TEXTIL|*Toallón|500| P|Remera talle M - Palestina|450.00
TEXTIL|*Toalla de mano|250| P|Remera talle L - Palestina|450.00
TEXTIL|*Turbante toalla|350| P|Remera talle XL - Palestina|450.00
TEXTIL|*Tapaboca de tela|50| P|Bandera 60x90 cm - Coordinadora por Palestina|450.00
ARTÍCULOS DE MADRES Y FAMILIARES|Pañuelo Madres y Familiares de Detenidos Desaparecidos|50|Madres y familiares P|Pin Coordinadora por Palestina|40.00
ARTÍCULOS DE MADRES Y FAMILIARES|Balconera Madres y Familiares de Detenidos Desaparecidos|100|Madres y familiares P|Balconera "Paremos el genocidio"|150.00
ARTÍCULOS DE MADRES Y FAMILIARES|Pack 2 - 1 Pin redondo + Lapicera + Pegotines y Marcalibros|100|Madres y familiares P|Banderita para el auto |100.00
PRODUCTOS DEL MPS|Pack de 5 pegotines del MPS (2 logos y 3 consignas, todo a color).|40|Madres y familiares P|Kit 5 pegotines - Coordinadora por Palestina|80.00
BONOS Y FINANCIAMIENTO SORORO|Campaña solidaria MPS - apoyo a ollas y merenderos|20|MPS P|Remera talle S - Palestina - Puño - único color Negro *NUEVO|500.00
BONOS Y FINANCIAMIENTO SORORO|Financiamiento sororo para copa menstrual|20| P|Remera talle M - Palestina - Puño - único color Negro *NUEVO|500.00
BONOS Y FINANCIAMIENTO SORORO|Galpón de corrales|20| P|Remera talle L - Palestina - Puño - único color Negro *NUEVO|500.00
PRODUCTOS DE GESTIÓN MENSTRUAL|Copa menstrual de silicona, ecológica |750| P|Remera talle XL - Palestina - Puño - único color Negro *NUEVO|500.00
PRODUCTOS DE GESTIÓN MENSTRUAL|Copa menstrual de silicona, ecológica (financiamiento sororo)|0| PRODUCTOS ESPECIALES Y DE FIN DE AÑO||
PRODUCTOS DE GESTIÓN MENSTRUAL|Vaso esterilizador para copa menstrual|290| P|*Cuaderno artesanal 80 hojas rayado|100.00
PRODUCTOS DE GESTIÓN MENSTRUAL|*Toallita de tela Nocturna "Chúlin"|170|Chúlin P|*Cuaderno artesanal 80 hojas liso|100.00
PRODUCTOS DE GESTIÓN MENSTRUAL|*Toallita de tela para Colaless "Chúlin"|170|Chúlin P|*Cuaderno artesanal 200 hojas rayado|180.00
PRODUCTOS DE GESTIÓN MENSTRUAL|*Toallitas de tela para Bombacha "Chúlin"|200|Chúlin P|*Cuaderno artesanal 200 hojas liso|180.00
PRODUCTOS DE GESTIÓN MENSTRUAL|*Protector Diario de tela "Chúlin"|160|Chúlin P|*Agenda 2025 NUEVO!|420.00
PRODUCTOS DE GESTIÓN MENSTRUAL|*Pack 1: 2 protectores diarios + 2 toallitas para bombacha "Chúlin"|610|Chúlin P|Gorro del MPS - Ciudad Vieja NUEVO!|150.00
PRODUCTOS DE GESTIÓN MENSTRUAL|*Pack 2: 3 protectores diarios "Chúlin" |410|Chúlin P|*Papas con sal 230 gr NUEVO!|154.00
PRODUCTOS DE GESTIÓN MENSTRUAL|Ladysoft Clasicas 8un|20.3| P|*Papas sin sal 250 gr NUEVO!|154.00
PRODUCTOS DE GESTIÓN MENSTRUAL|Tampones Medianos Ladysoft 10un|84.7| P|Turrón Portezuelo Blando 70g NUEVO!|39.67
PRODUCTOS DE GESTIÓN MENSTRUAL|Tampones Grandes Ladysoft 10un|84.7| P|Turrón Portezuelo Bañado 70g NUEVO!|39.67
P |*Budín chocolate 300g NUEVO!|200.00
P|*Budín vainilla/cítrico 300g NUEVO!|200.00
P|*Budín marmolado 300g NUEVO!|200.00
P|Pan dulce artesanal con frutas y pasas 500gms NUEVO!|210.00
P|Libro para infancias "Encendiendo Memorias" NUEVO!|350.00
TRANSPORTE, BONOS Y FINANCIAMIENTO SORORO||
T|Por cada $ 500 de consumo, abonar $ 15 para transporte y gastos operativos, ej:$520 son $30|15.00
B|Campaña solidaria MPS - apoyo a ollas y merenderos|30.00
B|Financiamiento sororo para copa menstrual|20.00
B|Bono especial - Apoyo a la familia del compañero Alberto Colman|20.00
B|Bono especial - Apoyo al fletero Ramón|20.00
PRODUCTOS SUBSIDIADOS POR FINANCIAMIENTO SORORO||
P|*Toallita de tela Nocturna "Chúlin"|210.00
P|*Toallita de tela para Colaless "Chúlin"|168.00
P|*Toallitas de tela para Bombacha "Chúlin"|175.00
P|*Protector Diario de tela "Chúlin"|126.00
P|*Pack 1: 2 protectores diarios + 2 toallitas para bombacha "Chúlin"|560.00
P|*Pack 2: 3 protectores diarios "Chúlin"|364.00
P|Ladysoft Clasicas 8un|27.00
P|Tampones algodón orgánico - Talle mini- caja 18 un. |208.00
P|Tampones algodón orgánico -Talle medio- caja 18un. |208.00
P|Tampones algodón orgánico -Talle super-caja 15 un. |208.00
Can't render this file because it contains an unexpected character in line 19 and column 39.

135
resources/js/app.js vendored
View file

@ -3,10 +3,12 @@
* includes Vue and other libraries. It is a great starting point when * includes Vue and other libraries. It is a great starting point when
* building robust, powerful web applications using Vue and Laravel. * building robust, powerful web applications using Vue and Laravel.
*/ */
import axios from 'axios';
require('./bootstrap'); import Vue from 'vue';
window.Vue = require('vue'); window.Vue = require('vue');
window.Event = new Vue();
window.axios = axios;
window.bulmaToast = require('bulma-toast');
/** /**
* The following block of code may be used to automatically register your * The following block of code may be used to automatically register your
@ -15,18 +17,133 @@ window.Vue = require('vue');
* *
* Eg. ./components/ExampleComponent.vue -> <example-component></example-component> * Eg. ./components/ExampleComponent.vue -> <example-component></example-component>
*/ */
import './components';
// const files = require.context('./', true, /\.vue$/i) /**
// files.keys().map(key => Vue.component(key.split('/').pop().split('.')[0], files(key).default)) * Constants
*/
Vue.component('example-component', require('./components/ExampleComponent.vue').default); Vue.prototype.$rootMiga = {
nombre: "Categorías",
href: "/productos"
}
/**
* Global methods
*/
Vue.prototype.$settearProducto = function(cantidad, id) {
Event.$emit("sync-subpedido", this.cant, this.producto.id)
}
Vue.prototype.$toast = function(mensaje, duration = 2000) {
return window.bulmaToast.toast({
message: mensaje,
duration: duration,
type: 'is-danger',
position: 'bottom-center',
});
}
Vue.prototype.$limpiarFloat = function(unFloat) {
return parseFloat(unFloat.replace(/,/g, ''))
}
Vue.prototype.$limpiarInt = function(unInt) {
return parseInt(unInt.replace(/,/g, ''))
}
/** /**
* Next, we will create a fresh Vue application instance and attach it to * Next, we will create a fresh Vue application instance and attach it to
* 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({ const app = new Vue({
el: '#app', el: '#root',
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', () => {
axios.get('/subpedidos/obtener_sesion')
.then(response => {
if (response.data.subpedido.id) {
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");
});
} else {
axios.get('/admin/obtener_sesion')
.then(response => {
this.gdc = response.data.gdc
});
}
})
})
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");
});
});
Event.$on('aprobacion-subpedido', (subpedidoId, aprobado) => {
axios.post("/api/admin/subpedidos/" + subpedidoId + "/aprobacion", {
aprobacion: aprobado
}).then((response) => {
Event.$emit('sync-aprobacion', response.data.data);
this.$toast('Pedido ' + (aprobado ? 'aprobado' : 'desaprobado') + ' exitosamente')
})
})
Event.$emit('obtener-sesion')
},
}); });

25
resources/js/components.js vendored Normal file
View file

@ -0,0 +1,25 @@
import Vue from 'vue';
const requireComponent = require.context('./components', true, /\.vue$/);
// Registro automático de componentes:
// e.g. components/foo/bar/UnComponente.vue
// se registra como 'foo-bar-un-componente'
requireComponent.keys().forEach(fileName => {
// Get the component config
const componentConfig = requireComponent(fileName);
// Get the PascalCase name of the component
const componentName = fileName
.replace(/^\.\/(.*)\.\w+$/, '$1') // Remove "./" from the beginning and the file extension from the end
.replace(/\//g, '-') // Replace directories with hyphens
.replace(/([a-z])([A-Z])/g, '$1-$2') // Insert hyphen between camelCase words
.toLowerCase() // Convert to lowercase
// Globally register the component
Vue.component(
componentName,
// Look for the component options on `.default`, which will
// exist if the component was exported with `export default`,
// otherwise fall back to module's root.
componentConfig.default || componentConfig
);
});

View file

@ -1,23 +0,0 @@
<template>
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">Example Component</div>
<div class="card-body">
I'm an example component.
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
mounted() {
console.log('Component mounted.')
}
}
</script>

View file

@ -0,0 +1,83 @@
<template>
<div class="block ml-3 mr-3 is-max-widescreen is-max-desktop">
<comunes-tabs-secciones :tabs="tabs" :tabInicial="tabActiva"></comunes-tabs-secciones>
<div class="block" id="pedidos-seccion"
:class="seccionActiva === 'pedidos-seccion' ? 'is-active' : 'is-hidden'">
<div class="block pb-6" id="pedidos-tabla-y-dropdown" v-if="hayPedidos">
<admin-dropdown-descargar
:gdc_id="gdc.id">
</admin-dropdown-descargar>
<admin-tabla-pedidos
:gdc="this.gdc"
></admin-tabla-pedidos>
</div>
<p class="has-text-centered" v-else>
Todavía no hay ningún pedido para administrar.
</p>
</div>
<div class="block pb-6" id="caracteristicas-seccion"
:class="seccionActiva === 'caracteristicas-seccion' ? 'is-active' : 'is-hidden'">
<admin-caracteristicas-opcionales>
</admin-caracteristicas-opcionales>
</div>
</div>
</template>
<script>
import CaracteristicasOpcionales from "./CaracteristicasOpcionales.vue";
import TabsSecciones from "../comunes/TabsSecciones.vue";
import DropdownDescargar from "./DropdownDescargar.vue";
import TablaPedidos from "./TablaPedidos.vue";
import TablaBonos from "./TablaBonos.vue";
import axios from "axios";
export default {
components: {
CaracteristicasOpcionales,
TabsSecciones,
DropdownDescargar,
TablaPedidos,
TablaBonos,
},
data() {
return {
gdc: undefined,
tabs: [{ id: "pedidos", nombre: "Pedidos" },
{ id: "caracteristicas", nombre: "Caracteristicas opcionales" }],
tabActiva: "pedidos",
seccionActiva: "pedidos-seccion",
}
},
computed: {
hayPedidos: function() {
return this.gdc && this.gdc.pedidos.length !== 0
},
hayAprobados: function() {
return this.gdc && this.gdc.pedidos.filter(p => p.aprobado).length > 0
}
},
methods: {
setSeccionActiva(tabId) {
this.tabActiva = tabId;
this.seccionActiva = tabId + "-seccion";
},
actualizar() {
axios.get('/api/grupos-de-compra/' + this.$root.gdc)
.then(response => {
this.gdc = response.data.data;
console.log(this.gdc);
})
}
},
async mounted() {
Event.$on('sync-aprobacion', (_) => {
this.actualizar();
});
await new Promise(r => setTimeout(r, 1000));
this.actualizar();
},
}
</script>
<style>
</style>

View file

@ -0,0 +1,12 @@
<template>
<div class="buttons is-right">
<a class="button is-danger is-light is-small" href="/admin">
<span class="icon">
<i class="fa fa-solid fa-user-check"></i>
</span>
<span>
Admin
</span>
</a>
</div>
</template>

View file

@ -0,0 +1,42 @@
<script>
import FilaCaracteristica from "./FilaCaracteristica.vue";
export default {
components: { FilaCaracteristica },
data() {
return {
caracteristicas: [
{
id: "devoluciones",
nombre: "Devoluciones",
habilitada: false
},
]
}
},
}
</script>
<template>
<div class="block">
<table class="table is-fullwidth is-striped is-bordered">
<thead>
<tr>
<th> Característica </th>
<th> Habilitada </th>
</tr>
</thead>
<tbody>
<admin-fila-caracteristica
v-for="(c,i) in caracteristicas"
:key="i"
:caracteristica="c">
</admin-fila-caracteristica>
</tbody>
</table>
</div>
</template>
<style scoped>
</style>

View file

@ -0,0 +1,56 @@
<template>
<div class="buttons is-right">
<div class="dropdown" :class="{'is-active': dropdownActivo}" @mouseleave="dropdownActivo = false">
<div class="dropdown-trigger">
<button class="button" aria-haspopup="true" aria-controls="dropdown-menu" :disabled="!hayAprobados" @click="dropdownActivo = !dropdownActivo">
<span class="icon is-small">
<i class="fas fa-download"></i>
</span>
<span>Descargar pedido</span>
<span class="icon is-small">
<i class="fas fa-angle-down" aria-hidden="true"></i>
</span>
</button>
</div>
<div class="dropdown-menu" id="dropdown-menu" role="menu">
<div class="dropdown-content">
<a :href="'/admin/exportar-pedido-a-csv/' + gdc_id" class="dropdown-item has-background-primary">
Planilla para central (CSV)
</a>
<a :href="'/admin/exportar-planillas-a-pdf/' + gdc_id" class="dropdown-item">
Planillas para armado (PDF)
</a>
<a :href="'/admin/exportar-pedido-con-nucleos-a-csv/' + gdc_id" class="dropdown-item">
Planilla completa de la canasta (CSV)
</a>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
gdc_id: {
type: Number,
required: true
},
},
data() {
return {
dropdownActivo: false
}
},
computed: {
hayAprobados: function() {
return this.$parent.hayAprobados;
}
},
}
</script>
<style>
</style>

View file

@ -0,0 +1,69 @@
<script>
import axios from "axios";
export default {
props: {
caracteristica: Object
},
data() {
return {
gdc: undefined
}
},
watch: {
'$root.gdc' : {
handler(newValue) {
if (newValue) {
this.gdc = newValue;
this.obtenerValor();
}
}
},
},
methods: {
toggleActivacion() {
const id = this.caracteristica.id;
axios.post(`/api/grupos-de-compra/${this.gdc}/${id}`)
.then(response => {
this.caracteristica.habilitada = response.data[id];
this.$root[id] = response.data[id];
});
},
obtenerValor() {
const id = this.caracteristica.id;
axios.get(`/api/grupos-de-compra/${this.gdc}/${id}`)
.then(response => {
this.caracteristica.habilitada = response.data[id];
this.$root[id] = response.data[id];
});
},
},
mounted() {
if (this.$root.gdc) {
this.gdc = this.$root.gdc;
this.obtenerValor();
}
}
}
</script>
<template>
<tr>
<td>{{ caracteristica.nombre }}</td>
<td>
<div class="field">
<input type="checkbox" class="switch is-rounded is-success"
:id="'switch-'+caracteristica.id"
:checked="caracteristica.habilitada"
@change="toggleActivacion(caracteristica)">
<label :for="'switch-'+caracteristica.id">
<span class="is-hidden-mobile">{{ caracteristica.habilitada ? 'Habilitada' : 'Deshabilitada' }}</span>
</label>
</div>
</td>
</tr>
</template>
<style scoped>
</style>

View file

@ -0,0 +1,36 @@
<template>
<tr>
<td>{{ pedido.nombre }}</td>
<td v-if="$root.devoluciones" class="has-text-right" >{{ pedido.total_sin_devoluciones }}</td>
<td v-if="$root.devoluciones" class="has-text-right" ><abbr :title="pedido.devoluciones_notas">-{{ pedido.devoluciones_total }}</abbr></td>
<td class="has-text-right" >{{ $root.devoluciones ? pedido.total : pedido.total_sin_devoluciones }}</td>
<td>
<admin-switch-aprobacion
:pedido="pedido">
</admin-switch-aprobacion>
</td>
</tr>
</template>
<script>
import SwitchAprobacion from "./SwitchAprobacion.vue";
export default {
components: {
SwitchAprobacion
},
props: {
pedido: Object
},
mounted() {
Event.$on('sync-aprobacion', (unPedido) => {
if (this.pedido.id === unPedido.id) {
this.pedido = unPedido
}
})
}
}
</script>
<style scoped>
</style>

View file

@ -0,0 +1,56 @@
<template>
<div v-show="visible" class="block">
<div class="field">
<label class="label has-text-white">Contraseña de administración del barrio</label>
<div class="field has-addons">
<div class="control">
<input required class="input" :type="this.passwordType" name="password" placeholder="Contraseña de admin del barrio">
</div>
<div class="control">
<a class="button is-warning" @click="togglePassword">
{{ (passwordVisible ? 'Ocultar' : 'Mostrar') + ' contraseña'}}
</a>
</div>
</div>
<p class="help has-text-white">Si no la sabés, consultá a la comisión informática.</p>
</div>
<div class="field">
<div class="control">
<input type="submit" class="button is-warning" value="Ingresar"/>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
visible: false,
gdc: null,
passwordVisible: false,
passwordType: "password",
}
},
mounted() {
Event.$on('gdc-seleccionado', (gdc) => {
this.gdc = gdc;
this.visible = true;
});
},
methods: {
togglePassword() {
if (this.passwordVisible) this.passwordType = "password";
else this.passwordType = "text"
this.passwordVisible = !this.passwordVisible
}
}
}
</script>
<style>
.help {
font-size: 1rem;
}
</style>

View file

@ -0,0 +1,46 @@
<template>
<div class="field">
<input type="checkbox" name="switchRoundedSuccess" class="switch is-rounded is-success"
:id="'switch'+this.pedido.id"
:checked="pedido.aprobado"
@change="toggleAprobacion">
<label :for="'switch'+this.pedido.id">
<span class="is-hidden-mobile">{{ mensaje }}</span>
</label>
</div>
</template>
<script>
export default {
props: {
pedido: Object
},
data() {
return {
aprobado: this.pedido.aprobado
}
},
computed: {
mensaje: function () {
return this.aprobado ? "Pagado" : "No pagado"
}
},
methods: {
toggleAprobacion() {
Event.$emit('aprobacion-subpedido', this.pedido.id, !this.aprobado);
this.aprobado = !this.aprobado
}
},
mounted() {
Event.$on('sync-aprobacion', (unPedido) => {
if (this.pedido.id === unPedido.id) {
this.pedido = unPedido
}
})
}
}
</script>
<style scoped>
</style>

View file

@ -0,0 +1,97 @@
<template>
<div class="block">
<div class="block" v-show="!hayBonos">
<p class="has-text-centered">
Todavía no hay bonos pedidos.
</p>
</div>
<div class="block" v-show="hayBonos">
<table class="table is-bordered is-striped is-hoverable is-fullwidth">
<thead>
<tr>
<th><abbr title="Núcleo">Núcleo</abbr></th>
<td v-for="(bono,i) in bonos" :key="i" class="is-1">
{{ bono.nombre }}
</td>
<th><abbr title="Total a Pagar">Total $</abbr></th>
</tr>
</thead>
<tbody>
<tr v-for="(bp, i) in bonosPorPedido" :key="i">
<td> {{ bp.nucleo }} </td>
<td v-for="(bono,j) in bp.bonos" :key="j" class="has-text-right">
{{ bono.cantidad }}
</td>
<td class="has-text-right"> {{ bp.total }} </td>
</tr>
</tbody>
<tfoot>
<tr>
<th></th>
<th :colspan="bonos.length">Total bonos</th>
<th class="has-text-right">$ {{ totalBonos }}</th>
</tr>
</tfoot>
</table>
</div>
</div>
</template>
<script>
export default {
props: {
pedidos: {
type: Array,
required: true
}
},
data() {
return {
bonos: []
}
},
computed: {
pedidosAprobados: function() {
return this.pedidos.filter(p => p.aprobado)
},
hayBonos: function() {
return this.pedidosAprobados.filter(p => p.subtotal_bonos != 0).length !== 0
},
bonosPorPedido: function() {
let bonosPorPedido = this.pedidosAprobados.map(p => p = {"nucleo":p.nombre, "bonos":p.productos.filter(x => x.bono), "total":p.subtotal_bonos});
bonosPorPedido.forEach(bp => {
bp.bonos = bp.bonos.map(b => b = {"bono":b.nombre, "cantidad":b.pivot.cantidad, "total":b.pivot.total, "id":b.id})
})
return bonosPorPedido.map(bp => this.completarBonos(bp));
},
totalBonos: function() {
let total = 0
this.bonosPorPedido.map(bp => total += parseInt(bp.total))
return total
},
},
methods: {
completarBonos(bonosPedido) {
this.bonos.map(b => {
if (!bonosPedido.bonos.map(x => x.id).includes(b.id))
bonosPedido.bonos.push({"bono":b.nombre, "cantidad":0, "total":0, "id":b.id})
})
bonosPedido.bonos = bonosPedido.bonos.sort((b1,b2) => b1.id - b2.id)
return bonosPedido
}
},
beforeMount() {
axios.get("../api/productos", {
params: {
categoria:'TRANSPORTE, BONOS Y FINANCIAMIENTO SORORO',
}
}).then(response => {
this.bonos = response.data.data;
});
},
}
</script>
<style>
</style>

View file

@ -0,0 +1,69 @@
<template>
<div>
<table class="table is-fullwidth is-striped is-bordered">
<thead>
<tr>
<th>Núcleo</th>
<th v-if="$root.devoluciones"><abbr title="Total sin tomar en cuenta las devoluciones">Total parcial $</abbr></th>
<th v-if="$root.devoluciones"><abbr title="Devoluciones correspondientes al núcleo">Devoluciones $</abbr></th>
<th><abbr title="Total a Pagar por el núleo">{{ $root.devoluciones ? 'Total real' : 'Total' }} $</abbr></th>
<th class="is-1"><abbr title="Pagado">Pagado</abbr></th>
</tr>
</thead>
<tbody>
<admin-fila-pedido
v-for="pedido in gdc.pedidos"
:pedido="pedido" :key="pedido.id">
</admin-fila-pedido>
</tbody>
</table>
<table class="table is-striped is-bordered">
<tr>
<th colspan="2" class="has-background-black has-text-white has-text-centered">TOTALES</th>
</tr>
<tr>
<th>Total a recaudar:</th>
<td class="has-text-right">$ {{ gdc.total_a_recaudar }}</td>
</tr>
<tr>
<th>Total bonos barriales:</th>
<td class="has-text-right">$ {{ gdc.total_barrial }}</td>
</tr>
<tr v-if="$root.devoluciones">
<th>Total devoluciones:</th>
<td class="has-text-right">- $ {{ gdc.total_devoluciones }}</td>
</tr>
<tr>
<th>Cantidad bonos de transporte:</th>
<td class="has-text-right">{{ gdc.cantidad_transporte }}</td>
</tr>
<tr>
<th>Total bonos de transporte:</th>
<td class="has-text-right">$ {{ gdc.total_transporte }}</td>
</tr>
<tr>
<th>Total a depositar:</th>
<td class="has-text-right">$ {{ gdc.total_a_transferir }}</td>
</tr>
</table>
</div>
</template>
<script>
import FilaPedido from "./FilaPedido.vue";
export default {
components: {
FilaPedido
},
props: {
gdc: {
type: Object,
required: true
}
}
}
</script>
<style>
</style>

View file

@ -0,0 +1,75 @@
<template>
<div class="block ml-3 mr-3 is-max-widescreen is-max-desktop">
<comunes-tabs-secciones :tabs="tabs" :tabInicial="tabActiva"></comunes-tabs-secciones>
<div class="block pb-6" id="pedidos-compras-seccion"
:class="seccionActiva === 'pedidos-compras-seccion' ? 'is-active' : 'is-hidden'">
<div class="block" id="pedidos-compras-tabla-y-dropdown">
<compras-dropdown-descargar>
</compras-dropdown-descargar>
</div>
</div>
<div class="block pb-6" id="canasta-compras-seccion"
:class="seccionActiva === 'canasta-compras-seccion' ? 'is-active' : 'is-hidden'">
<div class="block" id="canasta-compras-seccion">
<article class="message is-warning">
<div class="message-header">
<p>Formato de la canasta</p>
</div>
<div class="message-body">
<div class="content">
La planilla de la canasta tiene que tener el siguiente formato para que la aplicación la lea correctamente:
<ul>
<li> Los precios deben usar punto y no coma decimal </li>
<li> El nombre de la columna de precios debe ser "Precio" </li>
<li> Las celdas deben separarse con '|' </li>
<li> No puede haber "enters" en ninguna celda </li>
<li> Todos los bonos deben tener tipo 'B' para evitar que paguen transporte </li>
<li> El bono de transporte debe tener tipo 'T' </li>
</ul>
<a class="has-text-info" href="/compras/canasta/ejemplo">Planilla de ejemplo.</a>
<article class="message is-danger mt-2">
<div class="message-body">
<div class="content">
Cuidado! Cargar una nueva canasta elimina todos los pedidos de la aplicación.
</div>
</div>
</article>
</div>
</div>
</article>
<div class="buttons is-right">
<compras-canasta-input></compras-canasta-input>
</div>
</div>
</div>
</div>
</template>
<script>
import TabsSecciones from "../comunes/TabsSecciones.vue";
import DropdownDescargar from "./DropdownDescargar.vue";
import CanastaInput from "./CanastaInput.vue";
export default {
components: {
TabsSecciones,
DropdownDescargar,
CanastaInput,
},
data() {
return {
tabs: [{ id: "pedidos-compras", nombre: "Pedidos" },
{ id: "canasta-compras", nombre: "Canasta" }],
tabActiva: "pedidos-compras",
seccionActiva: "pedidos-compras-seccion",
archivo: undefined,
}
},
methods: {
setSeccionActiva(tabId) {
this.tabActiva = tabId;
this.seccionActiva = tabId + "-seccion";
},
}
}
</script>

View file

@ -0,0 +1,69 @@
<template>
<div class="block">
<div class="file has-name is-right">
<label class="file-label">
<input
class="file-input"
type="file"
name="canasta"
@change="archivoSubido"
/>
<span class="file-cta">
<span class="file-icon">
<i class="fas fa-cloud-upload-alt"></i>
</span>
<span class="file-label">Subir canasta</span>
</span>
<span class="file-name" v-if="archivo">
{{ 'Cargando ' + archivo.nombre }}
</span>
</label>
</div>
</div>
</template>
<script>
import axios from "axios";
export default {
name: "CanastaInput",
data() {
return {
archivo: null,
cargando: false,
};
},
methods: {
async archivoSubido(event) {
const archivo = event.target.files[0];
if (archivo && archivo.type === "text/csv") {
this.archivo = {data: archivo, nombre: archivo.name};
const formData = new FormData();
formData.append("data", this.archivo.data);
try {
this.cargando = true;
const response = await axios.post("/compras/canasta", formData, {
headers: {
"Content-Type": "multipart/form-data",
},
});
this.$root.$toast(response.data.message || "Canasta cargada exitosamente");
} catch (error) {
this.$root.$toast(error.response?.data?.message || "Hubo errores.");
} finally {
this.cargando = false;
this.archivo = null;
}
} else {
this.$root.$toast("La canasta debe ser .CSV")
this.archivo = null;
}
},
},
};
</script>
<style scoped>
</style>

View file

@ -0,0 +1,44 @@
<template>
<div class="buttons is-right">
<div class="dropdown" :class="{'is-active': dropdownActivo}" @mouseleave="dropdownActivo = false">
<div class="dropdown-trigger">
<button class="button" aria-haspopup="true" aria-controls="dropdown-menu" @click="dropdownActivo = !dropdownActivo">
<span class="icon is-small">
<i class="fas fa-download"></i>
</span>
<span>Descargar planillas</span>
<span class="icon is-small">
<i class="fas fa-angle-down" aria-hidden="true"></i>
</span>
</button>
</div>
<div class="dropdown-menu" id="dropdown-menu" role="menu">
<div class="dropdown-content">
<a href="/compras/pedidos/descargar" class="dropdown-item">
Pedidos por barrio
</a>
<a href="/compras/pedidos/notas" class="dropdown-item">
Notas por barrio
</a>
<a href="/compras/pedidos/transporte" class="dropdown-item">
Transporte por barrio
</a>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
dropdownActivo: false
}
},
}
</script>
<style>
</style>

View file

@ -0,0 +1,52 @@
<template>
<div class="block">
<div class="field">
<label class="label">Usuario</label>
<div class="field">
<div class="control">
<input required class="input" type="text" name="name" placeholder="Usuario">
</div>
</div>
</div>
<div class="field">
<label class="label">Contraseña</label>
<div class="field has-addons">
<div class="control">
<input required class="input" :type="this.passwordType" name="password" placeholder="Contraseña">
</div>
<div class="control">
<a class="button is-dark" @click="togglePassword">
{{ (passwordVisible ? 'Ocultar' : 'Mostrar') + ' contraseña'}}
</a>
</div>
</div>
</div>
<div class="field">
<div class="control">
<input type="submit" class="button is-dark" value="Ingresar"/>
</div>
</div>
</div>
</template>
<script>
export default {
name: "LoginAdmin",
data() {
return {
passwordVisible: false,
passwordType: "password",
}
},
methods: {
togglePassword() {
if (this.passwordVisible) this.passwordType = "password";
else this.passwordType = "text"
this.passwordVisible = !this.passwordVisible
}
}
}
</script>
<style>
</style>

View file

@ -0,0 +1,51 @@
<template>
<div v-show="visible" class="block">
<div class="field">
<label class="label" :class="isAdmin ? 'has-text-white' : ''">Seleccioná tu barrio o grupo de compra</label>
<div class="control">
<div class="select">
<select @change="onGDCSelected" v-model="gdc" name="name">
<option :disabled="isDefaultDisabled==1" value=null>Seleccionar</option>
<option v-for="(gdc, index) in gdcs" :key="index" v-text="gdc.nombre + (isAdmin ? '_admin' : '')"
:name="gdc.nombre + (isAdmin ? '_admin' : '')">
</option>
</select>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
visible: false,
region: null,
gdcs: [],
isDefaultDisabled: 0,
gdc: null,
isAdmin: this.admin == null ? false : this.admin
}
},
mounted() {
Event.$on('region-seleccionada', (region)=> {
this.region = region;
this.fillGDC(region);
this.visible = true;
});
},
methods : {
fillGDC(region) {
axios.get("/api/grupos-de-compra").then(response => {
this.gdcs = response.data[this.region];
});
},
onGDCSelected() {
this.isDefaultDisabled = 1;
Event.$emit("gdc-seleccionado",this.gdc);
}
},
props: {'admin': Boolean}
}
</script>

View file

@ -0,0 +1,91 @@
<template>
<nav id="nav-bar" class="navbar is-danger is-fixed-top" role="navigation" aria-label="main navigation">
<div class="navbar-brand">
<a class="navbar-item" href="https://mps.org.uy">
<img src="/assets/logoMPS.png" height="28">
</a>
<!-- Styles nombre del barrio-->
<p class="navbar-item hide-below-1024">
<slot name="gdc"></slot>
</p>
<p class="navbar-item">
<slot name="subpedido"></slot>
</p>
<pedidos-chismosa-dropdown v-if="this.$root.pedido != null" class="hide-above-1023" id="mobile"></pedidos-chismosa-dropdown>
<a role="button" class="navbar-burger" :class="{'is-active':burgerActiva}" aria-label="menu" aria-expanded="false" data-target="nav-bar" @click="toggleBurger">
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
</div>
<div class="navbar-menu" :class="{'is-active':burgerActiva}">
<div class="navbar-end">
<div v-if="this.$root.pedido != null" class="navbar-item field has-addons mt-2 mr-3">
<a class="button is-small has-text-dark-grey" @click.capture="buscar">
<span class="icon">
<i class="fas fa-search"></i>
</span>
</a>
<input class="input is-small" type="text" placeholder="Harina" v-model="searchString" @keyup.enter="buscar" >
</div>
<pedidos-chismosa-dropdown v-if="this.$root.pedido != null" class="hide-below-1024" id="wide"></pedidos-chismosa-dropdown>
<div class="block navbar-item">
<a onclick="event.preventDefault(); document.getElementById('logout-form').submit();" class="text-a">
Cerrar sesión
</a>
<slot name="logout-form"></slot>
</div>
</div>
</div>
</nav>
</template>
<script>
import ChismosaDropdown from '../pedidos/ChismosaDropdown.vue';
export default {
components: { ChismosaDropdown },
data() {
return {
burgerActiva: false,
searchString: "",
}
},
methods: {
toggleBurger() {
this.burgerActiva = !this.burgerActiva
},
buscar() {
if (this.burgerActiva) this.toggleBurger()
Event.$emit("migas-setear-como-inicio", this.$rootMiga)
Event.$emit("filtrar-productos",'nombre',this.searchString)
}
},
};
</script>
<style>
p.navbar-item:empty {
display: none;
}
#nav-bar {
z-index: 10;
}
.text-a {
color: inherit;
}
@media (max-width: 1023px) {
.hide-below-1024 {
display: none !important;
}
}
@media (min-width: 1024px) {
.hide-above-1023 {
display: none !important;
}
}
</style>

View file

@ -0,0 +1,38 @@
<template>
<div class="block">
<div class="field">
<label class="label" :class="whiteText ? 'has-text-white' : ''">Seleccioná tu región</label>
<div class="control">
<div class="select">
<select @change="onRegionSelected" v-model="region">
<option :disabled="isDefaultDisabled===1" value=null>Seleccionar</option>
<option v-for="(region, index) in regiones" :key="index" v-text="region" :name="region"></option>
</select>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
regiones: [],
isDefaultDisabled: 0,
region: null,
whiteText: this.admin == null ? false : this.admin
}
},
mounted() {
axios.get("/api/regiones").then(response => this.regiones = response.data);
},
methods: {
onRegionSelected() {
this.isDefaultDisabled = 1;
Event.$emit("region-seleccionada",this.region);
}
},
props: {'admin': Boolean}
}
</script>

View file

@ -0,0 +1,55 @@
<template>
<div class="block">
<div class="tabs is-boxed" id="tabs">
<ul class="has-bottom-line">
<li v-for="(tab, index) in tabs" class="is-size-6"
:key="index"
:id="tab.id + '-tab'"
:class="{'is-active': tab.id === tabActiva}">
<a @click="setTabActiva(tab.id)">
<span>
{{ tab.nombre }}
</span>
</a>
</li>
</ul>
</div>
</div>
</template>
<script>
export default {
props: {
tabs: Array,
tabInicial: String,
},
data() {
return {
tabActiva: this.tabInicial,
}
},
methods: {
setTabActiva(tabId) {
this.$parent.setSeccionActiva(tabId);
this.tabActiva = tabId
}
}
}
</script>
<style lang="scss" scoped>
@import '../../../../node_modules/bulma';
hr {
border: none;
height: 1px;
}
.has-bottom-line {
border-bottom-color: #dbdbdb !important;
border-bottom-style: solid !important;
border-bottom-width: 1px !important;
}
.tabs li.is-active a {
border-bottom-color: #e3342f;
color: #e3342f;
}
</style>

View file

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

View file

@ -0,0 +1,32 @@
<template>
<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>
</style>

View file

@ -0,0 +1,41 @@
<template>
<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%" >
<div class="card-content">
<div class="media">
<div class="media-content" style="overflow:hidden">
<p class="title is-6" v-text="categoria"></p>
</div>
</div>
</div>
</div><!-- END CARD -->
</div><!-- END BLOCK COLUMN -->
</div><!-- END COLUMNS -->
</div><!-- END CONTAINER -->
</template>
<script>
export default {
data() {
return {
categorias: null,
visible: true
}
},
mounted() {
axios.get("/api/categorias").then(response => {
this.categorias = response.data;
});
Event.$emit("migas-setear-como-inicio", this.$rootMiga);
Event.$on("filtrar-productos", (_) => this.visible = false)
},
methods: {
seleccionarCategoria(categoria) {
this.visible = false;
Event.$emit("filtrar-productos",'categoria',categoria);
}
}
}
</script>

View file

@ -0,0 +1,102 @@
<template>
<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>
<pedidos-producto-row v-for="producto in productos" :producto="producto" :key="producto.id"></pedidos-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 {
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.$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>
<style>
.tabla-chismosa {
width: 100%;
}
.fixed-right {
position: fixed;
overflow-y: auto;
max-height: 81vh;
margin-right: 20px;
}
</style>

View file

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

View file

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

View file

@ -0,0 +1,55 @@
<template>
<div v-show="visible" class="block">
<div class="field">
<label class="label">Contraseña del barrio</label>
<div class="field has-addons">
<div class="control">
<input required class="input" :type="this.passwordType" name="password" placeholder="Contraseña del barrio">
</div>
<div class="control">
<a class="button is-info" @click="togglePassword">
{{ (passwordVisible ? 'Ocultar' : 'Mostrar') + ' contraseña'}}
</a>
</div>
</div>
<p class="help">Si no la sabés, consultá a tus compañerxs.</p>
</div>
<div class="field">
<div class="control">
<input type="submit" class="button is-success" value="Ingresar"/>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
visible: false,
gdc: this.$root.gdc,
passwordVisible: false,
passwordType: "password",
}
},
mounted() {
Event.$on('gdc-seleccionado', (gdc) => {
this.$root.gdc = gdc;
this.visible = true;
});
},
methods: {
togglePassword() {
if (this.passwordVisible) this.passwordType = "password";
else this.passwordType = "text"
this.passwordVisible = !this.passwordVisible
}
}
}
</script>
<style>
.help {
font-size: 1rem;
}
</style>

View file

@ -0,0 +1,54 @@
<template>
<nav class="breadcrumb is-centered has-background-danger-light is-fixed-top" aria-label="breadcrumbs" v-show="visible">
<ul class="mt-4">
<li v-for="(miga, i) in migas" :key="i" :class="{'is-active': i == migaActiva}">
<a :href="miga.href" v-text="miga.nombre"
:class="{'has-text-danger': i != migaActiva}"></a>
</li>
</ul>
</nav>
</template>
<script>
export default {
data() {
return {
migas: []
}
},
computed: {
visible: function() {
return this.migas.length > 0
},
migaActiva: function() {
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 = [];
});
Event.$on('migas-pop', () => {
this.migas.pop();
});
}
}
</script>
<style>
nav.breadcrumb.is-fixed-top {
position: fixed;
left: 0;
right: 0;
top: 3.25rem;
height: 2.75rem;
z-index: 5;
}
</style>

View file

@ -0,0 +1,140 @@
<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="disableConfirm()" 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" v-bind:class="{'has-icons-right': notas_warning_visible}" class="control is-full-width has-icons-left">
<span class="icon is-small is-left">
<i class="fas fa-sticky-note"></i>
</span>
<input v-model="notas" 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">
<i class="fas fa-exclamation-triangle"></i>
</span>
<article v-if="notas_warning_visible" class="message is-danger is-small">
<div class="message-body">
No se puede dejar este campo vac&iacute;o
</div>
</article>
</div>
</div>
</template>
<script>
export default {
props: {
producto: Object
},
data() {
return {
cantidad: this.cantidadEnChismosa(),
notas: this.notasEnChismosa(),
notas_warning_visible: false,
}
},
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() {
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>
<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;
}
.is-danger {
background-color: #fca697;
}
.is-danger::placeholder {
color: #fff;
opacity: 1; /* Firefox */
}
</style>

View file

@ -0,0 +1,113 @@
<script>
export default {
name: "ProductoCard",
props: {
producto: Object
},
data() {
return {
cantidad: this.producto.cantidad,
enChismosa: this.producto.cantidad,
notas: this.producto.notas,
}
},
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>
<template>
<div class="block column is-one-quarter-desktop is-full-mobile is-half-tablet min-width-from-desktop">
<div class="box" style="height:100%">
<div class="columns">
<div class="column">
<p class="title is-6">
{{ producto.nombre }}
</p>
<p class="subtitle is-7" v-text="producto.proveedor"></p>
<span class="subtitle is-7 hidden-from-tablet" v-if="enChismosa !== 0">{{ enChismosa }} en chismosa</span>
</div>
<div class="column is-one-quarter has-text-right">
<p class="has-text-weight-bold has-text-primary">
<span class="is-left-mobile">
<img v-show="producto.economia_solidaria" height="30px" width="30px" src="/assets/solidaria.png" alt="proveedor de economía solidaria">
<img v-show="producto.nacional" height="30px" width="30px" src="/assets/uruguay.png" alt="proveedor nacional"/>
</span>
$<span v-text="producto.precio"></span>
</p>
</div>
</div>
<footer class="columns">
<div class="column is-three-quarters">
<pedidos-producto-cantidad :producto="producto"></pedidos-producto-cantidad>
</div>
<div class="column">
<p class="subtitle is-7 is-hidden-mobile" v-if="enChismosa > 0">{{ enChismosa }} en chismosa</p>
</div>
</footer>
</div><!-- END BOX -->
</div>
</template>
<style lang="scss" scoped>
@use "../../../../node_modules/bulma/sass/utilities/mixins";
@include mixins.until(mixins.$desktop) {
.hidden-until-desktop {
display: none;
}
}
@include mixins.from(mixins.$desktop) {
.min-width-from-desktop {
min-width: 25rem;
}
.hidden-from-desktop {
display: none;
}
}
@include mixins.from(mixins.$tablet) {
.hidden-from-tablet {
display: none;
}
}
@include mixins.mobile() {
.is-left-mobile {
float: left;
}
}
</style>

View file

@ -0,0 +1,16 @@
<template>
<tr>
<td>{{ this.producto.nombre }}</td>
<td class="has-text-right">
<pedidos-producto-cantidad :producto="producto"></pedidos-producto-cantidad>
</td>
<td class="has-text-right">{{ Math.ceil(this.producto.pivot.total) }}</td>
</tr>
</template>
<script>
export default {
props: {
producto: Object
},
}
</script>

View file

@ -0,0 +1,55 @@
<template>
<div v-show="visible" class="column">
<div class="columns is-multiline is-mobile">
<pedidos-producto-card v-for="(producto,i) in productos" :key="i" :producto="producto">
</pedidos-producto-card><!-- END BLOCK COLUMN -->
</div><!-- END COLUMNS -->
</div><!-- END CONTAINER -->
</template>
<script>
export default {
data() {
return {
productos: [],
visible: false,
paginar: 150,
valor: null,
filtro: null
}
},
computed: {
miga: function(){
return {
nombre: this.valor,
href: "#" + this.valor
}
}
},
mounted() {
Event.$on('filtrar-productos', (filtro,valor) => {
this.filtro = filtro
this.valor = valor
axios.get("/api/productos", {
params: this.params(filtro,valor)
}).then(response => {
this.productos = response.data.data;
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);
});
},
methods: {
params(filtro,valor) {
let params = { paginar: this.paginar }
params[filtro] = valor
return params
},
}
}
</script>

View file

@ -0,0 +1,91 @@
<template>
<div>
<label class="label">Escribí el nombre de tu familia o grupo de convivencia</label>
<div class="columns">
<div class="column is-two-thirds">
<div class="field">
<div class="control">
<input class="input" @input="onType" v-model="subpedido"/>
</div>
<p class="help">Debe ser claro para que tus compas del barrio te identifiquen.</p>
</div>
</div>
<div class="column is-one-third buttons">
<button class="button is-danger" v-show="!botonCrearDesabilitado" @click="submit">Crear nuevo pedido</button>
</div>
</div>
<div v-if="subpedidosExistentes.length" class="block">
<label class="label">Si ya comenzaste a hacer tu pedido este mes, elegilo en esta lista:</label>
<p class="help">Podés seguir escribiendo en el campo de arriba para refinar la búsqueda.</p>
<div class="columns is-mobile" v-for="(subpedidoExistente, index) in subpedidosExistentes" :class="{'has-background-grey-lighter': index % 2}" :key="index">
<div class="column is-half-mobile is-two-thirds-desktop is-two-thirds-tablet">
<p style="padding-top: calc(.5em - 1px); margin-bottom: .5rem" v-text="subpedidoExistente.nombre"></p>
</div>
<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>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
subpedido: null,
subpedidosExistentes: []
}
},
computed: {
nombresDeSubpedidos: function() {
return this.subpedidosExistentes.map(a => a.nombre.toLowerCase())
},
botonCrearDesabilitado : function() {
return !this.subpedido || this.nombresDeSubpedidos.includes(this.subpedido.toLowerCase())
}
},
props: ["gdcid"],
mounted() {
console.log("ready");
},
methods: {
onType() {
if (!this.subpedido){
this.subpedidosExistentes = [];
return;
}
axios.get("/api/subpedidos", {
params: {
nombre: this.subpedido,
grupo_de_compra: this.gdcid
}
}).then(response => {
this.subpedidosExistentes = response.data
});
},
submit() {
axios.post("/api/subpedidos", {
nombre: this.subpedido,
grupo_de_compra_id: this.gdcid
}).then(response => {
//se creo el subpedido
this.elegirSubpedido(response.data);
});
},
elegirSubpedido(subpedido){
//lo guardamos en sesion
this.guardarSubpedidoEnSesion(subpedido);
},
guardarSubpedidoEnSesion(subpedido) {
axios.post("/subpedidos/guardar_sesion", {
subpedido: subpedido,
grupo_de_compra_id: this.gdcid
}).then(_ => {
Event.$emit('obtener-sesion')
window.location.href = 'productos';
});
}
}
}
</script>

View file

@ -4,5 +4,56 @@
// Variables // Variables
@import 'variables'; @import 'variables';
// Bootstrap @import 'bulma';
@import '~bootstrap/scss/bootstrap'; @import '~bulma-switch';
main.has-top-padding {
padding-top: 4.5rem !important;
}
table.table td {
vertical-align: middle;
}
.has-text-centered {
text-align: center;
margin: 0 1em;
}
.is-fixed-top {
position: fixed;
z-index: 30;
}
#main {
height: 100%;
}
.container {
max-height: 100% !important;
}
/*
Author: Aseem Lalfakawma <alalfakawma.github.io>
This SCSS mixin will allow sizing of table columns in Bulma CSS Framework.
The Bulma framework does not support this yet, this small code snippet fixes this.
USAGE:
* Should be applied on TH element, it controls all the columns under it *
The class should be "is-#",
is-1 will give the first widthamount, is-2 will give the second.
Eg. The code below shows the widthAmounts as (1, 2.5, 3, 4 , 5, 6, 7)
When typing <th class="is-2">, the width will be 2.5em, as the second value in widthAmounts array is 2.5
*/
$widthAmounts: (15); // Just add the numbers here, you can use points too.
$widthUnit: "em"; // Add the unit here (rem|em|px|%)
@each $width in $widthAmounts {
$i: index($widthAmounts, $width);
@media only screen and (min-width: 768px) {
.table thead th.is-#{$i} {
width: #{$width}#{$widthUnit} !important;
}
}
}

View file

@ -0,0 +1,34 @@
<!DOCTYPE html>
<html class="has-background-danger" lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{ config('app.name', 'Pedidos del MPS') }}</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.3/css/bulma.min.css">
<link rel="stylesheet" href="{{ mix('css/app.css') }}">
</head>
<body>
<section class="section">
<div id="root" class="container">
<h1 class="title has-text-white">
Administración de Pedidos MPS
</h1>
<p class="subtitle has-text-white">
Bienvenidx a la administración de pedidos del <strong class="has-text-white">Mercado Popular de Subsistencia</strong>
</p>
@error('name')
<div class="notification is-warning">
Contraseña incorrecta, intentalo nuevamente.
</div>
@enderror
<comunes-region-select v-bind:admin="true"></comunes-region-select>
<form method="post" action="login">
@csrf
<comunes-barrio-select v-bind:admin="true"></comunes-barrio-select>
<admin-login></admin-login>
</form>
</div>
</section>
<script src="{{ mix('js/app.js') }}" defer></script>
</body>
</html>

View file

@ -0,0 +1,5 @@
@extends('layouts.app')
@section('content')
<admin-body></admin-body>
@endsection

View file

@ -0,0 +1,33 @@
<!DOCTYPE html>
<html class="has-background-warning" lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{ config('app.name', 'Pedidos del MPS') }}</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.3/css/bulma.min.css">
<link rel="stylesheet" href="{{ mix('css/app.css') }}">
<script src="https://kit.fontawesome.com/9235d1c676.js" crossorigin="anonymous"></script>
</head>
<body>
<section class="section">
<div id="root" class="container">
<h1 class="title">
Pedidos MPS
</h1>
<p class="subtitle">
Bienvenidx a la sección de compras de la aplicación del <strong>Mercado Popular de Subsistencia</strong>
</p>
@error('name')
<div class="notification is-danger">
Contraseña incorrecta, intentalo nuevamente.
</div>
@enderror
<form method="post" action="login">
@csrf
<compras-login></compras-login>
</form>
</div>
</section>
<script src="{{ mix('js/app.js') }}" defer></script>
</body>
</html>

View file

@ -3,33 +3,34 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{ config('app.name', 'Compras del MPS') }}</title> <title>{{ config('app.name', 'Pedidos del MPS') }}</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.3/css/bulma.min.css"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.3/css/bulma.min.css">
<link rel="stylesheet" href="{{ mix('css/app.css') }}">
<script src="https://kit.fontawesome.com/9235d1c676.js" crossorigin="anonymous"></script>
</head> </head>
<body> <body>
<section class="section"> <section class="section">
<div id="root" class="container"> <div id="root" class="container">
<admin-boton-login></admin-boton-login>
<h1 class="title"> <h1 class="title">
Compras MPS Pedidos MPS
</h1> </h1>
<p class="subtitle"> <p class="subtitle">
Bienvenidx a la aplicación de compras del <strong>Mercado Popular de Subsistencia</strong> Bienvenidx a la aplicación de pedidos del <strong>Mercado Popular de Subsistencia</strong>
</p> </p>
@error('name') @error('name')
<div class="notification is-danger"> <div class="notification is-danger">
Contraseña incorrecta, intentalo nuevamente. Contraseña incorrecta, intentalo nuevamente.
</div> </div>
@enderror @enderror
<region-select></region-select> <comunes-region-select></comunes-region-select>
<form method="post" action="login"> <form method="post" action="login">
@csrf @csrf
<barrio-select></barrio-select> <comunes-barrio-select></comunes-barrio-select>
<login></login> <pedidos-login></pedidos-login>
</form> </form>
</div> </div>
</section> </section>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script> <script src="{{ mix('js/app.js') }}" defer></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script src="{{ asset('js/login.js') }}" defer></script>
</body> </body>
</html> </html>

View file

@ -0,0 +1,5 @@
@extends('layouts.app')
@section('content')
<compras-body></compras-body>
@endsection

View file

@ -7,20 +7,19 @@
<!-- 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', 'Compras del MPS') : config('app.name', 'Compras del MPS')}}</title> <title>{{ session("subpedido_nombre") ? "Pedido de " . session("subpedido_nombre") . " - " . config('app.name', 'Pedidos del MPS') : config('app.name', 'Pedidos del MPS')}}</title>
<link rel="icon" type="image/x-icon" href="/assets/favicon.png">
<!-- Fonts --> <!-- Fonts -->
<script src="https://kit.fontawesome.com/9235d1c676.js" crossorigin="anonymous"></script>
<!-- Styles --> <link rel="stylesheet" href="{{ mix('css/app.css') }}">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.3/css/bulma.min.css">
<link rel="stylesheet" href="{{ asset('css/app.css') }}">
@yield('stylesheets') @yield('stylesheets')
</head> </head>
<body> <body class="has-navbar-fixed-top">
<div id="app"> <div id="root">
<nav-bar> <comunes-nav-bar>
<template slot="subpedido">{{ session('subpedido_nombre') ? 'Pedido de '. session('subpedido_nombre') : Auth::user()->name }}</template> <template slot="subpedido">{{ session('subpedido_nombre') ? 'Pedido de '. session('subpedido_nombre') : Auth::user()->name }}</template>
<template slot="gdc">{{ session('subpedido_nombre') ? Auth::user()->name : "" }}</template> <template slot="gdc">{{ session('subpedido_nombre') ? Auth::user()->name : "" }}</template>
<template slot="logout-form"> <template slot="logout-form">
@ -28,23 +27,16 @@
@csrf @csrf
</form> </form>
</template> </template>
</nav-bar> </comunes-nav-bar>
<nav-migas inline-template> <pedidos-nav-migas></pedidos-nav-migas>
<nav class="breadcrumb is-centered has-background-danger-light" aria-label="breadcrumbs" v-show="visible">
<ul>
<li v-for="(miga, i) in migas" v-bind:class="i==migas.length-1 ? 'is-active' : ''"><a :href="miga.href" v-text="miga.nombre"></a></li>
</ul>
</nav>
</nav-migas>
<main class="py-4"> <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>
<!-- Scripts --> <!-- Scripts -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script> <script src="{{ mix('js/app.js') }}" defer></script>
<script src="{{ asset('js/app.js') }}" defer></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
@yield('scripts') @yield('scripts')
</body> </body>
</html> </html>

View file

@ -0,0 +1,44 @@
<!doctype html>
<style>
tr:nth-child(even) {
background: #CCC
}
</style>
<h3>{{$subpedido->nombre}}</h3>
<table style="width: 100%">
<tr>
<th>
Producto
</th>
<th>
Cantidad
</th>
<th>
Control 1
</th>
<th>
Control 2
</th>
<th>
Control 3
</th>
</tr>
@foreach($subpedido->productos as $producto)
@if(!$producto->bono)
<tr>
<td>
{{ $producto->nombre }}
@if($producto->pivot->notas)
<br /><b>Talle/Color:</b> {{ $producto->pivot->notas }}
@endif
</td>
<td style="text-align: center">
{{ $producto->pivot->cantidad }}
</td>
</tr>
@endif
@endforeach
</table>

View file

@ -1,15 +1,6 @@
@extends('layouts.app') @extends('layouts.app')
@section('stylesheets')
<link rel="stylesheet" href="{{ asset('css/productos.css') }}">
@endsection
@section('content') @section('content')
<categorias-container></categorias-container> <pedidos-body></pedidos-body>
<productos-container></productos-container> <pedidos-devoluciones-modal></pedidos-devoluciones-modal>
<producto-container></producto-container>
@endsection
@section('scripts')
<script src="{{ asset('js/productos.js') }}"></script>
@endsection @endsection

View file

@ -4,38 +4,15 @@
<section class="section"> <section class="section">
<div id="root" class="container"> <div id="root" class="container">
<h1 class="title"> <h1 class="title">
Compras MPS Pedidos MPS
</h1> </h1>
<p class="subtitle"> <p class="subtitle">
Bienvenidx a la aplicación de compras del <strong>Mercado Popular de Subsistencia</strong> Bienvenidx a la aplicación de pedidos del <strong>Mercado Popular de Subsistencia</strong>
</p> </p>
<subpedido-select inline-template gdcid="{{Auth::user()->grupoDeCompra->id}}"> <pedidos-subpedido-select gdcid="{{Auth::user()->grupoDeCompra->id}}"></pedidos-subpedido-select>
<div class="block">
<div class="field">
<label class="label">Escribí el nombre de tu familia o grupo de convivencia</label>
<div class="control">
<input class="input" @input="onType" v-model="subpedido"></input>
</div>
<p class="help">Intentá que sea claro como para que tus compas del barrio te identifiquen.</p>
</div>
<div class="buttons">
<button class="button is-primary" @click="submit">Crear nuevo pedido</button>
</div>
<div class="table-container">
<table class="table is-hoverable">
<tbody>
<tr v-for="subpedidoExistente in subpedidosExistentes" >
<td><a v-text="subpedidoExistente.nombre" :href="subpedidoExistente.nombre"></a></td>
</tr>
</tbody>
</table>
</div>
</div>
</subpedido-select>
</div> </div>
</section> </section>
@endsection @endsection
@section('scripts') @section('scripts')
<script src="{{ asset('js/subpedidos-create.js') }}"></script>
@endsection @endsection

Some files were not shown because too many files have changed in this diff Show more