forked from nathalie/pedi2
Compare commits
429 commits
agregar-pr
...
master
Author | SHA1 | Date | |
---|---|---|---|
![]() |
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 | ||
![]() |
0ec99a8cf5 | ||
![]() |
6f532eaf05 | ||
bc7b7e2f22 | |||
![]() |
b700239e18 | ||
0200160aa8 | |||
![]() |
39cc35341f | ||
![]() |
d17bc70c45 | ||
![]() |
48871e3f88 | ||
![]() |
546b901a05 |
119 changed files with 32174 additions and 1811 deletions
.directory.docker-compose.yml.swp.env.example.gitignoreDockerfileREADME.mddev-startdocker-compose.ymlpackage-lock.jsonpackage.json
app
CanastaLog.phpProducto.phpProveedor.phpSubpedido.phpUser.php
composer.jsoncomposer.lockConsole/Commands
Filtros
GrupoDeCompra.phpHelpers
Http
Controllers
Kernel.phpMiddleware
Resources
database
factories
migrations
2014_10_12_000000_create_users_table.php2020_09_23_180334_create_subpedidos_table.php2022_02_23_204330_agregar_columna_bono_a_tabla_de_productos.php2022_02_23_220046_agregar_columna_total_a_tabla_de_producto_subpedido.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.php
seeds
public
assets
css
js
resources
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
|
LOG_CHANNEL=stack
|
||||||
|
|
||||||
|
USERID=
|
||||||
|
|
||||||
DB_CONNECTION=mysql
|
DB_CONNECTION=mysql
|
||||||
DB_HOST=db
|
DB_HOST=db
|
||||||
DB_PORT=3306
|
DB_PORT_EXPOSED=3306
|
||||||
DB_DATABASE=pedi2
|
DB_DATABASE=pedi2
|
||||||
DB_USERNAME=pedi2
|
DB_USERNAME=pedi2
|
||||||
DB_PASSWORD=pedi2
|
DB_PASSWORD=pedi2
|
||||||
|
@ -48,3 +50,4 @@ MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
|
||||||
WEB_CLIENT_EMAIL=informaticamps@buzon.uy
|
WEB_CLIENT_EMAIL=informaticamps@buzon.uy
|
||||||
WEB_CLIENT_NAME=web
|
WEB_CLIENT_NAME=web
|
||||||
WEB_CLIENT_PASS=pass
|
WEB_CLIENT_PASS=pass
|
||||||
|
NGINX_PORT=8000
|
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -10,3 +10,9 @@ Homestead.json
|
||||||
Homestead.yaml
|
Homestead.yaml
|
||||||
npm-debug.log
|
npm-debug.log
|
||||||
yarn-error.log
|
yarn-error.log
|
||||||
|
.idea
|
||||||
|
/resources/csv/exports/*.csv
|
||||||
|
/resources/csv/canastas/*.csv
|
||||||
|
/public/css/
|
||||||
|
/public/js/
|
||||||
|
/public/mix-manifest.json
|
||||||
|
|
|
@ -12,7 +12,8 @@ RUN apt-get update && apt-get install -y \
|
||||||
libonig-dev \
|
libonig-dev \
|
||||||
libxml2-dev \
|
libxml2-dev \
|
||||||
zip \
|
zip \
|
||||||
unzip
|
unzip \
|
||||||
|
npm
|
||||||
|
|
||||||
# Clear cache
|
# Clear cache
|
||||||
RUN apt-get clean && rm -rf /var/lib/apt/lists/*
|
RUN apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||||
|
|
33
README.md
33
README.md
|
@ -1,6 +1,6 @@
|
||||||
# Pedi2
|
# Pedi2
|
||||||
|
|
||||||
Aplicación de compras del Mercado Popular de Subsistencia.
|
Aplicación de pedidos del Mercado Popular de Subsistencia.
|
||||||
|
|
||||||
Pedi2 está hecha en Laravel 7 y utiliza laravel7-docker de dyarleniber.
|
Pedi2 está hecha en Laravel 7 y utiliza laravel7-docker de dyarleniber.
|
||||||
|
|
||||||
|
@ -17,41 +17,39 @@ Se utilizan los siguientes servicios, separadamente:
|
||||||
## Instalación
|
## Instalación
|
||||||
1. Una vez descargado el proyecto, hacé una copia del archivo `.env.example` que se encuentra en la raíz del proyecto y nombrala `.env`. Seteá los valores correctos - específicamente, para las variables, `APP_URL`, `DB_USERNAME` y `DB_PASSWORD`. Prestá atención a que `DB_HOST` sea el nombre del servicio que corre MySQL (por defecto `DB_HOST=db`).
|
1. Una vez descargado el proyecto, hacé una copia del archivo `.env.example` que se encuentra en la raíz del proyecto y nombrala `.env`. Seteá los valores correctos - específicamente, para las variables, `APP_URL`, `DB_USERNAME` y `DB_PASSWORD`. Prestá atención a que `DB_HOST` sea el nombre del servicio que corre MySQL (por defecto `DB_HOST=db`).
|
||||||
|
|
||||||
2. Construí la imagen de la app
|
2. Levantá los contenedores, construyendo la imagen de la app primero
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker-compose build app
|
docker-compose up -d --build
|
||||||
```
|
|
||||||
|
|
||||||
3. Cuando termine, levantá los contenedores:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker-compose up -d
|
|
||||||
```
|
```
|
||||||
|
|
||||||
El ambiente ahora está andando, pero necesitamos ejecutar un par de comandos para terminar la instalación de Laravel. Podemos usar `docker-compose exec [nombre-del-servicio]` previo a un comando para ejecutarlo dentro del contenedor.
|
El ambiente ahora está andando, pero necesitamos ejecutar un par de comandos para terminar la instalación de Laravel. Podemos usar `docker-compose exec [nombre-del-servicio]` previo a un comando para ejecutarlo dentro del contenedor.
|
||||||
|
|
||||||
4. Terminá de instalar las dependencias de la app, según fueron definidas en `composer.json`.
|
3. Terminá de instalar las dependencias de la app, según fueron definidas en `composer.json`.
|
||||||
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker-compose exec app composer update
|
docker-compose exec app composer install
|
||||||
```
|
```
|
||||||
|
|
||||||
5. Generá una clave de aplicación. Esta clave se usa para encriptar datos sensibles.
|
4. Generá una clave de aplicación. Esta clave se usa para encriptar datos sensibles.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker-compose exec app php artisan key:generate
|
docker-compose exec app php artisan key:generate
|
||||||
```
|
```
|
||||||
|
|
||||||
6. Corré las migraciones y seeders de Laravel
|
5. Corré las migraciones y seeders de Laravel
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker-compose exec app php artisan migrate --seed
|
docker-compose exec app php artisan migrate:fresh --seed
|
||||||
```
|
```
|
||||||
|
|
||||||
7. Copia el token que se imprime al correr los seeders. Lo necesitamos para autenticar las llamadas que hagamos desde nuestro cliente web
|
6. Copia el token que se imprime al correr los seeders. Lo necesitamos para autenticar las llamadas que hagamos desde nuestro cliente web
|
||||||
|
|
||||||
|
7. Instala las dependencias de npm
|
||||||
|
```bash
|
||||||
|
docker-compose exec app npm install
|
||||||
|
```
|
||||||
|
|
||||||
Ahora la aplicación está corriendo y la podés ver en el puerto 8000 de tu dominio o IP. En caso de que estés en tu máquina local, la vas a ver accediendo a `http://localhost:8000` desde tu navegador.
|
Ahora la aplicación está corriendo y la podés ver en el puerto 8000 de tu dominio o IP. En caso de que estés en tu máquina local, la vas a ver accediendo a `http://localhost:8000` desde tu navegador.
|
||||||
|
|
||||||
|
@ -61,6 +59,11 @@ Podés usar el comando `logs` para ver los logs generados por tus servicios:
|
||||||
docker-compose logs nginx
|
docker-compose logs nginx
|
||||||
```
|
```
|
||||||
|
|
||||||
|
8. Ejecuta npm para compilar el js y css
|
||||||
|
```bash
|
||||||
|
docker-compose exec app npm run prod
|
||||||
|
```
|
||||||
|
|
||||||
## Services description
|
## Services description
|
||||||
|
|
||||||
### Dockerfile
|
### Dockerfile
|
||||||
|
|
11
app/CanastaLog.php
Normal file
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\Database\Eloquent\Model;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||||
|
use Throwable;
|
||||||
|
use TypeError;
|
||||||
|
|
||||||
class Filtro extends Model
|
class Filtro extends Model
|
||||||
{
|
{
|
||||||
protected $request;
|
protected Request $request;
|
||||||
protected $builder;
|
protected $builder;
|
||||||
protected $MENSAJES_ERROR = [
|
protected array $MENSAJES_ERROR = [
|
||||||
'ARGUMENTO' => 'Argumento inválido para el parámetro %s. Revise la documentación.'
|
'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.
|
* Apply all existing filters, if available.
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Database\Eloquent\Builder $builder
|
* @param Builder $builder
|
||||||
* @return \Illuminate\Database\Eloquent\Builder
|
* @return Builder
|
||||||
*/
|
*/
|
||||||
public function aplicar(Builder $builder)
|
public function aplicar(Builder $builder): Builder
|
||||||
{
|
{
|
||||||
$this->builder = $builder;
|
$this->builder = $builder;
|
||||||
|
|
||||||
|
@ -51,7 +54,7 @@ class Filtro extends Model
|
||||||
//Llamar métodos con argumentos
|
//Llamar métodos con argumentos
|
||||||
try {
|
try {
|
||||||
$this->$metodo($valor);
|
$this->$metodo($valor);
|
||||||
} catch (\Throwable $th) {
|
} catch (Throwable $th) {
|
||||||
if (is_a($th,'TypeError') ) { throw new HttpException(400, sprintf($this->MENSAJES_ERROR['ARGUMENTO'],$filtro)); }
|
if (is_a($th,'TypeError') ) { throw new HttpException(400, sprintf($this->MENSAJES_ERROR['ARGUMENTO'],$filtro)); }
|
||||||
throw $th;
|
throw $th;
|
||||||
}
|
}
|
||||||
|
@ -63,7 +66,7 @@ class Filtro extends Model
|
||||||
//Buscar un término en el nombre
|
//Buscar un término en el nombre
|
||||||
public function nombre(String $valor)
|
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')
|
public function alfabetico(String $order = 'asc')
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App\Filtros;
|
namespace App\Filtros;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
|
||||||
|
|
||||||
class FiltroDeProducto extends Filtro {
|
class FiltroDeProducto extends Filtro {
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
namespace App\Filtros;
|
namespace App\Filtros;
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use TypeError;
|
||||||
|
|
||||||
class FiltroDeSubpedido extends Filtro
|
class FiltroDeSubpedido extends Filtro
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,17 +2,279 @@
|
||||||
|
|
||||||
namespace App;
|
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\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class GrupoDeCompra extends Model
|
class GrupoDeCompra extends Model
|
||||||
{
|
{
|
||||||
public $timestamps = false;
|
public $timestamps = false;
|
||||||
protected $fillable = [ "nombre","region","telefono","correo","referente_finanzas","cantidad_de_nucleos"];
|
protected $fillable = ["nombre", "region", "telefono", "correo", "referente_finanzas", "cantidad_de_nucleos", "fila", "devoluciones_habilitadas"];
|
||||||
protected $table = 'grupos_de_compra';
|
protected $table = 'grupos_de_compra';
|
||||||
protected $hidden = ['password'];
|
protected $hidden = ['password'];
|
||||||
|
|
||||||
public function subpedidos() {
|
public function subpedidos(): HasMany
|
||||||
return $this->hasMany('App\Subpedido');
|
{
|
||||||
}
|
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 totalBarrial()
|
||||||
|
{
|
||||||
|
$total = 0;
|
||||||
|
foreach ($this->pedidosAprobados() as $subpedido) {
|
||||||
|
$total = $total + $subpedido->totalBarrial();
|
||||||
|
}
|
||||||
|
return $total;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function totalDevoluciones()
|
||||||
|
{
|
||||||
|
$total = 0;
|
||||||
|
foreach ($this->pedidosAprobados() as $subpedido) {
|
||||||
|
$total = $total + $subpedido->devoluciones_total;
|
||||||
|
}
|
||||||
|
return $total;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function totalATransferir()
|
||||||
|
{
|
||||||
|
return $this->totalCentralesQueNoPaganTransporte()
|
||||||
|
+ $this->totalCentralesQuePaganTransporte()
|
||||||
|
+ $this->totalTransporte();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function totalCentralesQueNoPaganTransporte()
|
||||||
|
{
|
||||||
|
$total = 0;
|
||||||
|
foreach ($this->pedidosAprobados() as $subpedido) {
|
||||||
|
$total = $total + $subpedido->totalCentralesQueNoPaganTransporte();
|
||||||
|
}
|
||||||
|
return $total;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function totalCentralesQuePaganTransporte()
|
||||||
|
{
|
||||||
|
$total = 0;
|
||||||
|
foreach ($this->pedidosAprobados() as $subpedido) {
|
||||||
|
$total = $total + $subpedido->totalCentralesQuePaganTransporte();
|
||||||
|
}
|
||||||
|
return $total;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function totalTransporte()
|
||||||
|
{
|
||||||
|
return TransporteHelper::totalTransporte($this->totalCentralesQuePaganTransporte());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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();
|
||||||
|
PdfHelper::exportarPedidos($this->nombre . '.pdf', $subpedidos);
|
||||||
|
}
|
||||||
|
|
||||||
|
function pedidoParaPdf(): array
|
||||||
|
{
|
||||||
|
$productos = $this->productosPedidos(true, true);
|
||||||
|
$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();
|
||||||
|
PdfHelper::exportarPedidos('pedidos_por_barrio.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
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function exportarPedidoEnCSV()
|
||||||
|
{
|
||||||
|
$records = $this->generarColumnaCantidades();
|
||||||
|
|
||||||
|
CsvHelper::generarCsv('csv/exports/' . $this->nombre . '.csv', $records);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
|
||||||
|
CsvHelper::generarCsv('csv/exports/' . $this->nombre . '-completo.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Collection
|
||||||
|
*/
|
||||||
|
public function productosPedidos($excluirBarriales = false, $excluirBonos = false): Collection
|
||||||
|
{
|
||||||
|
$query = DB::table('pedidos_aprobados')
|
||||||
|
->where('grupo_de_compra_id', $this->id);
|
||||||
|
|
||||||
|
if ($excluirBarriales)
|
||||||
|
$query = $query->where('producto_nombre','NOT LIKE','%barrial%');
|
||||||
|
if ($excluirBonos)
|
||||||
|
$query = $query->where('producto_es_bono',false);
|
||||||
|
|
||||||
|
return $query
|
||||||
|
->get()
|
||||||
|
->keyBy('producto_id');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
146
app/Helpers/CanastaHelper.php
Normal file
146
app/Helpers/CanastaHelper.php
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Helpers;
|
||||||
|
|
||||||
|
use App\Producto;
|
||||||
|
use App\Proveedor;
|
||||||
|
use App\CanastaLog;
|
||||||
|
use DatabaseSeeder;
|
||||||
|
use Illuminate\Support\Arr;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
|
||||||
|
class CanastaHelper
|
||||||
|
{
|
||||||
|
const TIPO = "Tipo";
|
||||||
|
const TOTAL = "TOTAL";
|
||||||
|
const ARCHIVO_SUBIDO = 'Archivo subido';
|
||||||
|
const CANASTA_CARGADA = 'Canasta cargada';
|
||||||
|
const TIPOS_BONO = ["B", "F", "BE"];
|
||||||
|
|
||||||
|
public static function guardarCanasta($data, $path): string {
|
||||||
|
$nombre = $data->getClientOriginalName();
|
||||||
|
|
||||||
|
$data->move(resource_path($path), $nombre);
|
||||||
|
|
||||||
|
self::log($path . $nombre, self::ARCHIVO_SUBIDO);
|
||||||
|
|
||||||
|
return $nombre;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function cargarCanasta($archivo) {
|
||||||
|
self::limpiarTablas();
|
||||||
|
|
||||||
|
$registros = CsvHelper::getRecords($archivo);
|
||||||
|
$toInsert = [];
|
||||||
|
$categoria = '';
|
||||||
|
|
||||||
|
foreach($registros as $i => $registro) {
|
||||||
|
// finalizar
|
||||||
|
if ($registro[self::TIPO] == self::TOTAL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// saltear filas que no tienen tipo
|
||||||
|
if (self::noTieneTipo($registro)) {
|
||||||
|
var_dump("no hay tipo en la fila " . $i);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// saltear bono de transporte
|
||||||
|
if ($registro[self::TIPO] == "T"){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// obtener categoria si no hay producto
|
||||||
|
if ($registro['Producto'] == '') {
|
||||||
|
// no es la pregunta de la copa?
|
||||||
|
if (!Str::contains($registro[self::TIPO],"¿"))
|
||||||
|
$categoria = $registro[self::TIPO];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// completar producto
|
||||||
|
$toInsert[] = [
|
||||||
|
'fila' => $i,
|
||||||
|
'categoria' => $categoria,
|
||||||
|
'nombre' => trim(str_replace('*', '',$registro['Producto'])),
|
||||||
|
'precio' => $registro['Precio'],
|
||||||
|
'proveedor_id' => self::obtenerProveedor($registro['Producto']),
|
||||||
|
'bono' => in_array($registro[self::TIPO], self::TIPOS_BONO),
|
||||||
|
'requiere_notas'=> $registro[self::TIPO] =="PTC",
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (array_chunk($toInsert,DatabaseSeeder::CHUNK_SIZE) as $chunk) {
|
||||||
|
DB::table('productos')->insert($chunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
self::agregarBonoBarrial();
|
||||||
|
|
||||||
|
self::log($archivo, self::CANASTA_CARGADA);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function obtenerProveedor($nombre) {
|
||||||
|
$result = null;
|
||||||
|
if (Str::contains($nombre,"*")){
|
||||||
|
$result = Proveedor::firstOrCreate([
|
||||||
|
'nombre' => 'Proveedor de economía solidaria',
|
||||||
|
'economia_solidaria' => 1,
|
||||||
|
'nacional' => 1
|
||||||
|
])->id;
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $path
|
||||||
|
* @param $descripcion
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private static function log($path, $descripcion): void
|
||||||
|
{
|
||||||
|
$log = new CanastaLog([
|
||||||
|
'path' => $path,
|
||||||
|
'descripcion' => $descripcion,
|
||||||
|
]);
|
||||||
|
$log->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function limpiarTablas()
|
||||||
|
{
|
||||||
|
DB::delete('delete from producto_subpedido');
|
||||||
|
DB::delete('delete from productos');
|
||||||
|
DB::delete('delete from subpedidos');
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function agregarBonoBarrial()
|
||||||
|
{
|
||||||
|
$categoria = Producto::all()
|
||||||
|
->pluck('categoria')
|
||||||
|
->unique()
|
||||||
|
->flatten()
|
||||||
|
->first(function ($c) {
|
||||||
|
return Str::contains($c, 'BONO');
|
||||||
|
});
|
||||||
|
|
||||||
|
DB::table('productos')->insert([
|
||||||
|
'fila' => 420,
|
||||||
|
'nombre' => "Bono barrial",
|
||||||
|
'precio' => 20,
|
||||||
|
'categoria' => $categoria,
|
||||||
|
'bono' => 1,
|
||||||
|
'proveedor_id' => null,
|
||||||
|
'requiere_notas'=> false,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $registro
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function noTieneTipo($registro): bool
|
||||||
|
{
|
||||||
|
return !Arr::has($registro, self::TIPO) || trim($registro[self::TIPO]) == '';
|
||||||
|
}
|
||||||
|
}
|
40
app/Helpers/CsvHelper.php
Normal file
40
app/Helpers/CsvHelper.php
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Helpers;
|
||||||
|
|
||||||
|
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
|
||||||
|
{
|
||||||
|
public static function getRecords($filePath): Iterator {
|
||||||
|
$csv = Reader::createFromPath(resource_path($filePath));
|
||||||
|
try {
|
||||||
|
$csv->setDelimiter("|");
|
||||||
|
$csv->setEnclosure("'");
|
||||||
|
$csv->setHeaderOffset(0);
|
||||||
|
return $csv->getRecords();
|
||||||
|
} catch (InvalidArgument|Exception $e) {
|
||||||
|
Log::error($e->getMessage());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function generarCsv($filePath, $contenido, $headers = null): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$writer = Writer::createFromPath(resource_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');
|
||||||
|
}
|
||||||
|
}
|
38
app/Helpers/TransporteHelper.php
Normal file
38
app/Helpers/TransporteHelper.php
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Helpers;
|
||||||
|
|
||||||
|
use App\CanastaLog;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function filaTransporte()
|
||||||
|
{
|
||||||
|
$ultimaCanasta = CanastaLog::where('descripcion', CanastaHelper::CANASTA_CARGADA)
|
||||||
|
->orderBy('created_at', 'desc')
|
||||||
|
->pluck('path')
|
||||||
|
->first();
|
||||||
|
|
||||||
|
$registros = CsvHelper::getRecords($ultimaCanasta);
|
||||||
|
|
||||||
|
foreach ($registros as $key => $registro)
|
||||||
|
if ($registro[CanastaHelper::TIPO] == 'T') return $key;
|
||||||
|
|
||||||
|
Log::error('No hay fila de tipo T en la planilla: ' . $ultimaCanasta);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,9 +2,35 @@
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use Illuminate\Http\Request;
|
use App\GrupoDeCompra;
|
||||||
|
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||||
|
|
||||||
class AdminController extends Controller
|
class AdminController extends Controller
|
||||||
{
|
{
|
||||||
//
|
public function show()
|
||||||
|
{
|
||||||
|
return view('auth/admin_login');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function index() {
|
||||||
|
return view('auth/admin_subpedidos');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function exportarPedidosAPdf(GrupoDeCompra $gdc) {
|
||||||
|
$gdc->exportarPedidosAPdf();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function exportarPedidoACSV(GrupoDeCompra $gdc): BinaryFileResponse
|
||||||
|
{
|
||||||
|
$gdc->exportarPedidoEnCSV();
|
||||||
|
$file = resource_path('csv/exports/'.$gdc->nombre.'.csv');
|
||||||
|
return response()->download($file);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function exportarPedidoConNucleosACSV(GrupoDeCompra $gdc): BinaryFileResponse
|
||||||
|
{
|
||||||
|
$gdc->exportarPedidoConNucleosEnCSV();
|
||||||
|
$file = resource_path('csv/exports/'.$gdc->nombre.'-completo.csv');
|
||||||
|
return response()->download($file);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
19
app/Http/Controllers/Api/GrupoDeCompraController.php
Normal file
19
app/Http/Controllers/Api/GrupoDeCompraController.php
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Api;
|
||||||
|
|
||||||
|
use App\GrupoDeCompra;
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Resources\GrupoDeCompraResource;
|
||||||
|
|
||||||
|
class GrupoDeCompraController extends Controller
|
||||||
|
{
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
return GrupoDeCompraResource::collection(GrupoDeCompra::all());
|
||||||
|
}
|
||||||
|
public function show(GrupoDeCompra $grupoDeCompra)
|
||||||
|
{
|
||||||
|
return new GrupoDeCompraResource($grupoDeCompra);
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,24 +10,11 @@ use App\Producto;
|
||||||
|
|
||||||
class ProductoController extends Controller
|
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)
|
public function index(FiltroDeProducto $filtros, Request $request)
|
||||||
{
|
{
|
||||||
return ProductoResource::collection(Producto::filtrar($filtros)->paginate(Producto::getPaginar($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 show(Producto $producto)
|
||||||
{
|
{
|
||||||
return new ProductoResource($producto);
|
return new ProductoResource($producto);
|
||||||
|
|
|
@ -3,35 +3,28 @@
|
||||||
namespace App\Http\Controllers\Api;
|
namespace App\Http\Controllers\Api;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Producto;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Filtros\FiltroDeSubpedido;
|
use App\Filtros\FiltroDeSubpedido;
|
||||||
use App\Subpedido;
|
use App\Subpedido;
|
||||||
use App\GrupoDeCompra;
|
use App\GrupoDeCompra;
|
||||||
use App\Producto;
|
use App\Http\Resources\SubpedidoResource;
|
||||||
use Illuminate\Validation\Rule;
|
use Illuminate\Validation\Rule;
|
||||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||||
|
|
||||||
|
|
||||||
class SubpedidoController extends Controller
|
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)
|
public function index(FiltroDeSubpedido $filtros, Request $request)
|
||||||
{
|
{
|
||||||
return Subpedido::filtrar($filtros)->get();
|
return Subpedido::filtrar($filtros)->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function indexResources(FiltroDeSubpedido $filtros, Request $request)
|
||||||
* Guardar un nuevo registro en el almacenamiento.
|
{
|
||||||
*
|
return SubpedidoResource::collection(Subpedido::filtrar($filtros)->get());
|
||||||
* @param \Illuminate\Http\Request $request
|
}
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
|
||||||
public function store(Request $request)
|
public function store(Request $request)
|
||||||
{
|
{
|
||||||
$validado = $this->validateSubpedido();
|
$validado = $this->validateSubpedido();
|
||||||
|
@ -45,29 +38,8 @@ class SubpedidoController extends Controller
|
||||||
return $s;
|
return $s;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
protected function validateSubpedido(): array
|
||||||
* Agregar un producto a un subpedido.
|
|
||||||
*
|
|
||||||
* @param \Illuminate\Http\Request $request
|
|
||||||
* @return \Illuminate\Http\Response
|
|
||||||
*/
|
|
||||||
public function updateProducto(Subpedido $subpedido, Producto $producto, Request $request)
|
|
||||||
{
|
{
|
||||||
$validado = $this->validateActualizacionDeProducto();
|
|
||||||
$cantidad = $validado['cantidad'];
|
|
||||||
|
|
||||||
if ($cantidad){
|
|
||||||
//si la cantidad es 1 o más se agrega el producto o actualiza la cantidad
|
|
||||||
$subpedido->productos()->syncWithoutDetaching([$producto->id => ['cantidad' => $cantidad]]);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
//si la cantidad es 0, se elimina el producto del subpedido
|
|
||||||
$subpedido->productos()->detach($producto->id);
|
|
||||||
}
|
|
||||||
return response('Producto ' . $producto->nombre . ' actualizado en subpedido de ' . $subpedido->nombre . ' (cantidad ' . $cantidad . ')', 200);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function validateSubpedido(){
|
|
||||||
return request()->validate([
|
return request()->validate([
|
||||||
'nombre' => 'required|max:255',
|
'nombre' => 'required|max:255',
|
||||||
'grupo_de_compra_id' => [
|
'grupo_de_compra_id' => [
|
||||||
|
@ -77,9 +49,49 @@ class SubpedidoController extends Controller
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function validateActualizacionDeProducto(){
|
public function show(Subpedido $subpedido)
|
||||||
return request()->validate([
|
{
|
||||||
'cantidad' => 'required|min:0'
|
return new SubpedidoResource($subpedido);
|
||||||
|
}
|
||||||
|
|
||||||
|
// recibe request, saca producto y cantidad, valida, y pasa a syncProducto en Subpedido
|
||||||
|
public function syncProductos(Subpedido $subpedido) {
|
||||||
|
if ($subpedido->aprobado)
|
||||||
|
return new SubpedidoResource($subpedido);
|
||||||
|
|
||||||
|
$valid = request()->validate([
|
||||||
|
'cantidad' => ['integer','required','min:0'],
|
||||||
|
'notas' => 'nullable',
|
||||||
|
'producto_id' => [
|
||||||
|
'required',
|
||||||
|
Rule::in(Producto::all()->pluck('id')),
|
||||||
|
]
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
$producto = Producto::find($valid['producto_id']);
|
||||||
|
$notas = $valid['notas'];
|
||||||
|
$cantidad = $valid['cantidad'];
|
||||||
|
$subpedido->syncProducto($producto, $cantidad, $notas ?? "");
|
||||||
|
return new SubpedidoResource($subpedido);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toggleAprobacion(Subpedido $subpedido) {
|
||||||
|
$valid = request()->validate([
|
||||||
|
'aprobacion' => 'required | boolean'
|
||||||
|
]);
|
||||||
|
$subpedido->toggleAprobacion($valid['aprobacion']);
|
||||||
|
return new SubpedidoResource($subpedido);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function syncDevoluciones(Subpedido $subpedido) {
|
||||||
|
if ($subpedido->aprobado) return new SubpedidoResource($subpedido);
|
||||||
|
|
||||||
|
$valid = request()->validate([
|
||||||
|
'total' => 'required|min:0',
|
||||||
|
'notas' => 'min:0'
|
||||||
|
]);
|
||||||
|
$subpedido->syncDevoluciones($valid['total'], $valid['notas'] ?? "");
|
||||||
|
|
||||||
|
return new SubpedidoResource($subpedido);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ namespace App\Http\Controllers\Auth;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Providers\RouteServiceProvider;
|
use App\Providers\RouteServiceProvider;
|
||||||
use Illuminate\Foundation\Auth\AuthenticatesUsers;
|
use Illuminate\Foundation\Auth\AuthenticatesUsers;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
class LoginController extends Controller
|
class LoginController extends Controller
|
||||||
|
@ -28,6 +29,18 @@ class LoginController extends Controller
|
||||||
*/
|
*/
|
||||||
protected $redirectTo = RouteServiceProvider::HOME;
|
protected $redirectTo = RouteServiceProvider::HOME;
|
||||||
|
|
||||||
|
protected function authenticated(Request $request, $user)
|
||||||
|
{
|
||||||
|
if ($user->is_compras) {
|
||||||
|
return redirect('compras/pedidos');
|
||||||
|
} else if ($user->is_admin) {
|
||||||
|
session(['admin_gdc' => $user->grupo_de_compra_id]);
|
||||||
|
return redirect('admin/pedidos');
|
||||||
|
} else {
|
||||||
|
return redirect('/');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new controller instance.
|
* Create a new controller instance.
|
||||||
*
|
*
|
||||||
|
|
62
app/Http/Controllers/ComprasController.php
Normal file
62
app/Http/Controllers/ComprasController.php
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\GrupoDeCompra;
|
||||||
|
use App\Helpers\CanastaHelper;
|
||||||
|
use App\Producto;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||||
|
|
||||||
|
class ComprasController
|
||||||
|
{
|
||||||
|
const CANASTAS_PATH = 'csv/canastas/';
|
||||||
|
|
||||||
|
public function indexPedidos() {
|
||||||
|
return view('compras_pedidos');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function descargarPedidos(): BinaryFileResponse
|
||||||
|
{
|
||||||
|
Producto::planillaTotales();
|
||||||
|
$file = resource_path('csv/exports/pedidos-por-barrio.csv');
|
||||||
|
return response()->download($file);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function descargarNotas(): BinaryFileResponse
|
||||||
|
{
|
||||||
|
Producto::planillaNotas();
|
||||||
|
$file = resource_path('csv/exports/notas-por-barrio.csv');
|
||||||
|
return response()->download($file);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function pdf() {
|
||||||
|
GrupoDeCompra::exportarPedidosBarrialesAPdf();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function show()
|
||||||
|
{
|
||||||
|
return view('auth/compras_login');
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
CanastaHelper::cargarCanasta(self::CANASTAS_PATH . $nombre);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'message' => 'Canasta cargada exitosamente',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function descargarCanastaEjemplo(): BinaryFileResponse
|
||||||
|
{
|
||||||
|
$file = resource_path('csv/productos.csv');
|
||||||
|
return response()->download($file);
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,8 +2,6 @@
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
|
|
||||||
class ProductoController extends Controller
|
class ProductoController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
@ -16,11 +14,6 @@ class ProductoController extends Controller
|
||||||
$this->middleware(['auth','subpedido']);
|
$this->middleware(['auth','subpedido']);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the application dashboard.
|
|
||||||
*
|
|
||||||
* @return \Illuminate\Contracts\Support\Renderable
|
|
||||||
*/
|
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
return view('productos');
|
return view('productos');
|
||||||
|
|
|
@ -56,6 +56,8 @@ class Kernel extends HttpKernel
|
||||||
*/
|
*/
|
||||||
protected $routeMiddleware = [
|
protected $routeMiddleware = [
|
||||||
'auth' => \App\Http\Middleware\Authenticate::class,
|
'auth' => \App\Http\Middleware\Authenticate::class,
|
||||||
|
'admin' => \App\Http\Middleware\Admin::class,
|
||||||
|
'compras' => \App\Http\Middleware\Compras::class,
|
||||||
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
|
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
|
||||||
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
|
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||||
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
|
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
|
||||||
|
|
20
app/Http/Middleware/Admin.php
Normal file
20
app/Http/Middleware/Admin.php
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class Admin
|
||||||
|
{
|
||||||
|
public function handle(Request $request, Closure $next)
|
||||||
|
{
|
||||||
|
$user = Auth::user();
|
||||||
|
if ($user->is_admin) {
|
||||||
|
return $next($request);
|
||||||
|
} else {
|
||||||
|
return response('Necesitás ser admin para hacer esto', 403);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
29
app/Http/Middleware/Compras.php
Normal file
29
app/Http/Middleware/Compras.php
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
|
class Compras
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle an incoming request.
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
* @param Closure $next
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function handle(Request $request, Closure $next)
|
||||||
|
{
|
||||||
|
if (!Auth::check())
|
||||||
|
return redirect()->route('compras_login.show');
|
||||||
|
|
||||||
|
if (Auth::user()->is_compras) {
|
||||||
|
return $next($request);
|
||||||
|
} else {
|
||||||
|
return response('Necesitás ser de comisión compras para hacer esto', 403);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,17 +3,18 @@
|
||||||
namespace App\Http\Middleware;
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
use Closure;
|
use Closure;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
class Subpedido
|
class Subpedido
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Handle an incoming request.
|
* Handle an incoming request.
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Http\Request $request
|
* @param Request $request
|
||||||
* @param \Closure $next
|
* @param Closure $next
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public function handle($request, Closure $next)
|
public function handle(Request $request, Closure $next)
|
||||||
{
|
{
|
||||||
if (!session('subpedido_nombre') || !session('subpedido_id')) {
|
if (!session('subpedido_nombre') || !session('subpedido_id')) {
|
||||||
return redirect()->route('subpedidos.create');
|
return redirect()->route('subpedidos.create');
|
||||||
|
|
31
app/Http/Resources/GrupoDeCompraResource.php
Normal file
31
app/Http/Resources/GrupoDeCompraResource.php
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
<?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),
|
||||||
|
'total_barrial' => number_format($this->totalBarrial(),2),
|
||||||
|
'total_devoluciones' => number_format($this->totalDevoluciones(),2),
|
||||||
|
'total_a_transferir' => number_format($this->totalATransferir(),2),
|
||||||
|
'total_transporte' => number_format($this->totalTransporte()),
|
||||||
|
'cantidad_transporte' => number_format($this->cantidadTransporte()),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace App\Http\Resources;
|
namespace App\Http\Resources;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Http\Resources\Json\JsonResource;
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
|
||||||
class ProductoResource extends JsonResource
|
class ProductoResource extends JsonResource
|
||||||
|
@ -9,10 +10,10 @@ class ProductoResource extends JsonResource
|
||||||
/**
|
/**
|
||||||
* Transform the resource into an array.
|
* Transform the resource into an array.
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Http\Request $request
|
* @param Request $request
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function toArray($request)
|
public function toArray($request): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'id' => $this->id,
|
'id' => $this->id,
|
||||||
|
@ -25,7 +26,8 @@ class ProductoResource extends JsonResource
|
||||||
'imagen' => optional($this->poster)->url(),
|
'imagen' => optional($this->poster)->url(),
|
||||||
'descripcion' => $this->descripcion,
|
'descripcion' => $this->descripcion,
|
||||||
'apto_veganxs' => $this->apto_veganxs,
|
'apto_veganxs' => $this->apto_veganxs,
|
||||||
'apto_celiacxs' => $this->apto_celiacxs
|
'apto_celiacxs' => $this->apto_celiacxs,
|
||||||
|
'requiere_notas' => $this->requiere_notas,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
32
app/Http/Resources/SubpedidoResource.php
Normal file
32
app/Http/Resources/SubpedidoResource.php
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Resources;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Http\Resources\Json\JsonResource;
|
||||||
|
|
||||||
|
class SubpedidoResource 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,
|
||||||
|
'grupo_de_compra' => $this->grupoDeCompra,
|
||||||
|
'productos' => $this->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
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
162
app/Producto.php
162
app/Producto.php
|
@ -2,35 +2,153 @@
|
||||||
|
|
||||||
namespace App;
|
namespace App;
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use App\Filtros\FiltroDeProducto;
|
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\BelongsTo;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
class Producto extends Model
|
class Producto extends Model
|
||||||
{
|
{
|
||||||
public $timestamps = false;
|
public $timestamps = false;
|
||||||
protected $fillable = [ "nombre", "precio", "presentacion", "stock", "categoria" ];
|
protected $fillable = ["nombre", "precio", "presentacion", "stock", "categoria"];
|
||||||
static $paginarPorDefecto = 10;
|
static int $paginarPorDefecto = 10;
|
||||||
|
|
||||||
public function subpedidos()
|
public function subpedidos(): BelongsToMany
|
||||||
{
|
{
|
||||||
return $this->belongsToMany('App\Subpedido','productos_subpedidos')->withPivot(["cantidad"]);
|
return $this->belongsToMany('App\Subpedido', 'productos_subpedidos')->withPivot(["cantidad", "notas"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function proveedor()
|
public function proveedor(): BelongsTo
|
||||||
{
|
{
|
||||||
return $this->belongsTo('App\Proveedor');
|
return $this->belongsTo('App\Proveedor');
|
||||||
}
|
}
|
||||||
|
|
||||||
//Este método permite que se apliquen los filtros al hacer una request (por ejemplo, de búsqueda)
|
//Este método permite que se apliquen los filtros al hacer una request (por ejemplo, de búsqueda)
|
||||||
public function scopeFiltrar($query, FiltroDeProducto $filtros)
|
public function scopeFiltrar($query, FiltroDeProducto $filtros): Builder
|
||||||
{
|
{
|
||||||
return $filtros->aplicar($query);
|
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::$paginarPorDefecto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function productosFilaID()
|
||||||
|
{
|
||||||
|
return Producto::pluck('id', 'fila')->all();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function productosIDFila()
|
||||||
|
{
|
||||||
|
return Producto::pluck('fila', 'id')->all();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function productosIDNombre()
|
||||||
|
{
|
||||||
|
return Producto::pluck('nombre', 'id')->all();
|
||||||
|
}
|
||||||
|
|
||||||
|
static public function cantidadesPorBarrio(): 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
CsvHelper::generarCsv('csv/exports/pedidos-por-barrio.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
CsvHelper::generarCsv('csv/exports/notas-por-barrio.csv', $planilla, $headers);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
namespace App;
|
namespace App;
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
|
|
||||||
class Proveedor extends Model
|
class Proveedor extends Model
|
||||||
{
|
{
|
||||||
|
@ -10,7 +11,7 @@ class Proveedor extends Model
|
||||||
protected $fillable = [ "nombre","direccion","telefono","correo","comentario" ];
|
protected $fillable = [ "nombre","direccion","telefono","correo","comentario" ];
|
||||||
protected $table = 'proveedores';
|
protected $table = 'proveedores';
|
||||||
|
|
||||||
public function productos()
|
public function productos(): HasMany
|
||||||
{
|
{
|
||||||
return $this->hasMany('App\Producto');
|
return $this->hasMany('App\Producto');
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,31 +2,130 @@
|
||||||
|
|
||||||
namespace App;
|
namespace App;
|
||||||
|
|
||||||
use League\Csv\Reader;
|
use App\Helpers\TransporteHelper;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Log;
|
|
||||||
use App\Filtros\FiltroDeSubpedido;
|
use App\Filtros\FiltroDeSubpedido;
|
||||||
|
|
||||||
class Subpedido extends Model
|
class Subpedido extends Model
|
||||||
{
|
{
|
||||||
public $timestamps = false;
|
public $timestamps = false;
|
||||||
protected $fillable = ['grupo_de_compra_id', 'aprobado', 'nombre'];
|
protected $fillable = ['grupo_de_compra_id', 'aprobado', 'nombre', 'devoluciones_total', 'devoluciones_notas'];
|
||||||
|
|
||||||
public function productos()
|
public function productos(): BelongsToMany
|
||||||
{
|
{
|
||||||
return $this->belongsToMany('App\Producto')->withPivot(["cantidad"]);
|
return $this->belongsToMany('App\Producto')->withPivot(["cantidad", "total", "notas"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function grupoDeCompra()
|
public function grupoDeCompra(): BelongsTo
|
||||||
{
|
{
|
||||||
return $this->belongsTo('App\GrupoDeCompra');
|
return $this->belongsTo('App\GrupoDeCompra');
|
||||||
}
|
}
|
||||||
|
|
||||||
//Este método permite que se apliquen los filtros al hacer una request (por ejemplo, de búsqueda)
|
// Permite que se apliquen los filtros al hacer una request (por ejemplo, de búsqueda)
|
||||||
public function scopeFiltrar($query, FiltroDeSubpedido $filtros)
|
public function scopeFiltrar($query, FiltroDeSubpedido $filtros): Builder
|
||||||
{
|
{
|
||||||
return $filtros->aplicar($query);
|
return $filtros->aplicar($query);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function total()
|
||||||
|
{
|
||||||
|
return $this->totalSinDevoluciones() - $this->devoluciones_total;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function totalSinDevoluciones()
|
||||||
|
{
|
||||||
|
return $this->totalBarrial() + $this->totalCentral();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function totalBarrial()
|
||||||
|
{
|
||||||
|
return DB::table('producto_subpedido')
|
||||||
|
->join('productos', 'producto_subpedido.producto_id', '=', 'productos.id')
|
||||||
|
->where('producto_subpedido.subpedido_id', $this->id)
|
||||||
|
->where('productos.nombre', 'like', '%barrial%')
|
||||||
|
->selectRaw('SUM(productos.precio * producto_subpedido.cantidad) as total')
|
||||||
|
->value('total');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function totalCentral()
|
||||||
|
{
|
||||||
|
return $this->totalCentralesQueNoPaganTransporte() + $this->totalCentralesQuePaganTransporte() + $this->totalTransporte();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function totalCentralesQueNoPaganTransporte()
|
||||||
|
{
|
||||||
|
return DB::table('producto_subpedido')
|
||||||
|
->join('productos', 'producto_subpedido.producto_id', '=', 'productos.id')
|
||||||
|
->where('producto_subpedido.subpedido_id', $this->id)
|
||||||
|
->where('productos.nombre', 'not like', '%barrial%')
|
||||||
|
->where(function ($query) {
|
||||||
|
$query->where('productos.categoria', 'like', '%SUBSIDIADO%')
|
||||||
|
->orWhere('productos.bono', true);
|
||||||
|
})
|
||||||
|
->selectRaw('SUM(productos.precio * producto_subpedido.cantidad) as total')
|
||||||
|
->value('total');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function totalCentralesQuePaganTransporte()
|
||||||
|
{
|
||||||
|
return DB::table('producto_subpedido')
|
||||||
|
->join('productos', 'producto_subpedido.producto_id', '=', 'productos.id')
|
||||||
|
->where('producto_subpedido.subpedido_id', $this->id)
|
||||||
|
->where('productos.nombre', 'not like', '%barrial%')
|
||||||
|
->where('productos.bono', false)
|
||||||
|
->where('productos.categoria', 'not like', '%SUBSIDIADO%')
|
||||||
|
->selectRaw('SUM(productos.precio * producto_subpedido.cantidad) as total')
|
||||||
|
->value('total');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function totalTransporte()
|
||||||
|
{
|
||||||
|
return TransporteHelper::totalTransporte($this->totalCentralesQuePaganTransporte());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function cantidadTransporte()
|
||||||
|
{
|
||||||
|
return TransporteHelper::cantidadTransporte($this->totalCentralesQuePaganTransporte());
|
||||||
|
}
|
||||||
|
|
||||||
|
//Actualiza el pedido, agregando o quitando del subpedido según sea necesario. Debe ser llamado desde el controlador de subpedidos, luego de validar que los parámetros $producto y $cantidad son correctos. También calcula el subtotal por producto.
|
||||||
|
public function syncProducto(Producto $producto, int $cantidad, string $notas)
|
||||||
|
{
|
||||||
|
if ($cantidad) {
|
||||||
|
//si la cantidad es 1 o más se agrega el producto o actualiza la cantidad
|
||||||
|
$this->productos()->syncWithoutDetaching([
|
||||||
|
$producto->id => [
|
||||||
|
'cantidad' => $cantidad,
|
||||||
|
'total' => $cantidad * $producto->precio,
|
||||||
|
'notas' => $notas,
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
//si la cantidad es 0, se elimina el producto del subpedido
|
||||||
|
$this->productos()->detach($producto->id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toggleAprobacion(bool $aprobacion)
|
||||||
|
{
|
||||||
|
$this->aprobado = $aprobacion;
|
||||||
|
$this->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function generarHTML()
|
||||||
|
{
|
||||||
|
$view = view("pdfgen.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;
|
namespace App;
|
||||||
|
|
||||||
use Illuminate\Contracts\Auth\MustVerifyEmail;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||||
use Illuminate\Notifications\Notifiable;
|
use Illuminate\Notifications\Notifiable;
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ class User extends Authenticatable
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
public function grupoDeCompra()
|
public function grupoDeCompra(): BelongsTo
|
||||||
{
|
{
|
||||||
return $this->belongsTo('App\GrupoDeCompra');
|
return $this->belongsTo('App\GrupoDeCompra');
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^7.2.5|^8.0",
|
"php": "^7.4",
|
||||||
"fideloper/proxy": "^4.4",
|
"fideloper/proxy": "^4.4",
|
||||||
"fruitcake/laravel-cors": "^2.0",
|
"fruitcake/laravel-cors": "^2.0",
|
||||||
"guzzlehttp/guzzle": "^6.3.1|^7.0.1",
|
"guzzlehttp/guzzle": "^6.3.1|^7.0.1",
|
||||||
|
@ -16,7 +16,9 @@
|
||||||
"laravel/sanctum": "^2.13",
|
"laravel/sanctum": "^2.13",
|
||||||
"laravel/tinker": "^2.5",
|
"laravel/tinker": "^2.5",
|
||||||
"laravel/ui": "*",
|
"laravel/ui": "*",
|
||||||
"league/csv": "^9.8"
|
"league/csv": "^9.8",
|
||||||
|
"mpdf/mpdf": "^8.1",
|
||||||
|
"prexview/prexview": "^1.1"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"facade/ignition": "^2.0",
|
"facade/ignition": "^2.0",
|
||||||
|
@ -52,13 +54,13 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"post-autoload-dump": [
|
"post-autoload-dump": [
|
||||||
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
|
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
|
||||||
"@php artisan package:discover --ansi"
|
"@php7.4 artisan package:discover --ansi"
|
||||||
],
|
],
|
||||||
"post-root-package-install": [
|
"post-root-package-install": [
|
||||||
"@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
|
"@php7.4 -r \"file_exists('.env') || copy('.env.example', '.env');\""
|
||||||
],
|
],
|
||||||
"post-create-project-cmd": [
|
"post-create-project-cmd": [
|
||||||
"@php artisan key:generate --ansi"
|
"@php7.4 artisan key:generate --ansi"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
1860
composer.lock
generated
1860
composer.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -1,9 +1,10 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
/** @var \Illuminate\Database\Eloquent\Factory $factory */
|
/** @var Factory $factory */
|
||||||
|
|
||||||
use App\User;
|
use App\User;
|
||||||
use Faker\Generator as Faker;
|
use Faker\Generator as Faker;
|
||||||
|
use Illuminate\Database\Eloquent\Factory;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -19,6 +19,8 @@ class CreateUsersTable extends Migration
|
||||||
$table->string('email')->unique()->nullable();
|
$table->string('email')->unique()->nullable();
|
||||||
$table->timestamp('email_verified_at')->nullable();
|
$table->timestamp('email_verified_at')->nullable();
|
||||||
$table->foreignId('grupo_de_compra_id')->nullable();
|
$table->foreignId('grupo_de_compra_id')->nullable();
|
||||||
|
$table->boolean('is_admin');
|
||||||
|
$table->unique(['name', 'is_admin']);
|
||||||
$table->string('password');
|
$table->string('password');
|
||||||
$table->rememberToken();
|
$table->rememberToken();
|
||||||
$table->timestamps();
|
$table->timestamps();
|
||||||
|
|
|
@ -17,7 +17,7 @@ class CreateSubpedidosTable extends Migration
|
||||||
$table->id();
|
$table->id();
|
||||||
$table->string('nombre');
|
$table->string('nombre');
|
||||||
$table->foreignId('grupo_de_compra_id');
|
$table->foreignId('grupo_de_compra_id');
|
||||||
$table->boolean('aprobado')->nullable();
|
$table->boolean('aprobado')->default(false);
|
||||||
$table->timestamps();
|
$table->timestamps();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
class AgregarColumnaBonoATablaDeProductos extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::table('productos', function (Blueprint $table) {
|
||||||
|
$table->boolean('bono')->after('apto_celiacxs');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('productos', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('bono');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
class AgregarColumnaTotalATablaDeProductoSubpedido extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::table('producto_subpedido', function (Blueprint $table) {
|
||||||
|
$table->double('total',10,2)->after('cantidad')->default(0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('producto_subpedido', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('total');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -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()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
19
database/seeds/CanastaSeeder.php
Normal file
19
database/seeds/CanastaSeeder.php
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Helpers\CanastaHelper;
|
||||||
|
use Illuminate\Database\Seeder;
|
||||||
|
|
||||||
|
class CanastaSeeder extends Seeder
|
||||||
|
{
|
||||||
|
const ARCHIVO_DEFAULT = 'csv/productos.csv';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the database seeds.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
CanastaHelper::cargarCanasta(self::ARCHIVO_DEFAULT);
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,7 +12,8 @@ class DatabaseSeeder extends Seeder
|
||||||
*/
|
*/
|
||||||
public function run()
|
public function run()
|
||||||
{
|
{
|
||||||
|
$this->call(CanastaSeeder::class);
|
||||||
$this->call(GrupoDeCompraSeeder::class);
|
$this->call(GrupoDeCompraSeeder::class);
|
||||||
$this->call(ProductoSeeder::class);
|
$this->call(UserSeeder::class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use App\Helpers\CsvHelper as CsvHelperAlias;
|
||||||
use Illuminate\Database\Seeder;
|
use Illuminate\Database\Seeder;
|
||||||
use League\Csv\Reader;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
|
||||||
class GrupoDeCompraSeeder extends Seeder
|
class GrupoDeCompraSeeder extends Seeder
|
||||||
{
|
{
|
||||||
|
@ -12,11 +14,7 @@ class GrupoDeCompraSeeder extends Seeder
|
||||||
*/
|
*/
|
||||||
public function run()
|
public function run()
|
||||||
{
|
{
|
||||||
$csv = Reader::createFromPath(resource_path('csv/barrios.csv'), 'r');
|
$registros = CsvHelperAlias::getRecords('csv/barrios.csv');
|
||||||
$csv->setDelimiter("|");
|
|
||||||
$csv->setEnclosure("'");
|
|
||||||
$csv->setHeaderOffset(0);
|
|
||||||
$registros = $csv->getRecords();
|
|
||||||
$gdcToInsert = [];
|
$gdcToInsert = [];
|
||||||
$usersToInsert = [];
|
$usersToInsert = [];
|
||||||
|
|
||||||
|
@ -31,7 +29,15 @@ class GrupoDeCompraSeeder extends Seeder
|
||||||
|
|
||||||
$usersToInsert[] = [
|
$usersToInsert[] = [
|
||||||
'name' => $registro['barrio'],
|
'name' => $registro['barrio'],
|
||||||
'password' => Hash::make($registro['barrio']),
|
'password' => Hash::make("123"),
|
||||||
|
"is_admin" => 0,
|
||||||
|
'grupo_de_compra_id' => $key
|
||||||
|
];
|
||||||
|
|
||||||
|
$usersToInsert[] = [
|
||||||
|
'name' => $registro['barrio'] . "_admin",
|
||||||
|
'password' => Hash::make("123"),
|
||||||
|
"is_admin" => 1,
|
||||||
'grupo_de_compra_id' => $key
|
'grupo_de_compra_id' => $key
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,39 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
use Illuminate\Database\Seeder;
|
|
||||||
use League\Csv\Reader;
|
|
||||||
use App\Proveedor;
|
|
||||||
|
|
||||||
class ProductoSeeder extends Seeder
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Run the database seeds.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function run()
|
|
||||||
{
|
|
||||||
$csv = Reader::createFromPath(resource_path('csv/productos.csv'), 'r');
|
|
||||||
$csv->setDelimiter("|");
|
|
||||||
$csv->setEnclosure("'");
|
|
||||||
$csv->setHeaderOffset(0);
|
|
||||||
$registros = $csv->getRecords();
|
|
||||||
$toInsert = [];
|
|
||||||
|
|
||||||
foreach($registros as $registro){
|
|
||||||
$toInsert[] = [
|
|
||||||
'categoria' => $registro['categoria'],
|
|
||||||
'nombre' => $registro['producto'],
|
|
||||||
'precio' => $registro['precio'],
|
|
||||||
'proveedor_id' => isset($registro['proveedor']) ? Proveedor::firstOrCreate([
|
|
||||||
'nombre' => $registro['proveedor']
|
|
||||||
])->id : null
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (array_chunk($toInsert,DatabaseSeeder::CHUNK_SIZE) as $chunk)
|
|
||||||
{
|
|
||||||
DB::table('productos')->insert($chunk);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
31
database/seeds/UserSeeder.php
Normal file
31
database/seeds/UserSeeder.php
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Seeder;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Hash;
|
||||||
|
|
||||||
|
class UserSeeder extends Seeder
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the database seeds.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
$usersToInsert = [];
|
||||||
|
|
||||||
|
$usersToInsert[] = [
|
||||||
|
'name' => 'compras',
|
||||||
|
'password' => Hash::make("123"),
|
||||||
|
'is_admin' => 0,
|
||||||
|
'is_compras' => 1
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
foreach (array_chunk($usersToInsert,DatabaseSeeder::CHUNK_SIZE) as $chunk)
|
||||||
|
{
|
||||||
|
DB::table('users')->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:
|
services:
|
||||||
app:
|
app:
|
||||||
build:
|
build:
|
||||||
args:
|
args:
|
||||||
user: www
|
user: www
|
||||||
uid: 1000
|
uid: ${USERID}
|
||||||
context: ./
|
context: ./
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
image: laravel-image
|
image: laravel-image
|
||||||
container_name: laravel-app
|
container_name: pedi2-app
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
working_dir: /var/www/
|
working_dir: /var/www/
|
||||||
volumes:
|
volumes:
|
||||||
|
@ -19,10 +20,8 @@ services:
|
||||||
|
|
||||||
db:
|
db:
|
||||||
image: mysql:5.7
|
image: mysql:5.7
|
||||||
container_name: laravel-db
|
container_name: pedi2-db
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
ports:
|
|
||||||
- "3306:3306"
|
|
||||||
environment:
|
environment:
|
||||||
MYSQL_DATABASE: ${DB_DATABASE}
|
MYSQL_DATABASE: ${DB_DATABASE}
|
||||||
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
|
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
|
||||||
|
@ -36,13 +35,15 @@ services:
|
||||||
- dbdata:/var/lib/mysql
|
- dbdata:/var/lib/mysql
|
||||||
networks:
|
networks:
|
||||||
- app-network
|
- app-network
|
||||||
|
ports:
|
||||||
|
- ${DB_PORT_EXPOSED}:3306
|
||||||
|
|
||||||
nginx:
|
nginx:
|
||||||
image: nginx:alpine
|
image: nginx:alpine
|
||||||
container_name: laravel-nginx
|
container_name: pedi2-nginx
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
- 8000:80
|
- ${NGINX_PORT}:80
|
||||||
volumes:
|
volumes:
|
||||||
- ./:/var/www
|
- ./:/var/www
|
||||||
- ./nginx/conf.d/:/etc/nginx/conf.d/
|
- ./nginx/conf.d/:/etc/nginx/conf.d/
|
||||||
|
|
26581
package-lock.json
generated
Normal file
26581
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
10
package.json
10
package.json
|
@ -10,9 +10,9 @@
|
||||||
"production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --config=node_modules/laravel-mix/setup/webpack.config.js"
|
"production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --config=node_modules/laravel-mix/setup/webpack.config.js"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"axios": "^0.19",
|
"axios": "^0.19.2",
|
||||||
"bootstrap": "^4.0.0",
|
"bootstrap": "^4.0.0",
|
||||||
"cross-env": "^7.0",
|
"cross-env": "^7.0.3",
|
||||||
"jquery": "^3.2",
|
"jquery": "^3.2",
|
||||||
"laravel-mix": "^5.0.1",
|
"laravel-mix": "^5.0.1",
|
||||||
"lodash": "^4.17.19",
|
"lodash": "^4.17.19",
|
||||||
|
@ -22,5 +22,11 @@
|
||||||
"sass-loader": "^8.0.0",
|
"sass-loader": "^8.0.0",
|
||||||
"vue": "^2.5.17",
|
"vue": "^2.5.17",
|
||||||
"vue-template-compiler": "^2.6.10"
|
"vue-template-compiler": "^2.6.10"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"animate.css": "^4.1.1",
|
||||||
|
"bulma": "^0.9.4",
|
||||||
|
"bulma-switch": "^2.0.4",
|
||||||
|
"bulma-toast": "^2.4.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
BIN
public/assets/chismosa.png
Normal file
BIN
public/assets/chismosa.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 2.4 KiB |
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;
|
|
||||||
}
|
|
73
public/js/app.js
vendored
73
public/js/app.js
vendored
|
@ -1,73 +0,0 @@
|
||||||
window.Event = new Vue();
|
|
||||||
|
|
||||||
Vue.component('nav-bar', {
|
|
||||||
template: `
|
|
||||||
<nav class="navbar is-danger" role="navigation" aria-label="main navigation">
|
|
||||||
<div class="navbar-brand">
|
|
||||||
<a class="navbar-item" href="https://mps.org.uy">
|
|
||||||
<img src="/assets/logoMPS.png" height="28">
|
|
||||||
</a>
|
|
||||||
<p style="margin:0 auto" class="navbar-item"><slot name="subpedido"></slot></p>
|
|
||||||
<a role="button" class="navbar-burger" :class="{'is-active':isActive}" aria-label="menu" aria-expanded="false" data-target="navbarBasicExample" @click="toggleState">
|
|
||||||
<span aria-hidden="true"></span>
|
|
||||||
<span aria-hidden="true"></span>
|
|
||||||
<span aria-hidden="true"></span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="navbarBasicExample" class="navbar-menu" :class="{'is-active':isActive}">
|
|
||||||
<div class="navbar-start has-text-right-mobile">
|
|
||||||
<!-- Styles nombre del barrio-->
|
|
||||||
<p class="navbar-item"><slot name="gdc"></slot></p>
|
|
||||||
<a class="navbar-item"
|
|
||||||
onclick="event.preventDefault();
|
|
||||||
document.getElementById('logout-form').submit();">
|
|
||||||
Cerrar sesión
|
|
||||||
</a>
|
|
||||||
<slot name="logout-form"></slot>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</nav>`,
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
isActive: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
toggleState() {
|
|
||||||
this.isActive = !this.isActive;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Vue.component('nav-migas', {
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
migas: []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
visible: function() {
|
|
||||||
return this.migas.length > 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
Event.$on('migas-setear-como-inicio', (miga) => {
|
|
||||||
this.migas = [];
|
|
||||||
this.migas.push(miga);
|
|
||||||
});
|
|
||||||
Event.$on('migas-agregar', (miga) => {
|
|
||||||
this.migas.push(miga);
|
|
||||||
});
|
|
||||||
Event.$on('migas-reset', () => {
|
|
||||||
this.migas = [];
|
|
||||||
});
|
|
||||||
Event.$on('migas-pop', () => {
|
|
||||||
this.migas.pop();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
new Vue({
|
|
||||||
el: '#app'
|
|
||||||
});
|
|
114
public/js/login.js
vendored
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);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
33
public/js/subpedidos-create.js
vendored
33
public/js/subpedidos-create.js
vendored
|
@ -1,33 +0,0 @@
|
||||||
Vue.component('subpedido-select', {
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
subpedido: null,
|
|
||||||
subpedidosExistentes: []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
props: ["gdcid"],
|
|
||||||
mounted() {
|
|
||||||
console.log("ready");
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
onType() {
|
|
||||||
axios.get("/api/subpedidos?nombre=" + this.subpedido).then(response => {
|
|
||||||
this.subpedidosExistentes = response.data
|
|
||||||
});
|
|
||||||
},
|
|
||||||
submit() {
|
|
||||||
axios.post("/api/subpedidos", {
|
|
||||||
nombre: this.subpedido,
|
|
||||||
grupo_de_compra_id: this.gdcid
|
|
||||||
}).then(response => {
|
|
||||||
|
|
||||||
//se creo el subpedido, guardamos el subpedido en sesion
|
|
||||||
axios.post("/subpedidos/guardar_sesion", {
|
|
||||||
subpedido: response.data
|
|
||||||
}).then(response => {
|
|
||||||
window.location.href = 'productos';
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,45 +1,4 @@
|
||||||
barrio|region|referente|telefono|correo
|
barrio|region|referente|telefono|correo
|
||||||
BUCEO|ESTE|||
|
ENTREVERO|SUR|||
|
||||||
MALVIN NORTE|ESTE|||
|
|
||||||
PINAR|ESTE|||
|
|
||||||
UNION|ESTE|||
|
|
||||||
SANTO DOMINGO|NORTE|||
|
|
||||||
21 DE FEBRERO|NORTE|||
|
|
||||||
PIEDRAS BLANCAS|NORTE|||
|
|
||||||
BELLA ITALIA|NORTE|||
|
|
||||||
JARDINES|NORTE|||
|
|
||||||
LA SOCIALISTA|NORTE|||
|
|
||||||
VILLA GARCIA|NORTE|||
|
|
||||||
LAS ACACIAS|NORTE|||
|
|
||||||
MANGA|NORTE|||
|
|
||||||
CERRITO|OESTE|||
|
|
||||||
LEZICA|OESTE|||
|
|
||||||
PEÑAROL|OESTE|||
|
|
||||||
LAS PIEDRAS|OESTE|||
|
|
||||||
A.C.T.E.O|OESTE|||
|
|
||||||
NUEVO PARIS|OESTE|||
|
|
||||||
SANTA CATALINA|OESTE|||
|
|
||||||
BELVEDERE|OESTE|||
|
|
||||||
BATLLE BERRES|OESTE|||
|
|
||||||
CERRO PTI|OESTE|||
|
|
||||||
COLECTIVO UTU LAVALLEJA|OESTE|||
|
|
||||||
FOGONES|OESTE|||
|
|
||||||
LAVALLEJA|OESTE|||
|
|
||||||
REJUNTE|OESTE|||
|
|
||||||
CAPURRO|OESTE|||
|
|
||||||
PARQUE RODO|SUR|||
|
|
||||||
REDUCTO|SUR|||
|
|
||||||
AGUADA|SUR|||
|
|
||||||
CASA DEL VECINO|SUR|||
|
|
||||||
CIUDAD VIEJA|SUR|||
|
|
||||||
COOP EJIDO|SUR|||
|
|
||||||
COVIREUS|SUR|||
|
|
||||||
LA BLANQUEADA|SUR|||
|
|
||||||
NITEP|SUR|||
|
|
||||||
LA CURVA|SUR|||
|
|
||||||
PANADERIA VIDAL|SUR|||
|
|
||||||
SUA|SUR|||
|
|
||||||
TRES CRUCES|SUR|||
|
TRES CRUCES|SUR|||
|
||||||
VILLA ESPAÑOLA|SUR|||
|
PRUEBA|SIN REGION|||
|
||||||
AUDA|OTRA|||
|
|
||||||
SINTEP|OTRA|||
|
|
|
0
resources/csv/exports/.gitignore
vendored
Normal file
0
resources/csv/exports/.gitignore
vendored
Normal file
|
@ -1,359 +1,381 @@
|
||||||
categoria|producto|precio|proveedor
|
Tipo|Producto|Precio
|
||||||
ALIMENTOS NO PERECEDEROS|Yerba Compuesta La Herboristería 1kg |140.3|
|
ALIMENTOS NO PERECEDEROS||
|
||||||
ALIMENTOS NO PERECEDEROS|Yerba Yusa tradicional 1kg |121.8|
|
P|Yerba Compuesta La Herboristería 1kg|157.63
|
||||||
ALIMENTOS NO PERECEDEROS|Yerba Yusa tradicional 500grs|65|
|
P|Yerba Yusa tradicional 1kg|148.00
|
||||||
ALIMENTOS NO PERECEDEROS|Yerba Sara tradicional 1kg|129.7|
|
P|Yerba Yusa tradicional 500grs|81.00
|
||||||
ALIMENTOS NO PERECEDEROS|Yerba Sara suave 1kg|132.2|
|
P|Yerba Sara tradicional 1kg (Sin TACC)|139.40
|
||||||
ALIMENTOS NO PERECEDEROS|Yerba Kiero mate 500grs|72.5|
|
P|Yerba Sara suave 1kg (Sin TACC)|139.40
|
||||||
ALIMENTOS NO PERECEDEROS|*Harina Santa Unión 000 1kg|27.3|Santa Unión
|
P|*Harina Santa Unión 000 1kg|33.11
|
||||||
ALIMENTOS NO PERECEDEROS|*Harina Santa Unión 0000 1kg|34.8|Santa Unión
|
P|*Harina Santa Unión 0000 1kg|38.70
|
||||||
ALIMENTOS NO PERECEDEROS|*Harina de trigo integral Pasaná 1 kg|65|Pasaná
|
P|*Harina de arroz Pasaná 1 kg (Puede contener gluten)|90.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Harina de arroz Pasaná 1 kg |65|Pasaná
|
P|*Harina de Garbanzos Pasaná 1 kg (Puede contener gluten)|140.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Harina de Garbanzos Pasaná 1 kg |140|Pasaná
|
P|*Mezcla para faina Pasaná 1 kg (Puede contener gluten)|160.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Mezcla para faina Pasaná 1 kg |150|Pasaná
|
P|*Fécula de Mandioca Pasaná 1 kg (Puede contener gluten)|140.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Fécula de Mandioca Pasaná 1 kg |85|Pasaná
|
P|Fécula de Mandioca Hornex 800g (Sin TACC)|125.00
|
||||||
ALIMENTOS NO PERECEDEROS|Tres Harinas 500grs. |85|
|
P|Tres Harinas Hornex 800grs (Sin TAAC)|129.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Harina Santa Unión 000 Bolsa 25kg|560.6|Santa Unión
|
P|*Harina Santa Unión 000 Bolsa 25kg|602.86
|
||||||
ALIMENTOS NO PERECEDEROS|*Polenta Santa Unión 450gr|15.4|Santa Unión
|
P|*Polenta Santa Unión 450gr|16.34
|
||||||
ALIMENTOS NO PERECEDEROS|*Mezcla de Fainá Santa Unión 5kg|294.8|Santa Unión
|
P|*Mezcla de Fainá Santa Unión 5kg|431.29
|
||||||
ALIMENTOS NO PERECEDEROS|*Fideos Caorsi Tirabuzón 1kg|59|Caorsi
|
P|*Harina de trigo intergal orgánica "La linda sauceña"|97.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Fideos Caorsi Tallarín 1kg|69|Caorsi
|
P|*Fideos Caorsi Tirabuzón 1kg|73.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Fideos Caorsi Moñita 1kg|69|Caorsi
|
P|*Fideos Caorsi Tallarín 1kg|81.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Fideos Caorsi para sopa 1kg|59|Caorsi
|
P|*Fideos Caorsi Moñita 1kg|81.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Fideos Caorsi para sopa 5kg|268|Caorsi
|
P|*Fideos Caorsi Tirabuzón 5kg|353.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Fideos Caorsi Tirabuzón 5kg|268|Caorsi
|
P|Arroz Blue Patna 1kg|50.02
|
||||||
ALIMENTOS NO PERECEDEROS|Arroz Blue Patna 1kg|40.2|
|
P|Arroz Shiva 1kg|35.65
|
||||||
ALIMENTOS NO PERECEDEROS|Arroz Shiva 1kg|27|
|
P|*Arroz integral 1kg|72.00
|
||||||
ALIMENTOS NO PERECEDEROS|Arroz integral 1kg |55|
|
P|*Arroz integral 3kg|204.00
|
||||||
ALIMENTOS NO PERECEDEROS|Arroz integral 3kg|155|
|
P|Aceite Condesa de Soja 900 cc.|59.80
|
||||||
ALIMENTOS NO PERECEDEROS|Aceite Condesa de Soja 900 cc.|84|
|
P|Aceite Uruguay de Girasol 900 cc.|81.70
|
||||||
ALIMENTOS NO PERECEDEROS|Aceite Uruguay de Girasol 900 cc.|108|
|
P|Aceite Optimo canola 900 cc.|75.00
|
||||||
ALIMENTOS NO PERECEDEROS|Aceite Optimo canola 900 cc.|82.4|
|
P|Vinagre Uruguay 900ml|61.60
|
||||||
ALIMENTOS NO PERECEDEROS|*Aceite de oliva 500 ml. |195|
|
P|*Salsa de soja La Posta 250 ml.|120.00
|
||||||
ALIMENTOS NO PERECEDEROS|Vinagre Uruguay 900ml|77.9|
|
P|*Aceitunas verdes sin carozo en frasco La Posta 500 gr.|220.00
|
||||||
ALIMENTOS NO PERECEDEROS|Aceite de Oliva Cuatro Piedras 3 lt|1090|
|
P|*Aceitunas negras sin carozo en frasco La Posta 500 gr.|240.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Salsa de soja La Posta 250 ml. |95|
|
P|Lata de atún Golden Fish desmenuzado al aceite 170g|33.35
|
||||||
ALIMENTOS NO PERECEDEROS|*Aceitunas verdes sin carozo en frasco La Posta 500 gr. |180|La Posta
|
P|Lata de arvejas Campero 300g|18.28
|
||||||
ALIMENTOS NO PERECEDEROS|*Aceitunas negras sin carozo en frasco frasco La Posta 500 gr. |180|La Posta
|
P|Lata de choclo Cosecha 300g|32.29
|
||||||
ALIMENTOS NO PERECEDEROS|Lata atún Golden Fish desmenuzado al aceite 170g|31.1|
|
P|Lata de jardinera Cosecha|30.34
|
||||||
ALIMENTOS NO PERECEDEROS|Lata de arvejas Campero 300g|18.3|
|
P|Lata de porotos negros Cosecha|37.06
|
||||||
ALIMENTOS NO PERECEDEROS|Lata de choclo Cosecha 300g|22|
|
P|Lata de porotos de frutilla Cosecha|37.06
|
||||||
ALIMENTOS NO PERECEDEROS|Lata de jardinera Cosecha|25|
|
P|Lata de duraznos en almíbar Campero|73.07
|
||||||
ALIMENTOS NO PERECEDEROS|Lata de porotos negros Cosecha|31.1|
|
P|Mayonesa Uruguay 500g|81.40
|
||||||
ALIMENTOS NO PERECEDEROS|Lata de porotos de frutilla Cosecha|31.1|
|
P|Azúcar Bella Unión 1kg|44.90
|
||||||
ALIMENTOS NO PERECEDEROS|Lata de duraznos en almíbar Campero |66.6|
|
P|Azúcar Mascabo 500g|102.00
|
||||||
ALIMENTOS NO PERECEDEROS|Mayonesa Uruguay 500g|77.9|
|
P|Azúcar impalpable Hornex 200 gr|39.00
|
||||||
ALIMENTOS NO PERECEDEROS|Azúcar Azucarlito 25kg|1007.5|
|
P|Almidón de maíz Hornex 1Kg|89.00
|
||||||
ALIMENTOS NO PERECEDEROS|Azúcar Bella Unión 1kg|39.8|
|
P|Almidón de maíz Ilu wayra 1Kg|75.00
|
||||||
ALIMENTOS NO PERECEDEROS|Azúcar impalpable Hornex 200 gr|31|
|
P|Polvo de Hornear Hornex 100 g + 20 g|38.00
|
||||||
ALIMENTOS NO PERECEDEROS|Azúcar impalpable Hornex 1kg|104|
|
P|*Esencia de vainilla La Posta 100ml|100.00
|
||||||
ALIMENTOS NO PERECEDEROS|Almidón de maíz Hornex 1Kg|64.5|
|
P|*Bicarbonato de sodio La Posta 250 gr|60.00
|
||||||
ALIMENTOS NO PERECEDEROS|Polvo de Hornear Hornex 1 kg|122|
|
P|Grasa Uruguay 400grs|45.80
|
||||||
ALIMENTOS NO PERECEDEROS|Polvo de Hornear Hornex 100 g + 20 g|27.9|
|
P|Levadura seca Hornex 125g|120.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Esencia de vainilla La Posta 100ml|80|
|
P|Café Sorocabana glaseado p/máquina 500 grs|396.00
|
||||||
ALIMENTOS NO PERECEDEROS|Grasa Uruguay 400grs|50|
|
P|Café Sorocabana natural p/máquina 500 grs|557.00
|
||||||
ALIMENTOS NO PERECEDEROS|Levadura seca Hornex 125g|85.5|
|
P|Café soluble Saint bollón 170 gr|232.50
|
||||||
ALIMENTOS NO PERECEDEROS|Café Sorocabana glaseado p/máquina 500 grs|232.8|
|
P|Té Negro en hebras 90gr hornimans|41.12
|
||||||
ALIMENTOS NO PERECEDEROS|Café Sorocabana natural p/máquina 500 grs |315.8|
|
P|Galletas de arroz SIN SAL Natural Rice 120 gr (Sin TACC)|39.00
|
||||||
ALIMENTOS NO PERECEDEROS|Café Saint 170 gr Instantaneo|185.3|
|
P|Galletas de arroz comunes Natural Rice 120 gr (Sin TACC)|39.00
|
||||||
ALIMENTOS NO PERECEDEROS|Té Negro en hebras 90gr hornimans|30.7|
|
P|Leche en polvo entera 250 g|105.00
|
||||||
ALIMENTOS NO PERECEDEROS|Galletas de arroz comunes Natural Rice 120 gr|34|
|
P|Leche en polvo entera 1kg|315.00
|
||||||
ALIMENTOS NO PERECEDEROS|* Leche en polvo 250grs|65|
|
P|* Coco rallado 200gr|72.00
|
||||||
ALIMENTOS NO PERECEDEROS|* Leche en polvo 1kg|220|
|
P|* Coco rallado 1kg|246.00
|
||||||
ALIMENTOS NO PERECEDEROS|* Coco rallado 200gr|70|
|
P|Cocoa Hornex 200gr|55.00
|
||||||
ALIMENTOS NO PERECEDEROS|* Coco rallado 1kg|275|
|
P|Postre de chocolate Hornex 8 porciones|44.00
|
||||||
ALIMENTOS NO PERECEDEROS|Cocoa Hornex 200gr|43|
|
P|Postre LIGHT de vainilla Hornex 8 porciones (aprobado por ADU)|68.00
|
||||||
ALIMENTOS NO PERECEDEROS|Postre de chocolate Hornex 8 porciones|36.5|
|
P|Flan de vainilla Hornex 8 porciones|44.00
|
||||||
ALIMENTOS NO PERECEDEROS|Prostre LIGHT de vainilla Hornex 8 porciones (aprobado por ADU)|57|
|
P|Gelatina de frutilla Hornex 8 porciones|44.00
|
||||||
ALIMENTOS NO PERECEDEROS|Flan de vainilla Hornex 8 porciones|36.5|
|
P|Bizcochuelo de vainilla SIN GLUTEN 500gr Hornex|180.00
|
||||||
ALIMENTOS NO PERECEDEROS|Gelatina de frutilla Hornex 8 porciones|36.5|
|
P|Pizza SIN GLUTEN 320gr Hornex|170.00
|
||||||
ALIMENTOS NO PERECEDEROS|Bizcochuelo de vainilla SIN GLUTEN 500gr Hornex|142|
|
P|Pulpa de Tomate De Ley 1lt (S-G)|50.43
|
||||||
ALIMENTOS NO PERECEDEROS|Pizza SIN GLUTEN 320gr Hornex|137|
|
P|Pure de papa instantaneo De Ley 125g|24.73
|
||||||
ALIMENTOS NO PERECEDEROS|Pulpa de Tomate De Ley 1lt|43.5|
|
P|*Sal fina sin fluor Polenteados 500g|36.00
|
||||||
ALIMENTOS NO PERECEDEROS|Pure de papa instantaneo De Ley 125g|21.3|
|
P|*Sal gruesa sin fluor Polenteados 500g|36.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Sal fina sin fluor Polenteados 500g|27|
|
P|*Sal Rosa 250gr |80.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Sal gruesa sin fluor Polenteados 500g|27|
|
P|*Salsa de tomate casera (puro tomate) 1 lt - (S-G) - azucar agregada: 1g/L - sal agregada: 0,25g/L|85.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Salsa de tomate casera (puro tomate) 1 lt|65|
|
P|*Barras de cereales (maní, sésamo, lino, girasol, avena, copos de arroz, copos de máiz, azúcar rubia y miel) - Pack x2|80.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Barras de cereales (maní, sésamo, lino, girasol, avena, copos de arroz, copos de máiz, azúcar rubia y miel) - Pack x2 |65|
|
P|*Barras de cereales bañadas en chocolate (maní, sésamo, lino, girasol, avena, copos de arroz, copos de máiz, azúcar rubia y miel) - Pack x2|90.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Barras de cereales bañadas en chocolate (maní, sésamo, lino, girasol, avena, copos de arroz, copos de máiz, azúcar rubia y miel) - Pack x2|75|
|
P|*Granola artesanal 500 gr Ing: copos ,avena,miel, vainilla,coco rallado, chia,girasol,sésamo, lino,maní, almendras, castañas de caju, nueces, chips de chocolate.|250.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Granola artesanal 500 gr Ing: copos ,avena,miel, vainilla,coco rallado, chia,girasol,sésamo, lino,maní, almendras, castañas de caju, nueces, chips de chocolate.|210|
|
P|*Granola simple (avena+ girasol+ pasaUva) 1kg|171.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Granola simple (avena+ girasol+ pasaUva) 1kg|160|
|
P|*Copos de maíz azucarados 500g|112.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Copos de maíz azucarados 500g|89|
|
P|*Copos de maíz naturales 500g|112.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Copos de maíz naturales 500g|89|
|
P|*Crema untable de maní 330 gr, envase de vidrio |225.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Crema untable de maní 250gr|89|
|
P|*Tableta artesanal chocolate semiamargo con frutos secos 100g |130.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Galletas de coco, avena y maní 400gr|100|
|
P|*Tableta artesanal chocolate semiamargo con pasas 100g |130.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Budin Panitep con cobertura de chocolate con almendras, maní, nueces y pasas 250grs|160|
|
P|*Tableta artesanal chocolate blanco con frutos secos 100g |130.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Budin Panitep con cobertura de almíbar y coco con almendras, maní, nueces y pasas 250grs|140|
|
P|*Tableta artesanal chocolate blanco con pasas 100g |130.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Budin Panitep de naranja 250grs|140|
|
P|Alfajor de chocolate negro 80 g (S-G) |48.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Chia 1/4 kg |65|
|
P|Galletitas dulces de chispas de chocolate y avena 150 g (S-G)|116.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Girasol 1/2 kg |85|
|
P|Crackers saladas de sésamo girasol y chía 180 g (S-G)|116.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Lino 1/4 kg |30|
|
P|*Lino 1/4 kg|42.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Sésamo 1/4 kg |55|
|
P|*Chía 1/4 kg|80.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Quinoa 1 kg |200|
|
P|*Girasol 1/2 kg|140.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Dátiles con carozo 500 gr|180|
|
P|*Sésamo 1/4 kg|65.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Cacao en polvo 250 grs |100|
|
P|*Quinoa 1 kg|210.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Almendra pelada (sin tostar) Polenteados 100g|80|Polenteados
|
P|*Dátiles con carozo 500 gr|240.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Pasas de Uva Polenteados 250 gr|69|Polenteados
|
P|*Cacao en polvo 250 grs (S-A)|125.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Nueces Polenteados 100g|79|Polenteados
|
P|*Almendra pelada (sin tostar) Polenteados 100g|93.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Castañas tostadas SIN sal 100grs|76|Polenteados
|
P|*Pasas de Uva Polenteados 500 gr|149.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Avena laminada instantánea Polenteados 500g|49|Polenteados
|
P|*Nueces Polenteados 100g|89.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Pan de molde Gigor Lacteado 550g|55|Gigor
|
P|*Castañas tostadas SIN sal 100grs|81.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Pan de molde Gigor Integral 550g|55|Gigor
|
P|*Avena laminada instantánea Polenteados 500g|69.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Galleta Malteada La Socialista 350g|56|La Socialista
|
P|*Pan de molde Gory Lacteado 550g|64.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Galleta Malteada c/semillas (sésamo, chia, lino) La Socialista 380gr |74|La Socialista
|
P|*Pan de molde Integral Gory 550g|64.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Galleta Cara Sucia La Socialista 350g|63|La Socialista
|
P|*Galleta Malteada La Socialista 350g|84.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Grisines La Socialista 350g|67|La Socialista
|
P|*Galleta Malteada c/semillas (sésamo, chia, lino) La Socialista 380gr|103.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Mezcla para panqueques La Socialista 2 x 250g|56|La Socialista
|
P|*Galleta Cara Sucia La Socialista 350g|92.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Mezcla para salsa blanca La Socialista 2 x 50g|46|La Socialista
|
P|*Grisines La Socialista 350g|96.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Maní pelado frito y salado Polenteados 500g|89|Polenteados
|
P|*Maní pelado frito y salado Polenteados 500g|103.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Maní pelado sin sal Polenteados 500g|89|Polenteados
|
P|*Maní pelado sin sal Polenteados 500g|103.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Garbanzo Polenteados 1kg|79|Polenteados
|
P|*Garbanzo Polenteados 1kg|109.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Lentejas Polenteados 1kg|96|Polenteados
|
P|* Maiz para pop 500grs|54.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Porotos negros Polenteados 1kg|86|Polenteados
|
P|*Lentejas Polenteados 1kg|125.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Porotos de manteca Polenteados 1kg |105|Polenteados
|
P|*Porotos negros Polenteados 1kg|125.00
|
||||||
ALIMENTOS NO PERECEDEROS|*Proteína de SOJA texturizada 1kg |125|
|
P|*Porotos de manteca Polenteados 1kg|149.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Tallarines frescos de yema Pastas Colon 1kg|155|Pastas Colón
|
P|*Porotos mung 1kg |150.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Tallarines frescos de espinaca Pastas Colon 1kg|165|Pastas Colón
|
P|*Arvejas 1kg |120.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Tallarines frescos de morrón Pastas Colon 1kg|165|Pastas Colón
|
P|*Proteína de SOJA texturizada 1kg|139.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Salsa pomarola 300gr ex trabajadores de La Spezia|90|
|
P|*Semillas Zapallo 100g.|60.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Fetuccine integral de zanahoria, apto veganos 1kg|190|
|
CONDIMENTOS, PERECEDEROS Y BEBIDAS||
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Romanitos rellenos jamón y queso ex trabajadores de La Spezia 1kg|490|
|
P|*Tallarines frescos de yema Pastas Colon 1kg|175.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Romanitos vegetarianos ex trabajadores de La Spezia 1kg|490|
|
P|*Tallarines frescos de espinaca Pastas Colon 1kg|185.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Sorrentinos jamón y queso 1Kg ex trabajadores de La Spezia|450|
|
P|*Tallarines frescos de morrón Pastas Colon 1kg|190.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Sorrentinos Ricota y Nuez 1kg ex Trabajadores de La Spezia|450|
|
P|*Prepizza 28cm ex trabajadores de La Spezia|90.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Raviolón vegetariano 1Kg ex trabajadores de La Spezia|450|
|
P|*Milanesas de carne 1kg|395.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Raviolón Caprese 1kg ex Trabajadores de La Spezia|450|
|
P|*Milanesas de pollo 1kg|370.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Prepizza de 28cm ex trabajadores de La Spezia|85|
|
P|*Empanada de pollo x 6|265.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Milanesas de carne empanadas 1kg|365|
|
P|*Empanada de carne x 6|265.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Milanesas de pollo empanadas 1kg|365|
|
P|*Pan rallado 1kg|75.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Milanesas de seitan x6 |300|
|
P|*Pan rallado saborizado 1Kg|95.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Hamburguesas parrilleras de soja no transgénica, sal, harina de avena y adobo sin picante x6|300|
|
P|*Pimienta blanca 30g|20.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Jamón vegano (gluten de trigo, salsa de tomate, sabor ahumado, sal) horma 250 g|200|
|
P|*Orégano 25g|20.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Hummus 200cc |140|
|
P|*Pimentón 30g|20.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Pate de zanahoria 200cc |140|
|
P|*Adobo 30g|20.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Pan rallado 1kg|55|
|
P|*Ajo y Perejil 30g|20.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Pan rallado saborizado 1Kg|75|
|
P|*Clavo de olor 15g|20.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Pimienta blanca 30g|20|
|
P|*Tomillo 25g|20.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Orégano 25g|20|
|
P|*PACK "A" Curry / Nuez moscada / Ajo en polvo / Condimento verde / Comino|100.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Pimentón 30g|20|
|
P|*PACK "B" Pimienta Negra polvo / Sal de ajo / Aji molido / Canela en polvo / Condimento para arroz|100.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Adobo 30g|20|
|
P|*PACK "C" Cebolla en polvo / Pimienta blanca en grano / Pimienta negra en grano / Ajo en escamas / Especias surtidas|100.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Ajo y Perejil 30g|20|
|
P|*Pimentón 250grs|110.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*PACK "A" Curry, nuez moscada, ajo polvo, condimento verde, comino|80|
|
P|*Orégano 250g|115.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*PACK "B" Pimienta Negra polvo / sal de ajo, aji molido, canela polvo y chimichurry|80|
|
P|*Nuez moscada entera 2 unidades|28.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*PACK "C" Cebolla en escamas, tomillo, clavo de olor, pimienta blanca en grano, ajo en escamas|80|
|
P|*Canela en rama 10g|25.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Pimentón 250grs |75|
|
P|*Cúrcuma 20g|25.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Orégano 250g|85|
|
P|*Pack "Mix sabores"- Paprika, Albahaca, Mostaza en polvo.|65.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Nuez moscada entera 2 unidades |21|
|
P|*Pack "Pal mate"- Boldo, Cedron, Marcela.|120.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Canela en rama 10g|21|
|
P|*Pack "Relax"- Tilo, Malva, Té rojo.|120.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Cúrcuma 20g |21|
|
P|*Pack "Power" - Ginseng, Carqueja, Ginkgo biloba.|120.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Pack "Sabores exoticos" - Paprika, fenogreco y cardamomo|57|
|
P|Atado de perejil|50.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|'''''''*Pack "Pa''''''''l mate" - Manzanilla, cedrón y carqueja'''''''|105|
|
P|Mix de hierbas (ciboullete, tomillo, laurel y pasto lim[on)|50.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|Pack "Medicinas de monte" - Tilo, malva y marcela|105|
|
P|Atado de romero|50.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Pack "Té helado light" - Té rojo, stevia y lemon grass|105|
|
P|Fernet 760 ml|405.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|Vino Santero Marselán 1 lt.|198|
|
P|Vino Santero Marselán 1 lt.|235.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|Vino Tannat-Cabernet Paso del Roble 1 lt.|90|
|
P|Frizzante de Maracuyá|246.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|Vino Rosado dulce Paso del Roble 1 lt.|90|
|
P|Frizzante de Frutos del bosque|246.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|Frizzante de Maracuyá|205|
|
P|*Cerveza artesanal APA Press 1L|170.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|Frizzante de Frutos del bosque|205|
|
P|* Cerveza artesanal IPA Press 1L |180.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Cerveza artesanal Sudaka Blonde 500cc|100|
|
P|*Cerveza artesanal Negra Press 1L|180.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Cerveza artesanal Sudaka Scottish 500cc|100|
|
P|* Cerveza artesanal Rubia Lager 1L |160.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Cerveza artesanal Punto Rojo Red Ipa 500cc|100|
|
P|Jugo en polvo "Juguito" sabores surtidos|8.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Cerveza artesanal Punto Rojo Negra 500cc|100|
|
P|Jugo Big C 200ml sabores surtidos|16.84
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Cerveza artesanal APA Guillotina 1L|180|
|
P|*Refresco U Naranja 2lt|94.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|Fernet artesanal 780 ml|370|
|
P|*Refresco U Mandarina 2lt|94.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|Jugo en polvo "Juguito" sabores surtidos|8.06|
|
P|*Refresco U Pomelo 2lt|94.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|Jugo Big C 200ml sabores surtidos|13.14|
|
P|*Refresco U Limonada 2lt|94.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Refresco U Naranja 2lt|82|
|
P|*Agua 6 lts|98.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Refresco U Mandarina 2lt|82|
|
P|*Queso Muzzarella 1/2 kg Unidad Cooperaria|172.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Refresco U Pomelo 2lt|82|
|
P|*Queso Magro s/sal 1/2 kg Unidad Cooperaria|191.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Refresco U Limonada 2lt|82|
|
P|*Queso Magro c/sal 1/2 kg Unidad Cooperaria|191.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Agua 6 lts|84|
|
P|*Queso Danbo 1/2 kg Unidad Cooperaria|188.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Queso Muzzarella 1/2 kg Unidad Cooperaria|130|
|
P|*Queso Sbrinz 1/2 kg Unidad Cooperaria|287.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Queso Magro s/sal 1/2 kg Unidad Cooperaria|147.5|
|
P|*Queso Colonia 1/2 Kg Unidad Cooperaria|197.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Queso Magro c/sal 1/2 kg Uniddad Cooperaria|147.5|
|
P|*Queso parrillero 350g Unidad Cooperaria|177.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Queso Danbo 1/2 kg Unidad Cooperaria|137.5|
|
P|*Queso semiduro 500grs (envasado al vacío) Productores Ismael Cortinas|258.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Queso Sbrinz 1/2 kg Unidad Cooperaria|170|
|
P|*Queso cuartirolo horma 1kg envasado al vacío|375.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Queso Colonia 1/2 Kg Unidad Cooperaria|160|
|
P|*Queso rallado 200grs|155.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Queso parrillero 350g Unidad Cooperaria|165|
|
P|*Dulce de Leche 1 Kg Unidad Cooperaria|269.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Queso de mandioca en horma 400 gr|200|
|
P|*Morrones en vinagre 330 gr|230.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Queso saborizado con ciboulette 600grs (envasado al vacío)|230|
|
P|*Berenjenas en vinagre 330 gr|230.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Queso saborizado con albahaca 600grs (envasado al vacío)|230|
|
P|*Mermelada de morrones 250 gr|230.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Queso saborizado con orégano 500grs (envasado al vacío)|250|
|
P|*Mermelada de frutilla, 450 grs.|145.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Queso semiduro 500grs (envasado al vacío) Productores Ismael Cortinas|195|
|
P|*Mermelada de durazno, 450 grs.|133.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Queso cuartirolo horma 1kg envasado al vacío|270|
|
P|*Mermelada de ciruela, 450 grs.|133.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Queso rallado 100grs|63|
|
P|*Mermelada de higo, 450 grs.|133.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Queso rallado 200grs|120|
|
P|*Mermelada de zapallo, 450 grs.|133.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Dulce de Leche 1 Kg Unidad Cooperaria|165|
|
P|*Mermelada de naranja, 450 grs.|134.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Dulce de leche de coco 360 gr|300|
|
P|*Mermelada de arándanos, 450 grs.|159.50
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Morrones en vinagre 330 gr|140|
|
P|*Dulce de membrillo, 900grs|123.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Berenjenas en vinagre 330 gr|140|
|
P|*Dulce de batata con chocolate 1kg|154.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Mermelada de morrones 250 gr|140|
|
P|*Dulce de zapallo 1kg|139.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Mermelada de frutilla, 450 grs. |123|
|
P|*Dulce de higo 1kg|134.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Mermelada de durazno, 450 grs.|110|
|
P|*Miel artesanal 500g|130.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Mermelada de ciruela, 450 grs. |115|
|
P|*Miel artesanal 1 kg|240.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Mermelada de higo, 450 grs. |110|
|
P|*Canasta de frutas y verduras "34 Sur Productos Orgánicos"|630.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Mermelada de zapallo, 450 grs.|110|
|
ARTÍCULOS PERSONALES Y DE LIMPIEZA||
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Mermelada de naranja, 450 grs. |115|
|
P|Preservativos Prime ultrafinos x3|89.70
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Mermelada de arándanos, 450 grs. |145|
|
P|Preservativos Kamasutra x3|34.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Dulce de membrillo, 900grs |105|
|
P|Tabaco Cerrito|125.67
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Dulce de batata con chocolate 1kg|115|
|
P|Hojilla JOB x30|28.36
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Dulce de zapallo 1kg|115|
|
P|Shampoo Suave 930ml|123.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|'''''''*Dulce de higo 1kg'''|115|
|
P|Acondicionador Suave 930ml|123.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|Miel artesanal 1 kg|210|
|
P|Jabón de tocador IO, 80gs|16.60
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Canasta de frutas y verduras "34 Sur Productos Orgánicos"|630|
|
P|Cepillo dental kolynos máster. |28.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Romero 25grs, El Ombú PTIc|45|
|
P|Pasta Dental kolynos 180 grs. |49.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Apio 25grs, El Ombú PTIc|45|
|
P|Pastillas para mosquitos Fuyi x 12|98.30
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Menta 25grs, El Ombú PTIc|45|
|
P|*Pack x3 jabones glicerina vegetal Natura|380.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Melissa 25grs, El Ombú Ptic|45|
|
P|*Shampoo artesanal pelo seco 250ml Natura|250.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Albahaca limón, El Ombú Ptic|45|
|
P|*Desodorante ecológico apto veganos Natura|190.00
|
||||||
CONDIMENTOS, PERECEDEROS Y BEBIDAS|*Llanten 25grs, El Ombú PTIc|45|
|
P|*Shampoo artesanal pelo graso 250ml Natura|250.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Preservativos Prudence clasico x3|59.09|
|
P|*Barrita quita manchas 75 gr Natura|100.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Tabaco Cerrito|99|
|
P|*Aromatizador ambiental fragancia floral de varilla Natura, 100ml |345.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Hojilla JOB x30 |22|
|
P|*Aromatizador ambiental fragancia cítrica de varilla Natura, 100ml |345.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Shampoo Ainé Cuidado Total 500cc|230|
|
P|*Talco pédico Natura, 200gr|235.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Shampoo Ainé Brillo Extremo 500cc|230|
|
P|*Repelente Natura, 125ml|245.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Acondicionador Ainé Cuidado Total 500cc |230|
|
P|*Shampoo pediculosis, envase 250 ml|320.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Acondicionador Ainé Brillo Extremo 500cc |230|
|
P|*Jabón en polvo Bonsai 800g|95.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Acondicionador Ainé Dos Minutos 500cc |230|
|
P|*Jabón en polvo Bonsai 5kg|550.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Shampoo Suave 930ml |144.09|
|
P|*Suavizante Bonsai 1lt|80.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Acondicionador Suave 930ml |144.09|
|
P|*Jabon liquido para lavarropas 900 cc Bonsai|85.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Jabón de tocador IO, 80gs |12|
|
P|*Jabon liquido para lavarropas 3 lts Bonsai|270.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Cepillo dental Introdento (medio)|29.74|
|
P|*Jabon liquido de Manos 500 cc Bonsai|60.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Pasta Dental Introdento menta 102 grs. |36.72|
|
P|*Perfumador de telas 250 cc Bonsai|120.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Loción repelente de mosquitos, 200 ml|210|
|
P|*Limpiador desengarsante para cocinas y baños aroma cítrico 1 litro (no es para cañerías)|120.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Pack x3 jabones glicerina vegetal Natura|330|
|
P|*Limpiador cremoso 650 cc *|120.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Desodorante ecológico apto veganos Natura|160|
|
P|*Entrebichitos - MEN 2lts. (graseras, pozos, cañerías, plantas)|180.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Pasta Dental Libre de Flúor Natura|165|
|
P|*Entrebichitos - MEN Limpieza 1lt (suelos, mesadas, paredes, combate hongos, bacterias y virus)|100.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Shampoo artesanal pelo graso 250ml Natura|235|
|
P|*Entrebichitos - Pastilla grasera|80.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Shampoo artesanal pelo seco 250ml Natura|230|
|
P|*Hipoclorito El Resistente 1800cc|76.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Shampoo sólido cabello seco y normal 50gr |340|
|
P|*Limpiador perfumado El Resistente (perfumol) 1800cc|76.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Protector solar factor 65, 200 ml. NUEVO!!|550|
|
P|*Detergente El Resistente 500ml|51.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Shampoo sólido cabello graso 50gr |355|
|
P|*KIT El Resistente (Hip./Perf./Det.)|188.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Acondicionador sólido 50gr |350|
|
P|Jabon en barra Primor x1|29.36
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Cepillo dental de bambú 97% biodegradable (niños y adultos)|165|
|
P|Rejilla de cocina 40 x 27.5 Tacuabé (ex Paylana) cm|36.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Talco pédico 200gr |205|
|
P|Trapo de piso 53 x 53 Tacuabé (ex Paylana)|36.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Bálsamo labial Herencias de aquelarre (protege y repara) |180|
|
P|Esponja de cocina|26.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Detergente ecológico grupo Flores Silvestres 500 grs|90|
|
P|Esponja de acero inoxidable|29.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Jabón en polvo Bonsai 800g|70|Bonsai
|
P|Repasador de algodón 43 x 65 cm|53.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Jabón en polvo Bonsai 5kg|350|Bonsai
|
P|Franela 34 x 34|37.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Suavizante Bonsai 1lt|70|Bonsai
|
P|Escoba|116.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Jabon liquido para lavarropas 900 cc Bonsai|80|Bonsai
|
P|Pala con mango|99.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Jabon liquido para lavarropas 3 lts Bonsai|220|Bonsai
|
P|Balde 9 Lts|109.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Jabon liquido de Manos 500 cc Bonsai|50|Bonsai
|
P|Bolsa de residuos 50x55 30 unidades|63.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Perfumador de telas 250 cc Bonsai|100|Bonsai
|
P|Lampazo|119.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Limpiador desengarsante para cocinas y baños aroma cítrico 1 litro (no es para cañerías)|90|Bonsai
|
P|Rollitos de aluminio Griselda x12|38.30
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Entrebichitos - MEN 2lts. (graseras, pozos, cañerías, plantas)|180|Entrebichitos
|
P|rollitos de aluminio jaspe x6|30.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Entrebichitos - MEN Limpieza 1lt (suelos, mesadas, paredes, combate hongos, bacterias y virus)|100|Entrebichitos
|
P|*Vela de apagón|8.40
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Entrebichitos - Pastilla grasera|80|Entrebichitos
|
P|*Vela de citronela 1 mecha|132.80
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Hipoclorito El Resistente 1800cc|66|El Resistente
|
P|Toallita de bebé BabySec ultra 50un|83.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Limpiador perfumado El Resistente (perfumol) 1800cc|66|El Resistente
|
P|Papel Higienico: Higienol Texturado x4|42.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Detergente El Resistente 500ml|43|El Resistente
|
P|Papel de Cocina Sussex extra x 2 -120 paños-|72.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*KIT El Resistente (Hip./Perf./Det.)|161|El Resistente
|
P|Pañales Babysec ULTRA (Celeste) XXG 24 unidades |448.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Jabon bulldog packx2|66.24|
|
P|Pañales Babysec ULTRA (Celeste) XG 24 unidades|448.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Rejilla de cocina 40 x 27.5 Tacuabé (ex Paylana) cm|22|
|
P|Pañales Babysec ULTRA (Celeste) G 30 unidades|448.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Trapo de piso 55 x 55 Tacuabé (ex Paylana)|35|
|
P|Pañales Babysec ULTRA (Celeste) M 36 unidades|448.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Esponja de cocina|22|
|
P|Pañales Babysec ULTRA (Celeste) P 36 unidades|448.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Esponja de acero inoxidable|23|
|
P|Pañales Babysec PREMIUM (Violeta) XXG 48 unidades|790.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Repasador de algodón 43 x 65 cm|39|
|
P|Pañales Babysec PREMIUM (Violeta) XG 48 unidades|790.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Franela 34 x 34|30|
|
P|Pañales Babysec PREMIUM (Violeta) G 60 unidades|790.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Escoba|97|
|
P|Pañales Babysec PREMIUM (Violeta) M 68 unidades|790.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Pala con mango|89|
|
P|Pañales para Adultes INCOPROTECT TALLE M|579.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Balde 9 Lts |99|
|
P|Pañales para Adultes INCOPROTECT TALLE G |617.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Bolsa de residuos 50x55 30 unidades |49|
|
P|Pañales para Adultes INCOPROTECT TALLE EXTRA G |743.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Lampazo |99|
|
TEXTIL||
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Guantes de latex talle M|80.1|
|
PTC|*Calza licra de algodon talle S|900.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Rollitos de alumnio x6 |27.3|
|
PTC|*Calza licra de algodon talle M|900.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Vela de apagón|8.37|
|
PTC|*Calza licra de algodon talle L|900.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|*Vela de citronela 1 mecha|122.2|
|
PTC|*Calza licra de algodon talle XL|900.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Pastillas para mosquitos Sapolio 12 unidades |52.61|
|
PTC|*Biker licra de algodón - Talle S |650.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Pañales Babysec ULTRA XXG 24 unidades|312|
|
PTC|*Biker licra de algodón - Talle M |650.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Pañales Babysec ULTRA XG 24 unidades|312|
|
PTC|*Biker licra de algodón - Talle L |650.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Pañales Babysec ULTRA G 30 unidades|312|
|
PTC|*Biker licra de algodón - Talle XL |650.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Pañales Babysec ULTRA M 36 unidades|312|
|
PTC|*Biker licra de algodón - Talle 0 |350.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Pañales Babysec ULTRA P 36 unidades|312|
|
PTC|*Biker licra de algodón - Talle 2 |350.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Toallita de bebé BabySec ultra 50un|67|
|
PTC|*Biker licra de algodón - Talle 4 |350.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Papel Higienico: Higienol Texturado x4|47|
|
PTC|*Biker licra de algodón - Talle 6 |400.00
|
||||||
ARTÍCULOS PERSONALES Y DE LIMPIEZA|Papel de Cocina Sussex extra x 2 -120 paños-|57|
|
PTC|*Biker licra de algodón - Talle 8 |400.00
|
||||||
TEXTIL|*Calza licra de algodon talle S|750|
|
PTC|*Biker licra de algodón - Talle 10 |400.00
|
||||||
TEXTIL|*Calza licra de algodon talle M|750|
|
PTC|*Biker licra de algodón - Talle 12 |500.00
|
||||||
TEXTIL|*Calza licra de algodon talle L|750|
|
PTC|*Biker licra de algodón - Talle 14 |500.00
|
||||||
TEXTIL|*Calza licra de algodon talle XL|750|
|
PTC|*Biker licra de algodón - Talle 16 |500.00
|
||||||
TEXTIL|*Calza licra de algodon talle 0|300|
|
P|*Conjunto primera muda 100% algodón (pack de pelele, bata y gorrito en bolsa de lienzo) color a elección sujeto a disponibilidad de tela|600.00
|
||||||
TEXTIL|*Calza licra de algodon talle 2 |300|
|
PTC|*Calza licra de algodon talle 0|350.00
|
||||||
TEXTIL|*Calza licra de algodon talle 4|300|
|
PTC|*Calza licra de algodon talle 2|350.00
|
||||||
TEXTIL|*Calza licra de algodon talle 6 |300|
|
PTC|*Calza licra de algodon talle 4|350.00
|
||||||
TEXTIL|*Calza licra de algodon talle 8 |300|
|
PTC|*Calza licra de algodon talle 6|450.00
|
||||||
TEXTIL|*Calza licra de algodon talle 10|300|
|
PTC|*Calza licra de algodon talle 8|450.00
|
||||||
TEXTIL|*Calza licra de algodon talle 12|300|
|
PTC|*Calza licra de algodon talle 10|450.00
|
||||||
TEXTIL|*Calza licra de algodon talle 14 |350|
|
PTC|*Calza licra de algodon talle 12|550.00
|
||||||
TEXTIL|*Calza licra de algodon talle 16 |350|
|
PTC|*Calza licra de algodon talle 14|550.00
|
||||||
TEXTIL|*Campera deportiva - Talle 0|350|
|
PTC|*Calza licra de algodon talle 16|550.00
|
||||||
TEXTIL|*Campera deportiva - Talle 2|350|
|
PTC|*Campera deportiva - Talle 0|400.00
|
||||||
TEXTIL|*Campera deportiva - Talle 4|350|
|
PTC|*Campera deportiva - Talle 2|400.00
|
||||||
TEXTIL|*Campera deportiva - Talle 6|400|
|
PTC|*Campera deportiva - Talle 4|400.00
|
||||||
TEXTIL|*Campera deportiva - Talle 8|400|
|
PTC|*Campera deportiva - Talle 6|450.00
|
||||||
TEXTIL|*Campera deportiva - Talle 10|400|
|
PTC|*Campera deportiva - Talle 8|450.00
|
||||||
TEXTIL|*Campera deportiva - Talle 12|450|
|
PTC|*Campera deportiva - Talle 10|450.00
|
||||||
TEXTIL|*Campera deportiva - Talle 14|450|
|
PTC|*Campera deportiva - Talle 12|500.00
|
||||||
TEXTIL|*Campera deportiva - Talle 16|450|
|
PTC|*Campera deportiva - Talle 14|500.00
|
||||||
TEXTIL|*Pantalón deportivo - Talle 0|250|
|
PTC|*Campera deportiva - Talle 16|500.00
|
||||||
TEXTIL|*Pantalón deportivo - Talle 2|250|
|
PTC|*Pantalón deportivo - Talle 0|300.00
|
||||||
TEXTIL|*Pantalón deportivo - Talle 4|250|
|
PTC|*Pantalón deportivo - Talle 2|300.00
|
||||||
TEXTIL|*Pantalón deportivo - Talle 6|300|
|
PTC|*Pantalón deportivo - Talle 4|300.00
|
||||||
TEXTIL|*Pantalón deportivo - Talle 8|300|
|
PTC|*Pantalón deportivo - Talle 6|350.00
|
||||||
TEXTIL|*Pantalón deportivo - Talle 10|300|
|
PTC|*Pantalón deportivo - Talle 8|350.00
|
||||||
TEXTIL|*Pantalón deportivo - Talle 12|350|
|
PTC|*Pantalón deportivo - Talle 10|350.00
|
||||||
TEXTIL|*Pantalón deportivo - Talle 14|350|
|
PTC|*Pantalón deportivo - Talle 12|400.00
|
||||||
TEXTIL|*Pantalón deportivo - Talle 16|350|
|
PTC|*Pantalón deportivo - Talle 14|400.00
|
||||||
TEXTIL|*Babucha deportiva en algodón - Talle 4|500|
|
PTC|*Pantalón deportivo - Talle 16|400.00
|
||||||
TEXTIL|*Babucha deportiva en algodón - Talle 6|500|
|
PTC|*Buzo deportivo de verano para adultes - Talle S |1000.00
|
||||||
TEXTIL|*Babucha deportiva en algodón - Talle 8 |500|
|
PTC|*Buzo deportivo de verano para adultes - Talle M |1000.00
|
||||||
TEXTIL|*Babucha deportiva en algodón - Talle 10 |600|
|
PTC|*Buzo deportivo de verano para adultes - Talle L |1000.00
|
||||||
TEXTIL|*Babucha deportiva en algodón - Talle 12 |600|
|
PTC|*Buzo deportivo de verano para adultes - Talle XL |1000.00
|
||||||
TEXTIL|*Babucha deportiva en algodón - Talle 14 |600|
|
PTC|*Pantalón deportivo de verano para adultes - Talle S |900.00
|
||||||
TEXTIL|*Babucha deportiva en algodón - Talle 16 |600|
|
PTC|*Pantalón deportivo de verano para adultes - Talle M |900.00
|
||||||
TEXTIL|*Babucha deportiva en algodón - Talle 18 |600|
|
PTC|*Pantalón deportivo de verano para adultes - Talle L |900.00
|
||||||
TEXTIL|*Pantalón deportivo liso de algodón - Talle S|850|
|
PTC|*Pantalón deportivo de verano para adultes - Talle XL |900.00
|
||||||
TEXTIL|*Pantalón deportivo liso de algodón - Talle M|850|
|
P|*Juego de sábanas de algodón 1 plaza|1300.00
|
||||||
TEXTIL|*Pantalón deportivo liso de algodón - Talle L|850|
|
P|*Juego de sábanas de algodón 2 plazas (para sommier)|1500.00
|
||||||
TEXTIL|*Pantalón deportivo liso de algodón - Talle XL |850|
|
P|*Materas de Lona.|450.00
|
||||||
TEXTIL|*Canguro deportivo liso con capucha de algodón - TalleS |1000|
|
P|*Sábana sola con elástico, 2 plazas (para sommier)|950.00
|
||||||
TEXTIL|*Canguro deportivo liso con capucha de algodón - Talle M |1000|
|
P|*Juego de toallón y toalla de algodón|900.00
|
||||||
TEXTIL|*Canguro deportivo liso con capucha de algodón - Talle L |1000|
|
P|*Toallón|750.00
|
||||||
TEXTIL|*Canguro deportivo liso con capucha de algodón - Talle XL|1000|
|
P|*Toalla de mano|350.00
|
||||||
TEXTIL|*Túnica niñe con cinto en espalda y tajo detrás- talles 6 a 16|480|
|
P|*Turbante toalla|450.00
|
||||||
TEXTIL|*Túnica niñe con martingala, festón y pinzas talles 6 a 16|480|
|
P|*Juego de Sábanas de poliéster 1 plaza |850.00
|
||||||
TEXTIL|*Pintor verde - talles 2 a 8|300|
|
P|*Juego de sábanas de poliéster 2 plazas |1000.00
|
||||||
TEXTIL|*Pintor azul - talles 2 a 8|300|
|
MADRES Y FAMILIARES||
|
||||||
TEXTIL|*Pintor rojo - talles 2 a 8|300|
|
PTC|Camiseta EDICION ESPECIAL - talles S al XXL|450.00
|
||||||
TEXTIL|*Pintor amarillo - talles 2 a 8|300|
|
PTC|Canguros Madres y Familiares |950.00
|
||||||
TEXTIL|*Túnicas adulto - talles 1 a 5|1100|
|
P|Pack 1: 1 pin redondo + 1 lapicera + 1 Pañuelo + Pegotines y marcalibros|150.00
|
||||||
TEXTIL|*Moña escolar satinada|50|
|
P|Pack 2: 1 Pin redondo + 1 Lapicera + Pegotines y marcalibros|100.00
|
||||||
TEXTIL|*Juego de sábanas de algodón 1 plaza|1000|
|
P|Pack 3: 1 Llavero + 1 Lapicera|100.00
|
||||||
TEXTIL|*Juego de sábanas de algodón 2 plazas (para sommier) |1200|
|
P|Libro "Desaparecidos"|50.00
|
||||||
TEXTIL|*Sábana sola sin elástico, 2 plazas (para sommier) |700|
|
ARTÍCULOS DE LA COORDINADORA POR PALESTINA||
|
||||||
TEXTIL|*Sábana sola con elástico, 2 plazas (para sommier) |700|
|
B|Bono colaboración|20.00
|
||||||
TEXTIL|*Juego de toallón y toalla de algodón |650|
|
P|Remera talle S - Palestina|450.00
|
||||||
TEXTIL|*Toallón|500|
|
P|Remera talle M - Palestina|450.00
|
||||||
TEXTIL|*Toalla de mano|250|
|
P|Remera talle L - Palestina|450.00
|
||||||
TEXTIL|*Turbante toalla|350|
|
P|Remera talle XL - Palestina|450.00
|
||||||
TEXTIL|*Tapaboca de tela|50|
|
P|Bandera 60x90 cm - Coordinadora por Palestina|450.00
|
||||||
ARTÍCULOS DE MADRES Y FAMILIARES|Pañuelo Madres y Familiares de Detenidos Desaparecidos|50|Madres y familiares
|
P|Pin Coordinadora por Palestina|40.00
|
||||||
ARTÍCULOS DE MADRES Y FAMILIARES|Balconera Madres y Familiares de Detenidos Desaparecidos|100|Madres y familiares
|
P|Balconera "Paremos el genocidio"|150.00
|
||||||
ARTÍCULOS DE MADRES Y FAMILIARES|Pack 2 - 1 Pin redondo + Lapicera + Pegotines y Marcalibros|100|Madres y familiares
|
P|Banderita para el auto |100.00
|
||||||
PRODUCTOS DEL MPS|Pack de 5 pegotines del MPS (2 logos y 3 consignas, todo a color).|40|Madres y familiares
|
P|Kit 5 pegotines - Coordinadora por Palestina|80.00
|
||||||
BONOS Y FINANCIAMIENTO SORORO|Campaña solidaria MPS - apoyo a ollas y merenderos|20|MPS
|
P|Remera talle S - Palestina - Puño - único color Negro *NUEVO|500.00
|
||||||
BONOS Y FINANCIAMIENTO SORORO|Financiamiento sororo para copa menstrual|20|
|
P|Remera talle M - Palestina - Puño - único color Negro *NUEVO|500.00
|
||||||
BONOS Y FINANCIAMIENTO SORORO|Galpón de corrales|20|
|
P|Remera talle L - Palestina - Puño - único color Negro *NUEVO|500.00
|
||||||
PRODUCTOS DE GESTIÓN MENSTRUAL|Copa menstrual de silicona, ecológica |750|
|
P|Remera talle XL - Palestina - Puño - único color Negro *NUEVO|500.00
|
||||||
PRODUCTOS DE GESTIÓN MENSTRUAL|Copa menstrual de silicona, ecológica (financiamiento sororo)|0|
|
PRODUCTOS ESPECIALES Y DE FIN DE AÑO||
|
||||||
PRODUCTOS DE GESTIÓN MENSTRUAL|Vaso esterilizador para copa menstrual|290|
|
P|*Cuaderno artesanal 80 hojas rayado|100.00
|
||||||
PRODUCTOS DE GESTIÓN MENSTRUAL|*Toallita de tela Nocturna "Chúlin"|170|Chúlin
|
P|*Cuaderno artesanal 80 hojas liso|100.00
|
||||||
PRODUCTOS DE GESTIÓN MENSTRUAL|*Toallita de tela para Colaless "Chúlin"|170|Chúlin
|
P|*Cuaderno artesanal 200 hojas rayado|180.00
|
||||||
PRODUCTOS DE GESTIÓN MENSTRUAL|*Toallitas de tela para Bombacha "Chúlin"|200|Chúlin
|
P|*Cuaderno artesanal 200 hojas liso|180.00
|
||||||
PRODUCTOS DE GESTIÓN MENSTRUAL|*Protector Diario de tela "Chúlin"|160|Chúlin
|
P|*Agenda 2025 NUEVO!|420.00
|
||||||
PRODUCTOS DE GESTIÓN MENSTRUAL|*Pack 1: 2 protectores diarios + 2 toallitas para bombacha "Chúlin"|610|Chúlin
|
P|Gorro del MPS - Ciudad Vieja NUEVO!|150.00
|
||||||
PRODUCTOS DE GESTIÓN MENSTRUAL|*Pack 2: 3 protectores diarios "Chúlin" |410|Chúlin
|
P|*Papas con sal 230 gr NUEVO!|154.00
|
||||||
PRODUCTOS DE GESTIÓN MENSTRUAL|Ladysoft Clasicas 8un|20.3|
|
P|*Papas sin sal 250 gr NUEVO!|154.00
|
||||||
PRODUCTOS DE GESTIÓN MENSTRUAL|Tampones Medianos Ladysoft 10un|84.7|
|
P|Turrón Portezuelo Blando 70g NUEVO!|39.67
|
||||||
PRODUCTOS DE GESTIÓN MENSTRUAL|Tampones Grandes Ladysoft 10un|84.7|
|
P|Turrón Portezuelo Bañado 70g NUEVO!|39.67
|
||||||
|
P |*Budín chocolate 300g NUEVO!|200.00
|
||||||
|
P|*Budín vainilla/cítrico 300g NUEVO!|200.00
|
||||||
|
P|*Budín marmolado 300g NUEVO!|200.00
|
||||||
|
P|Pan dulce artesanal con frutas y pasas 500gms NUEVO!|210.00
|
||||||
|
P|Libro para infancias "Encendiendo Memorias" NUEVO!|350.00
|
||||||
|
TRANSPORTE, BONOS Y FINANCIAMIENTO SORORO||
|
||||||
|
T|Por cada $ 500 de consumo, abonar $ 15 para transporte y gastos operativos, ej:$520 son $30|15.00
|
||||||
|
B|Campaña solidaria MPS - apoyo a ollas y merenderos|30.00
|
||||||
|
B|Financiamiento sororo para copa menstrual|20.00
|
||||||
|
B|Bono especial - Apoyo a la familia del compañero Alberto Colman|20.00
|
||||||
|
B|Bono especial - Apoyo al fletero Ramón|20.00
|
||||||
|
PRODUCTOS SUBSIDIADOS POR FINANCIAMIENTO SORORO||
|
||||||
|
P|*Toallita de tela Nocturna "Chúlin"|210.00
|
||||||
|
P|*Toallita de tela para Colaless "Chúlin"|168.00
|
||||||
|
P|*Toallitas de tela para Bombacha "Chúlin"|175.00
|
||||||
|
P|*Protector Diario de tela "Chúlin"|126.00
|
||||||
|
P|*Pack 1: 2 protectores diarios + 2 toallitas para bombacha "Chúlin"|560.00
|
||||||
|
P|*Pack 2: 3 protectores diarios "Chúlin"|364.00
|
||||||
|
P|Ladysoft Clasicas 8un|27.00
|
||||||
|
P|Tampones algodón orgánico - Talle mini- caja 18 un. |208.00
|
||||||
|
P|Tampones algodón orgánico -Talle medio- caja 18un. |208.00
|
||||||
|
P|Tampones algodón orgánico -Talle super-caja 15 un. |208.00
|
Can't render this file because it contains an unexpected character in line 19 and column 39.
|
135
resources/js/app.js
vendored
135
resources/js/app.js
vendored
|
@ -3,10 +3,12 @@
|
||||||
* includes Vue and other libraries. It is a great starting point when
|
* includes Vue and other libraries. It is a great starting point when
|
||||||
* building robust, powerful web applications using Vue and Laravel.
|
* building robust, powerful web applications using Vue and Laravel.
|
||||||
*/
|
*/
|
||||||
|
import axios from 'axios';
|
||||||
require('./bootstrap');
|
import Vue from 'vue';
|
||||||
|
|
||||||
window.Vue = require('vue');
|
window.Vue = require('vue');
|
||||||
|
window.Event = new Vue();
|
||||||
|
window.axios = axios;
|
||||||
|
window.bulmaToast = require('bulma-toast');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The following block of code may be used to automatically register your
|
* The following block of code may be used to automatically register your
|
||||||
|
@ -15,18 +17,133 @@ window.Vue = require('vue');
|
||||||
*
|
*
|
||||||
* Eg. ./components/ExampleComponent.vue -> <example-component></example-component>
|
* Eg. ./components/ExampleComponent.vue -> <example-component></example-component>
|
||||||
*/
|
*/
|
||||||
|
import './components';
|
||||||
|
|
||||||
// const files = require.context('./', true, /\.vue$/i)
|
/**
|
||||||
// files.keys().map(key => Vue.component(key.split('/').pop().split('.')[0], files(key).default))
|
* Constants
|
||||||
|
*/
|
||||||
Vue.component('example-component', require('./components/ExampleComponent.vue').default);
|
Vue.prototype.$rootMiga = {
|
||||||
|
nombre: "Categorías",
|
||||||
|
href: "/productos"
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Global methods
|
||||||
|
*/
|
||||||
|
Vue.prototype.$settearProducto = function(cantidad, id) {
|
||||||
|
Event.$emit("sync-subpedido", this.cant, this.producto.id)
|
||||||
|
}
|
||||||
|
Vue.prototype.$toast = function(mensaje, duration = 2000) {
|
||||||
|
return window.bulmaToast.toast({
|
||||||
|
message: mensaje,
|
||||||
|
duration: duration,
|
||||||
|
type: 'is-danger',
|
||||||
|
position: 'bottom-center',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Vue.prototype.$limpiarFloat = function(unFloat) {
|
||||||
|
return parseFloat(unFloat.replace(/,/g, ''))
|
||||||
|
}
|
||||||
|
Vue.prototype.$limpiarInt = function(unInt) {
|
||||||
|
return parseInt(unInt.replace(/,/g, ''))
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Next, we will create a fresh Vue application instance and attach it to
|
* Next, we will create a fresh Vue application instance and attach it to
|
||||||
* the page. Then, you may begin adding components to this application
|
* the page. Then, you may begin adding components to this application
|
||||||
* or customize the JavaScript scaffolding to fit your unique needs.
|
* or customize the JavaScript scaffolding to fit your unique needs.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const app = new Vue({
|
const app = new Vue({
|
||||||
el: '#app',
|
el: '#root',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
gdc: null,
|
||||||
|
pedido: null,
|
||||||
|
devoluciones: null,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
productos: function() {
|
||||||
|
return this.pedido.productos
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
cantidad(producto) {
|
||||||
|
let pedido = this.productos.some(p => p.id == producto.id)
|
||||||
|
return pedido ? this.productos.find(p => p.id == producto.id).pivot.cantidad : 0
|
||||||
|
},
|
||||||
|
notas(producto) {
|
||||||
|
let pedido = this.productos.some(p => p.id == producto.id);
|
||||||
|
return pedido ? this.productos.find(p => p.id == producto.id).pivot.notas : "";
|
||||||
|
},
|
||||||
|
settearDevoluciones() {
|
||||||
|
axios.get(`/api/grupos-de-compra/${this.gdc}/devoluciones`)
|
||||||
|
.then(response => {
|
||||||
|
this.devoluciones = response.data.devoluciones;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
Event.$on('obtener-sesion', () => {
|
||||||
|
axios.get('/subpedidos/obtener_sesion')
|
||||||
|
.then(response => {
|
||||||
|
if (response.data.subpedido.id) {
|
||||||
|
this.gdc = response.data.gdc;
|
||||||
|
this.settearDevoluciones();
|
||||||
|
this.pedido = response.data.subpedido.id;
|
||||||
|
axios.get('/api/subpedidos/' + this.pedido)
|
||||||
|
.then(response => {
|
||||||
|
this.pedido = response.data.data;
|
||||||
|
Event.$emit("pedido-actualizado");
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
axios.get('/admin/obtener_sesion')
|
||||||
|
.then(response => {
|
||||||
|
this.gdc = response.data.gdc
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
Event.$on('sync-subpedido', (cantidad, id, notas) => {
|
||||||
|
if (this.pedido.aprobado) {
|
||||||
|
this.$toast('No se puede modificar un pedido ya aprobado', 2000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
axios.post("/api/subpedidos/" + this.pedido.id + "/sync", {
|
||||||
|
cantidad: cantidad,
|
||||||
|
producto_id: id,
|
||||||
|
notas: notas,
|
||||||
|
}).then((response) => {
|
||||||
|
this.pedido = response.data.data
|
||||||
|
this.$toast('Pedido actualizado exitosamente')
|
||||||
|
Event.$emit("pedido-actualizado");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
// Actualizar monto y notas de devoluciones
|
||||||
|
Event.$on('sync-devoluciones', (total, notas) => {
|
||||||
|
if (this.pedido.aprobado) {
|
||||||
|
this.$toast('No se puede modificar un pedido ya aprobado', 2000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
axios.post("api/subpedidos/" + this.pedido.id + "/sync_devoluciones", {
|
||||||
|
total: total,
|
||||||
|
notas: notas,
|
||||||
|
}).then((response) => {
|
||||||
|
this.pedido = response.data.data;
|
||||||
|
this.$toast('Pedido actualizado');
|
||||||
|
Event.$emit("pedido-actualizado");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
Event.$on('aprobacion-subpedido', (subpedidoId, aprobado) => {
|
||||||
|
axios.post("/api/admin/subpedidos/" + subpedidoId + "/aprobacion", {
|
||||||
|
aprobacion: aprobado
|
||||||
|
}).then((response) => {
|
||||||
|
Event.$emit('sync-aprobacion', response.data.data);
|
||||||
|
this.$toast('Pedido ' + (aprobado ? 'aprobado' : 'desaprobado') + ' exitosamente')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
Event.$emit('obtener-sesion')
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
25
resources/js/components.js
vendored
Normal file
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
|
||||||
|
);
|
||||||
|
});
|
|
@ -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>
|
|
83
resources/js/components/admin/Body.vue
Normal file
83
resources/js/components/admin/Body.vue
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
<template>
|
||||||
|
<div class="block ml-3 mr-3 is-max-widescreen is-max-desktop">
|
||||||
|
<comunes-tabs-secciones :tabs="tabs" :tabInicial="tabActiva"></comunes-tabs-secciones>
|
||||||
|
<div class="block" id="pedidos-seccion"
|
||||||
|
:class="seccionActiva === 'pedidos-seccion' ? 'is-active' : 'is-hidden'">
|
||||||
|
<div class="block pb-6" id="pedidos-tabla-y-dropdown" v-if="hayPedidos">
|
||||||
|
<admin-dropdown-descargar
|
||||||
|
:gdc_id="gdc.id">
|
||||||
|
</admin-dropdown-descargar>
|
||||||
|
<admin-tabla-pedidos
|
||||||
|
:gdc="this.gdc"
|
||||||
|
></admin-tabla-pedidos>
|
||||||
|
</div>
|
||||||
|
<p class="has-text-centered" v-else>
|
||||||
|
Todavía no hay ningún pedido para administrar.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="block pb-6" id="caracteristicas-seccion"
|
||||||
|
:class="seccionActiva === 'caracteristicas-seccion' ? 'is-active' : 'is-hidden'">
|
||||||
|
<admin-caracteristicas-opcionales>
|
||||||
|
</admin-caracteristicas-opcionales>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import CaracteristicasOpcionales from "./CaracteristicasOpcionales.vue";
|
||||||
|
import TabsSecciones from "../comunes/TabsSecciones.vue";
|
||||||
|
import DropdownDescargar from "./DropdownDescargar.vue";
|
||||||
|
import TablaPedidos from "./TablaPedidos.vue";
|
||||||
|
import TablaBonos from "./TablaBonos.vue";
|
||||||
|
import axios from "axios";
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
CaracteristicasOpcionales,
|
||||||
|
TabsSecciones,
|
||||||
|
DropdownDescargar,
|
||||||
|
TablaPedidos,
|
||||||
|
TablaBonos,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
gdc: undefined,
|
||||||
|
tabs: [{ id: "pedidos", nombre: "Pedidos" },
|
||||||
|
{ id: "caracteristicas", nombre: "Caracteristicas opcionales" }],
|
||||||
|
tabActiva: "pedidos",
|
||||||
|
seccionActiva: "pedidos-seccion",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
hayPedidos: function() {
|
||||||
|
return this.gdc && this.gdc.pedidos.length !== 0
|
||||||
|
},
|
||||||
|
hayAprobados: function() {
|
||||||
|
return this.gdc && this.gdc.pedidos.filter(p => p.aprobado).length > 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
setSeccionActiva(tabId) {
|
||||||
|
this.tabActiva = tabId;
|
||||||
|
this.seccionActiva = tabId + "-seccion";
|
||||||
|
},
|
||||||
|
actualizar() {
|
||||||
|
axios.get('/api/grupos-de-compra/' + this.$root.gdc)
|
||||||
|
.then(response => {
|
||||||
|
this.gdc = response.data.data;
|
||||||
|
console.log(this.gdc);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async mounted() {
|
||||||
|
Event.$on('sync-aprobacion', (_) => {
|
||||||
|
this.actualizar();
|
||||||
|
});
|
||||||
|
await new Promise(r => setTimeout(r, 1000));
|
||||||
|
this.actualizar();
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
</style>
|
12
resources/js/components/admin/BotonLogin.vue
Normal file
12
resources/js/components/admin/BotonLogin.vue
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<template>
|
||||||
|
<div class="buttons is-right">
|
||||||
|
<a class="button is-danger is-light is-small" href="/admin">
|
||||||
|
<span class="icon">
|
||||||
|
<i class="fa fa-solid fa-user-check"></i>
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
Admin
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</template>
|
42
resources/js/components/admin/CaracteristicasOpcionales.vue
Normal file
42
resources/js/components/admin/CaracteristicasOpcionales.vue
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
<script>
|
||||||
|
import FilaCaracteristica from "./FilaCaracteristica.vue";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: { FilaCaracteristica },
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
caracteristicas: [
|
||||||
|
{
|
||||||
|
id: "devoluciones",
|
||||||
|
nombre: "Devoluciones",
|
||||||
|
habilitada: false
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="block">
|
||||||
|
<table class="table is-fullwidth is-striped is-bordered">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th> Característica </th>
|
||||||
|
<th> Habilitada </th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<admin-fila-caracteristica
|
||||||
|
v-for="(c,i) in caracteristicas"
|
||||||
|
:key="i"
|
||||||
|
:caracteristica="c">
|
||||||
|
</admin-fila-caracteristica>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
56
resources/js/components/admin/DropdownDescargar.vue
Normal file
56
resources/js/components/admin/DropdownDescargar.vue
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
<template>
|
||||||
|
<div class="buttons is-right">
|
||||||
|
<div class="dropdown" :class="{'is-active': dropdownActivo}" @mouseleave="dropdownActivo = false">
|
||||||
|
<div class="dropdown-trigger">
|
||||||
|
<button class="button" aria-haspopup="true" aria-controls="dropdown-menu" :disabled="!hayAprobados" @click="dropdownActivo = !dropdownActivo">
|
||||||
|
<span class="icon is-small">
|
||||||
|
<i class="fas fa-download"></i>
|
||||||
|
</span>
|
||||||
|
<span>Descargar pedido</span>
|
||||||
|
<span class="icon is-small">
|
||||||
|
<i class="fas fa-angle-down" aria-hidden="true"></i>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="dropdown-menu" id="dropdown-menu" role="menu">
|
||||||
|
<div class="dropdown-content">
|
||||||
|
<a :href="'/admin/exportar-pedido-a-csv/' + gdc_id" class="dropdown-item has-background-primary">
|
||||||
|
Planilla para central (CSV)
|
||||||
|
</a>
|
||||||
|
<a :href="'/admin/exportar-planillas-a-pdf/' + gdc_id" class="dropdown-item">
|
||||||
|
Planillas para armado (PDF)
|
||||||
|
</a>
|
||||||
|
<a :href="'/admin/exportar-pedido-con-nucleos-a-csv/' + gdc_id" class="dropdown-item">
|
||||||
|
Planilla completa de la canasta (CSV)
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
gdc_id: {
|
||||||
|
type: Number,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
dropdownActivo: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
hayAprobados: function() {
|
||||||
|
return this.$parent.hayAprobados;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
</style>
|
69
resources/js/components/admin/FilaCaracteristica.vue
Normal file
69
resources/js/components/admin/FilaCaracteristica.vue
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
<script>
|
||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
caracteristica: Object
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
gdc: undefined
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
'$root.gdc' : {
|
||||||
|
handler(newValue) {
|
||||||
|
if (newValue) {
|
||||||
|
this.gdc = newValue;
|
||||||
|
this.obtenerValor();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
toggleActivacion() {
|
||||||
|
const id = this.caracteristica.id;
|
||||||
|
axios.post(`/api/grupos-de-compra/${this.gdc}/${id}`)
|
||||||
|
.then(response => {
|
||||||
|
this.caracteristica.habilitada = response.data[id];
|
||||||
|
this.$root[id] = response.data[id];
|
||||||
|
});
|
||||||
|
},
|
||||||
|
obtenerValor() {
|
||||||
|
const id = this.caracteristica.id;
|
||||||
|
axios.get(`/api/grupos-de-compra/${this.gdc}/${id}`)
|
||||||
|
.then(response => {
|
||||||
|
this.caracteristica.habilitada = response.data[id];
|
||||||
|
this.$root[id] = response.data[id];
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
if (this.$root.gdc) {
|
||||||
|
this.gdc = this.$root.gdc;
|
||||||
|
this.obtenerValor();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<tr>
|
||||||
|
<td>{{ caracteristica.nombre }}</td>
|
||||||
|
<td>
|
||||||
|
<div class="field">
|
||||||
|
<input type="checkbox" class="switch is-rounded is-success"
|
||||||
|
:id="'switch-'+caracteristica.id"
|
||||||
|
:checked="caracteristica.habilitada"
|
||||||
|
@change="toggleActivacion(caracteristica)">
|
||||||
|
<label :for="'switch-'+caracteristica.id">
|
||||||
|
<span class="is-hidden-mobile">{{ caracteristica.habilitada ? 'Habilitada' : 'Deshabilitada' }}</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
36
resources/js/components/admin/FilaPedido.vue
Normal file
36
resources/js/components/admin/FilaPedido.vue
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
<template>
|
||||||
|
<tr>
|
||||||
|
<td>{{ pedido.nombre }}</td>
|
||||||
|
<td v-if="$root.devoluciones" class="has-text-right" >{{ pedido.total_sin_devoluciones }}</td>
|
||||||
|
<td v-if="$root.devoluciones" class="has-text-right" ><abbr :title="pedido.devoluciones_notas">-{{ pedido.devoluciones_total }}</abbr></td>
|
||||||
|
<td class="has-text-right" >{{ $root.devoluciones ? pedido.total : pedido.total_sin_devoluciones }}</td>
|
||||||
|
<td>
|
||||||
|
<admin-switch-aprobacion
|
||||||
|
:pedido="pedido">
|
||||||
|
</admin-switch-aprobacion>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import SwitchAprobacion from "./SwitchAprobacion.vue";
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
SwitchAprobacion
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
pedido: Object
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
Event.$on('sync-aprobacion', (unPedido) => {
|
||||||
|
if (this.pedido.id === unPedido.id) {
|
||||||
|
this.pedido = unPedido
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
56
resources/js/components/admin/Login.vue
Normal file
56
resources/js/components/admin/Login.vue
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
<template>
|
||||||
|
<div v-show="visible" class="block">
|
||||||
|
<div class="field">
|
||||||
|
<label class="label has-text-white">Contraseña de administración del barrio</label>
|
||||||
|
<div class="field has-addons">
|
||||||
|
<div class="control">
|
||||||
|
<input required class="input" :type="this.passwordType" name="password" placeholder="Contraseña de admin del barrio">
|
||||||
|
</div>
|
||||||
|
<div class="control">
|
||||||
|
<a class="button is-warning" @click="togglePassword">
|
||||||
|
{{ (passwordVisible ? 'Ocultar' : 'Mostrar') + ' contraseña'}}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="help has-text-white">Si no la sabés, consultá a la comisión informática.</p>
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<div class="control">
|
||||||
|
<input type="submit" class="button is-warning" value="Ingresar"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
visible: false,
|
||||||
|
gdc: null,
|
||||||
|
passwordVisible: false,
|
||||||
|
passwordType: "password",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
Event.$on('gdc-seleccionado', (gdc) => {
|
||||||
|
this.gdc = gdc;
|
||||||
|
this.visible = true;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
togglePassword() {
|
||||||
|
if (this.passwordVisible) this.passwordType = "password";
|
||||||
|
else this.passwordType = "text"
|
||||||
|
this.passwordVisible = !this.passwordVisible
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.help {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
</style>
|
46
resources/js/components/admin/SwitchAprobacion.vue
Normal file
46
resources/js/components/admin/SwitchAprobacion.vue
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
<template>
|
||||||
|
<div class="field">
|
||||||
|
<input type="checkbox" name="switchRoundedSuccess" class="switch is-rounded is-success"
|
||||||
|
:id="'switch'+this.pedido.id"
|
||||||
|
:checked="pedido.aprobado"
|
||||||
|
@change="toggleAprobacion">
|
||||||
|
<label :for="'switch'+this.pedido.id">
|
||||||
|
<span class="is-hidden-mobile">{{ mensaje }}</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
pedido: Object
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
aprobado: this.pedido.aprobado
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
mensaje: function () {
|
||||||
|
return this.aprobado ? "Pagado" : "No pagado"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
toggleAprobacion() {
|
||||||
|
Event.$emit('aprobacion-subpedido', this.pedido.id, !this.aprobado);
|
||||||
|
this.aprobado = !this.aprobado
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
Event.$on('sync-aprobacion', (unPedido) => {
|
||||||
|
if (this.pedido.id === unPedido.id) {
|
||||||
|
this.pedido = unPedido
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
97
resources/js/components/admin/TablaBonos.vue
Normal file
97
resources/js/components/admin/TablaBonos.vue
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
<template>
|
||||||
|
<div class="block">
|
||||||
|
<div class="block" v-show="!hayBonos">
|
||||||
|
<p class="has-text-centered">
|
||||||
|
Todavía no hay bonos pedidos.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="block" v-show="hayBonos">
|
||||||
|
<table class="table is-bordered is-striped is-hoverable is-fullwidth">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th><abbr title="Núcleo">Núcleo</abbr></th>
|
||||||
|
<td v-for="(bono,i) in bonos" :key="i" class="is-1">
|
||||||
|
{{ bono.nombre }}
|
||||||
|
</td>
|
||||||
|
<th><abbr title="Total a Pagar">Total $</abbr></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr v-for="(bp, i) in bonosPorPedido" :key="i">
|
||||||
|
<td> {{ bp.nucleo }} </td>
|
||||||
|
<td v-for="(bono,j) in bp.bonos" :key="j" class="has-text-right">
|
||||||
|
{{ bono.cantidad }}
|
||||||
|
</td>
|
||||||
|
<td class="has-text-right"> {{ bp.total }} </td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
<tfoot>
|
||||||
|
<tr>
|
||||||
|
<th></th>
|
||||||
|
<th :colspan="bonos.length">Total bonos</th>
|
||||||
|
<th class="has-text-right">$ {{ totalBonos }}</th>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
pedidos: {
|
||||||
|
type: Array,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
bonos: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
pedidosAprobados: function() {
|
||||||
|
return this.pedidos.filter(p => p.aprobado)
|
||||||
|
},
|
||||||
|
hayBonos: function() {
|
||||||
|
return this.pedidosAprobados.filter(p => p.subtotal_bonos != 0).length !== 0
|
||||||
|
},
|
||||||
|
bonosPorPedido: function() {
|
||||||
|
let bonosPorPedido = this.pedidosAprobados.map(p => p = {"nucleo":p.nombre, "bonos":p.productos.filter(x => x.bono), "total":p.subtotal_bonos});
|
||||||
|
bonosPorPedido.forEach(bp => {
|
||||||
|
bp.bonos = bp.bonos.map(b => b = {"bono":b.nombre, "cantidad":b.pivot.cantidad, "total":b.pivot.total, "id":b.id})
|
||||||
|
})
|
||||||
|
return bonosPorPedido.map(bp => this.completarBonos(bp));
|
||||||
|
},
|
||||||
|
totalBonos: function() {
|
||||||
|
let total = 0
|
||||||
|
this.bonosPorPedido.map(bp => total += parseInt(bp.total))
|
||||||
|
return total
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
completarBonos(bonosPedido) {
|
||||||
|
this.bonos.map(b => {
|
||||||
|
if (!bonosPedido.bonos.map(x => x.id).includes(b.id))
|
||||||
|
bonosPedido.bonos.push({"bono":b.nombre, "cantidad":0, "total":0, "id":b.id})
|
||||||
|
})
|
||||||
|
bonosPedido.bonos = bonosPedido.bonos.sort((b1,b2) => b1.id - b2.id)
|
||||||
|
return bonosPedido
|
||||||
|
}
|
||||||
|
},
|
||||||
|
beforeMount() {
|
||||||
|
axios.get("../api/productos", {
|
||||||
|
params: {
|
||||||
|
categoria:'TRANSPORTE, BONOS Y FINANCIAMIENTO SORORO',
|
||||||
|
}
|
||||||
|
}).then(response => {
|
||||||
|
this.bonos = response.data.data;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
</style>
|
69
resources/js/components/admin/TablaPedidos.vue
Normal file
69
resources/js/components/admin/TablaPedidos.vue
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<table class="table is-fullwidth is-striped is-bordered">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Núcleo</th>
|
||||||
|
<th v-if="$root.devoluciones"><abbr title="Total sin tomar en cuenta las devoluciones">Total parcial $</abbr></th>
|
||||||
|
<th v-if="$root.devoluciones"><abbr title="Devoluciones correspondientes al núcleo">Devoluciones $</abbr></th>
|
||||||
|
<th><abbr title="Total a Pagar por el núleo">{{ $root.devoluciones ? 'Total real' : 'Total' }} $</abbr></th>
|
||||||
|
<th class="is-1"><abbr title="Pagado">Pagado</abbr></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<admin-fila-pedido
|
||||||
|
v-for="pedido in gdc.pedidos"
|
||||||
|
:pedido="pedido" :key="pedido.id">
|
||||||
|
</admin-fila-pedido>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<table class="table is-striped is-bordered">
|
||||||
|
<tr>
|
||||||
|
<th colspan="2" class="has-background-black has-text-white has-text-centered">TOTALES</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Total a recaudar:</th>
|
||||||
|
<td class="has-text-right">$ {{ gdc.total_a_recaudar }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Total bonos barriales:</th>
|
||||||
|
<td class="has-text-right">$ {{ gdc.total_barrial }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr v-if="$root.devoluciones">
|
||||||
|
<th>Total devoluciones:</th>
|
||||||
|
<td class="has-text-right">- $ {{ gdc.total_devoluciones }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Cantidad bonos de transporte:</th>
|
||||||
|
<td class="has-text-right">{{ gdc.cantidad_transporte }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Total bonos de transporte:</th>
|
||||||
|
<td class="has-text-right">$ {{ gdc.total_transporte }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Total a depositar:</th>
|
||||||
|
<td class="has-text-right">$ {{ gdc.total_a_transferir }}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import FilaPedido from "./FilaPedido.vue";
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
FilaPedido
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
gdc: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
</style>
|
74
resources/js/components/compras/Body.vue
Normal file
74
resources/js/components/compras/Body.vue
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
<template>
|
||||||
|
<div class="block ml-3 mr-3 is-max-widescreen is-max-desktop">
|
||||||
|
<comunes-tabs-secciones :tabs="tabs" :tabInicial="tabActiva"></comunes-tabs-secciones>
|
||||||
|
<div class="block pb-6" id="pedidos-compras-seccion"
|
||||||
|
:class="seccionActiva === 'pedidos-compras-seccion' ? 'is-active' : 'is-hidden'">
|
||||||
|
<div class="block" id="pedidos-compras-tabla-y-dropdown">
|
||||||
|
<compras-dropdown-descargar>
|
||||||
|
</compras-dropdown-descargar>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="block pb-6" id="canasta-compras-seccion"
|
||||||
|
:class="seccionActiva === 'canasta-compras-seccion' ? 'is-active' : 'is-hidden'">
|
||||||
|
<div class="block" id="canasta-compras-seccion">
|
||||||
|
<article class="message is-warning">
|
||||||
|
<div class="message-header">
|
||||||
|
<p>Formato de la canasta</p>
|
||||||
|
</div>
|
||||||
|
<div class="message-body">
|
||||||
|
<div class="content">
|
||||||
|
La planilla de la canasta tiene que tener el siguiente formato para que la aplicación la lea correctamente:
|
||||||
|
<ul>
|
||||||
|
<li> Los precios deben usar punto y no coma decimal </li>
|
||||||
|
<li> El nombre de las columnas deben ser "Tipo", "Producto", y "Precio" respectivamente </li>
|
||||||
|
<li> Las celdas deben separarse con '|' </li>
|
||||||
|
<li> No puede haber "enters" en ninguna celda </li>
|
||||||
|
<li> El bono de transporte debe tener tipo 'T' </li>
|
||||||
|
</ul>
|
||||||
|
<a class="has-text-info" href="/compras/canasta/ejemplo">Planilla de ejemplo.</a>
|
||||||
|
<article class="message is-danger mt-2">
|
||||||
|
<div class="message-body">
|
||||||
|
<div class="content">
|
||||||
|
Cuidado! Cargar una nueva canasta elimina todos los pedidos de la aplicación.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
<div class="buttons is-right">
|
||||||
|
<compras-canasta-input></compras-canasta-input>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import TabsSecciones from "../comunes/TabsSecciones.vue";
|
||||||
|
import DropdownDescargar from "./DropdownDescargar.vue";
|
||||||
|
import CanastaInput from "./CanastaInput.vue";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
TabsSecciones,
|
||||||
|
DropdownDescargar,
|
||||||
|
CanastaInput,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
tabs: [{ id: "pedidos-compras", nombre: "Pedidos" },
|
||||||
|
{ id: "canasta-compras", nombre: "Canasta" }],
|
||||||
|
tabActiva: "pedidos-compras",
|
||||||
|
seccionActiva: "pedidos-compras-seccion",
|
||||||
|
archivo: undefined,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
setSeccionActiva(tabId) {
|
||||||
|
this.tabActiva = tabId;
|
||||||
|
this.seccionActiva = tabId + "-seccion";
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
69
resources/js/components/compras/CanastaInput.vue
Normal file
69
resources/js/components/compras/CanastaInput.vue
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
<template>
|
||||||
|
<div class="block">
|
||||||
|
<div class="file has-name is-right">
|
||||||
|
<label class="file-label">
|
||||||
|
<input
|
||||||
|
class="file-input"
|
||||||
|
type="file"
|
||||||
|
name="canasta"
|
||||||
|
@change="archivoSubido"
|
||||||
|
/>
|
||||||
|
<span class="file-cta">
|
||||||
|
<span class="file-icon">
|
||||||
|
<i class="fas fa-cloud-upload-alt"></i>
|
||||||
|
</span>
|
||||||
|
<span class="file-label">Subir canasta</span>
|
||||||
|
</span>
|
||||||
|
<span class="file-name" v-if="archivo">
|
||||||
|
{{ 'Cargando ' + archivo.nombre }}
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "CanastaInput",
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
archivo: null,
|
||||||
|
cargando: false,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async archivoSubido(event) {
|
||||||
|
const archivo = event.target.files[0];
|
||||||
|
if (archivo && archivo.type === "text/csv") {
|
||||||
|
this.archivo = {data: archivo, nombre: archivo.name};
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append("data", this.archivo.data);
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.cargando = true;
|
||||||
|
const response = await axios.post("/compras/canasta", formData, {
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "multipart/form-data",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
this.$root.$toast(response.data.message || "Canasta cargada exitosamente");
|
||||||
|
} catch (error) {
|
||||||
|
this.$root.$toast(error.response?.data?.message || "Hubo errores.");
|
||||||
|
} finally {
|
||||||
|
this.cargando = false;
|
||||||
|
this.archivo = null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.$root.$toast("La canasta debe ser .CSV")
|
||||||
|
this.archivo = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
44
resources/js/components/compras/DropdownDescargar.vue
Normal file
44
resources/js/components/compras/DropdownDescargar.vue
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
<template>
|
||||||
|
<div class="buttons is-right">
|
||||||
|
<div class="dropdown" :class="{'is-active': dropdownActivo}" @mouseleave="dropdownActivo = false">
|
||||||
|
<div class="dropdown-trigger">
|
||||||
|
<button class="button" aria-haspopup="true" aria-controls="dropdown-menu" @click="dropdownActivo = !dropdownActivo">
|
||||||
|
<span class="icon is-small">
|
||||||
|
<i class="fas fa-download"></i>
|
||||||
|
</span>
|
||||||
|
<span>Descargar planillas</span>
|
||||||
|
<span class="icon is-small">
|
||||||
|
<i class="fas fa-angle-down" aria-hidden="true"></i>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="dropdown-menu" id="dropdown-menu" role="menu">
|
||||||
|
<div class="dropdown-content">
|
||||||
|
<a href="/compras/pedidos/descargar" class="dropdown-item">
|
||||||
|
Pedidos por barrio
|
||||||
|
</a>
|
||||||
|
<a href="/compras/pedidos/notas" class="dropdown-item">
|
||||||
|
Notas por barrio
|
||||||
|
</a>
|
||||||
|
<a href="/compras/pedidos/pdf" class="dropdown-item">
|
||||||
|
Pedidos por barrio en pdf
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
dropdownActivo: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
</style>
|
52
resources/js/components/compras/Login.vue
Normal file
52
resources/js/components/compras/Login.vue
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
<template>
|
||||||
|
<div class="block">
|
||||||
|
<div class="field">
|
||||||
|
<label class="label">Usuario</label>
|
||||||
|
<div class="field">
|
||||||
|
<div class="control">
|
||||||
|
<input required class="input" type="text" name="name" placeholder="Usuario">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label class="label">Contraseña</label>
|
||||||
|
<div class="field has-addons">
|
||||||
|
<div class="control">
|
||||||
|
<input required class="input" :type="this.passwordType" name="password" placeholder="Contraseña">
|
||||||
|
</div>
|
||||||
|
<div class="control">
|
||||||
|
<a class="button is-dark" @click="togglePassword">
|
||||||
|
{{ (passwordVisible ? 'Ocultar' : 'Mostrar') + ' contraseña'}}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<div class="control">
|
||||||
|
<input type="submit" class="button is-dark" value="Ingresar"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "LoginAdmin",
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
passwordVisible: false,
|
||||||
|
passwordType: "password",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
togglePassword() {
|
||||||
|
if (this.passwordVisible) this.passwordType = "password";
|
||||||
|
else this.passwordType = "text"
|
||||||
|
this.passwordVisible = !this.passwordVisible
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
51
resources/js/components/comunes/BarrioSelect.vue
Normal file
51
resources/js/components/comunes/BarrioSelect.vue
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
<template>
|
||||||
|
<div v-show="visible" class="block">
|
||||||
|
<div class="field">
|
||||||
|
<label class="label" :class="isAdmin ? 'has-text-white' : ''">Seleccioná tu barrio o grupo de compra</label>
|
||||||
|
<div class="control">
|
||||||
|
<div class="select">
|
||||||
|
<select @change="onGDCSelected" v-model="gdc" name="name">
|
||||||
|
<option :disabled="isDefaultDisabled==1" value=null>Seleccionar</option>
|
||||||
|
<option v-for="(gdc, index) in gdcs" :key="index" v-text="gdc.nombre + (isAdmin ? '_admin' : '')"
|
||||||
|
:name="gdc.nombre + (isAdmin ? '_admin' : '')">
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
visible: false,
|
||||||
|
region: null,
|
||||||
|
gdcs: [],
|
||||||
|
isDefaultDisabled: 0,
|
||||||
|
gdc: null,
|
||||||
|
isAdmin: this.admin == null ? false : this.admin
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
Event.$on('region-seleccionada', (region)=> {
|
||||||
|
this.region = region;
|
||||||
|
this.fillGDC(region);
|
||||||
|
this.visible = true;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
methods : {
|
||||||
|
fillGDC(region) {
|
||||||
|
axios.get("/api/grupos-de-compra").then(response => {
|
||||||
|
this.gdcs = response.data[this.region];
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onGDCSelected() {
|
||||||
|
this.isDefaultDisabled = 1;
|
||||||
|
Event.$emit("gdc-seleccionado",this.gdc);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
props: {'admin': Boolean}
|
||||||
|
}
|
||||||
|
</script>
|
91
resources/js/components/comunes/NavBar.vue
Normal file
91
resources/js/components/comunes/NavBar.vue
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
<template>
|
||||||
|
<nav id="nav-bar" class="navbar is-danger is-fixed-top" role="navigation" aria-label="main navigation">
|
||||||
|
<div class="navbar-brand">
|
||||||
|
<a class="navbar-item" href="https://mps.org.uy">
|
||||||
|
<img src="/assets/logoMPS.png" height="28">
|
||||||
|
</a>
|
||||||
|
<!-- Styles nombre del barrio-->
|
||||||
|
<p class="navbar-item hide-below-1024">
|
||||||
|
<slot name="gdc"></slot>
|
||||||
|
</p>
|
||||||
|
<p class="navbar-item">
|
||||||
|
<slot name="subpedido"></slot>
|
||||||
|
</p>
|
||||||
|
<pedidos-chismosa-dropdown v-if="this.$root.pedido != null" class="hide-above-1023" id="mobile"></pedidos-chismosa-dropdown>
|
||||||
|
<a role="button" class="navbar-burger" :class="{'is-active':burgerActiva}" aria-label="menu" aria-expanded="false" data-target="nav-bar" @click="toggleBurger">
|
||||||
|
<span aria-hidden="true"></span>
|
||||||
|
<span aria-hidden="true"></span>
|
||||||
|
<span aria-hidden="true"></span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="navbar-menu" :class="{'is-active':burgerActiva}">
|
||||||
|
<div class="navbar-end">
|
||||||
|
<div v-if="this.$root.pedido != null" class="navbar-item field has-addons mt-2 mr-3">
|
||||||
|
<a class="button is-small has-text-dark-grey" @click.capture="buscar">
|
||||||
|
<span class="icon">
|
||||||
|
<i class="fas fa-search"></i>
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
<input class="input is-small" type="text" placeholder="Harina" v-model="searchString" @keyup.enter="buscar" >
|
||||||
|
</div>
|
||||||
|
<pedidos-chismosa-dropdown v-if="this.$root.pedido != null" class="hide-below-1024" id="wide"></pedidos-chismosa-dropdown>
|
||||||
|
<div class="block navbar-item">
|
||||||
|
<a onclick="event.preventDefault(); document.getElementById('logout-form').submit();" class="text-a">
|
||||||
|
Cerrar sesión
|
||||||
|
</a>
|
||||||
|
<slot name="logout-form"></slot>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import ChismosaDropdown from '../pedidos/ChismosaDropdown.vue';
|
||||||
|
export default {
|
||||||
|
components: { ChismosaDropdown },
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
burgerActiva: false,
|
||||||
|
searchString: "",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
toggleBurger() {
|
||||||
|
this.burgerActiva = !this.burgerActiva
|
||||||
|
},
|
||||||
|
buscar() {
|
||||||
|
if (this.burgerActiva) this.toggleBurger()
|
||||||
|
Event.$emit("migas-setear-como-inicio", this.$rootMiga)
|
||||||
|
Event.$emit("filtrar-productos",'nombre',this.searchString)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
p.navbar-item:empty {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#nav-bar {
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-a {
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1023px) {
|
||||||
|
.hide-below-1024 {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1024px) {
|
||||||
|
.hide-above-1023 {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
38
resources/js/components/comunes/RegionSelect.vue
Normal file
38
resources/js/components/comunes/RegionSelect.vue
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
<template>
|
||||||
|
<div class="block">
|
||||||
|
<div class="field">
|
||||||
|
<label class="label" :class="whiteText ? 'has-text-white' : ''">Seleccioná tu región</label>
|
||||||
|
<div class="control">
|
||||||
|
<div class="select">
|
||||||
|
<select @change="onRegionSelected" v-model="region">
|
||||||
|
<option :disabled="isDefaultDisabled===1" value=null>Seleccionar</option>
|
||||||
|
<option v-for="(region, index) in regiones" :key="index" v-text="region" :name="region"></option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
regiones: [],
|
||||||
|
isDefaultDisabled: 0,
|
||||||
|
region: null,
|
||||||
|
whiteText: this.admin == null ? false : this.admin
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
axios.get("/api/regiones").then(response => this.regiones = response.data);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onRegionSelected() {
|
||||||
|
this.isDefaultDisabled = 1;
|
||||||
|
Event.$emit("region-seleccionada",this.region);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
props: {'admin': Boolean}
|
||||||
|
}
|
||||||
|
</script>
|
55
resources/js/components/comunes/TabsSecciones.vue
Normal file
55
resources/js/components/comunes/TabsSecciones.vue
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
<template>
|
||||||
|
<div class="block">
|
||||||
|
<div class="tabs is-boxed" id="tabs">
|
||||||
|
<ul class="has-bottom-line">
|
||||||
|
<li v-for="(tab, index) in tabs" class="is-size-6"
|
||||||
|
:key="index"
|
||||||
|
:id="tab.id + '-tab'"
|
||||||
|
:class="{'is-active': tab.id === tabActiva}">
|
||||||
|
<a @click="setTabActiva(tab.id)">
|
||||||
|
<span>
|
||||||
|
{{ tab.nombre }}
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
tabs: Array,
|
||||||
|
tabInicial: String,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
tabActiva: this.tabInicial,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
setTabActiva(tabId) {
|
||||||
|
this.$parent.setSeccionActiva(tabId);
|
||||||
|
this.tabActiva = tabId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import '../../../../node_modules/bulma';
|
||||||
|
hr {
|
||||||
|
border: none;
|
||||||
|
height: 1px;
|
||||||
|
}
|
||||||
|
.has-bottom-line {
|
||||||
|
border-bottom-color: #dbdbdb !important;
|
||||||
|
border-bottom-style: solid !important;
|
||||||
|
border-bottom-width: 1px !important;
|
||||||
|
}
|
||||||
|
.tabs li.is-active a {
|
||||||
|
border-bottom-color: #e3342f;
|
||||||
|
color: #e3342f;
|
||||||
|
}
|
||||||
|
</style>
|
22
resources/js/components/pedidos/Body.vue
Normal file
22
resources/js/components/pedidos/Body.vue
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<template>
|
||||||
|
<div class="columns ml-3 mr-3">
|
||||||
|
<pedidos-categorias-container :class="chismosaActiva ? 'hide-below-1024' : ''"></pedidos-categorias-container>
|
||||||
|
<pedidos-productos-container :class="chismosaActiva ? 'hide-below-1024' : ''"></pedidos-productos-container>
|
||||||
|
<pedidos-chismosa v-show="chismosaActiva"></pedidos-chismosa>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
chismosaActiva: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
Event.$on('toggle-chismosa', (activa) => {
|
||||||
|
this.chismosaActiva = activa;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
32
resources/js/components/pedidos/CartelPedidoAprobado.vue
Normal file
32
resources/js/components/pedidos/CartelPedidoAprobado.vue
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
<template>
|
||||||
|
<div v-show="aprobado" class="notification is-warning has-text-centered">
|
||||||
|
Tu pedido fue <strong>aprobado</strong>, por lo que no puede ser modificado
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
aprobado: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
Event.$on('pedido-actualizado', this.actualizarEstado);
|
||||||
|
if (this.$root.pedido != null) {
|
||||||
|
this.actualizarEstado();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
pedidoAprobado: function() {
|
||||||
|
return this.$root.pedido.aprobado;
|
||||||
|
},
|
||||||
|
actualizarEstado: function() {
|
||||||
|
this.aprobado = this.pedidoAprobado();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
</style>
|
41
resources/js/components/pedidos/CategoriasContainer.vue
Normal file
41
resources/js/components/pedidos/CategoriasContainer.vue
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
<template>
|
||||||
|
<div v-show="visible" class="column">
|
||||||
|
<div class="columns is-multiline is-mobile">
|
||||||
|
<div v-for="(categoria,i) in categorias" :key="i" class="block column is-one-quarter-desktop is-one-third-tablet is-half-mobile">
|
||||||
|
<div @click.capture="seleccionarCategoria(categoria)" class="card" style="height:100%" >
|
||||||
|
<div class="card-content">
|
||||||
|
<div class="media">
|
||||||
|
<div class="media-content" style="overflow:hidden">
|
||||||
|
<p class="title is-6" v-text="categoria"></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div><!-- END CARD -->
|
||||||
|
</div><!-- END BLOCK COLUMN -->
|
||||||
|
</div><!-- END COLUMNS -->
|
||||||
|
</div><!-- END CONTAINER -->
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
categorias: null,
|
||||||
|
visible: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
axios.get("/api/categorias").then(response => {
|
||||||
|
this.categorias = response.data;
|
||||||
|
});
|
||||||
|
Event.$emit("migas-setear-como-inicio", this.$rootMiga);
|
||||||
|
Event.$on("filtrar-productos", (_) => this.visible = false)
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
seleccionarCategoria(categoria) {
|
||||||
|
this.visible = false;
|
||||||
|
Event.$emit("filtrar-productos",'categoria',categoria);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
102
resources/js/components/pedidos/Chismosa.vue
Normal file
102
resources/js/components/pedidos/Chismosa.vue
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
<template>
|
||||||
|
<div class="column is-one-third">
|
||||||
|
<div class="fixed-right">
|
||||||
|
<table v-show="mostrar_tabla" class="table is-striped is-bordered tabla-chismosa is-narrow">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Producto</th>
|
||||||
|
<th>Cantidad</th>
|
||||||
|
<th><abbr title="Precio Total">$</abbr></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tfoot>
|
||||||
|
<tr>
|
||||||
|
<th><abbr title="Bonos de Transporte">B. Transporte</abbr></th>
|
||||||
|
<th class="has-text-right">{{ cantidad_bonos_transporte }}</th>
|
||||||
|
<th class="has-text-right">{{ total_bonos_transporte }}</th>
|
||||||
|
</tr>
|
||||||
|
<tr v-if="this.$root.devoluciones">
|
||||||
|
<th><p>Devoluciones</p></th>
|
||||||
|
<td>
|
||||||
|
<abbr :title="notas_devoluciones">{{ notas_devoluciones_abbr }}</abbr>
|
||||||
|
<button @click.capture="modificarDevoluciones()" class="button is-warning is-small">
|
||||||
|
<span class="icon">
|
||||||
|
<i class="fas fa-edit"></i>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
<th class="has-text-right">-{{ devoluciones }}</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Total total</th>
|
||||||
|
<th></th>
|
||||||
|
<th class="has-text-right">{{ total }}</th>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
<tbody>
|
||||||
|
<pedidos-producto-row v-for="producto in productos" :producto="producto" :key="producto.id"></pedidos-producto-row>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<p class="has-text-centered" v-show="!mostrar_tabla">
|
||||||
|
Compa, todavía no agregaste nada a la chismosa.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
mostrar_tabla: false,
|
||||||
|
cantidad_bonos_transporte: 0,
|
||||||
|
total_bonos_transporte: 0,
|
||||||
|
devoluciones: 0,
|
||||||
|
notas_devoluciones: "",
|
||||||
|
notas_devoluciones_abbr: "",
|
||||||
|
total: 0,
|
||||||
|
productos: [],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
Event.$on('pedido-actualizado', this.pedidoActualizado);
|
||||||
|
Event.$on('toggle-chismosa', this.pedidoActualizado);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
pedidoActualizado: function() {
|
||||||
|
this.mostrar_tabla = this.$root.productos.length > 0;
|
||||||
|
this.cantidad_bonos_transporte = this.cantidadBonosDeTransporte();
|
||||||
|
this.total_bonos_transporte = this.totalBonosDeTransporte();
|
||||||
|
this.devoluciones = this.$root.pedido.devoluciones_total;
|
||||||
|
this.notas_devoluciones = this.$root.pedido.devoluciones_notas;
|
||||||
|
this.notas_devoluciones_abbr = this.notas_devoluciones.substring(0, 15);
|
||||||
|
if (this.notas_devoluciones.length > 15) {
|
||||||
|
this.notas_devoluciones_abbr += "...";
|
||||||
|
}
|
||||||
|
this.total = this.$root.pedido.total;
|
||||||
|
this.productos = this.$root.productos;
|
||||||
|
},
|
||||||
|
modificarDevoluciones: function() {
|
||||||
|
Event.$emit("modificar-devoluciones");
|
||||||
|
},
|
||||||
|
cantidadBonosDeTransporte: function() {
|
||||||
|
return this.$root.pedido.cantidad_transporte;
|
||||||
|
},
|
||||||
|
totalBonosDeTransporte: function() {
|
||||||
|
return this.$root.pedido.total_transporte
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.tabla-chismosa {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.fixed-right {
|
||||||
|
position: fixed;
|
||||||
|
overflow-y: auto;
|
||||||
|
max-height: 81vh;
|
||||||
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
45
resources/js/components/pedidos/ChismosaDropdown.vue
Normal file
45
resources/js/components/pedidos/ChismosaDropdown.vue
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
<template>
|
||||||
|
<div class="dropdown is-right navbar-item" :class="{'is-active':activa}">
|
||||||
|
<div class="dropdown-trigger">
|
||||||
|
<a class="text-a" aria-haspopup="true" :aria-controls="id" @click.capture="toggle">
|
||||||
|
<span class="icon is-small mr-1">
|
||||||
|
<img src="/assets/chismosa.png">
|
||||||
|
</span>
|
||||||
|
<span v-text="'$' + total"></span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Chismosa from './Chismosa.vue'
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
Chismosa
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
id: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
activa: false,
|
||||||
|
total: 0,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
Event.$on('pedido-actualizado', this.actualizar);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
toggle() {
|
||||||
|
this.activa = !this.activa;
|
||||||
|
Event.$emit("toggle-chismosa", this.activa);
|
||||||
|
},
|
||||||
|
actualizar() {
|
||||||
|
this.total = this.$root.pedido.total;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
67
resources/js/components/pedidos/DevolucionesModal.vue
Normal file
67
resources/js/components/pedidos/DevolucionesModal.vue
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
<template>
|
||||||
|
<div v-bind:class="visible ? 'is-active modal' : 'modal'">
|
||||||
|
<div class="modal-background"></div>
|
||||||
|
<div class="modal-card">
|
||||||
|
<header class="modal-card-head">
|
||||||
|
<p class="modal-card-title">Devoluciones</p>
|
||||||
|
<button class="delete" aria-label="close" @click.capture="cerrar"></button>
|
||||||
|
</header>
|
||||||
|
<section class="modal-card-body">
|
||||||
|
<div class="field has-addons is-centered is-thin-centered">
|
||||||
|
<p class="control">
|
||||||
|
Total:
|
||||||
|
<input id="total" class="input" type="number" v-model="total" style="text-align: center">
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="field has-addons is-centered is-thin-centered">
|
||||||
|
<p class="control">
|
||||||
|
Notas:
|
||||||
|
<input id="notas" class="input" type="text" v-model.text="notas">
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<footer class="modal-card-foot">
|
||||||
|
<button class="button is-success" @click="modificar">Aceptar</button>
|
||||||
|
<button class="button" @click.capture="cerrar">Cancelar</button>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
visible: false,
|
||||||
|
total: 0,
|
||||||
|
notas: "",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
miga: function() {
|
||||||
|
return {
|
||||||
|
nombre: "Devoluciones",
|
||||||
|
href: "#devoluciones",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
cerrar() {
|
||||||
|
this.visible = false;
|
||||||
|
Event.$emit("migas-pop");
|
||||||
|
},
|
||||||
|
modificar() {
|
||||||
|
Event.$emit('sync-devoluciones', this.total, this.notas);
|
||||||
|
this.cerrar();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
Event.$on('modificar-devoluciones', () => {
|
||||||
|
this.visible = true;
|
||||||
|
this.total = this.$root.pedido.devoluciones_total;
|
||||||
|
this.notas = this.$root.pedido.devoluciones_notas;
|
||||||
|
Event.$emit("migas-agregar", this.miga);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
55
resources/js/components/pedidos/Login.vue
Normal file
55
resources/js/components/pedidos/Login.vue
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
<template>
|
||||||
|
<div v-show="visible" class="block">
|
||||||
|
<div class="field">
|
||||||
|
<label class="label">Contraseña del barrio</label>
|
||||||
|
<div class="field has-addons">
|
||||||
|
<div class="control">
|
||||||
|
<input required class="input" :type="this.passwordType" name="password" placeholder="Contraseña del barrio">
|
||||||
|
</div>
|
||||||
|
<div class="control">
|
||||||
|
<a class="button is-info" @click="togglePassword">
|
||||||
|
{{ (passwordVisible ? 'Ocultar' : 'Mostrar') + ' contraseña'}}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p class="help">Si no la sabés, consultá a tus compañerxs.</p>
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<div class="control">
|
||||||
|
<input type="submit" class="button is-success" value="Ingresar"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
visible: false,
|
||||||
|
gdc: this.$root.gdc,
|
||||||
|
passwordVisible: false,
|
||||||
|
passwordType: "password",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
Event.$on('gdc-seleccionado', (gdc) => {
|
||||||
|
this.$root.gdc = gdc;
|
||||||
|
this.visible = true;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
togglePassword() {
|
||||||
|
if (this.passwordVisible) this.passwordType = "password";
|
||||||
|
else this.passwordType = "text"
|
||||||
|
this.passwordVisible = !this.passwordVisible
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.help {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
</style>
|
54
resources/js/components/pedidos/NavMigas.vue
Normal file
54
resources/js/components/pedidos/NavMigas.vue
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
<template>
|
||||||
|
<nav class="breadcrumb is-centered has-background-danger-light is-fixed-top" aria-label="breadcrumbs" v-show="visible">
|
||||||
|
<ul class="mt-4">
|
||||||
|
<li v-for="(miga, i) in migas" :key="i" :class="{'is-active': i == migaActiva}">
|
||||||
|
<a :href="miga.href" v-text="miga.nombre"
|
||||||
|
:class="{'has-text-danger': i != migaActiva}"></a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
migas: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
visible: function() {
|
||||||
|
return this.migas.length > 0
|
||||||
|
},
|
||||||
|
migaActiva: function() {
|
||||||
|
return this.migas.length-1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
Event.$on('migas-setear-como-inicio', (miga) => {
|
||||||
|
this.migas = [];
|
||||||
|
this.migas.push(miga);
|
||||||
|
});
|
||||||
|
Event.$on('migas-agregar', (miga) => {
|
||||||
|
this.migas.push(miga);
|
||||||
|
});
|
||||||
|
Event.$on('migas-reset', () => {
|
||||||
|
this.migas = [];
|
||||||
|
});
|
||||||
|
Event.$on('migas-pop', () => {
|
||||||
|
this.migas.pop();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
nav.breadcrumb.is-fixed-top {
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
top: 3.25rem;
|
||||||
|
height: 2.75rem;
|
||||||
|
z-index: 5;
|
||||||
|
}
|
||||||
|
</style>
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue