forked from nathalie/pedi2
Compare commits
670 commits
precio-tot
...
master
Author | SHA1 | Date | |
---|---|---|---|
![]() |
116875b769 | ||
78b9d682cc | |||
1115764d81 | |||
5be87b5c26 | |||
670bb39e75 | |||
1498b67200 | |||
a7096e7dc0 | |||
422be13c51 | |||
0e63e795e4 | |||
37cdbe5480 | |||
de635d1a82 | |||
9f0319fe48 | |||
8928fb2842 | |||
c514569acd | |||
0fc370e9d1 | |||
9332aa33c1 | |||
c11331695a | |||
688abf406d | |||
ceaddcabc3 | |||
f9a0ee5146 | |||
e879daa73e | |||
91225d7796 | |||
a3b6d686d3 | |||
612abc4378 | |||
ac559770c0 | |||
5c3d68a4e9 | |||
a497ae134e | |||
f16b18c8b1 | |||
![]() |
665ab517fb | ||
![]() |
eee23082db | ||
![]() |
eb1b5bbc2e | ||
![]() |
46675f9acf | ||
c58824ff52 | |||
fcb2d2c5bc | |||
686fcf3bd5 | |||
c064e80116 | |||
f26234c3bf | |||
0173d7bd36 | |||
a16487cc3f | |||
![]() |
d9747c9280 | ||
dbaff75734 | |||
a96adedb82 | |||
![]() |
8d50a29355 | ||
5b8f9cb694 | |||
214292bc8f | |||
![]() |
b752f9e8c5 | ||
![]() |
6787dde711 | ||
![]() |
02aba80fc9 | ||
![]() |
afddeadeac | ||
17148d73f8 | |||
a38bceab82 | |||
ff96c104a2 | |||
854278bc99 | |||
197b087097 | |||
5c51653037 | |||
a5be67df2e | |||
d8c8865d13 | |||
9a310484d6 | |||
80b5dc60ac | |||
517e5203c9 | |||
dbdb97a78e | |||
79bdb04ce2 | |||
3503be8e56 | |||
faa947e6a7 | |||
fdd3232345 | |||
b72fc57b8d | |||
3cb27c5c30 | |||
b4458862f4 | |||
7a4aa6d7a0 | |||
0637b7a208 | |||
af8879eadd | |||
9e93b914ac | |||
![]() |
687768d860 | ||
1b920093c4 | |||
210c91f3a8 | |||
2ee7fca584 | |||
258bccf59b | |||
ca42526a62 | |||
f484bfff79 | |||
9384d09ff6 | |||
f460cdd6ce | |||
4b4a284914 | |||
a641247748 | |||
82a518fa1d | |||
deaa65d857 | |||
4af9e53a50 | |||
8d64d85b8b | |||
2c720faca7 | |||
85fa9f1e9b | |||
c8d1969352 | |||
1eb77be1d0 | |||
3949cf3400 | |||
973d099bf1 | |||
802d4d0c0b | |||
134ed0cd22 | |||
2bfcf59f3e | |||
4e197204a9 | |||
2075bcab0f | |||
c0d8392f6e | |||
ef9a296f5c | |||
bc55b4c34f | |||
e779111856 | |||
d6990f8c88 | |||
8eb385c67e | |||
2970982c77 | |||
9e63c83126 | |||
439f69a30c | |||
d0ce8e8e23 | |||
3b858f5b2b | |||
0512ea9ab2 | |||
8488d9d6c5 | |||
354045c5df | |||
ae1f8673e7 | |||
4f74bf38f9 | |||
8a2539f207 | |||
04673b1754 | |||
88af33d998 | |||
23af6ccd61 | |||
777f442118 | |||
7cae00e613 | |||
5a61ca46c5 | |||
e379825fd9 | |||
6b2da42160 | |||
48cf57a6d8 | |||
aa545ff82a | |||
b29d63ed4d | |||
1e91f443a7 | |||
6782b7f675 | |||
85b3f1dd0f | |||
a006fc15fa | |||
37fd0fb4d3 | |||
d794dbd2b0 | |||
7140796ccd | |||
5b9908e0b5 | |||
f837b7f066 | |||
0dba210a6a | |||
571b02382e | |||
2f071e631d | |||
1e830e3cfd | |||
0381bb0567 | |||
adabd09ea7 | |||
a9ca04811e | |||
5458fae6d9 | |||
5023032ac2 | |||
fb0e13089f | |||
21aa36e3d1 | |||
f81141d18b | |||
8f0d715f8c | |||
45dcf643bf | |||
5468b79562 | |||
08a731673b | |||
94e384c83c | |||
a594e8a049 | |||
fd055cd7c6 | |||
d4df72afe2 | |||
442d35eac8 | |||
154e21fae6 | |||
1a8f9eda18 | |||
128dd05b9a | |||
181fbf924f | |||
8d1eb03ffc | |||
baeff66aaf | |||
1709468f1f | |||
b46b56159b | |||
b8390c4ac6 | |||
36af26a647 | |||
cdf5663b16 | |||
8fbfa75144 | |||
5a0cf73218 | |||
44bd8045b8 | |||
8a32841f9d | |||
e0bb8127f4 | |||
1610acfbe7 | |||
fff9b5b65f | |||
d64659d653 | |||
f92084d399 | |||
f4560c0be5 | |||
fe529c2242 | |||
3509b9348f | |||
83027245e8 | |||
248b346f78 | |||
191f01a398 | |||
408531bec3 | |||
be24daf998 | |||
020d554019 | |||
dd30726d10 | |||
59b6c29508 | |||
2f7ee48930 | |||
caebf1b53b | |||
b76ecf57dc | |||
0dc8f39f07 | |||
e82dd59c34 | |||
0836584192 | |||
b490cd8b25 | |||
a512f8e162 | |||
7bfbbd9309 | |||
6c7e62bcb0 | |||
f4138510cd | |||
ac9b0a00e8 | |||
db5262d655 | |||
ff07551762 | |||
40e466aa82 | |||
5b65bc5d9f | |||
4b3ab56565 | |||
eee3f53672 | |||
fe57e8c6b3 | |||
fe292802cd | |||
da5f0051c8 | |||
47ce7e3bd8 | |||
e6770172ac | |||
fbbb400892 | |||
85746f2d4d | |||
09bc8e7670 | |||
8a1334bae5 | |||
63b51fd92c | |||
e2c716f576 | |||
61e4c341f3 | |||
a485994a72 | |||
6d3173cd1f | |||
e047b0a23c | |||
60a6f3e781 | |||
6bcb22ea00 | |||
1e7afc034e | |||
ea8611771b | |||
6e0238eef7 | |||
ac6fc6bc0e | |||
025b9239c3 | |||
8799446e57 | |||
44465c2783 | |||
0b445ee1c5 | |||
8ad179c61c | |||
f0f046d3cb | |||
a9e9966c93 | |||
2e78d39f12 | |||
de1bae8620 | |||
b330d991c6 | |||
2245eb4939 | |||
eb3e4730bf | |||
2faea3b007 | |||
50d77b0108 | |||
f8b487cebd | |||
fc367c05a3 | |||
bed975e944 | |||
e508e71b81 | |||
498ecd5ec1 | |||
01dbb9667a | |||
f85a8b777f | |||
3bd7219ca2 | |||
087f9c84bf | |||
![]() |
0c322400c2 | ||
b0ae4abc4d | |||
751b89c01d | |||
58211913f4 | |||
250bfd8a33 | |||
b8d1520c54 | |||
9aa5b390f8 | |||
2df7f6fc4b | |||
d526b944bd | |||
916f963e7b | |||
8887a1970c | |||
b04e7e8f45 | |||
b1caed8b15 | |||
ff0a17c776 | |||
9c3b328de0 | |||
d02505a70b | |||
9fcdc5a52a | |||
b1b424897c | |||
ead7483e19 | |||
f909a78e74 | |||
e3f2e63435 | |||
eb05a7de6a | |||
7c7149c5a1 | |||
94760279e7 | |||
70bbaad3c7 | |||
eed099245b | |||
31bc076989 | |||
b5f37c9de9 | |||
b9e964435d | |||
c492876c06 | |||
7eb7dd04d7 | |||
45757f0ae1 | |||
45e8a189cf | |||
fd2c1b2970 | |||
2587c759fb | |||
2a1394a5c4 | |||
56eb59ddeb | |||
354079519a | |||
2ca91addb0 | |||
c46073ed06 | |||
df0b66bf65 | |||
641eb6a4d3 | |||
e598e1496b | |||
085d72b4f8 | |||
c54a0b361f | |||
2a5c215f40 | |||
584cebb902 | |||
d4bffd1df8 | |||
94c2baff07 | |||
7b36aa0b0c | |||
5feb2ff22f | |||
d0ffcda226 | |||
1f2ab91bd3 | |||
184b53cfc8 | |||
345be9c688 | |||
30eb822201 | |||
76f2af2ef9 | |||
9f93a17053 | |||
83016d38b0 | |||
cc734866c5 | |||
c31b808f05 | |||
95a9a404d2 | |||
57b8d6bcce | |||
ac4d5895be | |||
131bf33a73 | |||
5a4b933f11 | |||
bea8de2c8c | |||
92782be7f6 | |||
22cbac14f1 | |||
bddaf223e4 | |||
4b2ed9f90e | |||
cad8dffbcf | |||
c4eb4563d5 | |||
cef38cf69c | |||
8a0f8fbe13 | |||
9abeb98239 | |||
fab7695e6c | |||
2486826dba | |||
1b82700db3 | |||
635cecedb7 | |||
5c97fc9e70 | |||
8e885c18d8 | |||
b5d23c6740 | |||
f778a4f24e | |||
acc21091f9 | |||
ec10bdca92 | |||
f84e1f2954 | |||
df05b31b86 | |||
1b16669512 | |||
d170f9e46e | |||
f5f9838fc3 | |||
c58f24d2d0 | |||
e75fcc562a | |||
6dae6afe95 | |||
1c5b8ecb29 | |||
00b41afa5a | |||
1324898483 | |||
ba22988026 | |||
9c9b1dc6cb | |||
73f02dfff0 | |||
bbb57e1d7f | |||
2996cf4100 | |||
97ec11331b | |||
8c9a0ee4c1 | |||
01d5abdd99 | |||
![]() |
f9e55b38a5 | ||
![]() |
3ad9500f23 | ||
![]() |
538cc84e10 | ||
4e7e46f92d | |||
61e756f9e5 | |||
![]() |
be945b0eee | ||
![]() |
b5f4443836 | ||
c53e342f54 | |||
ff213bd90d | |||
![]() |
1e443ea2ca | ||
![]() |
c1af6909c4 | ||
![]() |
e31c375867 | ||
![]() |
6d10fbc0bf | ||
96eea84997 | |||
10273e2159 | |||
0b55fa8109 | |||
![]() |
9fc47513c2 | ||
![]() |
ff332fadc1 | ||
e106faceda | |||
![]() |
5ef5e93543 | ||
![]() |
177ba193de | ||
88e3532418 | |||
07289b01e9 | |||
5c1fa931eb | |||
![]() |
82f5862063 | ||
![]() |
7eeeae6a1e | ||
744b867af3 | |||
![]() |
52bea8f9b6 | ||
![]() |
d2fde9df83 | ||
![]() |
80a28f4162 | ||
![]() |
1586a1190a | ||
![]() |
a998f76d44 | ||
![]() |
b845637064 | ||
![]() |
6fc7021317 | ||
![]() |
728c54b3f3 | ||
917e3e1df3 | |||
517b95f14f | |||
2337ad9a37 | |||
99f327445e | |||
b4ca119f9a | |||
9d9ebd75b5 | |||
b79548624f | |||
![]() |
fbae6770df | ||
5f565a3f5a | |||
![]() |
69cd306263 | ||
bf3f697299 | |||
53691f6a30 | |||
9259248caf | |||
9f6f36e2e6 | |||
1204a80b3c | |||
b9702a736e | |||
4283eae3be | |||
28f2b3b498 | |||
079b21af04 | |||
ffd4570d44 | |||
82ad4dd910 | |||
e334234c9f | |||
3340de941b | |||
3770d728c3 | |||
c86eb97cb9 | |||
d91d46c589 | |||
449579a768 | |||
bb29e34b1b | |||
![]() |
078e29a01f | ||
189342d785 | |||
003cb86ec0 | |||
12b77de018 | |||
5453b1158f | |||
18ede25c16 | |||
6d58524823 | |||
2a57fdc1e9 | |||
ddd8d57d2b | |||
781ef8a7a1 | |||
43f2a1e928 | |||
97139905cc | |||
438071eea3 | |||
937e7ec16c | |||
9d96010752 | |||
4e7c1232b0 | |||
9b06839798 | |||
4a59b8e146 | |||
![]() |
39e1eaddcf | ||
![]() |
5ca11324a0 | ||
![]() |
758c425f91 | ||
2d7a90f6b2 | |||
11d18ad4a5 | |||
2beda0bf5b | |||
48e1a04bae | |||
f0f05f8361 | |||
800fed2097 | |||
![]() |
203b70e2ef | ||
![]() |
bf703489fd | ||
c57fd0436d | |||
d04650facf | |||
4ee91ed5a0 | |||
32d84879c7 | |||
6f1b4581ce | |||
0659f67e84 | |||
42f0cc11d4 | |||
05d13008fb | |||
5921767654 | |||
475d2a6cd9 | |||
9781d63a60 | |||
057170118d | |||
0c79d3b002 | |||
105335a773 | |||
749940233d | |||
d9e8264cd0 | |||
9babf1975f | |||
716d1ca6fa | |||
388beba5cc | |||
75b7507bbe | |||
9e7eb89014 | |||
808980d77e | |||
66984043bc | |||
05f2777a49 | |||
725a599b6a | |||
1c5cabb253 | |||
31dadcc10b | |||
70755ba0a2 | |||
8fc1a3b256 | |||
814295e8ee | |||
![]() |
fefd052a8e | ||
![]() |
ab7e44fd85 | ||
b66c2fe19d | |||
9cf4a117df | |||
0b427e4796 | |||
85238695c7 | |||
e9321678e2 | |||
43b0b04859 | |||
5036c2baa9 | |||
b19556fd39 | |||
35b0533664 | |||
![]() |
16e5075825 | ||
0665770972 | |||
1ccfbe11a7 | |||
4376586a23 | |||
d16a8de5ac | |||
10f4fefb0c | |||
f3ee5ea7d9 | |||
5b2c489f2d | |||
e7100121d4 | |||
e0a64d3653 | |||
fe2d8608cb | |||
e7c90a4899 | |||
0a51ccba2a | |||
988bf266e8 | |||
![]() |
3941dc0fd2 | ||
![]() |
1a8448ca45 | ||
9954dbd66a | |||
![]() |
14361a858e | ||
8f8733cb7b | |||
aab05541b2 | |||
![]() |
5b6fd933e3 | ||
9634f51054 | |||
80fbbd510d | |||
c278e0a7a5 | |||
f55ac3a4ff | |||
![]() |
e1aa6e2f68 | ||
71b4c1c38d | |||
a7a1f69c5a | |||
3a894f2965 | |||
381909fb7e | |||
17cc127f2e | |||
9991337b87 | |||
b58261bbf0 | |||
![]() |
b09d284a1d | ||
5a4a1ff391 | |||
72b3d1e4af | |||
ca3af75b5a | |||
![]() |
f50d4b975d | ||
![]() |
bf3b888e71 | ||
cadd9de7a0 | |||
![]() |
ccdba6efd4 | ||
dc339fb025 | |||
![]() |
962d6ec58a | ||
![]() |
8d3f686fa1 | ||
![]() |
148f0e5244 | ||
129d52d6d6 | |||
22e4253ea9 | |||
121dfa4c49 | |||
![]() |
9bf68050a7 | ||
![]() |
615c9427b9 | ||
023cef2bf3 | |||
2426638414 | |||
d18de9e4c0 | |||
6f2721a0f2 | |||
70aaadd901 | |||
daa998c89e | |||
c2ce43d295 | |||
d19c83289d | |||
2eac2a9554 | |||
599d55b684 | |||
ea6596a5b4 | |||
![]() |
3203f48f76 | ||
4acc2b0605 | |||
![]() |
55a94cb05b | ||
ddb09d56e7 | |||
![]() |
835cb14042 | ||
474e6871e3 | |||
![]() |
13a445ef64 | ||
![]() |
ee7cdc8d10 | ||
e712d3265f | |||
11ec71cd7e | |||
7b94e05d0a | |||
bc8e6cad10 | |||
![]() |
9e55955970 | ||
![]() |
334da613fa | ||
![]() |
1593a84b34 | ||
![]() |
a340647df4 | ||
![]() |
c8054a5272 | ||
![]() |
b56d82fff1 | ||
![]() |
9e1ea6299d | ||
![]() |
78a5e8ad61 | ||
![]() |
e61ad02dc2 | ||
![]() |
bb122c5e39 | ||
![]() |
2b68c2ea8d | ||
![]() |
d52382c1dc | ||
![]() |
f9f72cf830 | ||
eea1f2c3a2 | |||
aa70fa1c8d | |||
![]() |
896baf18dd | ||
![]() |
1a961c0732 | ||
![]() |
6005cc01b7 | ||
![]() |
323b77f6dc | ||
![]() |
f572b5a6bc | ||
![]() |
733e13ff66 | ||
![]() |
f8484959d6 | ||
![]() |
cf82e1e21e | ||
![]() |
b76f114ab0 | ||
![]() |
1b519ca440 | ||
![]() |
f67232f55c | ||
![]() |
426052ba09 | ||
![]() |
85f0a5a06b | ||
cf77fc5e61 | |||
![]() |
3e426d088d | ||
![]() |
4da7ff2431 | ||
![]() |
4906d2bb4d | ||
![]() |
69b244d074 | ||
![]() |
155a86975c | ||
![]() |
5c134989d2 | ||
![]() |
3f34483fd5 | ||
![]() |
e0d5bc5739 | ||
![]() |
f4d269721a | ||
a88e7ffb87 | |||
![]() |
60e8725ac3 | ||
![]() |
c0dd9c1124 | ||
![]() |
8284b793d3 | ||
be4ea4906a | |||
![]() |
f0a1a68144 | ||
![]() |
098b23b864 | ||
![]() |
cdb8522f65 | ||
b1f1444a0c | |||
![]() |
4939dbbd83 | ||
![]() |
25d5830462 | ||
![]() |
ac13e0a3f2 | ||
![]() |
1aa112aac2 | ||
![]() |
7468ca9086 | ||
![]() |
11cd073a51 | ||
![]() |
50cdbe57e8 | ||
![]() |
a3a4ecdd33 | ||
![]() |
6a00c6db22 | ||
![]() |
401c0e888f | ||
![]() |
75401556aa | ||
![]() |
53a203b067 | ||
![]() |
33d59073e3 | ||
c06a3ed38c | |||
eda9d5ce6c | |||
![]() |
4160f72615 | ||
![]() |
498c550a15 | ||
![]() |
b733100269 | ||
![]() |
8502fb72d9 | ||
![]() |
0d5551406a | ||
![]() |
72bbaac9a6 | ||
![]() |
ee916afdfd | ||
![]() |
ece866a3ec | ||
![]() |
77bdccdf86 | ||
![]() |
c8768665e0 | ||
f2dee0359f | |||
![]() |
5b18461bd9 | ||
![]() |
b0f25de000 | ||
![]() |
509ceaeefe | ||
![]() |
bcb1e1b2c8 | ||
![]() |
aa416b7ee4 | ||
![]() |
9e554b0a65 | ||
![]() |
b2e84204ce | ||
![]() |
dd1b66bd06 | ||
![]() |
8d5e780f94 | ||
dce0620365 | |||
323ab09238 | |||
3a2ffde0ab | |||
![]() |
a9bb6df711 | ||
![]() |
0410e844b1 | ||
![]() |
2d302d0116 | ||
![]() |
e4a08f5aed | ||
![]() |
70235970ab | ||
![]() |
67aadf157f | ||
![]() |
54e515cb7a | ||
![]() |
c82fdeee96 | ||
![]() |
34e4fd6bb5 | ||
![]() |
9fb5275007 | ||
![]() |
667d7dbddb | ||
![]() |
f7f06cfa3a | ||
![]() |
1779f573ec | ||
![]() |
fba73636de | ||
![]() |
3814022411 | ||
![]() |
53b998f1e5 | ||
86d2c0e9f6 | |||
8b4e07d66e | |||
420387cdb7 | |||
763fd3f646 | |||
7975528317 | |||
![]() |
89c9a85204 | ||
2f397c88d4 | |||
![]() |
3bf776b6f7 | ||
bc7b7e2f22 |
152 changed files with 34076 additions and 2130 deletions
.directory.docker-compose.yml.swp.env.example.gitignoreDockerfileREADME.mddev-startdocker-compose.ymlpackage-lock.jsonpackage.json
app
CanastaLog.phpProducto.phpProveedor.phpSubpedido.phpUser.phpUserRole.php
composer.jsoncomposer.lockConsole/Commands
Filtros
GrupoDeCompra.phpHelpers
Http
Controllers
AdminController.php
Kernel.phpApi
Auth
ComisionesController.phpProductoController.phpRouteController.phpSessionController.phpUserController.phpMiddleware
Resources
database
factories
migrations
2014_10_12_000000_create_users_table.php2020_09_23_180334_create_subpedidos_table.php2022_09_11_020612_agregar_columna_fila_en_planilla_a_tabla_de_productos.php2023_07_06_015926_call_crear_pedidos_aprobados.php2023_11_12_142350_devoluciones_pedido.php2023_11_12_145219_habilitar_devoluciones.php2024_08_28_000025_agregar_is_compras_a_user.php2024_09_17_234635_notas_producto.php2024_09_19_230732_producto_requiere_notas.php2024_12_21_181409_crear_carga_de_canastas.php2025_05_12_214437_call_agregar_es_bono_a_pedidos_aprobados.php2025_05_15_021941_create_user_roles_table.php2025_05_15_023829_agregar_rol_a_user.php2025_05_15_033316_simplificar_users.php2025_05_15_033711_simplificar_barrios.php2025_05_15_034325_simplificar_productos.php2025_05_15_034910_simplificar_producto_subpedido.php2025_05_15_035305_agregar_es_solidario.php2025_05_15_035807_eliminar_proveedor.php2025_05_15_041404_eliminar_admin.php2025_05_23_193246_hacer_fila_nullable.php2025_05_23_212603_quitar_password_de_grupo_de_compra.php2025_06_14_172643_agregar_saldos_a_barrios.php
seeds
public
resources
csv
js
9
.directory
Normal file
9
.directory
Normal 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
BIN
.docker-compose.yml.swp
Normal file
Binary file not shown.
|
@ -6,9 +6,11 @@ APP_URL=http://localhost
|
|||
|
||||
LOG_CHANNEL=stack
|
||||
|
||||
USERID=
|
||||
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=db
|
||||
DB_PORT=3306
|
||||
DB_PORT_EXPOSED=3306
|
||||
DB_DATABASE=pedi2
|
||||
DB_USERNAME=pedi2
|
||||
DB_PASSWORD=pedi2
|
||||
|
@ -48,3 +50,4 @@ MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
|
|||
WEB_CLIENT_EMAIL=informaticamps@buzon.uy
|
||||
WEB_CLIENT_NAME=web
|
||||
WEB_CLIENT_PASS=pass
|
||||
NGINX_PORT=8000
|
8
.gitignore
vendored
8
.gitignore
vendored
|
@ -10,3 +10,11 @@ Homestead.json
|
|||
Homestead.yaml
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
.idea
|
||||
/resources/csv/exports/*.csv
|
||||
/resources/csv/canastas/*.csv
|
||||
/storage/csv/exports/*.csv
|
||||
/storage/csv/canastas/*.csv
|
||||
/public/css/
|
||||
/public/js/
|
||||
/public/mix-manifest.json
|
||||
|
|
|
@ -14,6 +14,10 @@ RUN apt-get update && apt-get install -y \
|
|||
zip \
|
||||
unzip
|
||||
|
||||
# Install node
|
||||
RUN curl -fsSL https://deb.nodesource.com/setup_18.x | bash - && \
|
||||
apt-get install -y nodejs
|
||||
|
||||
# Clear cache
|
||||
RUN apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
|
|
33
README.md
33
README.md
|
@ -1,6 +1,6 @@
|
|||
# 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.
|
||||
|
||||
|
@ -17,41 +17,39 @@ Se utilizan los siguientes servicios, separadamente:
|
|||
## 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`).
|
||||
|
||||
2. Construí la imagen de la app
|
||||
2. Levantá los contenedores, construyendo la imagen de la app primero
|
||||
|
||||
```bash
|
||||
docker-compose build app
|
||||
```
|
||||
|
||||
3. Cuando termine, levantá los contenedores:
|
||||
|
||||
```bash
|
||||
docker-compose up -d
|
||||
docker-compose up -d --build
|
||||
```
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
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.
|
||||
|
||||
|
@ -61,6 +59,11 @@ Podés usar el comando `logs` para ver los logs generados por tus servicios:
|
|||
docker-compose logs nginx
|
||||
```
|
||||
|
||||
8. Ejecuta npm para compilar el js y css
|
||||
```bash
|
||||
docker-compose exec app npm run prod
|
||||
```
|
||||
|
||||
## Services description
|
||||
|
||||
### Dockerfile
|
||||
|
|
11
app/CanastaLog.php
Normal file
11
app/CanastaLog.php
Normal 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";
|
||||
}
|
72
app/Console/Commands/AgregarEsBonoAPedidosAprobados.php
Normal file
72
app/Console/Commands/AgregarEsBonoAPedidosAprobados.php
Normal file
|
@ -0,0 +1,72 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class AgregarEsBonoAPedidosAprobados extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'command:AgregarEsBonoAPedidosAprobados';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Agrega "producto_bono" a la view PedidosAprobados';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function handle(): int
|
||||
{
|
||||
DB::statement("
|
||||
ALTER VIEW pedidos_aprobados(
|
||||
grupo_de_compra_id,
|
||||
grupo_de_compra_nombre,
|
||||
grupo_de_compra_region,
|
||||
producto_id,
|
||||
producto_nombre,
|
||||
producto_precio,
|
||||
cantidad_pedida,
|
||||
total_por_producto,
|
||||
producto_es_bono
|
||||
) 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,
|
||||
pr.bono
|
||||
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;
|
||||
}
|
||||
}
|
62
app/Console/Commands/CrearPedidosAprobadosViewCommand.php
Normal file
62
app/Console/Commands/CrearPedidosAprobadosViewCommand.php
Normal 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(): int
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -5,12 +5,15 @@ namespace App\Filtros;
|
|||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
use Throwable;
|
||||
use TypeError;
|
||||
|
||||
class Filtro extends Model
|
||||
{
|
||||
protected $request;
|
||||
protected Request $request;
|
||||
protected $builder;
|
||||
protected $MENSAJES_ERROR = [
|
||||
protected array $MENSAJES_ERROR = [
|
||||
'ARGUMENTO' => 'Argumento inválido para el parámetro %s. Revise la documentación.'
|
||||
];
|
||||
|
||||
|
@ -22,10 +25,10 @@ class Filtro extends Model
|
|||
/**
|
||||
* Apply all existing filters, if available.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $builder
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
* @param Builder $builder
|
||||
* @return Builder
|
||||
*/
|
||||
public function aplicar(Builder $builder)
|
||||
public function aplicar(Builder $builder): Builder
|
||||
{
|
||||
$this->builder = $builder;
|
||||
|
||||
|
@ -51,7 +54,7 @@ class Filtro extends Model
|
|||
//Llamar métodos con argumentos
|
||||
try {
|
||||
$this->$metodo($valor);
|
||||
} catch (\Throwable $th) {
|
||||
} catch (Throwable $th) {
|
||||
if (is_a($th,'TypeError') ) { throw new HttpException(400, sprintf($this->MENSAJES_ERROR['ARGUMENTO'],$filtro)); }
|
||||
throw $th;
|
||||
}
|
||||
|
@ -63,7 +66,7 @@ class Filtro extends Model
|
|||
//Buscar un término en el nombre
|
||||
public function nombre(String $valor)
|
||||
{
|
||||
$this->builder->where('nombre', "LIKE", "%" . $valor . "%")->orderByRaw("IF(nombre = '{$valor}',2,IF(nombre LIKE '{$valor}%',1,0)) DESC");
|
||||
$this->builder->where('nombre', "LIKE", "%" . $valor . "%")->orderByRaw("IF(nombre = '$valor',2,IF(nombre LIKE '$valor%',1,0)) DESC");
|
||||
}
|
||||
|
||||
public function alfabetico(String $order = 'asc')
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
<?php
|
||||
|
||||
namespace App\Filtros;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class FiltroDeProducto extends Filtro {
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace App\Filtros;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use TypeError;
|
||||
|
||||
class FiltroDeSubpedido extends Filtro
|
||||
{
|
||||
|
|
|
@ -2,17 +2,311 @@
|
|||
|
||||
namespace App;
|
||||
|
||||
use App\Helpers\CsvHelper;
|
||||
use App\Helpers\PdfHelper;
|
||||
use App\Helpers\TransporteHelper;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use League\Csv\Exception;
|
||||
|
||||
class GrupoDeCompra extends Model
|
||||
{
|
||||
public $timestamps = false;
|
||||
protected $fillable = [ "nombre","region","telefono","correo","referente_finanzas","cantidad_de_nucleos"];
|
||||
protected $fillable = ["nombre", "region", "devoluciones_habilitadas", "saldo"];
|
||||
protected $table = 'grupos_de_compra';
|
||||
protected $hidden = ['password'];
|
||||
|
||||
public function subpedidos() {
|
||||
return $this->hasMany('App\Subpedido');
|
||||
public function subpedidos(): HasMany
|
||||
{
|
||||
return $this->hasMany(Subpedido::class);
|
||||
}
|
||||
|
||||
public function toggleDevoluciones(): bool
|
||||
{
|
||||
$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 totalSinDevoluciones() {
|
||||
$total = 0;
|
||||
foreach ($this->pedidosAprobados() as $subpedido) {
|
||||
$total = $total + $subpedido->totalSinDevoluciones();
|
||||
}
|
||||
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 totalDePedido()
|
||||
{
|
||||
return $this->totalCentralesQueNoPaganTransporte()
|
||||
+ $this->totalCentralesQuePaganTransporte()
|
||||
+ $this->totalTransporte()
|
||||
;
|
||||
}
|
||||
|
||||
public function totalATransferir()
|
||||
{
|
||||
return $this->totalDePedido() - $this->saldo;
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
* Calcula la cantidad de bonos de transporte del barrio
|
||||
*/
|
||||
public function cantidadTransporte(): int
|
||||
{
|
||||
return TransporteHelper::cantidadTransporte($this->totalCentralesQuePaganTransporte());
|
||||
}
|
||||
|
||||
public function exportarPedidosAPdf()
|
||||
{
|
||||
$subpedidos = $this->pedidosAprobados();
|
||||
$fecha = now()->format('Y-m-d');
|
||||
PdfHelper::exportarPedidos($this->nombre . '-' . $fecha . '.pdf', $subpedidos);
|
||||
}
|
||||
|
||||
function pedidoParaPdf(): array
|
||||
{
|
||||
$productos = $this->productosPedidos(true, 'producto_id');
|
||||
$pedido = [];
|
||||
$pedido['productos'] = [];
|
||||
|
||||
$pedido['nombre'] = $this->nombre;
|
||||
foreach ($productos as $producto) {
|
||||
$productoParaPdf = [];
|
||||
$productoParaPdf['pivot'] = [];
|
||||
$productoParaPdf['nombre'] = $producto->producto_nombre;
|
||||
$productoParaPdf['pivot']['cantidad'] = $producto->cantidad_pedida;
|
||||
$productoParaPdf['pivot']['notas'] = false;
|
||||
$productoParaPdf['bono'] = $producto->producto_es_bono;
|
||||
|
||||
$pedido['productos'][] = $productoParaPdf;
|
||||
}
|
||||
|
||||
return $pedido;
|
||||
}
|
||||
|
||||
public function generarHTML()
|
||||
{
|
||||
$view = view("pdfgen.pedido_tabla", ["pedido" => $this->pedidoParaPdf()]);
|
||||
return $view->render();
|
||||
}
|
||||
|
||||
public static function exportarPedidosBarrialesAPdf()
|
||||
{
|
||||
$barrios = GrupoDeCompra::barriosMenosPrueba()->get();
|
||||
$fecha = now()->format('Y-m-d');
|
||||
PdfHelper::exportarPedidos('pedidos_por_barrio-' . $fecha . '.pdf', $barrios);
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function obtenerTemplateDeFilasVacias(int $columns): array
|
||||
{
|
||||
$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[TransporteHelper::filaTransporte()] = GrupoDeCompra::filaVacia("Bonos de transporte", $columns);
|
||||
return $template;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function exportarPedidoEnCSV()
|
||||
{
|
||||
$records = $this->generarColumnaCantidades();
|
||||
|
||||
$fecha = now()->format('Y-m-d');
|
||||
CsvHelper::generarCsv('csv/exports/' . $this->nombre . '-' . $fecha . '.csv', $records);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function generarColumnaCantidades(): array
|
||||
{
|
||||
$productos_en_pedido = $this->productosPedidos();
|
||||
|
||||
//si no hay pedidos aprobados, salir
|
||||
if ($productos_en_pedido->count() == 0) {
|
||||
Log::debug("El grupo de compra " . $this->nombre . " no tiene pedidos aprobados.");
|
||||
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[TransporteHelper::filaTransporte()][1] = $this->cantidadTransporte();
|
||||
|
||||
return $records;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function exportarPedidoConNucleosEnCSV()
|
||||
{
|
||||
$productos_en_pedido = $this->productosPedidos();
|
||||
|
||||
// si no hay pedidos aprobados, salir
|
||||
if ($productos_en_pedido->count() == 0) {
|
||||
Log::debug("El grupo de compra " . $this->nombre . " no tiene pedidos aprobados.");
|
||||
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));
|
||||
|
||||
$fecha = now()->format('Y-m-d');
|
||||
CsvHelper::generarCsv('csv/exports/' . $this->nombre . '-completo-' . $fecha . '.csv', $records);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
public static function barriosMenosPrueba(): Builder
|
||||
{
|
||||
return self::where('nombre', '<>', 'PRUEBA')
|
||||
->orderBy('region')
|
||||
->orderBy('nombre');
|
||||
}
|
||||
|
||||
public static function transportePorBarrio(): array
|
||||
{
|
||||
$result = [];
|
||||
$barrios = GrupoDeCompra::barriosMenosPrueba()->get();
|
||||
|
||||
foreach ($barrios as $barrio) {
|
||||
$result[] = $barrio->cantidadTransporte();
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function productosPedidos($excluirBonos = false, $orderBy = 'producto_nombre'): Collection
|
||||
{
|
||||
$query = DB::table('pedidos_aprobados')
|
||||
->where('grupo_de_compra_id', $this->id)
|
||||
->where('producto_nombre','NOT LIKE','%barrial%');
|
||||
|
||||
if ($excluirBonos)
|
||||
$query = $query->where('producto_es_bono',false);
|
||||
|
||||
return $query
|
||||
->orderBy($orderBy)
|
||||
->get()
|
||||
->keyBy('producto_id');
|
||||
}
|
||||
|
||||
public function setSaldo(float $saldo) {
|
||||
$this->saldo = $saldo;
|
||||
$this->save();
|
||||
}
|
||||
}
|
||||
|
|
144
app/Helpers/CanastaHelper.php
Normal file
144
app/Helpers/CanastaHelper.php
Normal file
|
@ -0,0 +1,144 @@
|
|||
<?php
|
||||
|
||||
namespace App\Helpers;
|
||||
|
||||
use App\Producto;
|
||||
use App\CanastaLog;
|
||||
use DatabaseSeeder;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Str;
|
||||
use League\Csv\Exception;
|
||||
|
||||
class CanastaHelper
|
||||
{
|
||||
const TIPO = "Tipo";
|
||||
const PRODUCTO = 'Producto';
|
||||
const PRECIO = 'Precio';
|
||||
const REGEX_BONO = "/^[BF]/i";
|
||||
const ARCHIVO_SUBIDO = 'Archivo subido';
|
||||
const CANASTA_CARGADA = 'Canasta cargada';
|
||||
const PRODUCTO_TALLE_COLOR = "PTC";
|
||||
|
||||
public static function canastaActual() {
|
||||
$result = [];
|
||||
$log = CanastaLog::where('descripcion', self::CANASTA_CARGADA)
|
||||
->orderBy('created_at', 'desc')
|
||||
->first();
|
||||
$nombre = str_replace(storage_path(), "", $log->path);
|
||||
$nombre = str_replace("/csv/canastas/", "", $nombre);
|
||||
$result["nombre"] = str_replace(".csv", "", $nombre);
|
||||
$result["fecha"] = $log->created_at;
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function guardarCanasta($data, $path): string {
|
||||
if (!File::exists(storage_path('csv/canastas'))) {
|
||||
File::makeDirectory(storage_path('csv/canastas'), 0755, true);
|
||||
}
|
||||
|
||||
$nombre = $data->getClientOriginalName();
|
||||
|
||||
$storage_path = storage_path($path);
|
||||
$data->move($storage_path, $nombre);
|
||||
|
||||
self::log($storage_path . $nombre, self::ARCHIVO_SUBIDO);
|
||||
|
||||
return $nombre;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function cargarCanasta($archivo) {
|
||||
self::limpiarTablas();
|
||||
|
||||
$registros = CsvHelper::getRecords($archivo, "No se pudo leer el archivo.");
|
||||
|
||||
$toInsert = [];
|
||||
$categoria = '';
|
||||
|
||||
foreach($registros as $i => $registro) {
|
||||
// saltear bono de transporte y filas que no tienen tipo
|
||||
if (self::noTieneTipo($registro) || $registro[self::TIPO] == "T")
|
||||
continue;
|
||||
|
||||
// obtener categoria si no hay producto
|
||||
if ($registro[self::PRODUCTO] == '') {
|
||||
// no es la pregunta de la copa?
|
||||
if (!Str::contains($registro[self::TIPO],"¿"))
|
||||
$categoria = $registro[self::TIPO];
|
||||
continue; // saltear si es la pregunta de la copa
|
||||
}
|
||||
|
||||
// completar producto
|
||||
$toInsert[] = DatabaseSeeder::addTimestamps([
|
||||
'fila' => $i,
|
||||
'categoria' => $categoria,
|
||||
'nombre' => trim(str_replace('*', '',$registro[self::PRODUCTO])),
|
||||
'precio' => $registro[self::PRECIO],
|
||||
'es_solidario' => Str::contains($registro[self::PRODUCTO],"*"),
|
||||
'bono' => preg_match(self::REGEX_BONO, $registro[self::TIPO]),
|
||||
'requiere_notas'=> $registro[self::TIPO] == self::PRODUCTO_TALLE_COLOR,
|
||||
]);
|
||||
}
|
||||
|
||||
foreach (array_chunk($toInsert,DatabaseSeeder::CHUNK_SIZE) as $chunk)
|
||||
Producto::insert($chunk);
|
||||
|
||||
self::agregarBonoBarrial();
|
||||
|
||||
self::log($archivo, self::CANASTA_CARGADA);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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');
|
||||
});
|
||||
|
||||
Producto::create([
|
||||
'nombre' => "Bono barrial",
|
||||
'precio' => 20,
|
||||
'categoria' => $categoria,
|
||||
'bono' => 1,
|
||||
'es_solidario' => 0,
|
||||
'requiere_notas'=> false,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $registro
|
||||
* @return bool
|
||||
*/
|
||||
public static function noTieneTipo($registro): bool
|
||||
{
|
||||
return !Arr::has($registro, self::TIPO) || trim($registro[self::TIPO]) == '';
|
||||
}
|
||||
}
|
48
app/Helpers/CsvHelper.php
Normal file
48
app/Helpers/CsvHelper.php
Normal file
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
namespace App\Helpers;
|
||||
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Iterator;
|
||||
use League\Csv\CannotInsertRecord;
|
||||
use League\Csv\Exception;
|
||||
use League\Csv\InvalidArgument;
|
||||
use League\Csv\Reader;
|
||||
use League\Csv\Writer;
|
||||
|
||||
class CsvHelper
|
||||
{
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function getRecords($filePath, $message): Iterator {
|
||||
$csv = Reader::createFromPath($filePath);
|
||||
try {
|
||||
$csv->setDelimiter("|");
|
||||
$csv->setEnclosure("'");
|
||||
$csv->setHeaderOffset(0);
|
||||
return $csv->getRecords();
|
||||
} catch (InvalidArgument|Exception $e) {
|
||||
Log::error($e->getMessage());
|
||||
throw new Exception($message, $e);
|
||||
}
|
||||
}
|
||||
|
||||
public static function generarCsv($filePath, $contenido, $headers = null): void
|
||||
{
|
||||
if (!File::exists(storage_path('csv/exports'))) {
|
||||
File::makeDirectory(storage_path('csv/exports'), 0755, true);
|
||||
}
|
||||
|
||||
try {
|
||||
$writer = Writer::createFromPath(storage_path($filePath), 'w');
|
||||
if ($headers) {
|
||||
$writer->insertOne($headers);
|
||||
}
|
||||
$writer->insertAll($contenido);
|
||||
} catch (CannotInsertRecord $e) {
|
||||
Log::error($e->getMessage(), $e->getTrace());
|
||||
}
|
||||
}
|
||||
}
|
29
app/Helpers/PdfHelper.php
Normal file
29
app/Helpers/PdfHelper.php
Normal file
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
namespace App\Helpers;
|
||||
|
||||
use Mpdf\Mpdf;
|
||||
use Mpdf\MpdfException;
|
||||
|
||||
class PdfHelper
|
||||
{
|
||||
/**
|
||||
* Requiere que el segundo argumento tenga definida la función generarHTML()
|
||||
* para crear la tabla con los datos del pedido que se inserta en el pdf.
|
||||
*
|
||||
* @return void
|
||||
* @throws MpdfException
|
||||
*/
|
||||
public static function exportarPedidos($filepath, $pedidos)
|
||||
{
|
||||
$mpdf = new Mpdf();
|
||||
|
||||
foreach ($pedidos as $pedido) {
|
||||
$html = $pedido->generarHTML();
|
||||
$mpdf->WriteHTML($html);
|
||||
$mpdf->AddPage();
|
||||
}
|
||||
|
||||
$mpdf->Output($filepath, 'D');
|
||||
}
|
||||
}
|
44
app/Helpers/TransporteHelper.php
Normal file
44
app/Helpers/TransporteHelper.php
Normal file
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
namespace App\Helpers;
|
||||
|
||||
use App\CanastaLog;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use League\Csv\Exception;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function filaTransporte()
|
||||
{
|
||||
$ultimaCanasta = CanastaLog::where('descripcion', CanastaHelper::CANASTA_CARGADA)
|
||||
->orderBy('created_at', 'desc')
|
||||
->pluck('path')
|
||||
->first();
|
||||
|
||||
$registros = CsvHelper::getRecords($ultimaCanasta, "No se encontró la ultima canasta.");
|
||||
$error = 'No hay fila de tipo T en la planilla: ' . $ultimaCanasta;
|
||||
|
||||
foreach ($registros as $key => $registro)
|
||||
if ($registro[CanastaHelper::TIPO] == 'T')
|
||||
return $key;
|
||||
|
||||
Log::error($error);
|
||||
throw new Exception($error);
|
||||
}
|
||||
}
|
|
@ -2,9 +2,55 @@
|
|||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\GrupoDeCompra;
|
||||
use League\Csv\Exception;
|
||||
|
||||
class AdminController extends Controller
|
||||
{
|
||||
//
|
||||
public function show()
|
||||
{
|
||||
return view('auth/login');
|
||||
}
|
||||
|
||||
public function index() {
|
||||
return view('auth/admin_subpedidos');
|
||||
}
|
||||
|
||||
public function exportarPedidosAPdf(GrupoDeCompra $gdc) {
|
||||
$gdc->exportarPedidosAPdf();
|
||||
}
|
||||
|
||||
public function exportarPedidoACSV(GrupoDeCompra $gdc)
|
||||
{
|
||||
try {
|
||||
$gdc->exportarPedidoEnCSV();
|
||||
} catch (Exception $e) {
|
||||
return response()->json(['message' => $e->getMessage()]);
|
||||
}
|
||||
$pattern = storage_path('csv/exports/'. $gdc->nombre . '-*.csv');
|
||||
$files = glob($pattern);
|
||||
|
||||
usort($files, function ($a, $b) {
|
||||
return filemtime($b) <=> filemtime($a);
|
||||
});
|
||||
|
||||
return response()->download($files[0]);
|
||||
}
|
||||
|
||||
public function exportarPedidoConNucleosACSV(GrupoDeCompra $gdc)
|
||||
{
|
||||
try {
|
||||
$gdc->exportarPedidoConNucleosEnCSV();
|
||||
} catch (Exception $e) {
|
||||
return response()->json(['message' => $e->getMessage()]);
|
||||
}
|
||||
$pattern = storage_path('csv/exports/'.$gdc->nombre.'-completo-*.csv');
|
||||
$files = glob($pattern);
|
||||
|
||||
usort($files, function ($a, $b) {
|
||||
return filemtime($b) <=> filemtime($a);
|
||||
});
|
||||
|
||||
return response()->download($files[0]);
|
||||
}
|
||||
}
|
||||
|
|
13
app/Http/Controllers/Api/CanastaController.php
Normal file
13
app/Http/Controllers/Api/CanastaController.php
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Helpers\CanastaHelper;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class CanastaController extends Controller
|
||||
{
|
||||
public function canastaActual() {
|
||||
return response()->json(CanastaHelper::canastaActual());
|
||||
}
|
||||
}
|
48
app/Http/Controllers/Api/GrupoDeCompraController.php
Normal file
48
app/Http/Controllers/Api/GrupoDeCompraController.php
Normal file
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\GrupoDeCompra;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Resources\GrupoDeCompraComisionesResource;
|
||||
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);
|
||||
}
|
||||
public function regiones()
|
||||
{
|
||||
return GrupoDeCompra::all()->pluck('region')->unique()->flatten();
|
||||
}
|
||||
|
||||
public function region(string $region)
|
||||
{
|
||||
return GrupoDeCompra::where('region', $region)->get();
|
||||
}
|
||||
|
||||
public function toggleDevoluciones(int $gdc) {
|
||||
GrupoDeCompra::find($gdc)->toggleDevoluciones();
|
||||
return response()->noContent();
|
||||
}
|
||||
|
||||
public function setSaldo(int $gdc) {
|
||||
$valid = request()->validate([
|
||||
'saldo' => ['required', 'min:0'],
|
||||
]);
|
||||
$grupoDeCompra = GrupoDeCompra::find($gdc);
|
||||
$grupoDeCompra->setSaldo($valid['saldo']);
|
||||
return response()->noContent();
|
||||
}
|
||||
|
||||
public function saldos()
|
||||
{
|
||||
return GrupoDeCompraComisionesResource::collection(GrupoDeCompra::all());
|
||||
}
|
||||
}
|
|
@ -2,35 +2,21 @@
|
|||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Filtros\FiltroDeProducto;
|
||||
use App\Http\Resources\ProductoResource;
|
||||
use App\Producto;
|
||||
|
||||
class ProductoController extends Controller
|
||||
{
|
||||
/**
|
||||
* Mostrar una lista de productos.
|
||||
*
|
||||
* @param App\Filtros\FiltroDeProducto $filtros
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index(FiltroDeProducto $filtros, Request $request)
|
||||
{
|
||||
return ProductoResource::collection(Producto::filtrar($filtros)->paginate(Producto::getPaginar($request)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @param \App\Producto $producto
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function show(Producto $producto)
|
||||
public function categorias()
|
||||
{
|
||||
return new ProductoResource($producto);
|
||||
return Producto::all()->pluck('categoria')->unique()->flatten();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Producto;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Filtros\FiltroDeSubpedido;
|
||||
use App\Subpedido;
|
||||
|
@ -14,24 +15,16 @@ use Symfony\Component\HttpKernel\Exception\HttpException;
|
|||
|
||||
class SubpedidoController extends Controller
|
||||
{
|
||||
/**
|
||||
* Mostrar una lista de productos.
|
||||
*
|
||||
* @param App\Filtros\FiltroDeSubpedido $filtros
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index(FiltroDeSubpedido $filtros, Request $request)
|
||||
{
|
||||
return Subpedido::filtrar($filtros)->get();
|
||||
return Subpedido::filtrar($filtros)->select('id','nombre')->get();
|
||||
}
|
||||
|
||||
public function indexResources(FiltroDeSubpedido $filtros, Request $request)
|
||||
{
|
||||
return SubpedidoResource::collection(Subpedido::filtrar($filtros)->get());
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$validado = $this->validateSubpedido();
|
||||
|
@ -42,10 +35,11 @@ class SubpedidoController extends Controller
|
|||
$s->nombre = $validado["nombre"];
|
||||
$s->grupo_de_compra_id = $validado["grupo_de_compra_id"];
|
||||
$s->save();
|
||||
return $s;
|
||||
return $this->show($s);
|
||||
}
|
||||
|
||||
protected function validateSubpedido(){
|
||||
protected function validateSubpedido(): array
|
||||
{
|
||||
return request()->validate([
|
||||
'nombre' => 'required|max:255',
|
||||
'grupo_de_compra_id' => [
|
||||
|
@ -55,14 +49,50 @@ class SubpedidoController extends Controller
|
|||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @param \App\Subpedido $subpedido
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function show(Subpedido $subpedido)
|
||||
{
|
||||
return new SubpedidoResource($subpedido);
|
||||
}
|
||||
|
||||
// recibe request, saca producto y cantidad, valida, y pasa a syncProducto en Subpedido
|
||||
public function syncProductos(Subpedido $subpedido) {
|
||||
if ($subpedido->aprobado)
|
||||
abort(400, "No se puede modificar un pedido aprobado.");
|
||||
|
||||
$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 response()->noContent();
|
||||
}
|
||||
|
||||
public function syncDevoluciones(Subpedido $subpedido) {
|
||||
if ($subpedido->aprobado)
|
||||
abort(400, "No se puede modificar un pedido aprobado.");
|
||||
|
||||
$valid = request()->validate([
|
||||
'total' => 'required|min:0',
|
||||
'notas' => 'min:0'
|
||||
]);
|
||||
$subpedido->syncDevoluciones($valid['total'], $valid['notas'] ?? "");
|
||||
|
||||
return new SubpedidoResource($subpedido);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ namespace App\Http\Controllers\Auth;
|
|||
use App\Http\Controllers\Controller;
|
||||
use App\Providers\RouteServiceProvider;
|
||||
use Illuminate\Foundation\Auth\AuthenticatesUsers;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class LoginController extends Controller
|
||||
{
|
||||
|
@ -28,6 +28,11 @@ class LoginController extends Controller
|
|||
*/
|
||||
protected $redirectTo = RouteServiceProvider::HOME;
|
||||
|
||||
protected function authenticated(Request $request, $user)
|
||||
{
|
||||
return redirect('/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
|
|
107
app/Http/Controllers/ComisionesController.php
Normal file
107
app/Http/Controllers/ComisionesController.php
Normal file
|
@ -0,0 +1,107 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\GrupoDeCompra;
|
||||
use App\Helpers\CanastaHelper;
|
||||
use App\Helpers\CsvHelper;
|
||||
use App\Http\Resources\GrupoDeCompraResource;
|
||||
use App\Producto;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use League\Csv\Exception;
|
||||
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||
|
||||
class ComisionesController
|
||||
{
|
||||
const CANASTAS_PATH = 'csv/canastas/';
|
||||
const BARRIO = "Barrio";
|
||||
const SALDO = "Saldo";
|
||||
|
||||
public function show()
|
||||
{
|
||||
return view('auth/login');
|
||||
}
|
||||
|
||||
public function descargarPedidos()
|
||||
{
|
||||
try {
|
||||
Producto::planillaTotales();
|
||||
} catch (Exception $e) {
|
||||
return response()->json(['message' => $e->getMessage()], 500);
|
||||
}
|
||||
$pattern = storage_path('csv/exports/pedidos-por-barrio-*.csv');
|
||||
$files = glob($pattern);
|
||||
|
||||
usort($files, function ($a, $b) {
|
||||
return filemtime($b) <=> filemtime($a);
|
||||
});
|
||||
|
||||
return response()->download($files[0]);
|
||||
}
|
||||
|
||||
public function descargarNotas(): BinaryFileResponse
|
||||
{
|
||||
Producto::planillaNotas();
|
||||
$pattern = storage_path('csv/exports/notas-por-barrio-*.csv');
|
||||
$files = glob($pattern);
|
||||
|
||||
usort($files, function ($a, $b) {
|
||||
return filemtime($b) <=> filemtime($a);
|
||||
});
|
||||
|
||||
return response()->download($files[0]);
|
||||
}
|
||||
|
||||
public function pdf() {
|
||||
GrupoDeCompra::exportarPedidosBarrialesAPdf();
|
||||
}
|
||||
|
||||
public function cargarCanasta(Request $request): JsonResponse
|
||||
{
|
||||
$request->validate([
|
||||
'data' => 'required|file|mimes:csv,txt|max:2048',
|
||||
]);
|
||||
|
||||
$nombre = CanastaHelper::guardarCanasta($request->file('data'), self::CANASTAS_PATH);
|
||||
try {
|
||||
CanastaHelper::cargarCanasta(storage_path(self::CANASTAS_PATH . $nombre));
|
||||
} catch (Exception $e) {
|
||||
return response()->json(['message' => $e->getMessage()], 500);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Canasta cargada exitosamente',
|
||||
]);
|
||||
}
|
||||
|
||||
public function descargarCanastaEjemplo(): BinaryFileResponse
|
||||
{
|
||||
$file = resource_path('csv/productos.csv');
|
||||
return response()->download($file);
|
||||
}
|
||||
|
||||
public function cargarSaldos(Request $request): JsonResponse
|
||||
{
|
||||
$request->validate([
|
||||
'data' => 'required|file|mimes:csv,txt|max:2048',
|
||||
]);
|
||||
|
||||
$file = $request->file('data')->getPathname();
|
||||
|
||||
try {
|
||||
$records = CsvHelper::getRecords($file, "No se pudo leer el archivo.");
|
||||
} catch (Exception $e) {
|
||||
return response()->json(['message' => $e->getMessage()], 500);
|
||||
}
|
||||
|
||||
foreach ($records as $record) {
|
||||
$barrio = $record[self::BARRIO];
|
||||
$saldo = $record[self::SALDO];
|
||||
GrupoDeCompra::where('nombre', $barrio)
|
||||
->update(['saldo' => $saldo]);
|
||||
}
|
||||
|
||||
return response()->json(GrupoDeCompraResource::collection(GrupoDeCompra::all()));
|
||||
}
|
||||
}
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ProductoController extends Controller
|
||||
{
|
||||
/**
|
||||
|
@ -16,11 +14,6 @@ class ProductoController extends Controller
|
|||
$this->middleware(['auth','subpedido']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the application dashboard.
|
||||
*
|
||||
* @return \Illuminate\Contracts\Support\Renderable
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return view('productos');
|
||||
|
|
34
app/Http/Controllers/RouteController.php
Normal file
34
app/Http/Controllers/RouteController.php
Normal file
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\UserRole;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class RouteController extends Controller
|
||||
{
|
||||
function home(Request $request) {
|
||||
if (!Auth::check())
|
||||
return redirect('/login');
|
||||
|
||||
$barrio = UserRole::where('nombre', 'barrio')->first();
|
||||
$admin = UserRole::where('nombre', 'admin_barrio')->first();
|
||||
$comision = UserRole::where('nombre', 'comision')->first();
|
||||
|
||||
switch ($request->user()->role_id) {
|
||||
case $barrio->id:
|
||||
return redirect('/pedido');
|
||||
case $admin->id:
|
||||
return redirect('/admin');
|
||||
case $comision->id:
|
||||
return redirect('/comisiones');
|
||||
default:
|
||||
abort(400, 'Rol de usuario invalido');
|
||||
}
|
||||
}
|
||||
|
||||
function main(Request $request) {
|
||||
return view('main');
|
||||
}
|
||||
}
|
35
app/Http/Controllers/SessionController.php
Normal file
35
app/Http/Controllers/SessionController.php
Normal file
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Subpedido;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class SessionController extends Controller
|
||||
{
|
||||
public function store(Request $request): Response
|
||||
{
|
||||
$grupo_de_compra_id = Auth::user()->grupo_de_compra_id;
|
||||
$validated = $request->validate([
|
||||
'id' => 'required',
|
||||
Rule::in(Subpedido::where('grupo_de_compra_id', $grupo_de_compra_id)->pluck('id')),
|
||||
]);
|
||||
session()->put('pedido_id', $validated["id"]);
|
||||
return response()->noContent();
|
||||
}
|
||||
|
||||
public function fetch(): JsonResponse
|
||||
{
|
||||
return response()->json(['id' => session('pedido_id')]);
|
||||
}
|
||||
|
||||
public function destroy(): Response
|
||||
{
|
||||
session()->forget('pedido_id');
|
||||
return response()->noContent();
|
||||
}
|
||||
}
|
37
app/Http/Controllers/UserController.php
Normal file
37
app/Http/Controllers/UserController.php
Normal file
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\GrupoDeCompra;
|
||||
use App\Http\Resources\GrupoDeCompraPedidoResource;
|
||||
use App\Http\Resources\GrupoDeCompraResource;
|
||||
use App\UserRole;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class UserController extends Controller
|
||||
{
|
||||
public function rol(Request $request) {
|
||||
return ["rol" => UserRole::find($request->user()->role_id)->nombre];
|
||||
}
|
||||
|
||||
public function grupoDeCompra(Request $request)
|
||||
{
|
||||
$user = Auth::user();
|
||||
$result = [ 'grupo_de_compra' => null, ];
|
||||
$grupo_de_compra = GrupoDeCompra::find($user->grupo_de_compra_id);
|
||||
switch (UserRole::findOrFail($user->role_id)->nombre) {
|
||||
case 'barrio':
|
||||
$result['grupo_de_compra'] = new GrupoDeCompraPedidoResource($grupo_de_compra);
|
||||
break;
|
||||
case 'admin_barrio':
|
||||
$result['grupo_de_compra'] = new GrupoDeCompraResource($grupo_de_compra);
|
||||
break;
|
||||
case 'comision':
|
||||
break;
|
||||
default:
|
||||
abort(400, 'Rol invalido.');
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Http;
|
||||
|
||||
use App\Http\Middleware\CheckRole;
|
||||
use Illuminate\Foundation\Http\Kernel as HttpKernel;
|
||||
use Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful;
|
||||
|
||||
|
@ -56,6 +57,7 @@ class Kernel extends HttpKernel
|
|||
*/
|
||||
protected $routeMiddleware = [
|
||||
'auth' => \App\Http\Middleware\Authenticate::class,
|
||||
'role' => \App\Http\Middleware\CheckRole::class,
|
||||
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
|
||||
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
|
||||
|
|
|
@ -15,6 +15,11 @@ class Authenticate extends Middleware
|
|||
protected function redirectTo($request)
|
||||
{
|
||||
if (!$request->expectsJson()) {
|
||||
$path = $request->path();
|
||||
if (preg_match('~^admin.*~i', $path))
|
||||
return route('admin.login');
|
||||
if (preg_match('~^comisiones.*~i', $path))
|
||||
return route('comisiones.login');
|
||||
return route('login');
|
||||
}
|
||||
}
|
||||
|
|
25
app/Http/Middleware/CheckRole.php
Normal file
25
app/Http/Middleware/CheckRole.php
Normal file
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use App\UserRole;
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class CheckRole
|
||||
{
|
||||
/**
|
||||
* Handle the incoming request.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Closure $next
|
||||
* @param string $role
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, Closure $next, $role)
|
||||
{
|
||||
$role_id = UserRole::where('nombre', $role)->first()->id;
|
||||
return $request->user()->role_id == $role_id ? $next($request)
|
||||
: response('No tenés permiso para esto.', 403);
|
||||
}
|
||||
}
|
|
@ -3,17 +3,18 @@
|
|||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class Subpedido
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @param Request $request
|
||||
* @param Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
public function handle(Request $request, Closure $next)
|
||||
{
|
||||
if (!session('subpedido_nombre') || !session('subpedido_id')) {
|
||||
return redirect()->route('subpedidos.create');
|
||||
|
|
22
app/Http/Resources/GrupoDeCompraComisionesResource.php
Normal file
22
app/Http/Resources/GrupoDeCompraComisionesResource.php
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Resources;
|
||||
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class GrupoDeCompraComisionesResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($request): array {
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'nombre' => $this->nombre,
|
||||
'saldo' => $this->saldo,
|
||||
];
|
||||
}
|
||||
}
|
22
app/Http/Resources/GrupoDeCompraPedidoResource.php
Normal file
22
app/Http/Resources/GrupoDeCompraPedidoResource.php
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Resources;
|
||||
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class GrupoDeCompraPedidoResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($request): array {
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'nombre' => $this->nombre,
|
||||
'devoluciones_habilitadas' => $this->devoluciones_habilitadas,
|
||||
];
|
||||
}
|
||||
}
|
34
app/Http/Resources/GrupoDeCompraResource.php
Normal file
34
app/Http/Resources/GrupoDeCompraResource.php
Normal file
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Resources;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class GrupoDeCompraResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($request): array
|
||||
{
|
||||
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),
|
||||
'saldo' => number_format($this->saldo, 2, ".", ""),
|
||||
'total_sin_devoluciones' => number_format($this->totalSinDevoluciones(),2),
|
||||
'total_barrial' => number_format($this->totalBarrial(),2),
|
||||
'total_devoluciones' => number_format($this->totalDevoluciones(),2),
|
||||
'total_de_pedido' => number_format($this->totalDePedido(),2),
|
||||
'total_a_transferir' => number_format($this->totalATransferir(),2),
|
||||
'total_transporte' => number_format($this->totalTransporte()),
|
||||
'cantidad_transporte' => number_format($this->cantidadTransporte()),
|
||||
];
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Http\Resources;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class ProductoResource extends JsonResource
|
||||
|
@ -9,23 +10,19 @@ class ProductoResource extends JsonResource
|
|||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param Request $request
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($request)
|
||||
public function toArray($request): array
|
||||
{
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'nombre' => $this->nombre,
|
||||
'precio' => $this->precio,
|
||||
'categoria' => $this->categoria,
|
||||
'proveedor' => optional($this->proveedor)->nombre,
|
||||
'economia_solidaria' => optional($this->proveedor)->economia_solidaria,
|
||||
'nacional' => optional($this->proveedor)->nacional,
|
||||
'imagen' => optional($this->poster)->url(),
|
||||
'descripcion' => $this->descripcion,
|
||||
'apto_veganxs' => $this->apto_veganxs,
|
||||
'apto_celiacxs' => $this->apto_celiacxs
|
||||
'economia_solidaria' => $this->es_solidario,
|
||||
'nacional' => $this->es_solidario,
|
||||
'requiere_notas' => $this->requiere_notas,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Http\Resources;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class SubpedidoResource extends JsonResource
|
||||
|
@ -9,20 +10,26 @@ class SubpedidoResource extends JsonResource
|
|||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param Request $request
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($request)
|
||||
public function toArray($request): array
|
||||
{
|
||||
$productos = $this->productos;
|
||||
foreach ($productos as $producto) {
|
||||
$producto['pivot']['total'] = number_format($producto->pivot->cantidad * $producto->precio, 2);
|
||||
}
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'nombre' => $this->nombre,
|
||||
'subtotal_productos' => number_format($this->getSubtotalProductos(),2),
|
||||
'subtotal_bonos' => number_format($this->getSubtotalBonos(),2),
|
||||
'bonos_de_transporte' => $this->cantidadBDT(),
|
||||
'subtotal_bonos_de_transporte' => number_format($this->getSubtotalBDT(),2),
|
||||
'total' => number_format($this->getTotal(),2),
|
||||
'grupo_de_compra' => $this->grupoDeCompra
|
||||
'productos' => $productos,
|
||||
'aprobado' => (bool) $this->aprobado,
|
||||
'total' => number_format($this->total(),2),
|
||||
'total_transporte' => number_format($this->totalTransporte()),
|
||||
'cantidad_transporte' => number_format($this->cantidadTransporte()),
|
||||
'total_sin_devoluciones' => number_format($this->totalSinDevoluciones(),2),
|
||||
'devoluciones_total' => number_format($this->devoluciones_total,2),
|
||||
'devoluciones_notas' => $this->devoluciones_notas
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
145
app/Producto.php
145
app/Producto.php
|
@ -2,35 +2,156 @@
|
|||
|
||||
namespace App;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Filtros\FiltroDeProducto;
|
||||
use App\Helpers\CsvHelper;
|
||||
use App\Helpers\TransporteHelper;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use League\Csv\Exception;
|
||||
|
||||
class Producto extends Model
|
||||
{
|
||||
public $timestamps = false;
|
||||
protected $fillable = [ "nombre", "precio", "presentacion", "stock", "categoria" ];
|
||||
static $paginarPorDefecto = 10;
|
||||
protected $fillable = ["nombre", "precio", "categoria", "bono", "es_solidario", "requiere_notas"];
|
||||
|
||||
public function subpedidos()
|
||||
public function subpedidos(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany('App\Subpedido','productos_subpedidos')->withPivot(["cantidad"]);
|
||||
return $this->belongsToMany(Subpedido::class, 'productos_subpedidos')->withPivot(["cantidad", "notas"]);
|
||||
}
|
||||
|
||||
public function proveedor()
|
||||
public static function noBarriales()
|
||||
{
|
||||
return $this->belongsTo('App\Proveedor');
|
||||
return self::where('nombre', 'not like', '%barrial%');
|
||||
}
|
||||
|
||||
// Este método permite que se apliquen los filtros al hacer una request (por ejemplo, de búsqueda)
|
||||
public function scopeFiltrar($query, FiltroDeProducto $filtros)
|
||||
public function scopeFiltrar($query, FiltroDeProducto $filtros): Builder
|
||||
{
|
||||
return $filtros->aplicar($query);
|
||||
}
|
||||
|
||||
public static function getPaginar(Request $request)
|
||||
public static function getPaginar(Request $request): int
|
||||
{
|
||||
return $request->has('paginar') && intval($request->input('paginar')) ? intval($request->input('paginar')) : self::$paginarPorDefecto;
|
||||
return $request->has('paginar') && intval($request->input('paginar')) ? intval($request->input('paginar')) : self::all()->count();
|
||||
}
|
||||
|
||||
public static function productosFilaID()
|
||||
{
|
||||
return self::noBarriales()->pluck('id', 'fila')->all();
|
||||
}
|
||||
|
||||
public static function productosIDFila()
|
||||
{
|
||||
return self::noBarriales()->pluck('fila', 'id')->all();
|
||||
}
|
||||
|
||||
public static function productosIDNombre()
|
||||
{
|
||||
return self::noBarriales()->pluck('nombre', 'id')->all();
|
||||
}
|
||||
|
||||
static public function cantidadesPorBarrio(): Collection
|
||||
{
|
||||
$barrios = GrupoDeCompra::barriosMenosPrueba()
|
||||
->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();
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
static public function planillaTotales()
|
||||
{
|
||||
$headers = ['Producto'];
|
||||
$barrios = GrupoDeCompra::barriosMenosPrueba()
|
||||
->pluck('nombre')->toArray();
|
||||
$headers = array_merge($headers, $barrios);
|
||||
|
||||
$cantidadesPorBarrio = self::cantidadesPorBarrio();
|
||||
$transportePorBarrio = GrupoDeCompra::transportePorBarrio();
|
||||
$planilla = [];
|
||||
$ultimaFila = 1;
|
||||
$filaTransporte = TransporteHelper::filaTransporte();
|
||||
|
||||
foreach ($cantidadesPorBarrio as $productoCantidades) {
|
||||
$fila = $productoCantidades->fila;
|
||||
while ($fila - $ultimaFila > 1) {
|
||||
$ultimaFila++;
|
||||
if ($ultimaFila == $filaTransporte) {
|
||||
$planilla[$ultimaFila] = ['Bono de transporte'];
|
||||
} else {
|
||||
$planilla[$ultimaFila] = ['---'];
|
||||
}
|
||||
}
|
||||
$planilla[$fila] = [$productoCantidades->producto];
|
||||
foreach ($barrios as $barrio) {
|
||||
$planilla[$fila][] = $productoCantidades->$barrio ?? 0;
|
||||
}
|
||||
$ultimaFila = $fila;
|
||||
}
|
||||
|
||||
foreach ($transportePorBarrio as $key => $cantidad) {
|
||||
$planilla[$filaTransporte][] = $cantidad;
|
||||
}
|
||||
|
||||
$fecha = now()->format('Y-m-d');
|
||||
CsvHelper::generarCsv('csv/exports/pedidos-por-barrio- ' . $fecha . '.csv', $planilla, $headers);
|
||||
}
|
||||
|
||||
public static function notasPorBarrio(): 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 = GrupoDeCompra::barriosMenosPrueba()
|
||||
->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;
|
||||
}
|
||||
|
||||
$fecha = now()->format('Y-m-d');
|
||||
CsvHelper::generarCsv('csv/exports/notas-por-barrio-' . $fecha . '.csv', $planilla, $headers);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Proveedor extends Model
|
||||
{
|
||||
public $timestamps = false;
|
||||
protected $fillable = [ "nombre","direccion","telefono","correo","comentario" ];
|
||||
protected $table = 'proveedores';
|
||||
|
||||
public function productos()
|
||||
{
|
||||
return $this->hasMany('App\Producto');
|
||||
}
|
||||
}
|
|
@ -2,90 +2,132 @@
|
|||
|
||||
namespace App;
|
||||
|
||||
use League\Csv\Reader;
|
||||
use App\Helpers\TransporteHelper;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Log;
|
||||
use App\Filtros\FiltroDeSubpedido;
|
||||
|
||||
class Subpedido extends Model
|
||||
{
|
||||
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(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany('App\Producto')->withPivot(["cantidad"]);
|
||||
return $this->belongsToMany(Producto::class)->withPivot(["cantidad", "notas"]);
|
||||
}
|
||||
|
||||
//Bonos del MPS, Sororo, etc. NO devuelve bonos de transporte
|
||||
private function bonos()
|
||||
public function grupoDeCompra(): BelongsTo
|
||||
{
|
||||
return $this->productos()->where('bono',1);
|
||||
}
|
||||
|
||||
private function productosSinBonos()
|
||||
{
|
||||
return $this->productos()->where('bono',false);
|
||||
}
|
||||
|
||||
|
||||
public function grupoDeCompra()
|
||||
{
|
||||
return $this->belongsTo('App\GrupoDeCompra');
|
||||
return $this->belongsTo(GrupoDeCompra::class);
|
||||
}
|
||||
|
||||
// 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): Builder
|
||||
{
|
||||
return $filtros->aplicar($query);
|
||||
}
|
||||
|
||||
//Subtotal de dinero de productos del pedido, sin bonos ni transporte
|
||||
public function getSubtotalProductos()
|
||||
public function total()
|
||||
{
|
||||
return $this->productosSinBonos()->sum('total');
|
||||
return $this->totalSinDevoluciones() - $this->devoluciones_total;
|
||||
}
|
||||
|
||||
//Cantidad de bonos de transporte
|
||||
public function cantidadBDT()
|
||||
public function totalSinDevoluciones()
|
||||
{
|
||||
return ceil($this->getSubtotalProductos() / 500);
|
||||
return $this->totalBarrial() + $this->totalCentral();
|
||||
}
|
||||
|
||||
//Subtotal de dinero de bonos de transporte
|
||||
public function getSubtotalBDT()
|
||||
public function totalBarrial()
|
||||
{
|
||||
return $this->cantidadBDT() * 15;
|
||||
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');
|
||||
}
|
||||
|
||||
//Subtotal de dinero de bonos (MPS, Sororo, etc)
|
||||
public function getSubtotalBonos()
|
||||
public function totalCentral()
|
||||
{
|
||||
return $this->bonos()->sum('total');
|
||||
return $this->totalCentralesQueNoPaganTransporte() + $this->totalCentralesQuePaganTransporte() + $this->totalTransporte();
|
||||
}
|
||||
|
||||
|
||||
public function getTotal()
|
||||
public function totalCentralesQueNoPaganTransporte()
|
||||
{
|
||||
return $this->getSubtotalProductos() + $this->getSubtotalBDT() + $this->getSubtotalBonos();
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
|
||||
$this->updated_at = now();
|
||||
$this->save();
|
||||
}
|
||||
|
||||
public function toggleAprobacion(bool $aprobacion)
|
||||
{
|
||||
$this->aprobado = $aprobacion;
|
||||
$this->update(['aprobado' => $aprobacion]);
|
||||
$this->save();
|
||||
}
|
||||
|
||||
public function generarHTML()
|
||||
{
|
||||
$view = view("pdfgen.pedido_tabla", ["pedido" => $this]);
|
||||
return $view->render();
|
||||
}
|
||||
|
||||
public function syncDevoluciones(float $total, string $notas)
|
||||
{
|
||||
$this->devoluciones_total = $total;
|
||||
$this->devoluciones_notas = $notas;
|
||||
$this->save();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace App;
|
||||
|
||||
use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
|
||||
|
@ -16,7 +16,7 @@ class User extends Authenticatable
|
|||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'name', 'email', 'password',
|
||||
'name', 'email', 'password', 'role_id',
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -38,8 +38,8 @@ class User extends Authenticatable
|
|||
];
|
||||
|
||||
|
||||
public function grupoDeCompra()
|
||||
public function grupoDeCompra(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo('App\GrupoDeCompra');
|
||||
return $this->belongsTo(GrupoDeCompra::class);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ namespace App;
|
|||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Admin extends Model
|
||||
class UserRole extends Model
|
||||
{
|
||||
//
|
||||
protected $fillable = ["nombre"];
|
||||
}
|
|
@ -8,7 +8,8 @@
|
|||
],
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"php": "^7.2.5|^8.0",
|
||||
"php": "^7.4",
|
||||
"doctrine/dbal": "^2.2.0",
|
||||
"fideloper/proxy": "^4.4",
|
||||
"fruitcake/laravel-cors": "^2.0",
|
||||
"guzzlehttp/guzzle": "^6.3.1|^7.0.1",
|
||||
|
@ -16,7 +17,9 @@
|
|||
"laravel/sanctum": "^2.13",
|
||||
"laravel/tinker": "^2.5",
|
||||
"laravel/ui": "*",
|
||||
"league/csv": "^9.8"
|
||||
"league/csv": "^9.8",
|
||||
"mpdf/mpdf": "^8.1",
|
||||
"prexview/prexview": "^1.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"facade/ignition": "^2.0",
|
||||
|
@ -52,13 +55,13 @@
|
|||
"scripts": {
|
||||
"post-autoload-dump": [
|
||||
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
|
||||
"@php artisan package:discover --ansi"
|
||||
"@php7.4 artisan package:discover --ansi"
|
||||
],
|
||||
"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": [
|
||||
"@php artisan key:generate --ansi"
|
||||
"@php7.4 artisan key:generate --ansi"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
2315
composer.lock
generated
2315
composer.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -1,9 +1,10 @@
|
|||
<?php
|
||||
|
||||
/** @var \Illuminate\Database\Eloquent\Factory $factory */
|
||||
/** @var Factory $factory */
|
||||
|
||||
use App\User;
|
||||
use Faker\Generator as Faker;
|
||||
use Illuminate\Database\Eloquent\Factory;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/*
|
||||
|
|
|
@ -19,6 +19,8 @@ class CreateUsersTable extends Migration
|
|||
$table->string('email')->unique()->nullable();
|
||||
$table->timestamp('email_verified_at')->nullable();
|
||||
$table->foreignId('grupo_de_compra_id')->nullable();
|
||||
$table->boolean('is_admin');
|
||||
$table->unique(['name', 'is_admin']);
|
||||
$table->string('password');
|
||||
$table->rememberToken();
|
||||
$table->timestamps();
|
||||
|
|
|
@ -17,7 +17,7 @@ class CreateSubpedidosTable extends Migration
|
|||
$table->id();
|
||||
$table->string('nombre');
|
||||
$table->foreignId('grupo_de_compra_id');
|
||||
$table->boolean('aprobado')->nullable();
|
||||
$table->boolean('aprobado')->default(false);
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
|
|
|
@ -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');
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CallCrearPedidosAprobados extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Artisan::call("view:CrearPedidosAprobadosView");
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
|
@ -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');
|
||||
});
|
||||
}
|
||||
}
|
|
@ -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');
|
||||
});
|
||||
}
|
||||
}
|
|
@ -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');
|
||||
});
|
||||
}
|
||||
}
|
32
database/migrations/2024_09_17_234635_notas_producto.php
Normal file
32
database/migrations/2024_09_17_234635_notas_producto.php
Normal 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');
|
||||
});
|
||||
}
|
||||
}
|
|
@ -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');
|
||||
});
|
||||
}
|
||||
}
|
|
@ -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');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
|
||||
class CallAgregarEsBonoAPedidosAprobados extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Artisan::call("command:AgregarEsBonoAPedidosAprobados");
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
use App\UserRole;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateUserRolesTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('user_roles', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('nombre');
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
$tipos = ["barrio", "admin_barrio", "comision"];
|
||||
foreach ($tipos as $tipo) {
|
||||
UserRole::create([
|
||||
"nombre" => $tipo,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('user_roles');
|
||||
}
|
||||
}
|
43
database/migrations/2025_05_15_023829_agregar_rol_a_user.php
Normal file
43
database/migrations/2025_05_15_023829_agregar_rol_a_user.php
Normal file
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
use App\User;
|
||||
use App\UserRole;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AgregarRolAUser extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->foreignId('role_id');
|
||||
});
|
||||
|
||||
$barrio = UserRole::where('nombre', 'barrio')->first();
|
||||
$admin_barrio = UserRole::where('nombre', 'admin_barrio')->first();
|
||||
$comision = UserRole::where('nombre', 'comision')->first();
|
||||
User::all()->each(function($user) use ($barrio, $comision, $admin_barrio) {
|
||||
$user->role_id = $user->is_admin ? $admin_barrio->id :
|
||||
($user->is_compras ? $comision->id : $barrio->id);
|
||||
$user->save();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('user', function (Blueprint $table) {
|
||||
$table->dropForeign('role_id');
|
||||
});
|
||||
}
|
||||
}
|
43
database/migrations/2025_05_15_033316_simplificar_users.php
Normal file
43
database/migrations/2025_05_15_033316_simplificar_users.php
Normal file
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
use App\User;
|
||||
use App\UserRole;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class SimplificarUsers extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->dropColumn(['is_admin', 'is_compras']);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->boolean('is_admin')->default(false);
|
||||
$table->boolean('is_compras')->default(false);
|
||||
});
|
||||
|
||||
$admin_barrio = UserRole::where('nombre', 'admin_barrio')->first();
|
||||
$comision = UserRole::where('nombre', 'comision')->first();
|
||||
foreach (User::all() as $user) {
|
||||
$user->is_admin = $user->role_id == $admin_barrio->id;
|
||||
$user->is_compras = $user->role_id == $comision->id;
|
||||
$user->save();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class SimplificarBarrios extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('grupos_de_compra', function (Blueprint $table) {
|
||||
$table->dropColumn([
|
||||
'cantidad_de_nucleos',
|
||||
'telefono',
|
||||
'correo',
|
||||
'referente_finanzas',
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('grupos_de_compra', function (Blueprint $table) {
|
||||
$table->double('cantidad_de_nucleos');
|
||||
$table->string('telefono');
|
||||
$table->string('correo');
|
||||
$table->string('referente_finanzas');
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class SimplificarProductos extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('productos', function (Blueprint $table) {
|
||||
$table->dropColumn([
|
||||
'presentacion',
|
||||
'stock',
|
||||
'imagen_id',
|
||||
'descripcion',
|
||||
'apto_veganxs',
|
||||
'apto_celiacxs',
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('productos', function (Blueprint $table) {
|
||||
$table->integer('presentacion')->nullable();
|
||||
$table->integer('stock')->nullable();
|
||||
$table->foreignId('imagen_id')->nullable();
|
||||
$table->string('descripcion')->nullable();
|
||||
$table->boolean('apto_veganxs')->nullable();
|
||||
$table->boolean('apto_celiacxs')->nullable();
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class SimplificarProductoSubpedido extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('producto_subpedido', function (Blueprint $table) {
|
||||
$table->dropColumn('total');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('producto_subpedido', function (Blueprint $table) {
|
||||
$table->double('total');
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
use App\Producto;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AgregarEsSolidario extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('productos', function (Blueprint $table) {
|
||||
$table->boolean('es_solidario')->default(false);
|
||||
});
|
||||
|
||||
foreach (Producto::all() as $producto) {
|
||||
$producto->es_solidario = $producto->proveedor_id != null;
|
||||
$producto->save();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('productos', function (Blueprint $table) {
|
||||
$table->dropColumn('es_solidario');
|
||||
});
|
||||
}
|
||||
}
|
59
database/migrations/2025_05_15_035807_eliminar_proveedor.php
Normal file
59
database/migrations/2025_05_15_035807_eliminar_proveedor.php
Normal file
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
|
||||
use App\Producto;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class EliminarProveedor extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('productos', function (Blueprint $table) {
|
||||
$table->dropColumn('proveedor_id');
|
||||
});
|
||||
Schema::dropIfExists('proveedores');
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::create('proveedores', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('nombre');
|
||||
$table->string('direccion')->nullable();
|
||||
$table->string('telefono')->nullable();
|
||||
$table->string('correo')->nullable();
|
||||
$table->boolean('economia_solidaria')->nullable();
|
||||
$table->boolean('nacional')->nullable();
|
||||
$table->text('detalles_de_pago')->nullable();
|
||||
$table->text('comentario')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::table('productos', function (Blueprint $table) {
|
||||
$table->foreignId('proveedor_id')->nullable();
|
||||
});
|
||||
|
||||
$proveedor_id = DB::table('proveedores')->insertGetId([
|
||||
['nombre' => 'Proveedor de economía solidaria',
|
||||
'economia_solidaria' => 1,
|
||||
'nacional' => 1]
|
||||
]);
|
||||
|
||||
foreach (Producto::all() as $producto) {
|
||||
$producto->proveedor_id = $producto->es_solidario ? $proveedor_id : null;
|
||||
$producto->save();
|
||||
}
|
||||
}
|
||||
}
|
35
database/migrations/2025_05_15_041404_eliminar_admin.php
Normal file
35
database/migrations/2025_05_15_041404_eliminar_admin.php
Normal file
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class EliminarAdmin extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::dropIfExists('admins');
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::create('admins', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('nombre');
|
||||
$table->foreignId('grupo_de_compra_id');
|
||||
$table->string('email');
|
||||
$table->string('contrasena');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class HacerFilaNullable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('productos', function (Blueprint $table) {
|
||||
$table->integer('fila')->nullable()->change();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('productos', function (Blueprint $table) {
|
||||
$table->integer('fila')->nullable(false)->change();
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class QuitarPasswordDeGrupoDeCompra extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('grupos_de_compra', function (Blueprint $table) {
|
||||
$table->dropColumn('password');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('grupos_de_compra', function (Blueprint $table) {
|
||||
$table->string('password')->nullable();
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AgregarSaldosABarrios extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
// Agregar columna 'saldo' a la tabla 'grupos_de_compra'
|
||||
Schema::table('grupos_de_compra', function (Blueprint $table) {
|
||||
$table->double('saldo', 10, 2)->default(0);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
// Remover columna 'saldo' de la tabla 'grupos_de_compra'
|
||||
Schema::table('grupos_de_compra', function (Blueprint $table) {
|
||||
$table->dropColumn('saldo');
|
||||
});
|
||||
}
|
||||
}
|
20
database/seeds/CanastaSeeder.php
Normal file
20
database/seeds/CanastaSeeder.php
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?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
|
||||
* @throws \League\Csv\Exception
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
CanastaHelper::cargarCanasta(resource_path(self::ARCHIVO_DEFAULT));
|
||||
}
|
||||
}
|
|
@ -1,10 +1,19 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class DatabaseSeeder extends Seeder
|
||||
{
|
||||
const CHUNK_SIZE = 100;
|
||||
|
||||
static function addTimestamps($object) {
|
||||
$now = DB::raw('CURRENT_TIMESTAMP');
|
||||
$object['created_at'] = $now;
|
||||
$object['updated_at'] = $now;
|
||||
return $object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Seed the application's database.
|
||||
*
|
||||
|
@ -12,7 +21,8 @@ class DatabaseSeeder extends Seeder
|
|||
*/
|
||||
public function run()
|
||||
{
|
||||
$this->call(CanastaSeeder::class);
|
||||
$this->call(GrupoDeCompraSeeder::class);
|
||||
$this->call(ProductoSeeder::class);
|
||||
$this->call(UserSeeder::class);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
<?php
|
||||
|
||||
use App\Helpers\CsvHelper;
|
||||
use App\GrupoDeCompra;
|
||||
use App\User;
|
||||
use App\UserRole;
|
||||
use Illuminate\Database\Seeder;
|
||||
use League\Csv\Reader;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
|
||||
class GrupoDeCompraSeeder extends Seeder
|
||||
{
|
||||
|
@ -9,41 +13,36 @@ class GrupoDeCompraSeeder extends Seeder
|
|||
* Run the database seeds.
|
||||
*
|
||||
* @return void
|
||||
* @throws \League\Csv\Exception
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$csv = Reader::createFromPath(resource_path('csv/barrios.csv'), 'r');
|
||||
$csv->setDelimiter("|");
|
||||
$csv->setEnclosure("'");
|
||||
$csv->setHeaderOffset(0);
|
||||
$registros = $csv->getRecords();
|
||||
$registros = CsvHelper::getRecords(resource_path('csv/barrios.csv'), 'No se pudo leer la planilla de barrios.');
|
||||
$gdcToInsert = [];
|
||||
$usersToInsert = [];
|
||||
$roles = UserRole::where('nombre', 'barrio')->orWhere('nombre', 'admin_barrio')->get();
|
||||
|
||||
foreach($registros as $key => $registro){
|
||||
$gdcToInsert[] = [
|
||||
$gdcToInsert[] = DatabaseSeeder::addTimestamps([
|
||||
'nombre' => $registro['barrio'],
|
||||
'region' => $registro['region'],
|
||||
'telefono' => $registro['telefono'],
|
||||
'correo' => $registro['correo'],
|
||||
'referente_finanzas' => $registro['referente']
|
||||
];
|
||||
]);
|
||||
|
||||
$usersToInsert[] = [
|
||||
'name' => $registro['barrio'],
|
||||
'password' => Hash::make($registro['barrio']),
|
||||
'grupo_de_compra_id' => $key
|
||||
];
|
||||
foreach($roles as $role) {
|
||||
$nombre = $registro['barrio'] . ($role->nombre == 'barrio' ? '' : '_admin');
|
||||
$usersToInsert[] = DatabaseSeeder::addTimestamps([
|
||||
'name' => $nombre,
|
||||
'password' => Hash::make("123"),
|
||||
'role_id' => $role->id,
|
||||
'grupo_de_compra_id' => $key,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (array_chunk($gdcToInsert,DatabaseSeeder::CHUNK_SIZE) as $chunk)
|
||||
{
|
||||
DB::table('grupos_de_compra')->insert($chunk);
|
||||
}
|
||||
GrupoDeCompra::insert($chunk);
|
||||
|
||||
foreach (array_chunk($usersToInsert,DatabaseSeeder::CHUNK_SIZE) as $chunk)
|
||||
{
|
||||
DB::table('users')->insert($chunk);
|
||||
}
|
||||
User::insert($chunk);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,40 +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,
|
||||
'bono' => $registro['categoria'] == 'BONOS Y FINANCIAMIENTO SORORO'
|
||||
];
|
||||
}
|
||||
|
||||
foreach (array_chunk($toInsert,DatabaseSeeder::CHUNK_SIZE) as $chunk)
|
||||
{
|
||||
DB::table('productos')->insert($chunk);
|
||||
}
|
||||
}
|
||||
}
|
29
database/seeds/UserSeeder.php
Normal file
29
database/seeds/UserSeeder.php
Normal file
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
use App\User;
|
||||
use App\UserRole;
|
||||
use Illuminate\Database\Seeder;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
|
||||
class UserSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
$usersToInsert = [];
|
||||
|
||||
$usersToInsert[] = DatabaseSeeder::addTimestamps([
|
||||
'name' => 'comi',
|
||||
'password' => Hash::make("123"),
|
||||
'role_id' => UserRole::where('nombre', 'comision')->first()->id,
|
||||
]);
|
||||
|
||||
|
||||
foreach (array_chunk($usersToInsert,DatabaseSeeder::CHUNK_SIZE) as $chunk)
|
||||
User::insert($chunk);
|
||||
}
|
||||
}
|
2
dev-start
Executable file
2
dev-start
Executable file
|
@ -0,0 +1,2 @@
|
|||
#!/usr/bin/bash
|
||||
docker-compose up -d && docker-compose exec app npm run watch
|
|
@ -1,14 +1,15 @@
|
|||
version: "3.7"
|
||||
version: '3.2'
|
||||
|
||||
services:
|
||||
app:
|
||||
build:
|
||||
args:
|
||||
user: www
|
||||
uid: 1000
|
||||
uid: ${USERID}
|
||||
context: ./
|
||||
dockerfile: Dockerfile
|
||||
image: laravel-image
|
||||
container_name: laravel-app
|
||||
container_name: pedi2-app
|
||||
restart: unless-stopped
|
||||
working_dir: /var/www/
|
||||
volumes:
|
||||
|
@ -19,10 +20,8 @@ services:
|
|||
|
||||
db:
|
||||
image: mysql:5.7
|
||||
container_name: laravel-db
|
||||
container_name: pedi2-db
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "3306:3306"
|
||||
environment:
|
||||
MYSQL_DATABASE: ${DB_DATABASE}
|
||||
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
|
||||
|
@ -36,13 +35,15 @@ services:
|
|||
- dbdata:/var/lib/mysql
|
||||
networks:
|
||||
- app-network
|
||||
ports:
|
||||
- ${DB_PORT_EXPOSED}:3306
|
||||
|
||||
nginx:
|
||||
image: nginx:alpine
|
||||
container_name: laravel-nginx
|
||||
container_name: pedi2-nginx
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- 8000:80
|
||||
- ${NGINX_PORT}:80
|
||||
volumes:
|
||||
- ./:/var/www
|
||||
- ./nginx/conf.d/:/etc/nginx/conf.d/
|
||||
|
|
26510
package-lock.json
generated
Normal file
26510
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
15
package.json
15
package.json
|
@ -10,17 +10,20 @@
|
|||
"production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --config=node_modules/laravel-mix/setup/webpack.config.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"axios": "^0.19",
|
||||
"bootstrap": "^4.0.0",
|
||||
"cross-env": "^7.0",
|
||||
"jquery": "^3.2",
|
||||
"axios": "^0.19.2",
|
||||
"cross-env": "^7.0.3",
|
||||
"laravel-mix": "^5.0.1",
|
||||
"lodash": "^4.17.19",
|
||||
"popper.js": "^1.12",
|
||||
"resolve-url-loader": "^2.3.1",
|
||||
"sass": "^1.20.1",
|
||||
"sass-loader": "^8.0.0",
|
||||
"vue": "^2.5.17",
|
||||
"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",
|
||||
"vuex": "^3.6.2"
|
||||
}
|
||||
}
|
||||
|
|
BIN
public/assets/favicon.png
Normal file
BIN
public/assets/favicon.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 3.1 KiB |
8
public/css/app.css
vendored
8
public/css/app.css
vendored
|
@ -1,8 +0,0 @@
|
|||
p.navbar-item:empty {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.breadcrumb a {
|
||||
color: #cc0f35;
|
||||
}
|
||||
|
4
public/css/productos.css
vendored
4
public/css/productos.css
vendored
|
@ -1,4 +0,0 @@
|
|||
figure.image.icono {
|
||||
float: right;
|
||||
margin: 4px;
|
||||
}
|
93
public/js/app.js
vendored
93
public/js/app.js
vendored
|
@ -1,93 +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 class="navbar-item" href="#">
|
||||
<img style="padding:0 0.3em;" src="/assets/chismosa.png" height="28">
|
||||
<p style="margin:0 auto; color:white">$ <span v-text="subpedido == null ? 0 : subpedido.total"></span></p>
|
||||
</a>
|
||||
<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,
|
||||
subpedido: null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleState() {
|
||||
this.isActive = !this.isActive;
|
||||
},
|
||||
actualizarSubpedido(){
|
||||
axios.get("/api/subpedidos/" + this.subpedido.id)
|
||||
.then(response => {
|
||||
this.subpedido = response.data.data;
|
||||
});
|
||||
}
|
||||
}, mounted() {
|
||||
axios.get("/subpedidos/obtener_sesion").then(response => {
|
||||
this.subpedido = response.data.subpedido;
|
||||
this.actualizarSubpedido()
|
||||
});
|
||||
//Emitir un evento subpedido-actualizado al agregar o eliminar un producto del subpedido para que el total de la chismosa se muestre correctamente
|
||||
Event.$on('subpedido-actualizado', () => {
|
||||
this.actualizarSubpedido();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
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
114
public/js/login.js
vendored
|
@ -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
171
public/js/productos.js
vendored
|
@ -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);
|
||||
});
|
||||
}
|
||||
});
|
56
public/js/subpedidos-create.js
vendored
56
public/js/subpedidos-create.js
vendored
|
@ -1,56 +0,0 @@
|
|||
Vue.component('subpedido-select', {
|
||||
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
|
||||
}).then(response => {
|
||||
window.location.href = 'productos';
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
|
@ -1,45 +1,4 @@
|
|||
barrio|region|referente|telefono|correo
|
||||
BUCEO|ESTE|||
|
||||
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|||
|
||||
ENTREVERO|SUR|||
|
||||
TRES CRUCES|SUR|||
|
||||
VILLA ESPAÑOLA|SUR|||
|
||||
AUDA|OTRA|||
|
||||
SINTEP|OTRA|||
|
||||
PRUEBA|SIN REGION|||
|
|
0
resources/csv/exports/.gitignore
vendored
Normal file
0
resources/csv/exports/.gitignore
vendored
Normal file
|
@ -1,359 +1,381 @@
|
|||
categoria|producto|precio|proveedor
|
||||
ALIMENTOS NO PERECEDEROS|Yerba Compuesta La Herboristería 1kg |140.3|
|
||||
ALIMENTOS NO PERECEDEROS|Yerba Yusa tradicional 1kg |121.8|
|
||||
ALIMENTOS NO PERECEDEROS|Yerba Yusa tradicional 500grs|65|
|
||||
ALIMENTOS NO PERECEDEROS|Yerba Sara tradicional 1kg|129.7|
|
||||
ALIMENTOS NO PERECEDEROS|Yerba Sara suave 1kg|132.2|
|
||||
ALIMENTOS NO PERECEDEROS|Yerba Kiero mate 500grs|72.5|
|
||||
ALIMENTOS NO PERECEDEROS|*Harina Santa Unión 000 1kg|27.3|Santa Unión
|
||||
ALIMENTOS NO PERECEDEROS|*Harina Santa Unión 0000 1kg|34.8|Santa Unión
|
||||
ALIMENTOS NO PERECEDEROS|*Harina de trigo integral Pasaná 1 kg|65|Pasaná
|
||||
ALIMENTOS NO PERECEDEROS|*Harina de arroz Pasaná 1 kg |65|Pasaná
|
||||
ALIMENTOS NO PERECEDEROS|*Harina de Garbanzos Pasaná 1 kg |140|Pasaná
|
||||
ALIMENTOS NO PERECEDEROS|*Mezcla para faina Pasaná 1 kg |150|Pasaná
|
||||
ALIMENTOS NO PERECEDEROS|*Fécula de Mandioca Pasaná 1 kg |85|Pasaná
|
||||
ALIMENTOS NO PERECEDEROS|Tres Harinas 500grs. |85|
|
||||
ALIMENTOS NO PERECEDEROS|*Harina Santa Unión 000 Bolsa 25kg|560.6|Santa Unión
|
||||
ALIMENTOS NO PERECEDEROS|*Polenta Santa Unión 450gr|15.4|Santa Unión
|
||||
ALIMENTOS NO PERECEDEROS|*Mezcla de Fainá Santa Unión 5kg|294.8|Santa Unión
|
||||
ALIMENTOS NO PERECEDEROS|*Fideos Caorsi Tirabuzón 1kg|59|Caorsi
|
||||
ALIMENTOS NO PERECEDEROS|*Fideos Caorsi Tallarín 1kg|69|Caorsi
|
||||
ALIMENTOS NO PERECEDEROS|*Fideos Caorsi Moñita 1kg|69|Caorsi
|
||||
ALIMENTOS NO PERECEDEROS|*Fideos Caorsi para sopa 1kg|59|Caorsi
|
||||
ALIMENTOS NO PERECEDEROS|*Fideos Caorsi para sopa 5kg|268|Caorsi
|
||||
ALIMENTOS NO PERECEDEROS|*Fideos Caorsi Tirabuzón 5kg|268|Caorsi
|
||||
ALIMENTOS NO PERECEDEROS|Arroz Blue Patna 1kg|40.2|
|
||||
ALIMENTOS NO PERECEDEROS|Arroz Shiva 1kg|27|
|
||||
ALIMENTOS NO PERECEDEROS|Arroz integral 1kg |55|
|
||||
ALIMENTOS NO PERECEDEROS|Arroz integral 3kg|155|
|
||||
ALIMENTOS NO PERECEDEROS|Aceite Condesa de Soja 900 cc.|84|
|
||||
ALIMENTOS NO PERECEDEROS|Aceite Uruguay de Girasol 900 cc.|108|
|
||||
ALIMENTOS NO PERECEDEROS|Aceite Optimo canola 900 cc.|82.4|
|
||||
ALIMENTOS NO PERECEDEROS|*Aceite de oliva 500 ml. |195|
|
||||
ALIMENTOS NO PERECEDEROS|Vinagre Uruguay 900ml|77.9|
|
||||
ALIMENTOS NO PERECEDEROS|Aceite de Oliva Cuatro Piedras 3 lt|1090|
|
||||
ALIMENTOS NO PERECEDEROS|*Salsa de soja La Posta 250 ml. |95|
|
||||
ALIMENTOS NO PERECEDEROS|*Aceitunas verdes sin carozo en frasco La Posta 500 gr. |180|La Posta
|
||||
ALIMENTOS NO PERECEDEROS|*Aceitunas negras sin carozo en frasco frasco La Posta 500 gr. |180|La Posta
|
||||
ALIMENTOS NO PERECEDEROS|Lata atún Golden Fish desmenuzado al aceite 170g|31.1|
|
||||
ALIMENTOS NO PERECEDEROS|Lata de arvejas Campero 300g|18.3|
|
||||
ALIMENTOS NO PERECEDEROS|Lata de choclo Cosecha 300g|22|
|
||||
ALIMENTOS NO PERECEDEROS|Lata de jardinera Cosecha|25|
|
||||
ALIMENTOS NO PERECEDEROS|Lata de porotos negros Cosecha|31.1|
|
||||
ALIMENTOS NO PERECEDEROS|Lata de porotos de frutilla Cosecha|31.1|
|
||||
ALIMENTOS NO PERECEDEROS|Lata de duraznos en almíbar Campero |66.6|
|
||||
ALIMENTOS NO PERECEDEROS|Mayonesa Uruguay 500g|77.9|
|
||||
ALIMENTOS NO PERECEDEROS|Azúcar Azucarlito 25kg|1007.5|
|
||||
ALIMENTOS NO PERECEDEROS|Azúcar Bella Unión 1kg|39.8|
|
||||
ALIMENTOS NO PERECEDEROS|Azúcar impalpable Hornex 200 gr|31|
|
||||
ALIMENTOS NO PERECEDEROS|Azúcar impalpable Hornex 1kg|104|
|
||||
ALIMENTOS NO PERECEDEROS|Almidón de maíz Hornex 1Kg|64.5|
|
||||
ALIMENTOS NO PERECEDEROS|Polvo de Hornear Hornex 1 kg|122|
|
||||
ALIMENTOS NO PERECEDEROS|Polvo de Hornear Hornex 100 g + 20 g|27.9|
|
||||
ALIMENTOS NO PERECEDEROS|*Esencia de vainilla La Posta 100ml|80|
|
||||
ALIMENTOS NO PERECEDEROS|Grasa Uruguay 400grs|50|
|
||||
ALIMENTOS NO PERECEDEROS|Levadura seca Hornex 125g|85.5|
|
||||
ALIMENTOS NO PERECEDEROS|Café Sorocabana glaseado p/máquina 500 grs|232.8|
|
||||
ALIMENTOS NO PERECEDEROS|Café Sorocabana natural p/máquina 500 grs |315.8|
|
||||
ALIMENTOS NO PERECEDEROS|Café Saint 170 gr Instantaneo|185.3|
|
||||
ALIMENTOS NO PERECEDEROS|Té Negro en hebras 90gr hornimans|30.7|
|
||||
ALIMENTOS NO PERECEDEROS|Galletas de arroz comunes Natural Rice 120 gr|34|
|
||||
ALIMENTOS NO PERECEDEROS|* Leche en polvo 250grs|65|
|
||||
ALIMENTOS NO PERECEDEROS|* Leche en polvo 1kg|220|
|
||||
ALIMENTOS NO PERECEDEROS|* Coco rallado 200gr|70|
|
||||
ALIMENTOS NO PERECEDEROS|* Coco rallado 1kg|275|
|
||||
ALIMENTOS NO PERECEDEROS|Cocoa Hornex 200gr|43|
|
||||
ALIMENTOS NO PERECEDEROS|Postre de chocolate Hornex 8 porciones|36.5|
|
||||
ALIMENTOS NO PERECEDEROS|Prostre LIGHT de vainilla Hornex 8 porciones (aprobado por ADU)|57|
|
||||
ALIMENTOS NO PERECEDEROS|Flan de vainilla Hornex 8 porciones|36.5|
|
||||
ALIMENTOS NO PERECEDEROS|Gelatina de frutilla Hornex 8 porciones|36.5|
|
||||
ALIMENTOS NO PERECEDEROS|Bizcochuelo de vainilla SIN GLUTEN 500gr Hornex|142|
|
||||
ALIMENTOS NO PERECEDEROS|Pizza SIN GLUTEN 320gr Hornex|137|
|
||||
ALIMENTOS NO PERECEDEROS|Pulpa de Tomate De Ley 1lt|43.5|
|
||||
ALIMENTOS NO PERECEDEROS|Pure de papa instantaneo De Ley 125g|21.3|
|
||||
ALIMENTOS NO PERECEDEROS|*Sal fina sin fluor Polenteados 500g|27|
|
||||
ALIMENTOS NO PERECEDEROS|*Sal gruesa sin fluor Polenteados 500g|27|
|
||||
ALIMENTOS NO PERECEDEROS|*Salsa de tomate casera (puro tomate) 1 lt|65|
|
||||
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|
|
||||
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|
|
||||
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|
|
||||
ALIMENTOS NO PERECEDEROS|*Granola simple (avena+ girasol+ pasaUva) 1kg|160|
|
||||
ALIMENTOS NO PERECEDEROS|*Copos de maíz azucarados 500g|89|
|
||||
ALIMENTOS NO PERECEDEROS|*Copos de maíz naturales 500g|89|
|
||||
ALIMENTOS NO PERECEDEROS|*Crema untable de maní 250gr|89|
|
||||
ALIMENTOS NO PERECEDEROS|*Galletas de coco, avena y maní 400gr|100|
|
||||
ALIMENTOS NO PERECEDEROS|*Budin Panitep con cobertura de chocolate con almendras, maní, nueces y pasas 250grs|160|
|
||||
ALIMENTOS NO PERECEDEROS|*Budin Panitep con cobertura de almíbar y coco con almendras, maní, nueces y pasas 250grs|140|
|
||||
ALIMENTOS NO PERECEDEROS|*Budin Panitep de naranja 250grs|140|
|
||||
ALIMENTOS NO PERECEDEROS|*Chia 1/4 kg |65|
|
||||
ALIMENTOS NO PERECEDEROS|*Girasol 1/2 kg |85|
|
||||
ALIMENTOS NO PERECEDEROS|*Lino 1/4 kg |30|
|
||||
ALIMENTOS NO PERECEDEROS|*Sésamo 1/4 kg |55|
|
||||
ALIMENTOS NO PERECEDEROS|*Quinoa 1 kg |200|
|
||||
ALIMENTOS NO PERECEDEROS|*Dátiles con carozo 500 gr|180|
|
||||
ALIMENTOS NO PERECEDEROS|*Cacao en polvo 250 grs |100|
|
||||
ALIMENTOS NO PERECEDEROS|*Almendra pelada (sin tostar) Polenteados 100g|80|Polenteados
|
||||
ALIMENTOS NO PERECEDEROS|*Pasas de Uva Polenteados 250 gr|69|Polenteados
|
||||
ALIMENTOS NO PERECEDEROS|*Nueces Polenteados 100g|79|Polenteados
|
||||
ALIMENTOS NO PERECEDEROS|*Castañas tostadas SIN sal 100grs|76|Polenteados
|
||||
ALIMENTOS NO PERECEDEROS|*Avena laminada instantánea Polenteados 500g|49|Polenteados
|
||||
ALIMENTOS NO PERECEDEROS|*Pan de molde Gigor Lacteado 550g|55|Gigor
|
||||
ALIMENTOS NO PERECEDEROS|*Pan de molde Gigor Integral 550g|55|Gigor
|
||||
ALIMENTOS NO PERECEDEROS|*Galleta Malteada La Socialista 350g|56|La Socialista
|
||||
ALIMENTOS NO PERECEDEROS|*Galleta Malteada c/semillas (sésamo, chia, lino) La Socialista 380gr |74|La Socialista
|
||||
ALIMENTOS NO PERECEDEROS|*Galleta Cara Sucia La Socialista 350g|63|La Socialista
|
||||
ALIMENTOS NO PERECEDEROS|*Grisines La Socialista 350g|67|La Socialista
|
||||
ALIMENTOS NO PERECEDEROS|*Mezcla para panqueques La Socialista 2 x 250g|56|La Socialista
|
||||
ALIMENTOS NO PERECEDEROS|*Mezcla para salsa blanca La Socialista 2 x 50g|46|La Socialista
|
||||
ALIMENTOS NO PERECEDEROS|*Maní pelado frito y salado Polenteados 500g|89|Polenteados
|
||||
ALIMENTOS NO PERECEDEROS|*Maní pelado sin sal Polenteados 500g|89|Polenteados
|
||||
ALIMENTOS NO PERECEDEROS|*Garbanzo Polenteados 1kg|79|Polenteados
|
||||
ALIMENTOS NO PERECEDEROS|*Lentejas Polenteados 1kg|96|Polenteados
|
||||
ALIMENTOS NO PERECEDEROS|*Porotos negros Polenteados 1kg|86|Polenteados
|
||||
ALIMENTOS NO PERECEDEROS|*Porotos de manteca Polenteados 1kg |105|Polenteados
|
||||
ALIMENTOS NO PERECEDEROS|*Proteína de SOJA texturizada 1kg |125|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Tallarines frescos de yema Pastas Colon 1kg|155|Pastas Colón
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Tallarines frescos de espinaca Pastas Colon 1kg|165|Pastas Colón
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Tallarines frescos de morrón Pastas Colon 1kg|165|Pastas Colón
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Salsa pomarola 300gr ex trabajadores de La Spezia|90|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Fetuccine integral de zanahoria, apto veganos 1kg|190|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Romanitos rellenos jamón y queso ex trabajadores de La Spezia 1kg|490|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Romanitos vegetarianos ex trabajadores de La Spezia 1kg|490|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Sorrentinos jamón y queso 1Kg ex trabajadores de La Spezia|450|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Sorrentinos Ricota y Nuez 1kg ex Trabajadores de La Spezia|450|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Raviolón vegetariano 1Kg ex trabajadores de La Spezia|450|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Raviolón Caprese 1kg ex Trabajadores de La Spezia|450|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Prepizza de 28cm ex trabajadores de La Spezia|85|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Milanesas de carne empanadas 1kg|365|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Milanesas de pollo empanadas 1kg|365|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Milanesas de seitan x6 |300|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Hamburguesas parrilleras de soja no transgénica, sal, harina de avena y adobo sin picante x6|300|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Jamón vegano (gluten de trigo, salsa de tomate, sabor ahumado, sal) horma 250 g|200|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Hummus 200cc |140|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Pate de zanahoria 200cc |140|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Pan rallado 1kg|55|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Pan rallado saborizado 1Kg|75|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Pimienta blanca 30g|20|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Orégano 25g|20|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Pimentón 30g|20|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Adobo 30g|20|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Ajo y Perejil 30g|20|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*PACK "A" Curry, nuez moscada, ajo polvo, condimento verde, comino|80|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*PACK "B" Pimienta Negra polvo / sal de ajo, aji molido, canela polvo y chimichurry|80|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*PACK "C" Cebolla en escamas, tomillo, clavo de olor, pimienta blanca en grano, ajo en escamas|80|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Pimentón 250grs |75|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Orégano 250g|85|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Nuez moscada entera 2 unidades |21|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Canela en rama 10g|21|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Cúrcuma 20g |21|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Pack "Sabores exoticos" - Paprika, fenogreco y cardamomo|57|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|'''''''*Pack "Pa''''''''l mate" - Manzanilla, cedrón y carqueja'''''''|105|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|Pack "Medicinas de monte" - Tilo, malva y marcela|105|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Pack "Té helado light" - Té rojo, stevia y lemon grass|105|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|Vino Santero Marselán 1 lt.|198|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|Vino Tannat-Cabernet Paso del Roble 1 lt.|90|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|Vino Rosado dulce Paso del Roble 1 lt.|90|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|Frizzante de Maracuyá|205|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|Frizzante de Frutos del bosque|205|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Cerveza artesanal Sudaka Blonde 500cc|100|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Cerveza artesanal Sudaka Scottish 500cc|100|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Cerveza artesanal Punto Rojo Red Ipa 500cc|100|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Cerveza artesanal Punto Rojo Negra 500cc|100|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Cerveza artesanal APA Guillotina 1L|180|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|Fernet artesanal 780 ml|370|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|Jugo en polvo "Juguito" sabores surtidos|8.06|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|Jugo Big C 200ml sabores surtidos|13.14|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Refresco U Naranja 2lt|82|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Refresco U Mandarina 2lt|82|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Refresco U Pomelo 2lt|82|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Refresco U Limonada 2lt|82|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Agua 6 lts|84|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Queso Muzzarella 1/2 kg Unidad Cooperaria|130|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Queso Magro s/sal 1/2 kg Unidad Cooperaria|147.5|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Queso Magro c/sal 1/2 kg Uniddad Cooperaria|147.5|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Queso Danbo 1/2 kg Unidad Cooperaria|137.5|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Queso Sbrinz 1/2 kg Unidad Cooperaria|170|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Queso Colonia 1/2 Kg Unidad Cooperaria|160|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Queso parrillero 350g Unidad Cooperaria|165|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Queso de mandioca en horma 400 gr|200|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Queso saborizado con ciboulette 600grs (envasado al vacío)|230|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Queso saborizado con albahaca 600grs (envasado al vacío)|230|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Queso saborizado con orégano 500grs (envasado al vacío)|250|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Queso semiduro 500grs (envasado al vacío) Productores Ismael Cortinas|195|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Queso cuartirolo horma 1kg envasado al vacío|270|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Queso rallado 100grs|63|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Queso rallado 200grs|120|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Dulce de Leche 1 Kg Unidad Cooperaria|165|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Dulce de leche de coco 360 gr|300|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Morrones en vinagre 330 gr|140|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Berenjenas en vinagre 330 gr|140|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Mermelada de morrones 250 gr|140|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Mermelada de frutilla, 450 grs. |123|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Mermelada de durazno, 450 grs.|110|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Mermelada de ciruela, 450 grs. |115|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Mermelada de higo, 450 grs. |110|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Mermelada de zapallo, 450 grs.|110|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Mermelada de naranja, 450 grs. |115|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Mermelada de arándanos, 450 grs. |145|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Dulce de membrillo, 900grs |105|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Dulce de batata con chocolate 1kg|115|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Dulce de zapallo 1kg|115|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|'''''''*Dulce de higo 1kg'''|115|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|Miel artesanal 1 kg|210|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Canasta de frutas y verduras "34 Sur Productos Orgánicos"|630|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Romero 25grs, El Ombú PTIc|45|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Apio 25grs, El Ombú PTIc|45|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Menta 25grs, El Ombú PTIc|45|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Melissa 25grs, El Ombú Ptic|45|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Albahaca limón, El Ombú Ptic|45|
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Llanten 25grs, El Ombú PTIc|45|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Preservativos Prudence clasico x3|59.09|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Tabaco Cerrito|99|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Hojilla JOB x30 |22|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Shampoo Ainé Cuidado Total 500cc|230|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Shampoo Ainé Brillo Extremo 500cc|230|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Acondicionador Ainé Cuidado Total 500cc |230|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Acondicionador Ainé Brillo Extremo 500cc |230|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Acondicionador Ainé Dos Minutos 500cc |230|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Shampoo Suave 930ml |144.09|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Acondicionador Suave 930ml |144.09|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Jabón de tocador IO, 80gs |12|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Cepillo dental Introdento (medio)|29.74|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Pasta Dental Introdento menta 102 grs. |36.72|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Loción repelente de mosquitos, 200 ml|210|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Pack x3 jabones glicerina vegetal Natura|330|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Desodorante ecológico apto veganos Natura|160|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Pasta Dental Libre de Flúor Natura|165|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Shampoo artesanal pelo graso 250ml Natura|235|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Shampoo artesanal pelo seco 250ml Natura|230|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Shampoo sólido cabello seco y normal 50gr |340|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Protector solar factor 65, 200 ml. NUEVO!!|550|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Shampoo sólido cabello graso 50gr |355|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Acondicionador sólido 50gr |350|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Cepillo dental de bambú 97% biodegradable (niños y adultos)|165|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Talco pédico 200gr |205|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Bálsamo labial Herencias de aquelarre (protege y repara) |180|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Detergente ecológico grupo Flores Silvestres 500 grs|90|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Jabón en polvo Bonsai 800g|70|Bonsai
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Jabón en polvo Bonsai 5kg|350|Bonsai
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Suavizante Bonsai 1lt|70|Bonsai
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Jabon liquido para lavarropas 900 cc Bonsai|80|Bonsai
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Jabon liquido para lavarropas 3 lts Bonsai|220|Bonsai
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Jabon liquido de Manos 500 cc Bonsai|50|Bonsai
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Perfumador de telas 250 cc Bonsai|100|Bonsai
|
||||
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
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Entrebichitos - MEN 2lts. (graseras, pozos, cañerías, plantas)|180|Entrebichitos
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Entrebichitos - MEN Limpieza 1lt (suelos, mesadas, paredes, combate hongos, bacterias y virus)|100|Entrebichitos
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Entrebichitos - Pastilla grasera|80|Entrebichitos
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Hipoclorito El Resistente 1800cc|66|El Resistente
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Limpiador perfumado El Resistente (perfumol) 1800cc|66|El Resistente
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Detergente El Resistente 500ml|43|El Resistente
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*KIT El Resistente (Hip./Perf./Det.)|161|El Resistente
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Jabon bulldog packx2|66.24|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Rejilla de cocina 40 x 27.5 Tacuabé (ex Paylana) cm|22|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Trapo de piso 55 x 55 Tacuabé (ex Paylana)|35|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Esponja de cocina|22|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Esponja de acero inoxidable|23|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Repasador de algodón 43 x 65 cm|39|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Franela 34 x 34|30|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Escoba|97|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Pala con mango|89|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Balde 9 Lts |99|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Bolsa de residuos 50x55 30 unidades |49|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Lampazo |99|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Guantes de latex talle M|80.1|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Rollitos de alumnio x6 |27.3|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Vela de apagón|8.37|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Vela de citronela 1 mecha|122.2|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Pastillas para mosquitos Sapolio 12 unidades |52.61|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Pañales Babysec ULTRA XXG 24 unidades|312|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Pañales Babysec ULTRA XG 24 unidades|312|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Pañales Babysec ULTRA G 30 unidades|312|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Pañales Babysec ULTRA M 36 unidades|312|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Pañales Babysec ULTRA P 36 unidades|312|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Toallita de bebé BabySec ultra 50un|67|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Papel Higienico: Higienol Texturado x4|47|
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Papel de Cocina Sussex extra x 2 -120 paños-|57|
|
||||
TEXTIL|*Calza licra de algodon talle S|750|
|
||||
TEXTIL|*Calza licra de algodon talle M|750|
|
||||
TEXTIL|*Calza licra de algodon talle L|750|
|
||||
TEXTIL|*Calza licra de algodon talle XL|750|
|
||||
TEXTIL|*Calza licra de algodon talle 0|300|
|
||||
TEXTIL|*Calza licra de algodon talle 2 |300|
|
||||
TEXTIL|*Calza licra de algodon talle 4|300|
|
||||
TEXTIL|*Calza licra de algodon talle 6 |300|
|
||||
TEXTIL|*Calza licra de algodon talle 8 |300|
|
||||
TEXTIL|*Calza licra de algodon talle 10|300|
|
||||
TEXTIL|*Calza licra de algodon talle 12|300|
|
||||
TEXTIL|*Calza licra de algodon talle 14 |350|
|
||||
TEXTIL|*Calza licra de algodon talle 16 |350|
|
||||
TEXTIL|*Campera deportiva - Talle 0|350|
|
||||
TEXTIL|*Campera deportiva - Talle 2|350|
|
||||
TEXTIL|*Campera deportiva - Talle 4|350|
|
||||
TEXTIL|*Campera deportiva - Talle 6|400|
|
||||
TEXTIL|*Campera deportiva - Talle 8|400|
|
||||
TEXTIL|*Campera deportiva - Talle 10|400|
|
||||
TEXTIL|*Campera deportiva - Talle 12|450|
|
||||
TEXTIL|*Campera deportiva - Talle 14|450|
|
||||
TEXTIL|*Campera deportiva - Talle 16|450|
|
||||
TEXTIL|*Pantalón deportivo - Talle 0|250|
|
||||
TEXTIL|*Pantalón deportivo - Talle 2|250|
|
||||
TEXTIL|*Pantalón deportivo - Talle 4|250|
|
||||
TEXTIL|*Pantalón deportivo - Talle 6|300|
|
||||
TEXTIL|*Pantalón deportivo - Talle 8|300|
|
||||
TEXTIL|*Pantalón deportivo - Talle 10|300|
|
||||
TEXTIL|*Pantalón deportivo - Talle 12|350|
|
||||
TEXTIL|*Pantalón deportivo - Talle 14|350|
|
||||
TEXTIL|*Pantalón deportivo - Talle 16|350|
|
||||
TEXTIL|*Babucha deportiva en algodón - Talle 4|500|
|
||||
TEXTIL|*Babucha deportiva en algodón - Talle 6|500|
|
||||
TEXTIL|*Babucha deportiva en algodón - Talle 8 |500|
|
||||
TEXTIL|*Babucha deportiva en algodón - Talle 10 |600|
|
||||
TEXTIL|*Babucha deportiva en algodón - Talle 12 |600|
|
||||
TEXTIL|*Babucha deportiva en algodón - Talle 14 |600|
|
||||
TEXTIL|*Babucha deportiva en algodón - Talle 16 |600|
|
||||
TEXTIL|*Babucha deportiva en algodón - Talle 18 |600|
|
||||
TEXTIL|*Pantalón deportivo liso de algodón - Talle S|850|
|
||||
TEXTIL|*Pantalón deportivo liso de algodón - Talle M|850|
|
||||
TEXTIL|*Pantalón deportivo liso de algodón - Talle L|850|
|
||||
TEXTIL|*Pantalón deportivo liso de algodón - Talle XL |850|
|
||||
TEXTIL|*Canguro deportivo liso con capucha de algodón - TalleS |1000|
|
||||
TEXTIL|*Canguro deportivo liso con capucha de algodón - Talle M |1000|
|
||||
TEXTIL|*Canguro deportivo liso con capucha de algodón - Talle L |1000|
|
||||
TEXTIL|*Canguro deportivo liso con capucha de algodón - Talle XL|1000|
|
||||
TEXTIL|*Túnica niñe con cinto en espalda y tajo detrás- talles 6 a 16|480|
|
||||
TEXTIL|*Túnica niñe con martingala, festón y pinzas talles 6 a 16|480|
|
||||
TEXTIL|*Pintor verde - talles 2 a 8|300|
|
||||
TEXTIL|*Pintor azul - talles 2 a 8|300|
|
||||
TEXTIL|*Pintor rojo - talles 2 a 8|300|
|
||||
TEXTIL|*Pintor amarillo - talles 2 a 8|300|
|
||||
TEXTIL|*Túnicas adulto - talles 1 a 5|1100|
|
||||
TEXTIL|*Moña escolar satinada|50|
|
||||
TEXTIL|*Juego de sábanas de algodón 1 plaza|1000|
|
||||
TEXTIL|*Juego de sábanas de algodón 2 plazas (para sommier) |1200|
|
||||
TEXTIL|*Sábana sola sin elástico, 2 plazas (para sommier) |700|
|
||||
TEXTIL|*Sábana sola con elástico, 2 plazas (para sommier) |700|
|
||||
TEXTIL|*Juego de toallón y toalla de algodón |650|
|
||||
TEXTIL|*Toallón|500|
|
||||
TEXTIL|*Toalla de mano|250|
|
||||
TEXTIL|*Turbante toalla|350|
|
||||
TEXTIL|*Tapaboca de tela|50|
|
||||
ARTÍCULOS DE MADRES Y FAMILIARES|Pañuelo Madres y Familiares de Detenidos Desaparecidos|50|Madres y familiares
|
||||
ARTÍCULOS DE MADRES Y FAMILIARES|Balconera Madres y Familiares de Detenidos Desaparecidos|100|Madres y familiares
|
||||
ARTÍCULOS DE MADRES Y FAMILIARES|Pack 2 - 1 Pin redondo + Lapicera + Pegotines y Marcalibros|100|Madres y familiares
|
||||
PRODUCTOS DEL MPS|Pack de 5 pegotines del MPS (2 logos y 3 consignas, todo a color).|40|Madres y familiares
|
||||
BONOS Y FINANCIAMIENTO SORORO|Campaña solidaria MPS - apoyo a ollas y merenderos|20|MPS
|
||||
BONOS Y FINANCIAMIENTO SORORO|Financiamiento sororo para copa menstrual|20|
|
||||
BONOS Y FINANCIAMIENTO SORORO|Galpón de corrales|20|
|
||||
PRODUCTOS DE GESTIÓN MENSTRUAL|Copa menstrual de silicona, ecológica |750|
|
||||
PRODUCTOS DE GESTIÓN MENSTRUAL|Copa menstrual de silicona, ecológica (financiamiento sororo)|0|
|
||||
PRODUCTOS DE GESTIÓN MENSTRUAL|Vaso esterilizador para copa menstrual|290|
|
||||
PRODUCTOS DE GESTIÓN MENSTRUAL|*Toallita de tela Nocturna "Chúlin"|170|Chúlin
|
||||
PRODUCTOS DE GESTIÓN MENSTRUAL|*Toallita de tela para Colaless "Chúlin"|170|Chúlin
|
||||
PRODUCTOS DE GESTIÓN MENSTRUAL|*Toallitas de tela para Bombacha "Chúlin"|200|Chúlin
|
||||
PRODUCTOS DE GESTIÓN MENSTRUAL|*Protector Diario de tela "Chúlin"|160|Chúlin
|
||||
PRODUCTOS DE GESTIÓN MENSTRUAL|*Pack 1: 2 protectores diarios + 2 toallitas para bombacha "Chúlin"|610|Chúlin
|
||||
PRODUCTOS DE GESTIÓN MENSTRUAL|*Pack 2: 3 protectores diarios "Chúlin" |410|Chúlin
|
||||
PRODUCTOS DE GESTIÓN MENSTRUAL|Ladysoft Clasicas 8un|20.3|
|
||||
PRODUCTOS DE GESTIÓN MENSTRUAL|Tampones Medianos Ladysoft 10un|84.7|
|
||||
PRODUCTOS DE GESTIÓN MENSTRUAL|Tampones Grandes Ladysoft 10un|84.7|
|
||||
Tipo|Producto|Precio
|
||||
ALIMENTOS NO PERECEDEROS||
|
||||
P|Yerba Compuesta La Herboristería 1kg|157.63
|
||||
P|Yerba Yusa tradicional 1kg|148.00
|
||||
P|Yerba Yusa tradicional 500grs|81.00
|
||||
P|Yerba Sara tradicional 1kg (Sin TACC)|139.40
|
||||
P|Yerba Sara suave 1kg (Sin TACC)|139.40
|
||||
P|*Harina Santa Unión 000 1kg|33.11
|
||||
P|*Harina Santa Unión 0000 1kg|38.70
|
||||
P|*Harina de arroz Pasaná 1 kg (Puede contener gluten)|90.00
|
||||
P|*Harina de Garbanzos Pasaná 1 kg (Puede contener gluten)|140.00
|
||||
P|*Mezcla para faina Pasaná 1 kg (Puede contener gluten)|160.00
|
||||
P|*Fécula de Mandioca Pasaná 1 kg (Puede contener gluten)|140.00
|
||||
P|Fécula de Mandioca Hornex 800g (Sin TACC)|125.00
|
||||
P|Tres Harinas Hornex 800grs (Sin TAAC)|129.00
|
||||
P|*Harina Santa Unión 000 Bolsa 25kg|602.86
|
||||
P|*Polenta Santa Unión 450gr|16.34
|
||||
P|*Mezcla de Fainá Santa Unión 5kg|431.29
|
||||
P|*Harina de trigo intergal orgánica "La linda sauceña"|97.00
|
||||
P|*Fideos Caorsi Tirabuzón 1kg|73.00
|
||||
P|*Fideos Caorsi Tallarín 1kg|81.00
|
||||
P|*Fideos Caorsi Moñita 1kg|81.00
|
||||
P|*Fideos Caorsi Tirabuzón 5kg|353.00
|
||||
P|Arroz Blue Patna 1kg|50.02
|
||||
P|Arroz Shiva 1kg|35.65
|
||||
P|*Arroz integral 1kg|72.00
|
||||
P|*Arroz integral 3kg|204.00
|
||||
P|Aceite Condesa de Soja 900 cc.|59.80
|
||||
P|Aceite Uruguay de Girasol 900 cc.|81.70
|
||||
P|Aceite Optimo canola 900 cc.|75.00
|
||||
P|Vinagre Uruguay 900ml|61.60
|
||||
P|*Salsa de soja La Posta 250 ml.|120.00
|
||||
P|*Aceitunas verdes sin carozo en frasco La Posta 500 gr.|220.00
|
||||
P|*Aceitunas negras sin carozo en frasco La Posta 500 gr.|240.00
|
||||
P|Lata de atún Golden Fish desmenuzado al aceite 170g|33.35
|
||||
P|Lata de arvejas Campero 300g|18.28
|
||||
P|Lata de choclo Cosecha 300g|32.29
|
||||
P|Lata de jardinera Cosecha|30.34
|
||||
P|Lata de porotos negros Cosecha|37.06
|
||||
P|Lata de porotos de frutilla Cosecha|37.06
|
||||
P|Lata de duraznos en almíbar Campero|73.07
|
||||
P|Mayonesa Uruguay 500g|81.40
|
||||
P|Azúcar Bella Unión 1kg|44.90
|
||||
P|Azúcar Mascabo 500g|102.00
|
||||
P|Azúcar impalpable Hornex 200 gr|39.00
|
||||
P|Almidón de maíz Hornex 1Kg|89.00
|
||||
P|Almidón de maíz Ilu wayra 1Kg|75.00
|
||||
P|Polvo de Hornear Hornex 100 g + 20 g|38.00
|
||||
P|*Esencia de vainilla La Posta 100ml|100.00
|
||||
P|*Bicarbonato de sodio La Posta 250 gr|60.00
|
||||
P|Grasa Uruguay 400grs|45.80
|
||||
P|Levadura seca Hornex 125g|120.00
|
||||
P|Café Sorocabana glaseado p/máquina 500 grs|396.00
|
||||
P|Café Sorocabana natural p/máquina 500 grs|557.00
|
||||
P|Café soluble Saint bollón 170 gr|232.50
|
||||
P|Té Negro en hebras 90gr hornimans|41.12
|
||||
P|Galletas de arroz SIN SAL Natural Rice 120 gr (Sin TACC)|39.00
|
||||
P|Galletas de arroz comunes Natural Rice 120 gr (Sin TACC)|39.00
|
||||
P|Leche en polvo entera 250 g|105.00
|
||||
P|Leche en polvo entera 1kg|315.00
|
||||
P|* Coco rallado 200gr|72.00
|
||||
P|* Coco rallado 1kg|246.00
|
||||
P|Cocoa Hornex 200gr|55.00
|
||||
P|Postre de chocolate Hornex 8 porciones|44.00
|
||||
P|Postre LIGHT de vainilla Hornex 8 porciones (aprobado por ADU)|68.00
|
||||
P|Flan de vainilla Hornex 8 porciones|44.00
|
||||
P|Gelatina de frutilla Hornex 8 porciones|44.00
|
||||
P|Bizcochuelo de vainilla SIN GLUTEN 500gr Hornex|180.00
|
||||
P|Pizza SIN GLUTEN 320gr Hornex|170.00
|
||||
P|Pulpa de Tomate De Ley 1lt (S-G)|50.43
|
||||
P|Pure de papa instantaneo De Ley 125g|24.73
|
||||
P|*Sal fina sin fluor Polenteados 500g|36.00
|
||||
P|*Sal gruesa sin fluor Polenteados 500g|36.00
|
||||
P|*Sal Rosa 250gr |80.00
|
||||
P|*Salsa de tomate casera (puro tomate) 1 lt - (S-G) - azucar agregada: 1g/L - sal agregada: 0,25g/L|85.00
|
||||
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
|
||||
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
|
||||
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
|
||||
P|*Granola simple (avena+ girasol+ pasaUva) 1kg|171.00
|
||||
P|*Copos de maíz azucarados 500g|112.00
|
||||
P|*Copos de maíz naturales 500g|112.00
|
||||
P|*Crema untable de maní 330 gr, envase de vidrio |225.00
|
||||
P|*Tableta artesanal chocolate semiamargo con frutos secos 100g |130.00
|
||||
P|*Tableta artesanal chocolate semiamargo con pasas 100g |130.00
|
||||
P|*Tableta artesanal chocolate blanco con frutos secos 100g |130.00
|
||||
P|*Tableta artesanal chocolate blanco con pasas 100g |130.00
|
||||
P|Alfajor de chocolate negro 80 g (S-G) |48.00
|
||||
P|Galletitas dulces de chispas de chocolate y avena 150 g (S-G)|116.00
|
||||
P|Crackers saladas de sésamo girasol y chía 180 g (S-G)|116.00
|
||||
P|*Lino 1/4 kg|42.00
|
||||
P|*Chía 1/4 kg|80.00
|
||||
P|*Girasol 1/2 kg|140.00
|
||||
P|*Sésamo 1/4 kg|65.00
|
||||
P|*Quinoa 1 kg|210.00
|
||||
P|*Dátiles con carozo 500 gr|240.00
|
||||
P|*Cacao en polvo 250 grs (S-A)|125.00
|
||||
P|*Almendra pelada (sin tostar) Polenteados 100g|93.00
|
||||
P|*Pasas de Uva Polenteados 500 gr|149.00
|
||||
P|*Nueces Polenteados 100g|89.00
|
||||
P|*Castañas tostadas SIN sal 100grs|81.00
|
||||
P|*Avena laminada instantánea Polenteados 500g|69.00
|
||||
P|*Pan de molde Gory Lacteado 550g|64.00
|
||||
P|*Pan de molde Integral Gory 550g|64.00
|
||||
P|*Galleta Malteada La Socialista 350g|84.00
|
||||
P|*Galleta Malteada c/semillas (sésamo, chia, lino) La Socialista 380gr|103.00
|
||||
P|*Galleta Cara Sucia La Socialista 350g|92.00
|
||||
P|*Grisines La Socialista 350g|96.00
|
||||
P|*Maní pelado frito y salado Polenteados 500g|103.00
|
||||
P|*Maní pelado sin sal Polenteados 500g|103.00
|
||||
P|*Garbanzo Polenteados 1kg|109.00
|
||||
P|* Maiz para pop 500grs|54.00
|
||||
P|*Lentejas Polenteados 1kg|125.00
|
||||
P|*Porotos negros Polenteados 1kg|125.00
|
||||
P|*Porotos de manteca Polenteados 1kg|149.00
|
||||
P|*Porotos mung 1kg |150.00
|
||||
P|*Arvejas 1kg |120.00
|
||||
P|*Proteína de SOJA texturizada 1kg|139.00
|
||||
P|*Semillas Zapallo 100g.|60.00
|
||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS||
|
||||
P|*Tallarines frescos de yema Pastas Colon 1kg|175.00
|
||||
P|*Tallarines frescos de espinaca Pastas Colon 1kg|185.00
|
||||
P|*Tallarines frescos de morrón Pastas Colon 1kg|190.00
|
||||
P|*Prepizza 28cm ex trabajadores de La Spezia|90.00
|
||||
P|*Milanesas de carne 1kg|395.00
|
||||
P|*Milanesas de pollo 1kg|370.00
|
||||
P|*Empanada de pollo x 6|265.00
|
||||
P|*Empanada de carne x 6|265.00
|
||||
P|*Pan rallado 1kg|75.00
|
||||
P|*Pan rallado saborizado 1Kg|95.00
|
||||
P|*Pimienta blanca 30g|20.00
|
||||
P|*Orégano 25g|20.00
|
||||
P|*Pimentón 30g|20.00
|
||||
P|*Adobo 30g|20.00
|
||||
P|*Ajo y Perejil 30g|20.00
|
||||
P|*Clavo de olor 15g|20.00
|
||||
P|*Tomillo 25g|20.00
|
||||
P|*PACK "A" Curry / Nuez moscada / Ajo en polvo / Condimento verde / Comino|100.00
|
||||
P|*PACK "B" Pimienta Negra polvo / Sal de ajo / Aji molido / Canela en polvo / Condimento para arroz|100.00
|
||||
P|*PACK "C" Cebolla en polvo / Pimienta blanca en grano / Pimienta negra en grano / Ajo en escamas / Especias surtidas|100.00
|
||||
P|*Pimentón 250grs|110.00
|
||||
P|*Orégano 250g|115.00
|
||||
P|*Nuez moscada entera 2 unidades|28.00
|
||||
P|*Canela en rama 10g|25.00
|
||||
P|*Cúrcuma 20g|25.00
|
||||
P|*Pack "Mix sabores"- Paprika, Albahaca, Mostaza en polvo.|65.00
|
||||
P|*Pack "Pal mate"- Boldo, Cedron, Marcela.|120.00
|
||||
P|*Pack "Relax"- Tilo, Malva, Té rojo.|120.00
|
||||
P|*Pack "Power" - Ginseng, Carqueja, Ginkgo biloba.|120.00
|
||||
P|Atado de perejil|50.00
|
||||
P|Mix de hierbas (ciboullete, tomillo, laurel y pasto lim[on)|50.00
|
||||
P|Atado de romero|50.00
|
||||
P|Fernet 760 ml|405.00
|
||||
P|Vino Santero Marselán 1 lt.|235.00
|
||||
P|Frizzante de Maracuyá|246.00
|
||||
P|Frizzante de Frutos del bosque|246.00
|
||||
P|*Cerveza artesanal APA Press 1L|170.00
|
||||
P|* Cerveza artesanal IPA Press 1L |180.00
|
||||
P|*Cerveza artesanal Negra Press 1L|180.00
|
||||
P|* Cerveza artesanal Rubia Lager 1L |160.00
|
||||
P|Jugo en polvo "Juguito" sabores surtidos|8.00
|
||||
P|Jugo Big C 200ml sabores surtidos|16.84
|
||||
P|*Refresco U Naranja 2lt|94.00
|
||||
P|*Refresco U Mandarina 2lt|94.00
|
||||
P|*Refresco U Pomelo 2lt|94.00
|
||||
P|*Refresco U Limonada 2lt|94.00
|
||||
P|*Agua 6 lts|98.00
|
||||
P|*Queso Muzzarella 1/2 kg Unidad Cooperaria|172.00
|
||||
P|*Queso Magro s/sal 1/2 kg Unidad Cooperaria|191.00
|
||||
P|*Queso Magro c/sal 1/2 kg Unidad Cooperaria|191.00
|
||||
P|*Queso Danbo 1/2 kg Unidad Cooperaria|188.00
|
||||
P|*Queso Sbrinz 1/2 kg Unidad Cooperaria|287.00
|
||||
P|*Queso Colonia 1/2 Kg Unidad Cooperaria|197.00
|
||||
P|*Queso parrillero 350g Unidad Cooperaria|177.00
|
||||
P|*Queso semiduro 500grs (envasado al vacío) Productores Ismael Cortinas|258.00
|
||||
P|*Queso cuartirolo horma 1kg envasado al vacío|375.00
|
||||
P|*Queso rallado 200grs|155.00
|
||||
P|*Dulce de Leche 1 Kg Unidad Cooperaria|269.00
|
||||
P|*Morrones en vinagre 330 gr|230.00
|
||||
P|*Berenjenas en vinagre 330 gr|230.00
|
||||
P|*Mermelada de morrones 250 gr|230.00
|
||||
P|*Mermelada de frutilla, 450 grs.|145.00
|
||||
P|*Mermelada de durazno, 450 grs.|133.00
|
||||
P|*Mermelada de ciruela, 450 grs.|133.00
|
||||
P|*Mermelada de higo, 450 grs.|133.00
|
||||
P|*Mermelada de zapallo, 450 grs.|133.00
|
||||
P|*Mermelada de naranja, 450 grs.|134.00
|
||||
P|*Mermelada de arándanos, 450 grs.|159.50
|
||||
P|*Dulce de membrillo, 900grs|123.00
|
||||
P|*Dulce de batata con chocolate 1kg|154.00
|
||||
P|*Dulce de zapallo 1kg|139.00
|
||||
P|*Dulce de higo 1kg|134.00
|
||||
P|*Miel artesanal 500g|130.00
|
||||
P|*Miel artesanal 1 kg|240.00
|
||||
P|*Canasta de frutas y verduras "34 Sur Productos Orgánicos"|630.00
|
||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA||
|
||||
P|Preservativos Prime ultrafinos x3|89.70
|
||||
P|Preservativos Kamasutra x3|34.00
|
||||
P|Tabaco Cerrito|125.67
|
||||
P|Hojilla JOB x30|28.36
|
||||
P|Shampoo Suave 930ml|123.00
|
||||
P|Acondicionador Suave 930ml|123.00
|
||||
P|Jabón de tocador IO, 80gs|16.60
|
||||
P|Cepillo dental kolynos máster. |28.00
|
||||
P|Pasta Dental kolynos 180 grs. |49.00
|
||||
P|Pastillas para mosquitos Fuyi x 12|98.30
|
||||
P|*Pack x3 jabones glicerina vegetal Natura|380.00
|
||||
P|*Shampoo artesanal pelo seco 250ml Natura|250.00
|
||||
P|*Desodorante ecológico apto veganos Natura|190.00
|
||||
P|*Shampoo artesanal pelo graso 250ml Natura|250.00
|
||||
P|*Barrita quita manchas 75 gr Natura|100.00
|
||||
P|*Aromatizador ambiental fragancia floral de varilla Natura, 100ml |345.00
|
||||
P|*Aromatizador ambiental fragancia cítrica de varilla Natura, 100ml |345.00
|
||||
P|*Talco pédico Natura, 200gr|235.00
|
||||
P|*Repelente Natura, 125ml|245.00
|
||||
P|*Shampoo pediculosis, envase 250 ml|320.00
|
||||
P|*Jabón en polvo Bonsai 800g|95.00
|
||||
P|*Jabón en polvo Bonsai 5kg|550.00
|
||||
P|*Suavizante Bonsai 1lt|80.00
|
||||
P|*Jabon liquido para lavarropas 900 cc Bonsai|85.00
|
||||
P|*Jabon liquido para lavarropas 3 lts Bonsai|270.00
|
||||
P|*Jabon liquido de Manos 500 cc Bonsai|60.00
|
||||
P|*Perfumador de telas 250 cc Bonsai|120.00
|
||||
P|*Limpiador desengarsante para cocinas y baños aroma cítrico 1 litro (no es para cañerías)|120.00
|
||||
P|*Limpiador cremoso 650 cc *|120.00
|
||||
P|*Entrebichitos - MEN 2lts. (graseras, pozos, cañerías, plantas)|180.00
|
||||
P|*Entrebichitos - MEN Limpieza 1lt (suelos, mesadas, paredes, combate hongos, bacterias y virus)|100.00
|
||||
P|*Entrebichitos - Pastilla grasera|80.00
|
||||
P|*Hipoclorito El Resistente 1800cc|76.00
|
||||
P|*Limpiador perfumado El Resistente (perfumol) 1800cc|76.00
|
||||
P|*Detergente El Resistente 500ml|51.00
|
||||
P|*KIT El Resistente (Hip./Perf./Det.)|188.00
|
||||
P|Jabon en barra Primor x1|29.36
|
||||
P|Rejilla de cocina 40 x 27.5 Tacuabé (ex Paylana) cm|36.00
|
||||
P|Trapo de piso 53 x 53 Tacuabé (ex Paylana)|36.00
|
||||
P|Esponja de cocina|26.00
|
||||
P|Esponja de acero inoxidable|29.00
|
||||
P|Repasador de algodón 43 x 65 cm|53.00
|
||||
P|Franela 34 x 34|37.00
|
||||
P|Escoba|116.00
|
||||
P|Pala con mango|99.00
|
||||
P|Balde 9 Lts|109.00
|
||||
P|Bolsa de residuos 50x55 30 unidades|63.00
|
||||
P|Lampazo|119.00
|
||||
P|Rollitos de aluminio Griselda x12|38.30
|
||||
P|rollitos de aluminio jaspe x6|30.00
|
||||
P|*Vela de apagón|8.40
|
||||
P|*Vela de citronela 1 mecha|132.80
|
||||
P|Toallita de bebé BabySec ultra 50un|83.00
|
||||
P|Papel Higienico: Higienol Texturado x4|42.00
|
||||
P|Papel de Cocina Sussex extra x 2 -120 paños-|72.00
|
||||
P|Pañales Babysec ULTRA (Celeste) XXG 24 unidades |448.00
|
||||
P|Pañales Babysec ULTRA (Celeste) XG 24 unidades|448.00
|
||||
P|Pañales Babysec ULTRA (Celeste) G 30 unidades|448.00
|
||||
P|Pañales Babysec ULTRA (Celeste) M 36 unidades|448.00
|
||||
P|Pañales Babysec ULTRA (Celeste) P 36 unidades|448.00
|
||||
P|Pañales Babysec PREMIUM (Violeta) XXG 48 unidades|790.00
|
||||
P|Pañales Babysec PREMIUM (Violeta) XG 48 unidades|790.00
|
||||
P|Pañales Babysec PREMIUM (Violeta) G 60 unidades|790.00
|
||||
P|Pañales Babysec PREMIUM (Violeta) M 68 unidades|790.00
|
||||
P|Pañales para Adultes INCOPROTECT TALLE M|579.00
|
||||
P|Pañales para Adultes INCOPROTECT TALLE G |617.00
|
||||
P|Pañales para Adultes INCOPROTECT TALLE EXTRA G |743.00
|
||||
TEXTIL||
|
||||
PTC|*Calza licra de algodon talle S|900.00
|
||||
PTC|*Calza licra de algodon talle M|900.00
|
||||
PTC|*Calza licra de algodon talle L|900.00
|
||||
PTC|*Calza licra de algodon talle XL|900.00
|
||||
PTC|*Biker licra de algodón - Talle S |650.00
|
||||
PTC|*Biker licra de algodón - Talle M |650.00
|
||||
PTC|*Biker licra de algodón - Talle L |650.00
|
||||
PTC|*Biker licra de algodón - Talle XL |650.00
|
||||
PTC|*Biker licra de algodón - Talle 0 |350.00
|
||||
PTC|*Biker licra de algodón - Talle 2 |350.00
|
||||
PTC|*Biker licra de algodón - Talle 4 |350.00
|
||||
PTC|*Biker licra de algodón - Talle 6 |400.00
|
||||
PTC|*Biker licra de algodón - Talle 8 |400.00
|
||||
PTC|*Biker licra de algodón - Talle 10 |400.00
|
||||
PTC|*Biker licra de algodón - Talle 12 |500.00
|
||||
PTC|*Biker licra de algodón - Talle 14 |500.00
|
||||
PTC|*Biker licra de algodón - Talle 16 |500.00
|
||||
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
|
||||
PTC|*Calza licra de algodon talle 0|350.00
|
||||
PTC|*Calza licra de algodon talle 2|350.00
|
||||
PTC|*Calza licra de algodon talle 4|350.00
|
||||
PTC|*Calza licra de algodon talle 6|450.00
|
||||
PTC|*Calza licra de algodon talle 8|450.00
|
||||
PTC|*Calza licra de algodon talle 10|450.00
|
||||
PTC|*Calza licra de algodon talle 12|550.00
|
||||
PTC|*Calza licra de algodon talle 14|550.00
|
||||
PTC|*Calza licra de algodon talle 16|550.00
|
||||
PTC|*Campera deportiva - Talle 0|400.00
|
||||
PTC|*Campera deportiva - Talle 2|400.00
|
||||
PTC|*Campera deportiva - Talle 4|400.00
|
||||
PTC|*Campera deportiva - Talle 6|450.00
|
||||
PTC|*Campera deportiva - Talle 8|450.00
|
||||
PTC|*Campera deportiva - Talle 10|450.00
|
||||
PTC|*Campera deportiva - Talle 12|500.00
|
||||
PTC|*Campera deportiva - Talle 14|500.00
|
||||
PTC|*Campera deportiva - Talle 16|500.00
|
||||
PTC|*Pantalón deportivo - Talle 0|300.00
|
||||
PTC|*Pantalón deportivo - Talle 2|300.00
|
||||
PTC|*Pantalón deportivo - Talle 4|300.00
|
||||
PTC|*Pantalón deportivo - Talle 6|350.00
|
||||
PTC|*Pantalón deportivo - Talle 8|350.00
|
||||
PTC|*Pantalón deportivo - Talle 10|350.00
|
||||
PTC|*Pantalón deportivo - Talle 12|400.00
|
||||
PTC|*Pantalón deportivo - Talle 14|400.00
|
||||
PTC|*Pantalón deportivo - Talle 16|400.00
|
||||
PTC|*Buzo deportivo de verano para adultes - Talle S |1000.00
|
||||
PTC|*Buzo deportivo de verano para adultes - Talle M |1000.00
|
||||
PTC|*Buzo deportivo de verano para adultes - Talle L |1000.00
|
||||
PTC|*Buzo deportivo de verano para adultes - Talle XL |1000.00
|
||||
PTC|*Pantalón deportivo de verano para adultes - Talle S |900.00
|
||||
PTC|*Pantalón deportivo de verano para adultes - Talle M |900.00
|
||||
PTC|*Pantalón deportivo de verano para adultes - Talle L |900.00
|
||||
PTC|*Pantalón deportivo de verano para adultes - Talle XL |900.00
|
||||
P|*Juego de sábanas de algodón 1 plaza|1300.00
|
||||
P|*Juego de sábanas de algodón 2 plazas (para sommier)|1500.00
|
||||
P|*Materas de Lona.|450.00
|
||||
P|*Sábana sola con elástico, 2 plazas (para sommier)|950.00
|
||||
P|*Juego de toallón y toalla de algodón|900.00
|
||||
P|*Toallón|750.00
|
||||
P|*Toalla de mano|350.00
|
||||
P|*Turbante toalla|450.00
|
||||
P|*Juego de Sábanas de poliéster 1 plaza |850.00
|
||||
P|*Juego de sábanas de poliéster 2 plazas |1000.00
|
||||
MADRES Y FAMILIARES||
|
||||
PTC|Camiseta EDICION ESPECIAL - talles S al XXL|450.00
|
||||
PTC|Canguros Madres y Familiares |950.00
|
||||
P|Pack 1: 1 pin redondo + 1 lapicera + 1 Pañuelo + Pegotines y marcalibros|150.00
|
||||
P|Pack 2: 1 Pin redondo + 1 Lapicera + Pegotines y marcalibros|100.00
|
||||
P|Pack 3: 1 Llavero + 1 Lapicera|100.00
|
||||
P|Libro "Desaparecidos"|50.00
|
||||
ARTÍCULOS DE LA COORDINADORA POR PALESTINA||
|
||||
B|Bono colaboración|20.00
|
||||
P|Remera talle S - Palestina|450.00
|
||||
P|Remera talle M - Palestina|450.00
|
||||
P|Remera talle L - Palestina|450.00
|
||||
P|Remera talle XL - Palestina|450.00
|
||||
P|Bandera 60x90 cm - Coordinadora por Palestina|450.00
|
||||
P|Pin Coordinadora por Palestina|40.00
|
||||
P|Balconera "Paremos el genocidio"|150.00
|
||||
P|Banderita para el auto |100.00
|
||||
P|Kit 5 pegotines - Coordinadora por Palestina|80.00
|
||||
P|Remera talle S - Palestina - Puño - único color Negro *NUEVO|500.00
|
||||
P|Remera talle M - Palestina - Puño - único color Negro *NUEVO|500.00
|
||||
P|Remera talle L - Palestina - Puño - único color Negro *NUEVO|500.00
|
||||
P|Remera talle XL - Palestina - Puño - único color Negro *NUEVO|500.00
|
||||
PRODUCTOS ESPECIALES Y DE FIN DE AÑO||
|
||||
P|*Cuaderno artesanal 80 hojas rayado|100.00
|
||||
P|*Cuaderno artesanal 80 hojas liso|100.00
|
||||
P|*Cuaderno artesanal 200 hojas rayado|180.00
|
||||
P|*Cuaderno artesanal 200 hojas liso|180.00
|
||||
P|*Agenda 2025 NUEVO!|420.00
|
||||
P|Gorro del MPS - Ciudad Vieja NUEVO!|150.00
|
||||
P|*Papas con sal 230 gr NUEVO!|154.00
|
||||
P|*Papas sin sal 250 gr NUEVO!|154.00
|
||||
P|Turrón Portezuelo Blando 70g NUEVO!|39.67
|
||||
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.
|
31
resources/js/app.js
vendored
31
resources/js/app.js
vendored
|
@ -3,10 +3,13 @@
|
|||
* includes Vue and other libraries. It is a great starting point when
|
||||
* building robust, powerful web applications using Vue and Laravel.
|
||||
*/
|
||||
|
||||
require('./bootstrap');
|
||||
import axios from 'axios';
|
||||
import Vue from '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
|
||||
|
@ -15,18 +18,28 @@ window.Vue = require('vue');
|
|||
*
|
||||
* Eg. ./components/ExampleComponent.vue -> <example-component></example-component>
|
||||
*/
|
||||
import './components';
|
||||
import store from "./store";
|
||||
|
||||
// const files = require.context('./', true, /\.vue$/i)
|
||||
// files.keys().map(key => Vue.component(key.split('/').pop().split('.')[0], files(key).default))
|
||||
|
||||
Vue.component('example-component', require('./components/ExampleComponent.vue').default);
|
||||
/**
|
||||
* Global methods
|
||||
*/
|
||||
Vue.prototype.$toast = function (mensaje, duration = 2000) {
|
||||
return window.bulmaToast.toast({
|
||||
message: mensaje,
|
||||
duration: duration,
|
||||
type: 'is-danger',
|
||||
position: 'bottom-center',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Next, we will create a fresh Vue application instance and attach it to
|
||||
* the page. Then, you may begin adding components to this application
|
||||
* or customize the JavaScript scaffolding to fit your unique needs.
|
||||
*/
|
||||
|
||||
const app = new Vue({
|
||||
el: '#app',
|
||||
new Vue({
|
||||
el: '#root',
|
||||
store,
|
||||
});
|
||||
|
||||
|
|
41
resources/js/bootstrap.js
vendored
41
resources/js/bootstrap.js
vendored
|
@ -1,41 +0,0 @@
|
|||
window._ = require('lodash');
|
||||
|
||||
/**
|
||||
* We'll load jQuery and the Bootstrap jQuery plugin which provides support
|
||||
* for JavaScript based Bootstrap features such as modals and tabs. This
|
||||
* code may be modified to fit the specific needs of your application.
|
||||
*/
|
||||
|
||||
try {
|
||||
window.Popper = require('popper.js').default;
|
||||
window.$ = window.jQuery = require('jquery');
|
||||
|
||||
require('bootstrap');
|
||||
} catch (e) {}
|
||||
|
||||
/**
|
||||
* We'll load the axios HTTP library which allows us to easily issue requests
|
||||
* to our Laravel back-end. This library automatically handles sending the
|
||||
* CSRF token as a header based on the value of the "XSRF" token cookie.
|
||||
*/
|
||||
|
||||
window.axios = require('axios');
|
||||
|
||||
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
|
||||
|
||||
/**
|
||||
* Echo exposes an expressive API for subscribing to channels and listening
|
||||
* for events that are broadcast by Laravel. Echo and event broadcasting
|
||||
* allows your team to easily build robust real-time web applications.
|
||||
*/
|
||||
|
||||
// import Echo from 'laravel-echo';
|
||||
|
||||
// window.Pusher = require('pusher-js');
|
||||
|
||||
// window.Echo = new Echo({
|
||||
// broadcaster: 'pusher',
|
||||
// key: process.env.MIX_PUSHER_APP_KEY,
|
||||
// cluster: process.env.MIX_PUSHER_APP_CLUSTER,
|
||||
// forceTLS: true
|
||||
// });
|
25
resources/js/components.js
vendored
Normal file
25
resources/js/components.js
vendored
Normal 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
|
||||
);
|
||||
});
|
28
resources/js/components/AppLogin.vue
Normal file
28
resources/js/components/AppLogin.vue
Normal file
|
@ -0,0 +1,28 @@
|
|||
<script>
|
||||
import LoginInput from "./login/LoginInput.vue";
|
||||
import LoginLoginTitulos from "./login/LoginTitulos.vue";
|
||||
import { mapGetters } from "vuex";
|
||||
import LoginDropdown from "./login/LoginDropdown.vue";
|
||||
|
||||
export default {
|
||||
name: 'LoginForm',
|
||||
components: { LoginDropdown, LoginTitulos: LoginLoginTitulos, LoginInput },
|
||||
computed: {
|
||||
...mapGetters("login", ["estilos"])
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div id="login-form" :class="estilos.fondo">
|
||||
<section class="section">
|
||||
<div class="columns is-centered">
|
||||
<div class="column is-half">
|
||||
<login-dropdown class="is-hidden-tablet"/>
|
||||
<login-titulos/>
|
||||
<login-input/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
35
resources/js/components/AppMain.vue
Normal file
35
resources/js/components/AppMain.vue
Normal file
|
@ -0,0 +1,35 @@
|
|||
<script>
|
||||
import NavBar from "./comunes/NavBar.vue";
|
||||
import { mapActions, mapState } from "vuex";
|
||||
import ComisionesBody from "./comisiones/Body.vue";
|
||||
import AdminBody from "./admin/Body.vue";
|
||||
import PedidosBody from "./pedidos/Body.vue";
|
||||
import InfoTags from "./comunes/InfoTags.vue";
|
||||
export default {
|
||||
name: 'Main',
|
||||
components: { InfoTags, ComisionesBody, AdminBody, PedidosBody, NavBar },
|
||||
computed: {
|
||||
...mapState("login", ["rol"]),
|
||||
},
|
||||
methods: {
|
||||
...mapActions("login", ["getRol"]),
|
||||
},
|
||||
async mounted() {
|
||||
await this.getRol();
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div id="app-main">
|
||||
<nav-bar/>
|
||||
<pedidos-body v-if="rol === 'barrio'"/>
|
||||
<admin-body v-else-if="rol === 'admin_barrio'"/>
|
||||
<comisiones-body v-else-if="rol === 'comision'"/>
|
||||
<info-tags/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -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>
|
61
resources/js/components/admin/Body.vue
Normal file
61
resources/js/components/admin/Body.vue
Normal file
|
@ -0,0 +1,61 @@
|
|||
<template>
|
||||
<div class="block ml-3 mr-3 is-max-widescreen is-max-desktop">
|
||||
<tabs-secciones :tabs="tabs" :tabInicial="tabActiva"/>
|
||||
<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">
|
||||
<dropdown-descargar/>
|
||||
<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'">
|
||||
<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 { mapActions, mapGetters } from "vuex";
|
||||
export default {
|
||||
name: "AdminBody",
|
||||
components: {
|
||||
CaracteristicasOpcionales,
|
||||
TabsSecciones,
|
||||
DropdownDescargar,
|
||||
TablaPedidos,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tabs: [{ id: "pedidos", nombre: "Pedidos" },
|
||||
{ id: "caracteristicas", nombre: "Caracteristicas opcionales" }],
|
||||
tabActiva: "pedidos",
|
||||
seccionActiva: "pedidos-seccion",
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('admin', ['hayPedidos']),
|
||||
},
|
||||
methods: {
|
||||
...mapActions('admin', ['getGrupoDeCompra']),
|
||||
setSeccionActiva(tabId) {
|
||||
this.tabActiva = tabId;
|
||||
this.seccionActiva = tabId + "-seccion";
|
||||
},
|
||||
},
|
||||
async mounted() {
|
||||
await this.getGrupoDeCompra();
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
40
resources/js/components/admin/CaracteristicasOpcionales.vue
Normal file
40
resources/js/components/admin/CaracteristicasOpcionales.vue
Normal file
|
@ -0,0 +1,40 @@
|
|||
<script>
|
||||
import FilaCaracteristica from "./FilaCaracteristica.vue";
|
||||
|
||||
export default {
|
||||
components: { FilaCaracteristica },
|
||||
data() {
|
||||
return {
|
||||
caracteristicas: [
|
||||
{
|
||||
id: "devoluciones",
|
||||
nombre: "Devoluciones"
|
||||
},
|
||||
]
|
||||
}
|
||||
},
|
||||
}
|
||||
</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>
|
||||
<fila-caracteristica
|
||||
v-for="(c,i) in caracteristicas"
|
||||
:key="i"
|
||||
:caracteristica="c"
|
||||
/>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
47
resources/js/components/admin/DropdownDescargar.vue
Normal file
47
resources/js/components/admin/DropdownDescargar.vue
Normal file
|
@ -0,0 +1,47 @@
|
|||
<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/' + grupo_de_compra_id" class="dropdown-item has-background-primary">
|
||||
Planilla para central (CSV)
|
||||
</a>
|
||||
<a :href="'/admin/exportar-planillas-a-pdf/' + grupo_de_compra_id" class="dropdown-item">
|
||||
Planillas para armado (PDF)
|
||||
</a>
|
||||
<a :href="'/admin/exportar-pedido-con-nucleos-a-csv/' + grupo_de_compra_id" class="dropdown-item">
|
||||
Planilla completa de la canasta (CSV)
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters, mapState } from "vuex";
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
dropdownActivo: false
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState('admin', ["grupo_de_compra_id"]),
|
||||
...mapGetters('admin', ["hayAprobados"]),
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style></style>
|
40
resources/js/components/admin/FilaCaracteristica.vue
Normal file
40
resources/js/components/admin/FilaCaracteristica.vue
Normal file
|
@ -0,0 +1,40 @@
|
|||
<script>
|
||||
import {mapActions, mapGetters, mapState} from "vuex";
|
||||
|
||||
export default {
|
||||
props: {
|
||||
caracteristica: Object
|
||||
},
|
||||
computed: {
|
||||
...mapState('admin',["grupo_de_compra_id"]),
|
||||
...mapGetters('admin',["getCaracteristica"]),
|
||||
habilitada() {
|
||||
return this.getCaracteristica(this.caracteristica.id);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions('admin',["toggleCaracteristica"]),
|
||||
}
|
||||
}
|
||||
</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="habilitada"
|
||||
@change="toggleCaracteristica({ caracteristica_id: caracteristica.id })">
|
||||
<label :for="'switch-' + caracteristica.id">
|
||||
<span class="is-hidden-mobile">
|
||||
{{ habilitada ? 'Habilitada' : 'Deshabilitada' }}
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
41
resources/js/components/admin/FilaPedido.vue
Normal file
41
resources/js/components/admin/FilaPedido.vue
Normal file
|
@ -0,0 +1,41 @@
|
|||
<template>
|
||||
<tr>
|
||||
<td>{{ pedido.nombre }}</td>
|
||||
<td v-if="devoluciones_habilitadas" class="has-text-right" >
|
||||
{{ pedido.total_sin_devoluciones }}
|
||||
</td>
|
||||
<td v-if="devoluciones_habilitadas" class="has-text-right" >
|
||||
<abbr :title="pedido.devoluciones_notas">
|
||||
-{{ pedido.devoluciones_total }}
|
||||
</abbr>
|
||||
</td>
|
||||
<td class="has-text-right" >
|
||||
{{ devoluciones_habilitadas ? pedido.total : pedido.total_sin_devoluciones }}
|
||||
</td>
|
||||
<td>
|
||||
<switch-aprobacion :pedido_id="pedido_id"/>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SwitchAprobacion from "./SwitchAprobacion.vue";
|
||||
import { mapGetters, mapState } from "vuex";
|
||||
export default {
|
||||
components: {
|
||||
SwitchAprobacion
|
||||
},
|
||||
props: {
|
||||
pedido_id: Number
|
||||
},
|
||||
computed: {
|
||||
...mapState('admin',["devoluciones_habilitadas"]),
|
||||
...mapGetters('admin',["getPedido"]),
|
||||
pedido() {
|
||||
return this.getPedido(this.pedido_id);
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
34
resources/js/components/admin/SwitchAprobacion.vue
Normal file
34
resources/js/components/admin/SwitchAprobacion.vue
Normal file
|
@ -0,0 +1,34 @@
|
|||
<template>
|
||||
<div class="field">
|
||||
<input type="checkbox" name="switchRoundedSuccess" class="switch is-rounded is-success"
|
||||
:id="'switch' + pedido_id"
|
||||
:checked="aprobado"
|
||||
@change="setAprobacionPedido({ pedido_id: pedido_id, aprobacion: !aprobado })">
|
||||
<label :for="'switch' + pedido_id">
|
||||
<span class="is-hidden-mobile">{{ mensaje }}</span>
|
||||
</label>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions, mapGetters } from "vuex";
|
||||
export default {
|
||||
props: {
|
||||
pedido_id: Number
|
||||
},
|
||||
computed: {
|
||||
...mapGetters('admin', ["getPedido"]),
|
||||
aprobado() {
|
||||
return this.getPedido(this.pedido_id).aprobado;
|
||||
},
|
||||
mensaje() {
|
||||
return this.aprobado ? "Aprobado" : "No aprobado";
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions('admin',["setAprobacionPedido"]),
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
87
resources/js/components/admin/TablaPedidos.vue
Normal file
87
resources/js/components/admin/TablaPedidos.vue
Normal file
|
@ -0,0 +1,87 @@
|
|||
<template>
|
||||
<div>
|
||||
<table class="table is-fullwidth is-striped is-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Núcleo</th>
|
||||
<th v-if="devoluciones_habilitadas"><abbr title="Total sin tomar en cuenta las devoluciones">Total parcial $</abbr></th>
|
||||
<th v-if="devoluciones_habilitadas"><abbr title="Devoluciones correspondientes al núcleo">Devoluciones $</abbr></th>
|
||||
<th><abbr title="Total a Pagar por el núleo">{{ devoluciones_habilitadas ? 'Total real' : 'Total' }} $</abbr></th>
|
||||
<th class="is-1"><abbr title="Aprobado">Aprobado</abbr></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<fila-pedido
|
||||
v-for="pedido in pedidos"
|
||||
:pedido_id="pedido.id"
|
||||
:key="pedido.id"
|
||||
/>
|
||||
</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">$ {{ devoluciones_habilitadas ? total_a_recaudar : total_sin_devoluciones }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Total bonos barriales:</th>
|
||||
<td class="has-text-right">$ {{ total_barrial }}</td>
|
||||
</tr>
|
||||
<tr v-if="devoluciones_habilitadas">
|
||||
<th>Total devoluciones:</th>
|
||||
<td class="has-text-right">- $ {{ total_devoluciones }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Cantidad bonos de transporte:</th>
|
||||
<td class="has-text-right">{{ cantidad_transporte }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Total bonos de transporte:</th>
|
||||
<td class="has-text-right">$ {{ total_transporte }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Total de pedido:</th>
|
||||
<td class="has-text-right">$ {{ total_de_pedido }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Saldo a favor:</th>
|
||||
<td class="has-text-right">- $ {{ saldo }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Total a transferir:</th>
|
||||
<td class="has-text-right">$ {{ total_a_transferir }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import FilaPedido from "./FilaPedido.vue";
|
||||
import { mapGetters, mapState } from "vuex";
|
||||
export default {
|
||||
components: {
|
||||
FilaPedido
|
||||
},
|
||||
computed: {
|
||||
...mapState('admin', [
|
||||
"devoluciones_habilitadas",
|
||||
"pedidos",
|
||||
"total_a_recaudar",
|
||||
"total_sin_devoluciones",
|
||||
"total_barrial",
|
||||
"total_devoluciones",
|
||||
"cantidad_transporte",
|
||||
"total_transporte",
|
||||
"total_de_pedido",
|
||||
"total_a_transferir",
|
||||
"saldo",
|
||||
]),
|
||||
...mapGetters('admin', ['pedidosAprobados']),
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style></style>
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue