0
1
Fork 0

Compare commits

...

153 Commits

Author SHA1 Message Date
Guillermo Bonet f57967cd17 Merge pull request 'feat: refs #7704 Change minQuantity' (!67) from 7704-itemMinimalQuantity into dev
Reviewed-on: verdnatura/hedera-web#67
Reviewed-by: Javi Gallego <jgallego@verdnatura.es>
2024-07-12 07:43:13 +00:00
Guillermo Bonet 1c54922692 feat: refs #7704 Refactor 2024-07-11 14:33:15 +02:00
Guillermo Bonet 8929f8c55a feat: refs #7704 Refactor 2024-07-11 14:32:56 +02:00
Guillermo Bonet 7f2c645682 feat: refs #7704 Refactor 2024-07-11 13:36:21 +02:00
Guillermo Bonet 099f494101 feat: refs #7704 Change minQuantity 2024-07-11 11:40:11 +02:00
Guillermo Bonet 61fac85554 Version increased 2024-06-25 08:36:13 +02:00
Guillermo Bonet 3a714debfc Merge pull request 'dev → test' (!64) from dev into test
Reviewed-on: verdnatura/hedera-web#64
2024-06-21 12:29:07 +00:00
Guillermo Bonet 647dd09013 Merge pull request 'fix: refs #7498 Download invoice out error' (!63) from 7498-fixInvoiceOuts into dev
Reviewed-on: verdnatura/hedera-web#63
2024-06-11 06:54:44 +00:00
Guillermo Bonet 05c71c7425 refactor: refs #7498 Version increased 2024-06-11 08:54:33 +02:00
Guillermo Bonet 90e2b0abb5 refactor: refs #7498 Deleted method 2024-06-07 08:51:03 +02:00
Guillermo Bonet bcbbee411f fix: refs #7498 Download invoice out error 2024-05-29 10:45:34 +02:00
Guillermo Bonet 961ff02053 Merge pull request 'test' (!61) from test into master
Reviewed-on: verdnatura/hedera-web#61
2024-05-28 06:22:39 +00:00
Guillermo Bonet e7eb2a01fe Merge branch 'master' into test 2024-05-28 06:20:48 +00:00
Juan Ferrer 98cefc8f0f feat: refs #7442 Kubernetes deploy 2024-05-27 10:11:41 +02:00
Juan Ferrer e40a28b649 feat: refs #7442 Kubernetes deploy 2024-05-27 10:11:03 +02:00
Guillermo Bonet f869e7413c Merge branch 'dev' into test 2024-05-27 07:18:04 +02:00
Guillermo Bonet 29e800ea30 refs #7039 Version increased 2024-05-27 07:15:44 +02:00
Robert Ferrús 1eb98b772a Merge pull request 'feat: refs #7039 change country to name' (!57) from 7039-country-country into dev
Reviewed-on: verdnatura/hedera-web#57
Reviewed-by: Guillermo Bonet <guillermo@verdnatura.es>
2024-05-15 09:04:33 +00:00
Guillermo Bonet 1fe6816c08 Version increased 2024-05-14 14:17:26 +02:00
Javi Gallego 5bbc342471 package 2024-05-14 13:37:32 +02:00
Javi Gallego d808fa71d1 changeLog 2024-05-14 13:25:46 +02:00
Juan Ferrer ac226205b0 Merge pull request 'feat: refs #7108 deletes exchange-rate' (!59) from 7108 into test
Reviewed-on: verdnatura/hedera-web#59
Reviewed-by: Juan Ferrer <juan@verdnatura.es>
2024-05-14 08:51:27 +00:00
Guillermo Bonet 87f17409f7 Merge pull request 'test → master' (!60) from test into master
Reviewed-on: verdnatura/hedera-web#60
2024-05-14 07:20:35 +00:00
Javi Gallego ae70cbaaf4 feat: refs #7108 deletes exchange-rate 2024-05-09 09:20:07 +02:00
Guillermo Bonet 6e1613a26c Merge branch '7039-country-country' of https://gitea.verdnatura.es/verdnatura/hedera-web into 7039-country-country 2024-05-07 14:05:45 +02:00
Guillermo Bonet 359ddb5d18 Fix 2024-05-07 14:05:44 +02:00
Guillermo Bonet d75fe3fc00 Merge branch 'dev' into 7039-country-country 2024-05-07 11:54:14 +00:00
Guillermo Bonet e6cd88ee82 Merge branch 'test' of https://gitea.verdnatura.es/verdnatura/hedera-web into test 2024-05-07 13:53:37 +02:00
Guillermo Bonet a405cba00b Version increased 2024-05-07 13:53:36 +02:00
Guillermo Bonet e4f55ca9e9 Merge pull request 'dev → test' (!58) from dev into test
Reviewed-on: verdnatura/hedera-web#58
2024-05-07 11:51:00 +00:00
Robert Ferrús d8ea9134d4 feat: refs #7039 change country to name 2024-05-07 07:29:00 +02:00
Guillermo Bonet a96859b6bb Merge pull request 'refactor: refs #7258 Deleted dependences of vn2008' (!56) from 7258-byeViewsVn2008 into dev
Reviewed-on: verdnatura/hedera-web#56
Reviewed-by: Juan Ferrer <juan@verdnatura.es>
2024-05-02 07:55:34 +00:00
Guillermo Bonet e210a09f6b Merge branch 'dev' into 7258-byeViewsVn2008 2024-04-24 08:16:20 +00:00
Guillermo Bonet 5304a77f94 Merge branch 'test' into dev 2024-04-24 10:06:48 +02:00
Guillermo Bonet 3f63da06f1 fix: refs #6492 Version increased 2024-04-24 10:00:25 +02:00
Guillermo Bonet 7d120598bc refactor: refs #7258 Deleted dependences of vn2008 2024-04-24 07:55:52 +02:00
Juan Ferrer 4cf91140f7 Merge pull request '#6492 replace procedure' (!55) from 6492-useAgencyVolume into master
Reviewed-on: verdnatura/hedera-web#55
Reviewed-by: Juan Ferrer <juan@verdnatura.es>
2024-04-23 14:08:14 +00:00
Jorge Penadés 06554b7dee fix: refs #6492 replace procedure 2024-04-23 12:02:04 +02:00
Juan Ferrer 83c6886ee6 feat(catalog): refs #7222 Set image aspect ratio to 1:1 2024-04-17 10:10:40 +02:00
Jorge Penadés 4765bc78de Merge pull request 'feat: refs #6492 replace procedure' (!54) from 6492-replaceAgencyVolume into dev
Reviewed-on: verdnatura/hedera-web#54
Reviewed-by: Juan Ferrer <juan@verdnatura.es>
2024-04-12 06:49:16 +00:00
Jorge Penadés 0a9635feb2 feat: refs #6492 replace procedure 2024-04-10 12:41:45 +02:00
Jorge Penadés 00c8e4b1e3 feat: refs #6492 replace procedure 2024-04-10 12:35:44 +02:00
Guillermo Bonet 1414b6c96e refactor: refs #5167 Version increased 2024-03-21 07:15:28 +01:00
Guillermo Bonet 244b3f939e Merge pull request 'refactor: refs #5167 Deleted provinces section' (!51) from 5167-removedProvince into master
Reviewed-on: verdnatura/hedera-web#51
Reviewed-by: Juan Ferrer <juan@verdnatura.es>
2024-03-21 06:03:58 +00:00
Guillermo Bonet 1d2f9061c5 refactor: refs #5167 Requested changes 2024-03-11 13:23:07 +01:00
Guillermo Bonet a121750fa7 refactor: refs #5167 Deleted provinces section 2024-03-11 08:52:43 +01:00
Guillermo Bonet 73ba16634e refactor: refs #5167 Deleted provinces section 2024-03-11 08:50:35 +01:00
Juan Ferrer 2515cbcee7 ci: HOTFIX Use version to tag docker images 2024-02-22 09:41:39 +01:00
Juan Ferrer d1cdba800d Jenkinsfile refactor 2024-02-22 09:25:38 +01:00
Juan Ferrer 02ddc87755 version increased 2024-02-22 09:03:28 +01:00
Juan Ferrer 7689be689f Merge branch 'master' into test 2024-02-22 08:56:16 +01:00
Juan Ferrer 33778629e6 Merge pull request 'dev' (!49) from dev into test
Reviewed-on: verdnatura/hedera-web#49
2024-02-15 12:35:15 +00:00
Juan Ferrer 7f1d8ebb8e version updated 2024-02-15 13:34:20 +01:00
Juan Ferrer 4d8a67f499 Merge pull request 'test' (!48) from test into dev
Reviewed-on: verdnatura/hedera-web#48
2024-02-15 12:32:01 +00:00
Guillermo Bonet c6120af93b Merge pull request 'refactor: refs #6780 Deleted references to warehouse vn2008' (!47) from 6780-changeViewDependencesVn2008 into dev
Reviewed-on: verdnatura/hedera-web#47
Reviewed-by: Juan Ferrer <juan@verdnatura.es>
2024-02-02 08:16:55 +00:00
Guillermo Bonet 95f819c22f refactor: refs #6780 Deleted references to warehouse vn2008 2024-02-01 09:46:16 +01:00
Juan Ferrer 496061fb3c refs #6200 Version increased 2023-10-10 14:17:50 +02:00
Juan Ferrer 0b85c1230a Merge branch 'master' of https://gitea.verdnatura.es/verdnatura/hedera-web 2023-10-10 12:46:42 +02:00
Juan Ferrer 3ed871cb4c refs #6200 fix 2023-10-10 12:46:05 +02:00
Juan Ferrer c7159a1e13 Merge pull request 'refs #6200 test into master' (!46) from test into master
Reviewed-on: verdnatura/hedera-web#46
2023-10-10 08:21:49 +00:00
Juan Ferrer fba880fb33 refs #6200 Version increased 2023-10-10 09:37:29 +02:00
Juan Ferrer 1535a557a8 refs #6200 Fixes: style & add to basket 2023-10-09 21:08:40 +02:00
Juan Ferrer 4a09fe39a8 refs #6200 style fixes, mock local date 2023-10-09 21:01:11 +02:00
Juan Ferrer 3977b258d3 refs #6200 Style fixes 2023-10-09 20:20:01 +02:00
Juan Ferrer 6915e06c71 refs #6200 Minimal amount 2023-10-09 19:51:59 +02:00
Juan Ferrer a474f9df05 Merge branch 'master' into test 2023-10-09 19:06:44 +02:00
Juan Ferrer 620bd53262 refs #5879 Fixes: PHP max upload filesize 2023-08-30 17:48:23 +02:00
Juan Ferrer 8f98597ea2 refs #5863 Fixes: Mailer, logout & run db 2023-08-21 11:41:51 +02:00
Alex Moreno a2cd8a711e Merge pull request 'refs #5762 feat(changePassword): salix compatibility' (!44) from 5762-recover-password_salix2 into test
Reviewed-on: verdnatura/hedera-web#44
Reviewed-by: Juan Ferrer <juan@verdnatura.es>
2023-08-18 06:57:15 +00:00
Alex Moreno 08b4a3437c refs #5762 feat(changePassword): salix compatibility 2023-08-07 07:25:11 +02:00
Juan Ferrer a59c44fb3a refs #5863 Version increased 2023-08-02 08:49:49 +02:00
Juan Ferrer 2adfd2299a Merge pull request 'hotFix(logout): correct order' (!43) from hotFix_correctOrder_logout into master
Reviewed-on: verdnatura/hedera-web#43
Reviewed-by: Juan Ferrer <juan@verdnatura.es>
2023-07-28 11:25:16 +00:00
Juan Ferrer f929e67d76 Merge branch 'master' into hotFix_correctOrder_logout 2023-07-28 11:24:56 +00:00
Juan Ferrer d37493b081 ticket #097414 Fix: Use client language 2023-07-28 13:11:33 +02:00
Alex Moreno 0f3ddb1a99 hotFix(logout): correct order 2023-07-28 10:16:28 +02:00
Juan Ferrer bb4e348d0c Merge pull request 'test into master' (!42) from test into master
Reviewed-on: verdnatura/hedera-web#42
2023-07-27 20:07:42 +00:00
Juan Ferrer 754b8cd6c4 refs #6079 Add tag 8 & modify france phone 2023-07-27 21:55:17 +02:00
Alex Moreno 7bb067223a Merge pull request '5863_logout_remove_session' (!40) from 5863_logout_remove_session into test
Reviewed-on: verdnatura/hedera-web#40
Reviewed-by: Juan Ferrer <juan@verdnatura.es>
2023-07-14 11:04:56 +00:00
Alex Moreno 9363cdf5a4 refs #5863 fix remove user session 2023-07-12 08:34:47 +02:00
Alex Moreno d17bc6115f refs #5863 logout remove $_SESSION['user'] 2023-07-12 07:17:20 +02:00
Javi Gallego 9475c26663 Merge pull request 'refs #5863 add echos in login' (!39) from 5863_service_add_echos2 into test
Reviewed-on: verdnatura/hedera-web#39
Reviewed-by: Javi Gallego <jgallego@verdnatura.es>
2023-07-11 11:57:09 +00:00
Alex Moreno 607513452f Merge branch 'test' of https://gitea.verdnatura.es/verdnatura/hedera-web into 5863_service_add_echos2 2023-07-11 11:36:50 +02:00
Alex Moreno 86be0278a6 refs #5863 add echos in login 2023-07-11 11:35:15 +02:00
Alex Moreno a8f98d62ab Merge pull request 'refs #5863 add echos in login' (!38) from 5863_service_add_echos into test
Reviewed-on: verdnatura/hedera-web#38
Reviewed-by: Javi Gallego <jgallego@verdnatura.es>
2023-07-11 07:21:12 +00:00
Alex Moreno 2af5851066 refs #5863 add echos in login 2023-07-11 09:18:34 +02:00
Javi Gallego 1470e77572 Merge pull request 'refs #5863 remove echos' (!37) from 5863-visit_user3 into test
Reviewed-on: verdnatura/hedera-web#37
Reviewed-by: Javi Gallego <jgallego@verdnatura.es>
2023-07-10 07:23:01 +00:00
Alex Moreno 32cc865290 refs #5863 remove echos 2023-07-10 09:17:16 +02:00
Javi Gallego 8bcfe9f50c Merge pull request 'refs #5863 echos' (!36) from 5863-visit_user2 into test
Reviewed-on: verdnatura/hedera-web#36
Reviewed-by: Javi Gallego <jgallego@verdnatura.es>
2023-07-10 06:44:52 +00:00
Alex Moreno f638143e3e refs #5863 echos 2023-07-10 08:43:15 +02:00
Javi Gallego 07bde10609 Merge pull request 'refs #5863 add echos' (!35) from 5863-visit_user into test
Reviewed-on: verdnatura/hedera-web#35
Reviewed-by: Javi Gallego <jgallego@verdnatura.es>
2023-07-10 05:54:10 +00:00
Alex Moreno 4231365e4f refs #5863 add echos 2023-07-10 07:52:24 +02:00
Juan Ferrer fa56a4e540 refs #5879 Jenkinsfile: debuild updated 2023-06-20 17:29:01 +02:00
Juan Ferrer 5bcfd5897c Merge pull request 'refs #5879 test into dev' (!34) from test into dev
Reviewed-on: verdnatura/hedera-web#34
2023-06-20 15:20:29 +00:00
Juan Ferrer 572d4b7b83 Merge branch 'master' into test 2023-06-20 17:18:54 +02:00
Juan Ferrer bbeb70eb6b refs #5879 Upgrade Debian image 2023-06-20 16:56:19 +02:00
Juan Ferrer 2905a6ab57 Merge branch 'master' of https://gitea.verdnatura.es/verdnatura/hedera-web 2023-06-20 16:08:14 +02:00
Juan Ferrer 5b84671d57 hotfix #097414 Version increased 2023-06-20 16:08:13 +02:00
Carlos Andrés 9146d28db5 Merge pull request 'hotfix-Ticket-#097414-traducción-meensaje-de-error' (!32) from hotfix-Ticket-#097414-traducción-meensaje-de-error into master
Reviewed-on: verdnatura/hedera-web#32
Reviewed-by: Juan Ferrer <juan@verdnatura.es>
2023-06-20 12:02:02 +00:00
Carlos Andrés 59242daa79 Merge branch 'master' into hotfix-Ticket-#097414-traducción-meensaje-de-error 2023-06-20 12:01:38 +00:00
Juan Ferrer fd32b3f15a refs #5489 Version increased 2023-06-16 08:28:05 +02:00
Juan Ferrer 56395aa91b refs #5489 Account.sync(): bcryptPassword not used, removed 2023-06-15 13:14:01 +02:00
Carlos Andrés 2610448e79 hotfix Ticket #097414 traducción mensajes de error 2023-06-15 10:06:28 +02:00
Carlos Andrés 9eba09ddf7 hotfix Ticket #097414 traducción mensajes de error 2023-06-15 10:04:58 +02:00
Juan Ferrer 74980fbdd7 refs #5553 Insert/Update image table before save 2023-04-14 10:39:59 +02:00
Juan Ferrer 01326dc91c Merge pull request 'test' (!31) from test into dev
Reviewed-on: verdnatura/hedera-web#31
2023-03-10 11:23:16 +00:00
Juan Ferrer 5ce2f46842 Merge pull request 'refs #3867 Fix: display message of forbidden errors' (!30) from master into test
Reviewed-on: verdnatura/hedera-web#30
2023-03-10 11:22:50 +00:00
Juan Ferrer 42f682739e refs #3867 Fix: display message of forbidden errors 2023-03-07 08:50:12 +01:00
Juan Ferrer bbe7f2ea14 Merge pull request 'refs #3723 Set docker memory limit' (!29) from master into test
Reviewed-on: verdnatura/hedera-web#29
2023-03-06 08:31:52 +00:00
Juan Ferrer cdafea824e refs #3723 Set docker memory limit 2023-03-06 09:25:02 +01:00
Juan Ferrer 5fce203252 Merge pull request 'test' (!28) from test into dev
Reviewed-on: verdnatura/hedera-web#28
2023-02-27 08:47:36 +00:00
Juan Ferrer 9945c8f1b6 Merge pull request 'master' (!27) from master into test
Reviewed-on: verdnatura/hedera-web#27
2023-02-27 08:46:45 +00:00
Juan Ferrer 1ef0d48ba7 refs #4253 Version increased 2023-02-26 02:13:28 +01:00
Juan Ferrer 197758f2bc refs #4253 supplant security code uncommented 2023-02-26 02:12:45 +01:00
Juan Ferrer 511e925467 refs #5122 Show shopping bag icon in basket 2023-02-24 08:59:45 +01:00
Juan Ferrer f47e7e07a7 refs #5122 Pending orders: Show taxable base instead of total 2023-02-24 08:46:49 +01:00
Juan Ferrer b32be540f3 Merge pull request 'test' (!26) from test into dev
Reviewed-on: verdnatura/hedera-web#26
2023-02-23 19:28:45 +00:00
Juan Ferrer 4190aad94e Merge pull request 'master' (!25) from master into test
Reviewed-on: verdnatura/hedera-web#25
2023-02-23 19:22:05 +00:00
Juan Ferrer 9bfd42eaf8 refs #5122 Navigation improved, date shows year, fixes 2023-02-23 20:19:56 +01:00
Juan Ferrer dd7185d5dd refs #5122 Backend fix: Return error code for user exceptions 2023-02-23 17:05:19 +01:00
Juan Ferrer 10d8128133 refs #5122 Order check fixes 2023-02-23 16:50:49 +01:00
Juan Ferrer b357c4a451 Merge pull request 'refs #5122 Version increased' (!24) from master into test
Reviewed-on: verdnatura/hedera-web#24
2023-02-23 13:40:14 +00:00
Juan Ferrer e5941266ed refs #5122 Version increased 2023-02-23 14:36:36 +01:00
Juan Ferrer 592f79fcbd Merge pull request 'master' (!23) from master into test
Reviewed-on: verdnatura/hedera-web#23
2023-02-23 13:35:17 +00:00
Juan Ferrer 0abc6bdc23 refs #5122 Fix 2023-02-23 14:32:13 +01:00
Juan Ferrer 210b7e7806 Merge pull request 'refs #5253' (!22) from test into master
Reviewed-on: verdnatura/hedera-web#22
2023-02-23 09:30:42 +00:00
Juan Ferrer 92a4bc458c Merge pull request 'dev' (!21) from dev into test
Reviewed-on: verdnatura/hedera-web#21
2023-02-16 10:33:51 +00:00
Juan Ferrer 520e0c1eff refs #5161 Version increased 2023-02-16 11:23:38 +01:00
Juan Ferrer afd23e08b7 Merge pull request 'refs #5122' (!20) from 5122-multipleBasket into dev
Reviewed-on: verdnatura/hedera-web#20
2023-02-15 19:57:41 +00:00
Juan Ferrer 18cdb4cc1b Merge branch 'dev' into 5122-multipleBasket 2023-02-15 19:54:25 +00:00
Juan Ferrer ca5f80f6c3 refs #5122 2023-02-15 17:18:54 +01:00
Juan Ferrer d1ff6889af Merge pull request '5122-multipleBasket' (!19) from 5122-multipleBasket into dev
Reviewed-on: verdnatura/hedera-web#19
2023-02-15 16:15:03 +00:00
Juan Ferrer a632a15242 refs #5122 2023-02-15 17:13:25 +01:00
Juan Ferrer 67b6f77b12 refs #5122 2023-02-15 14:07:09 +01:00
Juan Ferrer e8eab29887 Merge branch 'dev' into 5122-multipleBasket 2023-02-14 17:10:34 +01:00
Juan Ferrer 326aeee127 Merge pull request 'test' (!18) from test into dev
Reviewed-on: verdnatura/hedera-web#18
2023-01-31 13:15:47 +00:00
Juan Ferrer bbb0089b59 Merge pull request 'master' (!17) from master into test
Reviewed-on: verdnatura/hedera-web#17
2023-01-31 13:15:19 +00:00
Juan Ferrer 406b2f8300 #4253 Hotfix: OutdatedVersionError not handled 2023-01-31 14:09:01 +01:00
Juan Ferrer efc7342359 fixes #5174 Redsys TPV api migrated to salix 2023-01-31 13:38:59 +01:00
Juan Ferrer 806c4cc3ad refs #5122 Checkpoint 2023-01-30 11:08:26 +01:00
Juan Ferrer c463e967ca refs #3971 Form input locking when loading 2023-01-16 16:57:48 +01:00
Juan Ferrer be43a38b38 refs #3971 Order confirm style fixes 2023-01-16 14:18:07 +01:00
Juan Ferrer 59ed61ae9b refs #4253 Translation & UI fixes 2023-01-16 13:59:11 +01:00
Juan Ferrer 17e54cfc60 Merge pull request 'test' (!16) from test into dev
Reviewed-on: verdnatura/hedera-web#16
2022-12-09 11:55:42 +00:00
Juan Ferrer baa9bb7cdf Merge pull request 'refs #3971 Fixes: Checkout, pay' (!15) from master into test
Reviewed-on: verdnatura/hedera-web#15
2022-12-09 11:55:18 +00:00
Juan Ferrer 87d75be910 refs #3971 Fixes: Checkout, pay 2022-12-09 12:51:51 +01:00
Juan Ferrer ac629dc97b Merge pull request 'test' (!14) from test into dev
Reviewed-on: verdnatura/hedera-web#14
2022-12-05 09:21:44 +00:00
Juan Ferrer ff3320d590 Merge branch 'test' of https://gitea.verdnatura.es/verdnatura/hedera-web into test 2022-12-02 19:24:38 +01:00
Juan Ferrer e8b727ab6c refs #4922 .quasar dir added to gitignore 2022-12-02 09:18:09 +01:00
Juan Ferrer 5934ee3832 refs #3971 User supplant fixes 2022-12-02 09:15:43 +01:00
Juan Ferrer 4f09574697 Merge pull request 'test' (!13) from test into dev
Reviewed-on: verdnatura/hedera-web#13
2022-12-01 08:07:57 +00:00
Juan Ferrer 6d95dfb999 Merge pull request 'master' (!12) from master into test
Reviewed-on: verdnatura/hedera-web#12
2022-12-01 08:07:08 +00:00
Juan Ferrer 1fa9b1e8b0 refs #3971 Order checkout hotfix 2022-12-01 09:04:33 +01:00
Juan Ferrer 327508c3ee Merge pull request 'test' (!11) from test into master
Reviewed-on: verdnatura/hedera-web#11
2022-12-01 07:54:27 +00:00
174 changed files with 2476 additions and 3129 deletions

1
.gitignore vendored
View File

@ -2,3 +2,4 @@ node_modules
build/ build/
config.my.php config.my.php
.vscode/ .vscode/
.quasar

View File

@ -1,5 +1,5 @@
# Not using buster because of bug: https://bugs.php.net/bug.php?id=78870 # Not using buster because of bug: https://bugs.php.net/bug.php?id=78870
FROM debian:stretch-slim FROM debian:bookworm-slim
ARG DEBIAN_FRONTEND=noninteractive ARG DEBIAN_FRONTEND=noninteractive
@ -23,19 +23,19 @@ RUN a2dissite 000-default
# NodeJs # NodeJs
RUN curl -fsSL https://deb.nodesource.com/setup_14.x | bash - \ RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
&& apt-get install -y --no-install-recommends nodejs && apt-get install -y --no-install-recommends nodejs
# Hedera # Hedera
RUN curl -sL https://apt.verdnatura.es/conf/verdnatura.gpg | apt-key add - \ RUN curl -sL https://apt.verdnatura.es/conf/verdnatura.gpg | apt-key add - \
&& echo "deb http://apt.verdnatura.es/ stretch main" \ && echo "deb http://apt.verdnatura.es/ bookworm main" \
> /etc/apt/sources.list.d/vn.list \ > /etc/apt/sources.list.d/vn.list \
&& apt-get update \ && apt-get update \
&& apt-get install -y --no-install-recommends \ && apt-get install -y --no-install-recommends \
php-apcu \
php-image-text \ php-image-text \
php-text-captcha \ php-text-captcha \
php-apcu \
php-zip \ php-zip \
hedera-web \ hedera-web \
cron cron

61
Jenkinsfile vendored
View File

@ -1,34 +1,24 @@
#!/usr/bin/env groovy #!/usr/bin/env groovy
def BRANCH_ENV = [
test: 'test',
master: 'production'
]
node {
stage('Setup') {
env.NODE_ENV = BRANCH_ENV[env.BRANCH_NAME] ?: 'dev'
echo "NODE_NAME: ${env.NODE_NAME}"
echo "WORKSPACE: ${env.WORKSPACE}"
}
}
pipeline { pipeline {
agent any agent any
environment { environment {
PROJECT_NAME = 'hedera-web' PROJECT_NAME = 'hedera-web'
STACK_NAME = "${env.PROJECT_NAME}-${env.BRANCH_NAME}"
} }
stages { stages {
stage('Checkout') {
steps {
script {
def packageJson = readJSON file: 'package.json'
env.VERSION = packageJson.version
switch (env.BRANCH_NAME) {
case 'master':
env.NODE_ENV = 'production'
env.MAIN_REPLICAS = 3
env.CRON_REPLICAS = 1
break
case 'test':
env.NODE_ENV = 'test'
env.MAIN_REPLICAS = 1
env.CRON_REPLICAS = 0
break
}
}
setEnv()
}
}
stage('Debuild') { stage('Debuild') {
when { when {
anyOf { anyOf {
@ -38,7 +28,7 @@ pipeline {
} }
agent { agent {
docker { docker {
image 'registry.verdnatura.es/debuild:2.21.3-vn2' image 'registry.verdnatura.es/debuild:2.23.4-vn1'
registryUrl 'https://registry.verdnatura.es/' registryUrl 'https://registry.verdnatura.es/'
registryCredentialsId 'docker-registry' registryCredentialsId 'docker-registry'
args '-v /mnt/appdata/reprepro:/reprepro' args '-v /mnt/appdata/reprepro:/reprepro'
@ -46,7 +36,7 @@ pipeline {
} }
steps { steps {
sh 'debuild -us -uc -b' sh 'debuild -us -uc -b'
sh 'vn-includedeb stretch' sh 'vn-includedeb bookworm'
} }
} }
stage('Container') { stage('Container') {
@ -60,6 +50,10 @@ pipeline {
CREDS = credentials('docker-registry') CREDS = credentials('docker-registry')
} }
steps { steps {
script {
def packageJson = readJSON file: 'package.json'
env.VERSION = packageJson.version
}
sh 'docker login --username $CREDS_USR --password $CREDS_PSW $REGISTRY' sh 'docker login --username $CREDS_USR --password $CREDS_PSW $REGISTRY'
sh 'docker-compose build --build-arg BUILD_ID=$BUILD_ID --parallel' sh 'docker-compose build --build-arg BUILD_ID=$BUILD_ID --parallel'
sh 'docker-compose push' sh 'docker-compose push'
@ -72,16 +66,25 @@ pipeline {
branch 'test' branch 'test'
} }
} }
environment {
DOCKER_HOST = "${env.SWARM_HOST}"
}
steps { steps {
sh "docker stack deploy --with-registry-auth --compose-file docker-compose.yml ${env.STACK_NAME}" script {
def packageJson = readJSON file: 'package.json'
env.VERSION = packageJson.version
}
withKubeConfig([
serverUrl: "$KUBERNETES_API",
credentialsId: 'kubernetes',
namespace: 'salix'
]) {
sh 'kubectl set image deployment/hedera-web-$BRANCH_NAME hedera-web-$BRANCH_NAME=$REGISTRY/hedera-web:$VERSION'
sh 'kubectl set image deployment/hedera-web-cron-$BRANCH_NAME hedera-web-cron-$BRANCH_NAME=$REGISTRY/hedera-web:$VERSION'
}
} }
} }
} }
post { post {
unsuccessful { unsuccessful {
setEnv()
sendEmail() sendEmail()
} }
} }

View File

@ -1,18 +1,49 @@
# Hedera # Hedera
Hedera is the main web page for Verdnatura. Hedera is the main web shop page for Verdnatura.
## Getting Started ## Prerequisites
Required dependencies. Required applications.
* PHP >= 7.0 * PHP >= 8.4
* Node.js >= 8.0 * Node.js >= 20.0
Launch application for development. Take a look to *debian/control* file to see additional dependencies.
Copy config.php to *config.my.php* and place your DB config there.
### Installing dependencies and launching
Pull from repository.
Run this commands on project root directory to install Node dependencies.
``` ```
$ npm run dev $ npm install
``` ```
Install project dependences (debian/control).
Pull from repository [php-vn-lib](https://gitea.verdnatura.es/verdnatura/php-vn-lib) and install [dependences](https://gitea.verdnatura.es/verdnatura/php-vn-lib/src/branch/master/debian/control) of this project.
Configure config.php file.
Launch project fronted.
```
$ npm run front
```
Launch salix backend.
```
$ npm run db
$ npm run back
```
Launch project backend.
```
$ php -S 127.0.0.1:3001 -t . index.php
```
### Command line
Run server side method from command line. Run server side method from command line.
``` ```
$ php hedera-web.php -m method_path $ php hedera-web.php -m method_path
@ -20,6 +51,8 @@ $ php hedera-web.php -m method_path
## Built with ## Built with
* [nodejs](https://nodejs.org/)
* [php](https://www.php.net/)
* [Webpack](https://webpack.js.org/) * [Webpack](https://webpack.js.org/)
* [MooTools](https://mootools.net/) * [MooTools](https://mootools.net/)
* [TinyMCE](https://www.tinymce.com/) * [TinyMCE](https://www.tinymce.com/)

View File

@ -12,6 +12,8 @@
* *
* - http://www.mydomain.org -> config.www.php * - http://www.mydomain.org -> config.www.php
* - http://test.mydomain.org -> config.test.php * - http://test.mydomain.org -> config.test.php
*
* Put the password in base64.
*/ */
return [ return [
/** /**
@ -22,7 +24,7 @@ return [
,'port' => 3306 ,'port' => 3306
,'schema' => 'hedera' ,'schema' => 'hedera'
,'user' => 'hedera-web' ,'user' => 'hedera-web'
,'pass' => '' ,'pass' => '' // base64 encoded
,'tz' => 'Europe/madrid' ,'tz' => 'Europe/madrid'
] ]
]; ];

2
debian/changelog vendored
View File

@ -1,4 +1,4 @@
hedera-web (22.48.2) stable; urgency=low hedera-web (24.14.8) stable; urgency=low
* Initial Release. * Initial Release.

2
debian/control vendored
View File

@ -10,7 +10,7 @@ Vcs-Git: https://gitea.verdnatura.es/verdnatura/hedera-web
Package: hedera-web Package: hedera-web
Architecture: all Architecture: all
Depends: apache2 | httpd, nodejs, php-cli, php-vn-lib, php-apcu, php-imap, php-soap, libphp-phpmailer, php-gd, php-pear Depends: apache2 | httpd, nodejs, php-cli, php-vn-lib, php-apcu, php-imap, php-soap, libphp-phpmailer, php-gd, php-pear
Suggests: php-text-captcha, php-zip, cron Suggests: php-image-text, php-text-captcha, php-zip, cron
Section: misc Section: misc
Priority: optional Priority: optional
Description: Verdnatura's web page Description: Verdnatura's web page

2
debian/cron.d vendored
View File

@ -1,10 +1,8 @@
MAILTO=webmaster MAILTO=webmaster
*/1 * * * * root hedera-web.php -m misc/mail */1 * * * * root hedera-web.php -m misc/mail
*/4 * * * * root hedera-web.php -m tpv/confirm-mail
*/2 * * * * root hedera-web.php -m edi/load */2 * * * * root hedera-web.php -m edi/load
0 23 * * * root hedera-web.php -m edi/clean 0 23 * * * root hedera-web.php -m edi/clean
0 5 * * * root hedera-web.php -m edi/update 0 5 * * * root hedera-web.php -m edi/update
0 5 * * * root hedera-web.php -m misc/exchange-rate
0 0 * * * root hedera-web.php -m image/sync 0 0 * * * root hedera-web.php -m image/sync
0 1 * * * root /usr/share/hedera-web/utils/image-clean.sh > /dev/null 0 1 * * * root /usr/share/hedera-web/utils/image-clean.sh > /dev/null
0 */1 * * * root /usr/share/hedera-web/utils/update-browscap.sh > /dev/null 0 */1 * * * root /usr/share/hedera-web/utils/update-browscap.sh > /dev/null

2
debian/links vendored
View File

@ -1,3 +1,3 @@
usr/share/hedera-web/hedera-web.php usr/bin/hedera-web.php usr/share/hedera-web/hedera-web.php usr/bin/hedera-web.php
etc/hedera-web/apache.conf etc/apache2/conf-available/hedera-web.conf etc/hedera-web/apache.conf etc/apache2/conf-available/hedera-web.conf
etc/hedera-web/php.ini etc/php/7.0/apache2/conf.d/99-hedera-web.ini etc/hedera-web/php.ini etc/php/8.2/apache2/conf.d/99-hedera-web.ini

View File

@ -1,41 +1,12 @@
version: '3.7' version: '3.7'
services: services:
main: main:
image: registry.verdnatura.es/hedera-web:${BRANCH_NAME:?} image: registry.verdnatura.es/hedera-web:${VERSION:?}
build: build:
context: . context: .
dockerfile: Dockerfile dockerfile: Dockerfile
args: args:
- VERSION=${VERSION:?} - VERSION=${VERSION:?}
ports:
- 80
configs:
- source: config
target: /etc/hedera-web/config.my.php
volumes:
- /mnt/appdata:/mnt/storage
- /mnt/appdata/image:/var/lib/hedera-web/image-db
- /mnt/appdata/vn-access:/var/lib/hedera-web/vn-access
deploy:
replicas: ${MAIN_REPLICAS:?}
placement:
constraints:
- node.role == worker
cron: cron:
image: registry.verdnatura.es/hedera-web:${BRANCH_NAME:?} image: registry.verdnatura.es/hedera-web:${VERSION:?}
command: 'cron -f' command: 'cron -f'
configs:
- source: config
target: /etc/hedera-web/config.my.php
volumes:
- /mnt/appdata:/mnt/storage
- /mnt/appdata/image:/var/lib/hedera-web/image-db
deploy:
replicas: ${CRON_REPLICAS:?}
placement:
constraints:
- node.role == worker
configs:
config:
external: true
name: ${PROJECT_NAME:?}-${BRANCH_NAME:?}

View File

@ -65,8 +65,8 @@
one-way="true" one-way="true"
one-time="true"> one-time="true">
<db-model property="model"> <db-model property="model">
SELECT id, country FROM vn.country SELECT id, name FROM vn.country
ORDER BY country ORDER BY name
</db-model> </db-model>
</htk-combo> </htk-combo>
</div> </div>

View File

@ -7,70 +7,7 @@ export default new Class({
activate() { activate() {
this.$.userModel.setInfo('c', 'myClient', 'hedera'); this.$.userModel.setInfo('c', 'myClient', 'hedera');
this.$.userModel.setInfo('u', 'myUser', 'account'); this.$.userModel.setInfo('u', 'myUser', 'account');
this.$.changePassword.conn = this.conn
if (this.hash.$.verificationToken) this.$.changePassword.user = this.gui.user
this.onPassChangeClick();
} }
});
,onPassChangeClick() {
this.$.oldPassword.value = '';
this.$.newPassword.value = '';
this.$.repeatPassword.value = '';
var verificationToken = this.hash.$.verificationToken;
this.$.oldPassword.style.display = verificationToken ? 'none' : 'block';
this.$.changePassword.show();
if (verificationToken)
this.$.newPassword.focus();
else
this.$.oldPassword.focus();
}
,async onPassModifyClick() {
var oldPassword = this.$.oldPassword.value;
var newPassword = this.$.newPassword.value;
var repeatedPassword = this.$.repeatPassword.value;
if (newPassword == '' && repeatedPassword == '')
throw new Error(_('Passwords empty'));
if (newPassword !== repeatedPassword)
throw new Error(_('Passwords doesn\'t match'));
var verificationToken = this.hash.$.verificationToken;
var params = {newPassword};
let err;
try {
if (verificationToken) {
params.verificationToken = verificationToken;
await this.conn.send('user/restore-password', params);
} else {
let userId = this.gui.user.id;
params.oldPassword = oldPassword;
await this.conn.patch(
`Accounts/${userId}/changePassword`, params);
}
} catch(e) {
err = e;
Htk.Toast.showError(err.message);
if (this.hash.$.verificationToken)
this.$.newPassword.select();
else
this.$.oldPassword.select();
return;
}
this.$.changePassword.hide();
this.hash.unset('verificationToken');
Htk.Toast.showMessage(_('Password changed!'));
this.$.userForm.refresh();
}
,onPassInfoClick() {
this.$.passwordInfo.show();
}
});

View File

@ -1,11 +1,5 @@
<vn> <vn>
<vn-group> <vn-group>
<db-form v-model="passwordForm">
<db-model property="model">
SELECT length, nAlpha, nUpper, nDigits, nPunct
FROM account.userPassword
</db-model>
</db-form>
<db-form id="user-form"> <db-form id="user-form">
<db-model property="model" id="user-model" updatable="true"> <db-model property="model" id="user-model" updatable="true">
SELECT u.id, u.name, u.email, u.nickname, SELECT u.id, u.name, u.email, u.nickname,
@ -27,7 +21,7 @@
<htk-bar-button <htk-bar-button
icon="lock_reset" icon="lock_reset"
tip="_Change password" tip="_Change password"
on-click="this.onPassChangeClick()"/> on-click="this.$.changePassword.open()"/>
</div> </div>
<div id="form" class="conf"> <div id="form" class="conf">
<div class="form box vn-w-sm vn-pa-lg"> <div class="form box vn-w-sm vn-pa-lg">
@ -74,62 +68,5 @@
</div> </div>
</div> </div>
</div> </div>
<htk-popup <htk-change-password id="change-password"/>
id="change-password"
modal="true">
<div property="child-node" class="htk-dialog vn-w-xs vn-pa-lg">
<div class="form">
<h5 class="vn-mb-md">
<t>Change password</t>
</h5>
<input
id="old-password"
type="password"
placeholder="_Old password"/>
<input
id="new-password"
type="password"
placeholder="_New password"/>
<input
id="repeat-password"
type="password"
placeholder="_Repeat password"/>
</div>
<div class="button-bar">
<button class="thin" on-click="this.onPassModifyClick()">
<t>Modify</t>
</button>
<button class="thin" on-click="this.onPassInfoClick()">
<t>Requirements</t>
</button>
<div class="clear"/>
</div>
</div>
</htk-popup>
<htk-popup
id="password-info"
modal="true">
<div property="child-node" class="htk-dialog pass-info vn-w-xs vn-pa-lg">
<h5 class="vn-mb-md">
<t>Password requirements</t>
</h5>
<ul>
<li>
{{passwordForm.length}} <t>characters long</t>
</li>
<li>
{{passwordForm.nAlpha}} <t>alphabetic characters</t>
</li>
<li>
{{passwordForm.nUpper}} <t>capital letters</t>
</li>
<li>
{{passwordForm.nDigits}} <t>digits</t>
</li>
<li>
{{passwordForm.nPunct}} <t>symbols</t>
</li>
</ul>
</div>
</htk-popup>
</vn> </vn>

View File

@ -7,8 +7,8 @@ export default new Class({
,activate() { ,activate() {
if (!this.hash.$.to) if (!this.hash.$.to)
this.hash.assign({ this.hash.assign({
from: new Date(), from: Date.vnNew(),
to: new Date() to: Date.vnNew()
}); });
} }
}); });

View File

@ -3,12 +3,5 @@ import './style.scss';
export default new Class({ export default new Class({
Extends: Hedera.Form, Extends: Hedera.Form,
Template: require('./ui.xml'), Template: require('./ui.xml'),
onShowClick(column, agencyId) {
this.hash.setAll({
form: 'agencies/provinces',
agency: agencyId
});
}
}); });

View File

@ -1,5 +1,4 @@
ListByAgency: Paquets per agència ListByAgency: Paquets per agència
ShowByProvince: Mostrar desglose per província
Agency: Agència Agency: Agència
Exps: Exps. Exps: Exps.
Bundles: Paquets Bundles: Paquets

View File

@ -1,5 +1,4 @@
ListByAgency: Bundles by agency ListByAgency: Bundles by agency
ShowByProvince: Show breakdown by province
Agency: Agency Agency: Agency
Exps: Exps. Exps: Exps.
Bundles: Bundles Bundles: Bundles

View File

@ -1,5 +1,4 @@
ListByAgency: Bultos por agencia ListByAgency: Bultos por agencia
ShowByProvince: Mostrar desglose por provincia
Agency: Agencia Agency: Agencia
Exps: Exps. Exps: Exps.
Bundles: Bultos Bundles: Bultos

View File

@ -1,5 +1,4 @@
ListByAgency: Liste par agence ListByAgency: Liste par agence
ShowByProvince: Montrer par province
Agency: Agence Agency: Agence
Exps: Expéditeur Exps: Expéditeur
Bundles: Cartons Bundles: Cartons

View File

@ -1,5 +1,4 @@
ListByAgency: Bultos por agencia ListByAgency: Bultos por agencia
ShowByProvince: Mostrar desglosse por Distrito
Agency: Agencia Agency: Agencia
Exps: Exps. Exps: Exps.
Bundles: Bultos Bundles: Bultos

View File

@ -7,14 +7,9 @@
<htk-grid> <htk-grid>
<db-model property="model"> <db-model property="model">
<custom> <custom>
CALL vn2008.agencia_volume () CALL vn.agencyVolume()
</custom> </custom>
</db-model> </db-model>
<htk-column-button
column="agency_id"
icon="search"
tip="_ShowByProvince"
on-clicked="onShowClick"/>
<htk-column-text title="_Agency" column="Agencia"/> <htk-column-text title="_Agency" column="Agencia"/>
<htk-column-spin title="_Exps" column="expediciones"/> <htk-column-spin title="_Exps" column="expediciones"/>
<htk-column-spin title="_Bundles" column="Bultos"/> <htk-column-spin title="_Bundles" column="Bultos"/>

View File

@ -1,7 +0,0 @@
import './style.scss';
export default new Class({
Extends: Hedera.Form,
Template: require('./ui.xml')
});

View File

@ -1,6 +0,0 @@
ByProvince: Desglose per província
Return: Tornar
SelectAgency: Selecciona una agència al llistat de l'esquerra
Province: Província
Expeditions: Exps.
Left: Falten

View File

@ -1,6 +0,0 @@
ByProvince: Breakdown by province
Return: Return
SelectAgency: Select an agency
Province: Province
Expeditions: Exps.
Left: Left

View File

@ -1,6 +0,0 @@
ByProvince: Desglose por provincia
Return: Volver
SelectAgency: Selecciona una agencia
Province: Provincia
Expeditions: Exps.
Left: Faltan

View File

@ -1,6 +0,0 @@
ByProvince: Par province
Return: Retour
SelectAgency: Sélectionnez une agence
Province: Province
Expeditions: Expéditions
Left: Restant

View File

@ -1,6 +0,0 @@
ByProvince: Desglosse por Distritos
Return: Voltar
SelectAgency: Seleccione uma agência
Province: Distrito
Expeditions: Exps.
Left: Faltam

View File

@ -1,18 +0,0 @@
<vn>
<div id="title">
<h1><t>ByProvince</t></h1>
</div>
<div id="form" class="provinces vn-w-sm">
<div class="box">
<htk-grid>
<db-model property="model" lot="hash">
CALL vn2008.desglose_volume(#agency)
</db-model>
<htk-column-text title="_Province" column="Provincia"/>
<htk-column-spin title="_Expeditions" column="expediciones"/>
<htk-column-spin title="_Bundles" column="Bultos"/>
<htk-column-spin title="_Left" column="Prevision"/>
</htk-grid>
</div>
</div>
</vn>

View File

@ -14,7 +14,7 @@ export default new Class({
,refreshCaptcha() { ,refreshCaptcha() {
params = { params = {
srv: 'rest:misc/captcha', srv: 'rest:misc/captcha',
stamp: new Date().getTime() stamp: Date.vnNew().getTime()
}; };
this.$.captchaImg.src = '?'+ Vn.Url.makeUri(params); this.$.captchaImg.src = '?'+ Vn.Url.makeUri(params);
} }

View File

@ -13,7 +13,8 @@ BecauseOurSalesDep: >-
Pour nos professionnels de service commercial qui sera toujours de trouver une Pour nos professionnels de service commercial qui sera toujours de trouver une
solution à vos besoins. solution à vos besoins.
BecauseOurWorkShop: Parce que nous avons un atelier de couture pour aider. BecauseOurWorkShop: Parce que nous avons un atelier de couture pour aider.
BecauseWeHaveWhatYouNeed: Parce que nous avons ce que vous avez besoin quand vous en avez besoin ... BecauseWeHaveWhatYouNeed: >-
Parce que nous avons ce que vous avez besoin quand vous en avez besoin ...
AboutDesc: >- AboutDesc: >-
Nous sommes une société spécialisée dans le commerce de gros et de la Nous sommes une société spécialisée dans le commerce de gros et de la
distribution d'une large gamme d'accessoires, des verts et des fleurs à des distribution d'une large gamme d'accessoires, des verts et des fleurs à des
@ -31,6 +32,6 @@ AboutDisp: >-
Mercaflor - Mercavalencia (Valencia) qui effectuent des ventes directes Mercaflor - Mercavalencia (Valencia) qui effectuent des ventes directes
seulement. seulement.
AboutOrder: >- AboutOrder: >-
Vous pouvez faire vos commandes et réservations par téléphone au +33 781 533 Vous pouvez faire vos commandes et réservations par téléphone au +33 783 285
900, en ligne grâce à notre site Internet ou directement dans nos 437, en ligne grâce à notre site Internet ou directement dans nos
installations. installations.

View File

@ -5,17 +5,64 @@ export default new Class({
Template: require('./ui.xml'), Template: require('./ui.xml'),
async open() { async open() {
const isOk = await Hedera.BasketChecker.check(this.conn, this.hash); await this.loadOrder();
if (isOk) await Hedera.Form.prototype.open.call(this); if (this.orderId) {
await Hedera.Form.prototype.open.call(this);
this.$.lot.assign({id: this.orderId});
}
}, },
activate() { activate() {
this.$.items.setInfo('bi', 'myBasketItem', 'hedera'); this.$.items.setInfo('bi', 'myOrderRow', 'hedera');
},
async onHashChange() {
if (!this.isOpen) return;
await this.loadOrder();
if (this.orderId)
this.$.lot.assign({id: this.orderId});
},
async loadOrder() {
const basket = new Hedera.Basket(this.app);
if (this.hash.$.id) {
this.orderId = this.hash.$.id;
} else if (await basket.check()) {
this.orderId = basket.orderId;
}
},
onOrderReady(form) {
if (form.row < 0)
return;
if (form.$.method != 'PICKUP') {
Vn.Node.show(this.$.address);
Vn.Node.setText(this.$.method, _('Agency'));
} else {
Vn.Node.hide(this.$.address);
Vn.Node.setText(this.$.method, _('Warehouse'));
}
}, },
onConfigureClick() { onConfigureClick() {
Htk.Toast.showWarning(_('RememberReconfiguringImpact')); Htk.Toast.showWarning(_('RememberReconfiguringImpact'));
this.hash.setAll({form: 'ecomerce/checkout'}); this.hash.setAll({
form: 'ecomerce/checkout',
id: this.orderId
});
},
async onCatalogClick() {
const basket = new Hedera.Basket(this.app);
await basket.load(this.orderId);
},
onConfirmClick() {
this.hash.setAll({
form: 'ecomerce/confirm',
id: this.orderId
});
}, },
onDeleteClick(form) { onDeleteClick(form) {

View File

@ -1,11 +1,16 @@
ShoppingBasket: Cistella de la compra ShoppingBasket: Cistella de la compra
Order: Encàrrec
ShippingInformation: Dades d'enviament
DeliveryAddress: Adreça de lliurament
Delivery at: Lliurament el
Agency: Agència
Warehouse: Magatzem
Delete: Borrar encàrrec Delete: Borrar encàrrec
GoToCatalog: Anar al catàleg GoToCatalog: Anar al catàleg
ConfigureOrder: Configurar encàrrec ConfigureOrder: Configurar encàrrec
Checkout: Tramitar encàrrec Checkout: Tramitar encàrrec
OrderNumber: N encàrec OrderNumber: N encàrec
DateExit: Data d'eixida DateExit: Data d'eixida
Warehouse: Magatzem
OrderTotal: Total encàrrec OrderTotal: Total encàrrec
Amount: Quant Amount: Quant
Pack: Pack Pack: Pack

View File

@ -1,11 +1,16 @@
ShoppingBasket: Shopping basket ShoppingBasket: Shopping basket
Order: Order
ShippingInformation: Shipping information
DeliveryAddress: Delivery address
Delivery at: Delivery at
Agency: Agency
Warehouse: Store
Delete: Delete order Delete: Delete order
GoToCatalog: Go to catalog GoToCatalog: Go to catalog
ConfigureOrder: Configure order ConfigureOrder: Configure order
Checkout: Checkout Checkout: Checkout
OrderNumber: Order number OrderNumber: Order number
DateExit: Shipping date DateExit: Shipping date
Warehouse: Store
OrderTotal: Total OrderTotal: Total
Amount: Amount Amount: Amount
Pack: Pack Pack: Pack

View File

@ -1,11 +1,16 @@
ShoppingBasket: Cesta de la compra ShoppingBasket: Cesta de la compra
Order: Pedido
ShippingInformation: Datos de envío
DeliveryAddress: Dirección de entrega
Delivery at: Entrega el
Agency: Agencia
Warehouse: Almacén
Delete: Borrar pedido Delete: Borrar pedido
GoToCatalog: Ir al catálogo GoToCatalog: Ir al catálogo
ConfigureOrder: Configurar pedido ConfigureOrder: Configurar pedido
Checkout: Finalizar pedido Checkout: Finalizar pedido
OrderNumber: Nº pedido OrderNumber: Nº pedido
DateExit: Fecha de salida DateExit: Fecha de salida
Warehouse: Almacén
OrderTotal: Total OrderTotal: Total
Amount: Cantidad Amount: Cantidad
Pack: Pack Pack: Pack

View File

@ -1,11 +1,16 @@
ShoppingBasket: Panier ShoppingBasket: Panier
Order: Commande
ShippingInformation: Informations sur la livraison
DeliveryAddress: Addresse de livraison
Delivery at: Livraison à
Agency: Agence
Warehouse: Entrepôt
Delete: Effacer Delete: Effacer
GoToCatalog: Aller au catalogue GoToCatalog: Aller au catalogue
ConfigureOrder: Définissez l'ordre ConfigureOrder: Définissez l'ordre
Checkout: Caisse Checkout: Caisse
OrderNumber: Numéro de commande OrderNumber: Numéro de commande
DateExit: Date de sortie DateExit: Date de sortie
Warehouse: Magasin
OrderTotal: Total commande OrderTotal: Total commande
Amount: Quant Amount: Quant
Pack: Pack Pack: Pack

View File

@ -1,11 +1,16 @@
ShoppingBasket: Cesta da compra ShoppingBasket: Cesta da compra
Order: Encomenda
ShippingInformation: Dados de envio
DeliveryAddress: Endereço de entrega
Delivery at: Entrega na
Agency: Agência
Warehouse: Armazém
Delete: Eliminar encomenda Delete: Eliminar encomenda
GoToCatalog: Ir ao catálogo GoToCatalog: Ir ao catálogo
ConfigureOrder: Configurar encomenda ConfigureOrder: Configurar encomenda
Checkout: Finalizar encomenda Checkout: Finalizar encomenda
OrderNumber: Nº encomenda OrderNumber: Nº encomenda
DateExit: Data de saída DateExit: Data de saída
Warehouse: Armazém
OrderTotal: Total OrderTotal: Total
Amount: Quantidade Amount: Quantidade
Pack: Pack Pack: Pack

View File

@ -1,76 +1,93 @@
.basket .head { .hedera-basket {
border-bottom: 1px solid #DDD; .head {
} border-bottom: 1px solid #DDD;
.basket .head p {
font-weight: bold;
margin: 0;
padding: 0;
font-size: 1.4rem;
text-align: right;
}
.basket .form > p {
margin: 0;
font-size: 1.4rem;
color: white;
text-align: right;
}
/* Lines */ & > div > div {
margin: 15px 0;
}
& > div > div:first-child {
margin: 0;
}
p {
margin: 3px 0;
.basket .line { &.important {
display: flex; font-size: 1.2rem;
align-items: center; font-weight: bold;
gap: 12px; }
margin: 10px 0; }
height: 80px; .total {
}
.basket .line:first-child {
margin-top: 0;
}
.basket .line:last-child {
margin-bottom: 0;
}
.basket .line > .delete {
margin: 0 -8px;
}
.basket .line > .photo {
flex: none;
border-radius: 50%;
width: 68px;
height: 68px;
gap: 0;
}
.basket .line > .info {
flex: 1;
overflow: hidden;
}
.basket .line > .info > * {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.basket .line > .info > h2 {
font-size: 1rem;
font-weight: normal;
margin: 0;
}
.basket .line > .info > p {
margin: 0;
}
.basket .line > .info > .tags {
color: #777;
}
.basket .line .subtotal {
float: right;
}
/* Fields */ font-weight: bold;
margin: 0;
padding: 0;
font-size: 1.4rem;
text-align: right;
}
}
.form > p {
margin: 0;
font-size: 1.4rem;
color: white;
text-align: right;
}
.basket td.available-exceeded input { /* Lines */
background-color: #FCC;
}
.basket .icon > img {
border-radius: 50%;
}
.line {
display: flex;
align-items: center;
gap: 12px;
margin: 10px 0;
height: 80px;
}
.line:first-child {
margin-top: 0;
}
.line:last-child {
margin-bottom: 0;
}
.line > .delete {
margin: 0 -8px;
}
.line > .photo {
flex: none;
border-radius: 50%;
width: 68px;
height: 68px;
gap: 0;
}
.line > .info {
flex: 1;
overflow: hidden;
}
.line > .info > * {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.line > .info > h2 {
font-size: 1rem;
font-weight: normal;
margin: 0;
}
.line > .info > p {
margin: 0;
}
.line > .info > .tags {
color: #777;
}
.line .subtotal {
float: right;
}
/* Fields */
td.available-exceeded input {
background-color: #FCC;
}
.icon > img {
border-radius: 50%;
}
}

View File

@ -1,6 +1,6 @@
<vn> <vn>
<div id="title"> <div id="title">
<h1><t>ShoppingBasket</t></h1> <h1>{{_(params.$.id ? 'Order' : 'ShoppingBasket')}}</h1>
</div> </div>
<div id="actions"> <div id="actions">
<htk-bar-button <htk-bar-button
@ -8,18 +8,52 @@
tip="_ConfigureOrder" tip="_ConfigureOrder"
on-click="this.onConfigureClick()"/> on-click="this.onConfigureClick()"/>
<htk-bar-button <htk-bar-button
icon="local_florist" icon="shopping_bag"
tip="_Catalog" tip="_Catalog"
on-click="this.hash.setAll({form: 'ecomerce/catalog'})"/> on-click="this.onCatalogClick()"/>
<htk-bar-button <htk-bar-button
icon="shopping_cart_checkout" icon="shopping_cart_checkout"
tip="_Checkout" tip="_Checkout"
on-click="this.hash.setAll({form: 'ecomerce/confirm'})"/> on-click="this.onConfirmClick()"/>
</div> </div>
<div id="form" class="basket"> <vn-group>
<vn-lot-query id="params" on-change="this.onHashChange()">
<vn-spec name="id" type="Number"/>
</vn-lot-query>
<vn-lot id="lot"/>
<db-form v-model="order" on-ready="onOrderReady">
<db-model property="model" lot="lot">
SELECT o.id, o.sent,
ag.description agency, v.code method,
ad.nickname, ad.postalCode, ad.city, ad.street
FROM myOrder o
JOIN vn.agencyMode ag ON ag.id = o.agencyModeFk
LEFT JOIN myAddress ad ON ad.id = o.addressFk
JOIN vn.deliveryMethod v ON v.id = o.deliveryMethodFk
WHERE o.id = #id;
</db-model>
</db-form>
</vn-group>
<div id="form" class="hedera-basket">
<div class="box vn-w-sm vn-pa-lg"> <div class="box vn-w-sm vn-pa-lg">
<div class="head vn-pb-lg"> <div class="head vn-pb-lg">
<p> <h5>#{{order.id}}</h5>
<div class="delivery">
<h6><t>ShippingInformation</t></h6>
<p>{{order.nickname}}</p>
<p>
<t>Delivery at</t> {{Vn.Value.format(order.sent, _('%D'))}}
</p>
<p>
<span id="method"><t>Agency</t></span> {{order.agency}}
</p>
</div>
<div id="address" class="address vn-mt-md">
<h6><t>DeliveryAddress</t></h6>
<p>{{order.street}}</p>
<p>{{order.postalCode}}, {{order.city}}</p>
</div>
<p class="total">
<t>Total</t> <t>Total</t>
<htk-text format="%.2d€"> <htk-text format="%.2d€">
<db-calc-sum property="param" func="subtotal" model="items"/> <db-calc-sum property="param" func="subtotal" model="items"/>
@ -28,15 +62,16 @@
</div> </div>
<div class="lines vn-pt-lg"> <div class="lines vn-pt-lg">
<htk-repeater form-id="iter"> <htk-repeater form-id="iter">
<db-model id="items" property="model" updatable="true"> <db-model id="items" property="model" lot="lot" updatable="true">
SELECT bi.id, bi.amount, bi.price, i.longName item, SELECT bi.id, bi.amount, bi.price, i.longName item,
i.tag5, i.value5, i.tag6, i.value6, i.tag7, i.value7, i.tag5, i.value5, i.tag6, i.value6, i.tag7, i.value7,
i.image, im.updated i.image, im.updated
FROM myBasketItem bi FROM myOrderRow bi
JOIN vn.item i ON i.id = bi.itemFk JOIN vn.item i ON i.id = bi.itemFk
LEFT JOIN image im LEFT JOIN image im
ON im.collectionFk = 'catalog' ON im.collectionFk = 'catalog'
AND im.name = i.image AND im.name = i.image
WHERE orderFk = #id
</db-model> </db-model>
<custom> <custom>
<div class="line"> <div class="line">

View File

@ -7,19 +7,27 @@ const Catalog = new Class({
,_menuShown: false ,_menuShown: false
,async open() { ,async open() {
let isOk = true; const basket = new Hedera.Basket(this.app);
if (!localStorage.getItem('hederaGuest')) if (!localStorage.getItem('hederaGuest')) {
isOk = await Hedera.BasketChecker.check(this.conn, this.hash); if (await basket.check('catalog'))
else this.orderId = basket.orderId;
await this.conn.execQuery('CALL mybasket_configureForGuest'); } else {
const resultSet = await this.conn.execQuery(
'CALL myOrder_configureForGuest(@orderId); SELECT @orderId;');
if (isOk) await Hedera.Form.prototype.open.call(this); resultSet.fetchResult();
this.orderId = resultSet.fetchValue();
}
if (this.orderId)
await Hedera.Form.prototype.open.call(this);
} }
,activate() { ,activate() {
document.body.appendChild(this.$.rightPanel); document.body.appendChild(this.$.rightPanel);
this.$.items.setInfo('i', 'item', 'vn', ['id']); this.$.items.setInfo('i', 'item', 'vn', ['id']);
this.$.orderLot.assign({orderId: this.orderId});
if (localStorage.getItem('hederaView')) if (localStorage.getItem('hederaView'))
this.setView(parseInt(localStorage.getItem('hederaView'))); this.setView(parseInt(localStorage.getItem('hederaView')));
@ -98,6 +106,7 @@ const Catalog = new Class({
break; break;
} }
params.orderId = this.orderId;
const refreshItems = hasTagFilter const refreshItems = hasTagFilter
|| params.search != null || params.search != null
|| params.type != null; || params.type != null;
@ -193,6 +202,12 @@ const Catalog = new Class({
this.hideMenu(); this.hideMenu();
} }
,itemRenderer(builder, form) {
var minQuantity = builder.$.minQuantity;
minQuantity.style.display = form.$.minQuantity
? 'block' : 'hidden';
}
,realmRenderer(builder, form) { ,realmRenderer(builder, form) {
var link = builder.$.link; var link = builder.$.link;
@ -245,7 +260,11 @@ const Catalog = new Class({
if (this.isGuest()) if (this.isGuest())
return; return;
this.hash.setAll({form: 'ecomerce/checkout'}); this.hash.setAll({
form: 'ecomerce/checkout',
id: this.orderId,
continue: 'catalog'
});
} }
,onAddItemClick(event, form) { ,onAddItemClick(event, form) {
@ -255,8 +274,13 @@ const Catalog = new Class({
this.onEraseClick(); this.onEraseClick();
this.$.$card.row = form.row; this.$.$card.row = form.row;
this.$.cardLot.assign({item: form.$.id}); this.$.cardLot.assign({
item: form.$.id,
orderId: this.orderId
});
this.$.cardPopup.show(event.currentTarget); this.$.cardPopup.show(event.currentTarget);
this.$.cardMinQuantity.style.display = form.$.minQuantity
? 'block' : 'none';
} }
,onAddLotClick(column, value, row) { ,onAddLotClick(column, value, row) {
@ -284,7 +308,7 @@ const Catalog = new Class({
,async onConfirmClick() { ,async onConfirmClick() {
var sql = ''; var sql = '';
var query = new Sql.String({query: 'CALL myBasket_addItem(#warehouse, #item, #amount);'}); var query = new Sql.String({query: 'CALL myOrder_addItem(#orderId, #warehouse, #item, #amount);'});
var amountSum = 0; var amountSum = 0;
for (var warehouse in this.items) { for (var warehouse in this.items) {
@ -292,6 +316,7 @@ const Catalog = new Class({
amountSum += amount; amountSum += amount;
const params = { const params = {
orderId: this.orderId,
warehouse: warehouse, warehouse: warehouse,
item: this.$.cardLot.$.item, item: this.$.cardLot.$.item,
amount: amount amount: amount
@ -300,7 +325,7 @@ const Catalog = new Class({
} }
if (amountSum > 0) { if (amountSum > 0) {
this.conn.execQuery(sql); await this.conn.execQuery(sql);
var itemName = this.$.$card.get('item'); var itemName = this.$.$card.get('item');
Htk.Toast.showMessage( Htk.Toast.showMessage(

View File

@ -46,3 +46,4 @@ NoMoreAmountAvailable: No hi ha més quantitat disponible
MinimalGrouping: Empaquetat mínim MinimalGrouping: Empaquetat mínim
Available: Disponible Available: Disponible
GroupingPrice: Preu per grup GroupingPrice: Preu per grup
MinimalQuantity: Quantitat mínima

View File

@ -46,3 +46,4 @@ NoMoreAmountAvailable: No more amount available
MinimalGrouping: Minimal packing MinimalGrouping: Minimal packing
Available: Available Available: Available
GroupingPrice: Price per group GroupingPrice: Price per group
MinimalQuantity: Minimal quantity

View File

@ -46,3 +46,4 @@ NoMoreAmountAvailable: No hay más cantidad disponible
MinimalGrouping: Empaquetado mínimo MinimalGrouping: Empaquetado mínimo
Available: Disponible Available: Disponible
GroupingPrice: Precio per grupo GroupingPrice: Precio per grupo
MinimalQuantity: Cantidad mínima

View File

@ -46,3 +46,4 @@ NoMoreAmountAvailable: Pas plus disponible
MinimalGrouping: Emballage minimal MinimalGrouping: Emballage minimal
Available: Disponible Available: Disponible
GroupingPrice: Prix par groupe GroupingPrice: Prix par groupe
MinimalQuantity: Quantité minimum

View File

@ -46,3 +46,4 @@ NoMoreAmountAvailable: Não há mais quantidade disponível
MinimalGrouping: Embalagem mínima MinimalGrouping: Embalagem mínima
Available: Disponível Available: Disponível
GroupingPrice: Preço por grupo GroupingPrice: Preço por grupo
MinimalQuantity: Quantidade mínima

View File

@ -192,6 +192,25 @@
margin: 0; margin: 0;
margin-bottom: 1px; margin-bottom: 1px;
} }
& > .min-quantity {
bottom: 32px;
right: 0;
}
}
.min-quantity {
position: absolute;
display: none;
bottom: 30px;
right: 0;
font-size: .8rem;
color: #a44;
cursor: pointer;
& > span {
font-size: 16px;
vertical-align: middle;
}
} }
/* Tags */ /* Tags */
@ -256,7 +275,7 @@
} }
& > .htk-image { & > .htk-image {
width: 100%; width: 100%;
height: 180px; height: 210px;
& > img { & > img {
height: initial; height: initial;
@ -266,7 +285,7 @@
flex: auto; flex: auto;
overflow: hidden; overflow: hidden;
margin: 10px; margin: 10px;
height: 170px; height: 185px;
& > h2 { & > h2 {
max-height: 3rem; max-height: 3rem;
@ -351,6 +370,7 @@
& > .top { & > .top {
padding: 14px; padding: 14px;
position: relative;
& > .item-info { & > .item-info {
margin-left: 126px; margin-left: 126px;
@ -371,6 +391,11 @@
margin-top: 15px 0; margin-top: 15px 0;
font-size: .9rem; font-size: .9rem;
} }
& > .min-quantity {
bottom: 0;
right: 0;
padding: 14px;
}
} }
& > .lots-grid { & > .lots-grid {
border-top: 1px solid #DDD; border-top: 1px solid #DDD;

View File

@ -91,12 +91,13 @@
param="producer"/> param="producer"/>
</vn-group> </vn-group>
<vn-group> <vn-group>
<vn-lot id="order-lot"/>
<db-form v-model="basket"> <db-form v-model="basket">
<db-model property="model"> <db-model property="model" lot="order-lot">
SELECT b.id, b.sent, a.description agency, m.code method SELECT o.id, o.sent, ad.nickname
FROM myBasket b FROM myOrder o
JOIN vn.agencyMode a ON a.id = b.agencyModeFk LEFT JOIN myAddress ad ON ad.id = o.addressFk
JOIN vn.deliveryMethod m ON m.id = b.deliveryMethodFk WHERE o.id = #orderId
</db-model> </db-model>
</db-form> </db-form>
<db-model <db-model
@ -104,18 +105,18 @@
auto-load="false" auto-load="false"
result-index="3" result-index="3"
on-status-changed="onItemsChange"> on-status-changed="onItemsChange">
DROP TEMPORARY TABLE IF EXISTS tmp.item; CREATE OR REPLACE TEMPORARY TABLE tmp.item
CREATE TEMPORARY TABLE tmp.item
(INDEX (itemFk)) (INDEX (itemFk))
ENGINE = MEMORY ENGINE = MEMORY
SELECT i.id itemFk SELECT i.id itemFk
FROM vn.item i FROM vn.item i
JOIN vn.itemType t ON t.id = i.typeFk JOIN vn.itemType t ON t.id = i.typeFk
WHERE #filter; WHERE #filter;
CALL myBasket_calcCatalogFull; CALL myOrder_calcCatalogFull(#orderId);
SELECT i.id, i.longName item, i.subName, SELECT i.id, i.longName item, i.subName,
i.tag5, i.value5, i.tag6, i.value6, i.tag7, i.value7, i.tag5, i.value5, i.tag6, i.value6,
i.relevancy, i.size, i.category, i.tag7, i.value7, i.tag8, i.value8,
i.relevancy, i.size, i.category, b.minQuantity,
k.name ink, p.name producer, o.name origin, k.name ink, p.name producer, o.name origin,
b.available, b.price, b.`grouping`, b.available, b.price, b.`grouping`,
i.image, im.updated i.image, im.updated
@ -124,19 +125,13 @@
LEFT JOIN vn.ink k ON k.id = i.inkFk LEFT JOIN vn.ink k ON k.id = i.inkFk
LEFT JOIN vn.producer p ON p.id = i.producerFk LEFT JOIN vn.producer p ON p.id = i.producerFk
LEFT JOIN vn.origin o ON o.id = i.originFk LEFT JOIN vn.origin o ON o.id = i.originFk
LEFT JOIN image im LEFT JOIN image im ON im.collectionFk = 'catalog'
ON im.collectionFk = 'catalog'
AND im.name = i.image AND im.name = i.image
WHERE b.available > 0 WHERE b.available > 0
ORDER BY i.relevancy DESC, i.name, i.size ORDER BY i.relevancy DESC, i.name, i.size
LIMIT 5000; LIMIT 5000;
DROP TEMPORARY TABLE DROP TEMPORARY TABLE tmp.item;
tmp.item, CALL vn.ticketCalculatePurge();
tmp.ticketCalculateItem,
tmp.ticketComponentPrice,
tmp.ticketComponent,
tmp.ticketLot,
tmp.zoneGetShipped;
</db-model> </db-model>
<db-form id="$card" v-model="card" model="items"/> <db-form id="$card" v-model="card" model="items"/>
<vn-lot id="card-lot"/> <vn-lot id="card-lot"/>
@ -147,7 +142,8 @@
id="grid-view" id="grid-view"
empty-message="_Choose filter from right menu" empty-message="_Choose filter from right menu"
form-id="item" form-id="item"
model="items"> model="items"
renderer="itemRenderer">
<custom> <custom>
<div <div
id="item-box" id="item-box"
@ -185,6 +181,10 @@
<td>{{item.tag7}}</td> <td>{{item.tag7}}</td>
<td>{{item.value7}}</td> <td>{{item.value7}}</td>
</tr> </tr>
<tr>
<td>{{item.tag8}}</td>
<td>{{item.value8}}</td>
</tr>
</table> </table>
<div class="available-price"> <div class="available-price">
<span class="grouping" title="_MinimalGrouping"> <span class="grouping" title="_MinimalGrouping">
@ -197,6 +197,12 @@
{{Vn.Value.format(item.price, '%.02d€')}} {{Vn.Value.format(item.price, '%.02d€')}}
</span> </span>
</div> </div>
<div id="min-quantity" class="min-quantity" title="_MinimalQuantity">
<span class="htk-icon material-symbols-rounded">
production_quantity_limits
</span>
{{item.minQuantity}}
</div>
</div> </div>
</div> </div>
</custom> </custom>
@ -205,11 +211,8 @@
</div> </div>
<div id="right-panel" class="catalog-panel right-panel side-panel" on-click="onRightPanelClick"> <div id="right-panel" class="catalog-panel right-panel side-panel" on-click="onRightPanelClick">
<div class="basket-info"> <div class="basket-info">
<p>{{basket.nickname}}</p>
<p>{{Vn.Value.format(basket.sent, '%D')}}</p> <p>{{Vn.Value.format(basket.sent, '%D')}}</p>
<p>
{{_(basket.method != 'PICKUP' ? 'Agency' : 'Warehouse')}}
{{basket.agency}}
</p>
<button class="thin" on-click="this.onConfigureClick()"> <button class="thin" on-click="this.onConfigureClick()">
<t>Modify</t> <t>Modify</t>
</button> </button>
@ -261,7 +264,7 @@
lot="params" lot="params"
result-index="1" result-index="1"
on-status-changed="refreshTitle"> on-status-changed="refreshTitle">
CALL myBasket_getAvailable; CALL myOrder_getAvailable(#orderId);
SELECT DISTINCT t.id, l.name SELECT DISTINCT t.id, l.name
FROM vn.item i FROM vn.item i
JOIN vn.itemType t ON t.id = i.typeFk JOIN vn.itemType t ON t.id = i.typeFk
@ -283,7 +286,7 @@
property="model" property="model"
auto-load="false" auto-load="false"
result-index="1"> result-index="1">
CALL myBasket_getAvailable; CALL myOrder_getAvailable(#orderId);
SELECT DISTINCT l.id, l.name SELECT DISTINCT l.id, l.name
FROM vn.item i FROM vn.item i
JOIN vn.itemType t ON t.id = i.typeFk JOIN vn.itemType t ON t.id = i.typeFk
@ -304,7 +307,7 @@
property="model" property="model"
auto-load="false" auto-load="false"
result-index="1"> result-index="1">
CALL myBasket_getAvailable; CALL myOrder_getAvailable(#orderId);
SELECT DISTINCT p.id, p.name SELECT DISTINCT p.id, p.name
FROM vn.item i FROM vn.item i
JOIN vn.itemType t ON t.id = i.typeFk JOIN vn.itemType t ON t.id = i.typeFk
@ -325,7 +328,7 @@
property="model" property="model"
auto-load="false" auto-load="false"
result-index="1"> result-index="1">
CALL myBasket_getAvailable; CALL myOrder_getAvailable(#orderId);
SELECT DISTINCT o.id, l.name, o.code SELECT DISTINCT o.id, l.name, o.code
FROM vn.item i FROM vn.item i
JOIN vn.itemType t ON t.id = i.typeFk JOIN vn.itemType t ON t.id = i.typeFk
@ -347,7 +350,7 @@
property="model" property="model"
auto-load="false" auto-load="false"
result-index="1"> result-index="1">
CALL myBasket_getAvailable; CALL myOrder_getAvailable(#orderId);
SELECT DISTINCT i.category, i.category SELECT DISTINCT i.category, i.category
FROM vn.item i FROM vn.item i
JOIN vn.itemType t ON t.id = i.typeFk JOIN vn.itemType t ON t.id = i.typeFk
@ -458,6 +461,12 @@
</tr> </tr>
</custom> </custom>
</htk-repeater> </htk-repeater>
<div id="card-min-quantity" class="min-quantity" title="_MinimalQuantity">
<span class="htk-icon material-symbols-rounded">
production_quantity_limits
</span>
{{card.minQuantity}}
</div>
</div> </div>
<htk-grid class="lots-grid" show-header="false"> <htk-grid class="lots-grid" show-header="false">
<db-model <db-model
@ -466,7 +475,7 @@
result-index="1" result-index="1"
on-status-changed-after="onCardLoad" on-status-changed-after="onCardLoad"
lot="card-lot"> lot="card-lot">
CALL myBasket_calcCatalogFromItem(#item); CALL myOrder_calcCatalogFromItem(#orderId, #item);
SELECT l.warehouseFk, w.name warehouse, p.`grouping`, SELECT l.warehouseFk, w.name warehouse, p.`grouping`,
p.price, p.priceKg, p.rate, l.available p.price, p.priceKg, p.rate, l.available
FROM tmp.ticketLot l FROM tmp.ticketLot l

View File

@ -8,7 +8,7 @@ export default new Class({
this.autoStepLocked = true; this.autoStepLocked = true;
this.$.assistant.stepsIndex = this.agencySteps; this.$.assistant.stepsIndex = this.agencySteps;
this.today = new Date(); this.today = Date.vnNew();
this.today.setHours(0, 0, 0, 0); this.today.setHours(0, 0, 0, 0);
}, },
@ -22,8 +22,8 @@ export default new Class({
let date; let date;
const row = orderForm.$ || defaultsForm.$ || {}; const row = orderForm.$ || defaultsForm.$ || {};
if (!date || date.getTime() < (new Date()).getTime()) { if (!date || date.getTime() < (Date.vnNew()).getTime()) {
date = new Date(); date = Date.vnNew();
date.setHours(0, 0, 0, 0); date.setHours(0, 0, 0, 0);
let addDays = 0; let addDays = 0;
@ -44,7 +44,7 @@ export default new Class({
} }
this.$.lot.assign({ this.$.lot.assign({
date: date, date,
method: row.deliveryMethod, method: row.deliveryMethod,
agency: row.agencyModeFk, agency: row.agencyModeFk,
address: row.addressFk address: row.addressFk
@ -59,11 +59,21 @@ export default new Class({
async onConfirmClick() { async onConfirmClick() {
this.disableButtons(true); this.disableButtons(true);
const query = 'CALL myBasket_configure(#date, #method, #agency, #address)'; let id = this.$.params.$.id;
const params = Object.assign({}, this.$.lot.$);
let query;
if (id) {
params.id = id;
query = 'CALL myOrder_configure(#id, #date, #method, #agency, #address)';
} else {
query = 'CALL myOrder_create(@orderId, #date, #method, #agency, #address); SELECT @orderId;';
}
let resultSet; let resultSet;
try { try {
resultSet = await this.conn.execQuery(query, this.$.lot.$); resultSet = await this.conn.execQuery(query, params);
} finally { } finally {
this.disableButtons(false); this.disableButtons(false);
} }
@ -71,16 +81,31 @@ export default new Class({
if (!resultSet.fetchResult()) if (!resultSet.fetchResult())
return; return;
if (this.$.orderForm.numRows > 0) let redirect;
Htk.Toast.showMessage(_('OrderUpdated')); const basket = new Hedera.Basket(this.app);
else
Htk.Toast.showMessage(_('OrderStarted'));
this.hash.setAll({form: 'ecomerce/catalog'}); if (id) {
Htk.Toast.showMessage(_('OrderUpdated'));
switch(this.hash.$.continue) {
case 'catalog':
redirect = {form: 'ecomerce/catalog'};
break;
default:
redirect = {form: 'ecomerce/basket'};
if (id !== basket.orderId)
redirect.id = id;
}
} else {
basket.loadIntoBasket(resultSet.fetchValue());
redirect = {form: 'ecomerce/catalog'};
}
this.hash.setAll(redirect);
}, },
onCancelClick() { onCancelClick() {
if (this.$.orderForm.numRows > 0) if (this.$.params.$.id)
window.history.back(); window.history.back();
else else
this.hash.setAll({form: 'ecomerce/orders'}); this.hash.setAll({form: 'ecomerce/orders'});
@ -150,13 +175,9 @@ export default new Class({
this.$.assistant.moveNext(); this.$.assistant.moveNext();
}, },
goNextStep() {
this.$.assistant.moveNext();
},
onAddressClick(addressId) { onAddressClick(addressId) {
this.$.lot.set('address', addressId); this.$.lot.set('address', addressId);
this.goNextStep(); this.$.assistant.moveNext();
}, },
onAddressChange() { onAddressChange() {
@ -192,9 +213,9 @@ export default new Class({
const defaults = this.$.defaults.$ || {}; const defaults = this.$.defaults.$ || {};
if (defaults.agencyModeFk) if (defaults.agencyModeFk)
defaults.push(defaults.agencyModeFk); agencies.push(defaults.agencyModeFk);
if (defaults.defaultAgencyFk) if (defaults.defaultAgencyFk)
defaults.push(defaults.defaultAgencyFk); agencies.push(defaults.defaultAgencyFk);
for (const agency of agencies) for (const agency of agencies)
if (model.search('id', agency) !== -1) { if (model.search('id', agency) !== -1) {

View File

@ -1,54 +1,55 @@
.checkout .bar { .hedera-checkout {
margin-bottom: 16px; .bar {
} margin-bottom: 16px;
}
/* Step */ /* Step */
.answers button, .answers button,
.answers p, .answers p,
.radio > div { .radio > div {
font-size: 1.2rem; font-size: 1.2rem;
}
.answers .htk-select {
max-width: 15em;
margin: 0 auto;
font-size: 1.4rem;
}
.answers p {
margin: 0.3em 0;
}
.target {
max-width: 28em;
margin: 0 auto;
}
.address {
border-radius: 0.1em;
padding: 0.6em 1.4em;
}
.address.selected {
background-color: rgba(1, 1, 1, .1);
}
.address:hover {
cursor: pointer;
background-color: rgba(1, 1, 1, .05);
}
.address p.consignee {
font-weight: bold;
}
.radio {
max-width: 20em;
margin: 0 auto;
}
.radio > div {
padding: 0.5em;
}
.thin-calendar {
max-width: 24em;
margin: 0 auto;
box-shadow: none;
}
.htk-assistant .thin {
float: right;
}
} }
.answers .htk-select {
max-width: 15em;
margin: 0 auto;
font-size: 1.4rem;
}
.answers p {
margin: 0.3em 0;
}
.target {
max-width: 28em;
margin: 0 auto;
}
.address {
border-radius: 0.1em;
padding: 0.6em 1.4em;
}
.address.selected {
background-color: rgba(1, 1, 1, .1);
}
.address:hover {
cursor: pointer;
background-color: rgba(1, 1, 1, .05);
}
.address p.consignee {
font-weight: bold;
}
.radio {
max-width: 20em;
margin: 0 auto;
}
.radio > div {
padding: 0.5em;
}
.thin-calendar {
max-width: 24em;
margin: 0 auto;
box-shadow: none;
}
.htk-assistant .thin {
float: right;
}

View File

@ -1,4 +1,7 @@
<vn> <vn>
<vn-lot-query id="params">
<vn-spec name="id" type="Number"/>
</vn-lot-query>
<vn-group> <vn-group>
<vn-lot id="lot" on-change="this.onAddressChange()"/> <vn-lot id="lot" on-change="this.onAddressChange()"/>
<db-form id="defaults" on-ready="onValuesReady"> <db-form id="defaults" on-ready="onValuesReady">
@ -8,10 +11,11 @@
</db-model> </db-model>
</db-form> </db-form>
<db-form id="order-form" on-ready="onValuesReady"> <db-form id="order-form" on-ready="onValuesReady">
<db-model property="model"> <db-model property="model" lot="params">
SELECT m.code deliveryMethod, o.sent, o.agencyModeFk, o.addressFk SELECT m.code deliveryMethod, o.sent, o.agencyModeFk, o.addressFk
FROM myBasket o FROM myOrder o
JOIN vn.deliveryMethod m ON m.id = o.deliveryMethodFk JOIN vn.deliveryMethod m ON m.id = o.deliveryMethodFk
WHERE o.id = #id
</db-model> </db-model>
</db-form> </db-form>
<db-model id="agencies" <db-model id="agencies"
@ -54,7 +58,7 @@
tip="_Cancel" tip="_Cancel"
on-click="onCancelClick"/> on-click="onCancelClick"/>
</div> </div>
<div id="form" class="checkout"> <div id="form" class="hedera-checkout">
<div class="vn-w-sm"> <div class="vn-w-sm">
<div class="box bar"> <div class="box bar">
<htk-assistant-bar <htk-assistant-bar
@ -116,7 +120,7 @@
form-id="iter" form-id="iter"
on-change="onAddressChange"> on-change="onAddressChange">
<db-model property="model" id="addresses"> <db-model property="model" id="addresses">
SELECT a.id, a.nickname, p.name province, a.city, a.street, a.isActive, c.country SELECT a.id, a.nickname, p.name province, a.city, a.street, a.isActive, c.name
FROM myAddress a FROM myAddress a
LEFT JOIN vn.province p ON p.id = a.provinceFk LEFT JOIN vn.province p ON p.id = a.provinceFk
JOIN vn.country c ON c.id = p.countryFk JOIN vn.country c ON c.id = p.countryFk

View File

@ -5,8 +5,13 @@ export default new Class({
Template: require('./ui.xml'), Template: require('./ui.xml'),
async open() { async open() {
const isOk = await Hedera.BasketChecker.check(this.conn, this.hash); const basket = new Hedera.Basket(this.app);
if (isOk) await Hedera.Form.prototype.open.call(this); try {
await basket.checkOrder(this.hash.$.id);
} catch (err) {
Htk.Toast.showError(err.message);
}
await Hedera.Form.prototype.open.call(this);
}, },
onOrderReady(form) { onOrderReady(form) {
@ -106,25 +111,22 @@ export default new Class({
Vn.Node.addClass(this.$[id], 'selected'); Vn.Node.addClass(this.$[id], 'selected');
}, },
disableButtons(disable) {
this.$.modify.disabled = disable;
this.$.confirm.disabled = disable;
},
onModifyClick() { onModifyClick() {
window.history.back(); window.history.back();
}, },
async onConfirmClick() { async onConfirmClick() {
this.disableButtons(true); Vn.Node.disableInputs(this.node);
await this.$.confirmQuery.execute(); try {
}, await this.conn.execQuery(
'CALL myOrder_confirm(#id)',
onConfirm(query, resultSet) { this.$.params.$
this.disableButtons(false); );
Hedera.Basket.unload();
if (resultSet.fetchResult())
this.$.successDialog.show(); this.$.successDialog.show();
} finally {
Vn.Node.disableInputs(this.node, false);
}
}, },
async onDialogResponse() { async onDialogResponse() {

View File

@ -1,93 +1,95 @@
.confirm .summary { .hedera-confirm {
margin-bottom: 16px; .summary {
} margin-bottom: 16px;
.confirm p { }
margin: .2em 0; p {
} margin: .2em 0;
}
/* Table */ /* Table */
.confirm .debt-info { .debt-info {
padding: 0; padding: 0;
} }
.confirm .debt-info > table { .debt-info > table {
border-collapse: collapse; border-collapse: collapse;
} }
.confirm td { td {
padding: .15em 0; padding: .15em 0;
} }
.confirm .sum-total > td { .sum-total > td {
border-top: solid 1px #DDD; border-top: solid 1px #DDD;
font-weight: bold; font-weight: bold;
} }
.confirm .currency { .currency {
text-align: right; text-align: right;
} }
.confirm .credit-info { .credit-info {
display: none; display: none;
} }
.confirm .exceeded-info { .exceeded-info {
display: none; display: none;
color: #E53935; color: #E53935;
} }
/* Pay */ /* Pay */
.confirm .amount-selector, .amount-selector,
.confirm .pay-methods > div { .pay-methods > div {
display: none; display: none;
} }
.confirm .pay-methods > div { .pay-methods > div {
margin: .3em 0; margin: .3em 0;
} }
.confirm .pay-methods > div > label > input[type=radio] { .pay-methods > div > label > input[type=radio] {
margin: 0; margin: 0;
margin-right: .5em; margin-right: .5em;
vertical-align: middle; vertical-align: middle;
} }
.confirm .pay-methods > div > div { .pay-methods > div > div {
padding: .5em 1.5em; padding: .5em 1.5em;
display: none; display: none;
} }
.confirm .pay-methods > div.selected > div { .pay-methods > div.selected > div {
display: block; display: block;
} }
.confirm .transfer-account { .transfer-account {
margin-top: .5em; margin-top: .5em;
} }
.confirm .transfer-account > p { .transfer-account > p {
margin: .1em 0; margin: .1em 0;
} }
.confirm .payment > div { .payment > div {
margin-bottom: 1.4em; margin-bottom: 1.4em;
}
.payment > .button-bar {
display: flex;
justify-content: space-between;
margin-bottom: 0;
margin-top: 32px;
}
.payment > .button-bar button{
font-size: 1.2rem;
border-radius: 2rem;
padding: .5rem 1rem;
margin: 0;
}
.modify-order {
border: 1px solid #1a1a1a;
}
.modify-order:hover {
color: white;
background-color: #1a1a1a;
}
.confirm-order {
border: 1px solid #8cc63f;
background-color: #8cc63f;
color: white;
}
.confirm-order:hover {
background-color: transparent;
color: #6b5;
}
} }
.confirm .payment > .button-bar {
display: flex;
justify-content: space-between;
margin-bottom: 0;
margin-top: 32px;
}
.confirm .payment > .button-bar button{
font-size: 1.2rem;
border-radius: 2rem;
padding: .5rem 1rem;
margin: 0;
}
.confirm .modify-order {
border: 1px solid #1a1a1a;
}
.confirm .modify-order:hover {
color: white;
background-color: #1a1a1a;
}
.confirm .confirm-order {
border: 1px solid #8cc63f;
background-color: #8cc63f;
color: white;
}
.confirm .confirm-order:hover {
background-color: transparent;
color: #6b5;
}

View File

@ -1,13 +1,16 @@
<vn> <vn>
<vn-lot-query id="params">
<vn-spec name="id" type="Number"/>
</vn-lot-query>
<vn-group> <vn-group>
<db-form v-model="order" on-ready="onOrderReady"> <db-form v-model="order" on-ready="onOrderReady">
<db-model property="model" result-index="1"> <db-model property="model" result-index="1" lot="params">
CALL myBasket_getTax; CALL myOrder_getTax(#id);
SELECT o.id, o.sent, o.notes, o.companyFk, SELECT o.id, o.sent, o.notes, o.companyFk,
ag.description agency, v.code method, ag.description agency, v.code method,
ad.nickname, ad.postalCode, ad.city, ad.street, ad.nickname, ad.postalCode, ad.city, ad.street,
t.*, c.credit, myClient_getDebt(NULL) debt t.*, c.credit, myClient_getDebt(NULL) debt
FROM myBasket o FROM myOrder o
JOIN vn.agencyMode ag ON ag.id = o.agencyModeFk JOIN vn.agencyMode ag ON ag.id = o.agencyModeFk
LEFT JOIN myAddress ad ON ad.id = o.addressFk LEFT JOIN myAddress ad ON ad.id = o.addressFk
JOIN vn.deliveryMethod v ON v.id = o.deliveryMethodFk JOIN vn.deliveryMethod v ON v.id = o.deliveryMethodFk
@ -17,27 +20,27 @@
IFNULL(SUM(taxableBase), 0) taxableBase, IFNULL(SUM(taxableBase), 0) taxableBase,
IFNULL(SUM(tax), 0) tax IFNULL(SUM(tax), 0) tax
FROM tmp.orderAmount FROM tmp.orderAmount
) t; ) t
WHERE o.id = #id;
DROP TEMPORARY TABLE DROP TEMPORARY TABLE
tmp.orderAmount, tmp.orderAmount,
tmp.orderTax; tmp.orderTax;
</db-model> </db-model>
</db-form> </db-form>
<db-query id="confirm-query" on-ready="onConfirm">
CALL myBasket_confirm
</db-query>
</vn-group> </vn-group>
<div id="title"> <div id="title">
<h1><t>Order summary</t></h1> <h1><t>Order summary</t></h1>
</div> </div>
<div id="form" class="confirm"> <div id="form" class="hedera-confirm">
<div class="vn-w-sm"> <div class="vn-w-sm">
<div class="box vn-pa-lg summary"> <div class="box vn-pa-lg summary">
<div> <div>
<h5>#{{order.id}}</h5>
<div class="delivery"> <div class="delivery">
<h6><t>ShippingInformation</t></h6> <h6><t>ShippingInformation</t></h6>
<p>{{order.nickname}}</p>
<p> <p>
<t>Delivery at</t> {{Vn.Value.format(order.sent, _('%D'))}} <t>Delivery at</t> {{Vn.Value.format(order.sent, _('%D'))}}
</p> </p>
<p> <p>
<span id="method"><t>Agency</t></span> {{order.agency}} <span id="method"><t>Agency</t></span> {{order.agency}}
@ -45,7 +48,6 @@
</div> </div>
<div id="address" class="address vn-mt-md"> <div id="address" class="address vn-mt-md">
<h6><t>DeliveryAddress</t></h6> <h6><t>DeliveryAddress</t></h6>
<p>{{order.nickname}}</p>
<p>{{order.street}}</p> <p>{{order.street}}</p>
<p>{{order.postalCode}}, {{order.city}}</p> <p>{{order.postalCode}}, {{order.city}}</p>
</div> </div>

View File

@ -3,30 +3,17 @@ import './style.scss';
export default new Class({ export default new Class({
Extends: Hedera.Form, Extends: Hedera.Form,
Template: require('./ui.xml'), Template: require('./ui.xml'),
donwloadRenderer(column, invoice) {
var invoiceId = invoice.$.id;
if (invoice.$.hasPdf && invoiceId) { onDownloadClick(column, value, row) {
var params = { var model = this.$.invoices;
srv: 'rest:dms/invoice', var hasPdf = model.get(row, 'hasPdf');
invoice: invoiceId, var id = model.get(row, 'id');
access_token: this.conn.token
};
Object.assign(column, { if (hasPdf && id) {
tip: _('Download PDF'), let params = Vn.Url.makeUri({ access_token: this.conn.token });
disabled: false, window.open(`/api/InvoiceOuts/${id}/download?${params}`);
icon: 'download',
href: '?'+ Vn.Url.makeUri(params)
});
} else } else
Object.assign(column, { Htk.Toast.showWarning(_('Request the invoice to your salesperson'));
tip: _('Request the invoice to your salesperson'),
disabled: true,
icon: 'warning',
href: null
});
} }
}); });

View File

@ -2,11 +2,11 @@
<div id="title"> <div id="title">
<h1><t>Invoices</t></h1> <h1><t>Invoices</t></h1>
</div> </div>
<div id="form" class="invoices"> <div id="form" class="hedera-invoices">
<htk-grid <htk-grid
class="box vn-w-sm" class="box vn-w-sm"
show-header="false"> show-header="false">
<db-model property="model" id="tickets"> <db-model property="model" id="invoices">
SELECT id, ref, issued, amount, hasPdf SELECT id, ref, issued, amount, hasPdf
FROM myInvoice FROM myInvoice
ORDER BY issued DESC ORDER BY issued DESC
@ -16,8 +16,9 @@
<htk-column-date title="_Date" column="issued" format="_%e %b %Y"/> <htk-column-date title="_Date" column="issued" format="_%e %b %Y"/>
<htk-column-spin title="_Import" column="amount" unit="€" digits="2"/> <htk-column-spin title="_Import" column="amount" unit="€" digits="2"/>
<htk-column-button <htk-column-button
renderer="donwloadRenderer" icon="download"
target="_blank"/> tip="_Download PDF"
on-clicked="onDownloadClick"/>
</htk-grid> </htk-grid>
</div> </div>
</vn> </vn>

View File

@ -5,7 +5,7 @@ OrderNumber: N encàrrec
DateMake: Data de creació DateMake: Data de creació
DateExit: Data d'eixida DateExit: Data d'eixida
SendMethod: Forma d'enviament SendMethod: Forma d'enviament
LastOrders: Últimes comandes LastOrders: Comandes confirmades
'Balance:': 'Saldo:' 'Balance:': 'Saldo:'
PaymentInfo: >- PaymentInfo: >-
La quantitat mostrada és el teu saldo pendent (negatiu) o favorable a dia La quantitat mostrada és el teu saldo pendent (negatiu) o favorable a dia

View File

@ -5,7 +5,7 @@ OrderNumber: Order number
DateMake: Creation date DateMake: Creation date
DateExit: Shipping date DateExit: Shipping date
SendMethod: Delivery method SendMethod: Delivery method
LastOrders: Last orders LastOrders: Confirmed orders
'Balance:': 'Balance:' 'Balance:': 'Balance:'
PaymentInfo: >- PaymentInfo: >-
The amount shown is your slope (negative) or favorable balance today, it The amount shown is your slope (negative) or favorable balance today, it

View File

@ -5,7 +5,7 @@ OrderNumber: Nº pedido
DateMake: Fecha de creación DateMake: Fecha de creación
DateExit: Fecha de salida DateExit: Fecha de salida
SendMethod: Forma de envío SendMethod: Forma de envío
LastOrders: Últimos pedidos LastOrders: Pedidos confirmados
'Balance:': 'Saldo:' 'Balance:': 'Saldo:'
PaymentInfo: >- PaymentInfo: >-
La cantidad mostrada es tu saldo pendiente (negativa) o favorable a día de La cantidad mostrada es tu saldo pendiente (negativa) o favorable a día de

View File

@ -5,7 +5,7 @@ OrderNumber: Numéro de commande
DateMake: Date de creation DateMake: Date de creation
DateExit: Date de sortie DateExit: Date de sortie
SendMethod: Typo SendMethod: Typo
LastOrders: Les dernières commandes LastOrders: Commandes confirmées
'Balance:': 'Balance:' 'Balance:': 'Balance:'
PaymentInfo: >- PaymentInfo: >-
Le montant indiqué est votre pente (négative) ou balance favorable Le montant indiqué est votre pente (négative) ou balance favorable

View File

@ -1,37 +0,0 @@
OpenOrders: Open orders
StartOrder: Start order
ContinueOrder: Continue order
OrderNumber: Order number
DateMake: Creation date
DateExit: Shipping date
SendMethod: Delivery method
LastOrders: Last orders
'Balance:': 'Balance:'
PaymentInfo: >-
Үзүүлсэн хэмжээ цаашид захиалга эзэлж биш, таны налуу (сөрөг), эсвэл
тааламжтай тэнцвэр нь өнөөдөр юм. Хэрэв та дүн арилгаж гэж хэлж байсан нь доош
нь төлбөр хийж, өөрийн хүссэн хэмжээгээр орж хүсэж байгаа бол таны захиалга
ирдэг бол авах, энэ хэмжээ тэнцүү буюу 0-ээс их байх ёстой.
MakePayment: Make payment
Company: Company
Pending: Pending
Pay: Pay
Basket: Basket
ShoppingBasket: Shopping basket
SeeOrder: Show details of the order
Delivery: Delivery
TicketNumber: Ticket number
SentAddress: Delivery address
Consignee: Consignee
Boxes: Bundles
TotalWithVAT: Total with VAT
PayOrder: Pay order
'AmountToPay:': 'Amount to pay (€):'
AmountError: >-
The amount must be a positive number less than or equal to the outstanding
amount
PayError: Failed to make the payment
An error has been in the payment: >-
It seems that there has been an error in the payment
Retry: Retry
Accept: Accept

View File

@ -5,7 +5,7 @@ OrderNumber: Nº pedido
DateMake: Data de criação DateMake: Data de criação
DateExit: Data de saída DateExit: Data de saída
SendMethod: Forma de envío SendMethod: Forma de envío
LastOrders: Últimas encomendas LastOrders: Encomendas confirmadas
'Balance:': 'Saldo:' 'Balance:': 'Saldo:'
PaymentInfo: >- PaymentInfo: >-
A quantidade mostrada é seu saldo pendente (negativo) ou favorável a dia de A quantidade mostrada é seu saldo pendente (negativo) ou favorável a dia de

View File

@ -33,7 +33,6 @@
/* List */ /* List */
.orders .htk-list .total { .hedera-orders .htk-list .total {
float: right; float: right;
} }

View File

@ -34,7 +34,7 @@
tip="_ShoppingBasket" tip="_ShoppingBasket"
on-click="onBasketClick"/> on-click="onBasketClick"/>
</div> </div>
<div id="form" class="orders"> <div id="form" class="hedera-orders">
<htk-repeater <htk-repeater
class="htk-list box confirmed vn-w-sm" class="htk-list box confirmed vn-w-sm"
form-id="iter" form-id="iter"

View File

@ -0,0 +1,21 @@
import './style.scss';
export default new Class({
Extends: Hedera.Form,
Template: require('./ui.xml'),
activate() {
this.basket = new Hedera.Basket(this.app);
this.$.orders.setInfo('o', 'myOrder', 'hedera', ['id'], 'id');
},
async onRemoveOrderClick(form) {
if (confirm(_('AreYouSureDeleteOrder')))
await form.deleteRow();
},
async loadOrder(id) {
const basket = new Hedera.Basket(this.app);
await basket.load(id);
}
});

View File

@ -0,0 +1,8 @@
Pending: Pendents
PendingOrders: Comandes pendents
NewOrder: Nova comanda
ViewOrder: Veure comanda
RemoveOrder: Eliminar comanda
LoadOrderIntoCart: Carregar comanda a la cistella
AreYouSureDeleteOrder: Segur que vols esborrar la comanda?
OrderLoadedIntoBasket: Comanda carregada a la cistella!

View File

@ -0,0 +1,8 @@
Pending: Pending
PendingOrders: Pending orders
NewOrder: New order
ViewOrder: View order
RemoveOrder: Delete order
LoadOrderIntoCart: Load order into cart
AreYouSureDeleteOrder: Are you sure you want to delete the order?
OrderLoadedIntoBasket: Order loaded into basket!

View File

@ -0,0 +1,8 @@
Pending: Pendientes
PendingOrders: Pedidos pendientes
NewOrder: Nuevo pedido
ViewOrder: Ver pedido
RemoveOrder: Eliminar pedido
LoadOrderIntoCart: Cargar pedido en la cesta
AreYouSureDeleteOrder: ¿Seguro que quieres borrar el pedido?
OrderLoadedIntoBasket: ¡Pedido cargado en la cesta!

View File

@ -0,0 +1,8 @@
Pending: En attente
PendingOrders: Commandes en attente
NewOrder: Nouvelle commande
ViewOrder: Afficher la commande
RemoveOrder: Supprimer la commande
LoadOrderIntoCart: Charger la commande dans le panier
AreYouSureDeleteOrder: Êtes-vous sûr de vouloir supprimer la commande?
OrderLoadedIntoBasket: Commande chargée dans le panier!

View File

@ -0,0 +1,8 @@
Pending: Pendentes
PendingOrders: Pedidos pendentes
NewOrder: Novo pedido
ViewOrder: Ver pedido
RemoveOrder: Excluir pedido
LoadOrderIntoCart: Carrega o pedido no carrinho
AreYouSureDeleteOrder: Tem certeza de que deseja excluir o pedido?
OrderLoadedIntoBasket: Pedido carregado na cesta!

View File

@ -0,0 +1,54 @@
<vn>
<div id="title">
<h1><t>PendingOrders</t></h1>
</div>
<div id="actions">
<htk-bar-button
class="start-order"
icon="add_shopping_cart"
tip="_NewOrder"
on-click="hash.setAll({form: 'ecomerce/checkout'})"/>
</div>
<div id="form" class="hedera-pending">
<htk-repeater
class="htk-list box confirmed vn-w-sm"
form-id="iter">
<db-model property="model" id="orders">
SELECT o.id, o.sent, o.deliveryMethodFk, o.taxableBase,
a.nickname, am.description agency
FROM myOrder o
JOIN myAddress a ON a.id = o.addressFk
JOIN vn.agencyMode am ON am.id = o.agencyModeFk
WHERE NOT o.isConfirmed
ORDER BY o.sent DESC
</db-model>
<custom>
<a class="item"
title="{{_('ViewOrder')}}"
href="{{'#!form=ecomerce/basket&amp;id='+iter.id}}">
<div class="content">
<p class="important">
{{Vn.Value.format(iter.sent, '%D')}}
</p>
<p>#{{iter.id}}</p>
<p>{{iter.nickname}}</p>
<p>{{iter.agency}}</p>
<p>{{Vn.Value.format(iter.taxableBase, '%.2d€')}}</p>
</div>
<div
class="actions"
on-click="$event.preventDefault()">
<htk-button
icon="delete"
tip="_RemoveOrder"
on-click="this.onRemoveOrderClick($iter)"/>
<htk-button
icon="shopping_bag"
tip="_LoadOrderIntoCart"
on-click="this.loadOrder(iter.id)"/>
</div>
</a>
</custom>
</htk-repeater>
</div>
</vn>

View File

@ -1,78 +1,79 @@
/* Header */ .hedera-ticket {
/* Header */
.ticket .head { .head {
padding: 0; padding: 0;
padding-bottom: 3px; padding-bottom: 3px;
border-bottom: 1px solid #DDD; border-bottom: 1px solid #DDD;
margin-bottom: 1px; margin-bottom: 1px;
} }
.ticket .head > div > div { .head > div > div {
margin: 15px 0; margin: 15px 0;
} }
.ticket .head > div > div:first-child { .head > div > div:first-child {
margin: 0; margin: 0;
} }
.ticket .head p { .head p {
margin: 3px 0; margin: 3px 0;
} }
.ticket .head p.important { .head p.important {
font-size: 1.2rem; font-size: 1.2rem;
font-weight: bold; font-weight: bold;
} }
.ticket .total { .total {
text-align: right; text-align: right;
} }
.ticket .packages { .packages {
margin-top: 14px; margin-top: 14px;
padding-top: 14px; padding-top: 14px;
border-top: 1px solid #DDD; border-top: 1px solid #DDD;
display: block; display: block;
} }
/* Lines */ /* Lines */
.ticket .line { .line {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 12px; gap: 12px;
margin: 10px 0; margin: 10px 0;
height: 80px; height: 80px;
}
.line:last-child {
margin-bottom: 0;
}
.line > .photo {
flex: none;
border-radius: 50%;
width: 68px;
height: 68px;
gap: 0;
}
.line > .info {
flex: 1;
overflow: hidden;
}
.line > .info > * {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.line > .info > h2 {
font-size: 1rem;
font-weight: normal;
margin-bottom: 2px;
}
.line > .info > p {
margin: 0;
}
.line > .info > .tags {
color: #777;
}
.line > .info .discount {
color: green;
}
.line > .info > .subtotal {
float: right;
}
} }
.ticket .line:last-child {
margin-bottom: 0;
}
.ticket .line > .photo {
flex: none;
border-radius: 50%;
width: 68px;
height: 68px;
gap: 0;
}
.ticket .line > .info {
flex: 1;
overflow: hidden;
}
.ticket .line > .info > * {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.ticket .line > .info > h2 {
font-size: 1rem;
font-weight: normal;
margin-bottom: 2px;
}
.ticket .line > .info > p {
margin: 0;
}
.ticket .line > .info > .tags {
color: #777;
}
.ticket .line > .info .discount {
color: green;
}
.ticket .line > .info > .subtotal {
float: right;
}

View File

@ -14,7 +14,7 @@
tip="_Print delivery note" tip="_Print delivery note"
on-click="this.onPrintClick()"/> on-click="this.onPrintClick()"/>
</div> </div>
<div id="form" class="ticket"> <div id="form" class="hedera-ticket">
<div class="box vn-w-sm vn-pa-lg"> <div class="box vn-w-sm vn-pa-lg">
<htk-loader class="head" form="ticket-form"> <htk-loader class="head" form="ticket-form">
<h5>#{{ticket.id}}</h5> <h5>#{{ticket.id}}</h5>

View File

@ -1,42 +1,44 @@
<vn> <vn>
<vn-lot id="lot"/> <vn-lot id="lot"/>
<div id="title"> <div id="title">
<h1><t>Item list</t></h1> <h1><t>Item list</t></h1>
</div> </div>
<div id="actions" class="action-bar"> <div id="actions" class="action-bar">
<htk-bar-button <htk-bar-button
icon="print" icon="print"
tip="_Preview" tip="_Preview"
on-click="this.onPreviewClick()"/> on-click="this.onPreviewClick()"/>
</div> </div>
<div id="form" class="items"> <div id="form" class="items">
<div class="form box vn-w-sm vn-pa-lg"> <div class="form box vn-w-sm vn-pa-lg">
<div class="form-group"> <div class="form-group">
<label><t>Store</t></label> <label><t>Store</t></label>
<htk-combo form="lot" column="warehouse"> <htk-combo form="lot" column="warehouse">
<db-model property="model"> <db-model property="model">
SELECT id, name FROM vn2008.warehouse SELECT id, name
WHERE reserve ORDER BY name FROM vn.warehouse
</db-model> WHERE hasAvailable
</htk-combo> ORDER BY name
</div> </db-model>
<div class="form-group"> </htk-combo>
<label><t>Realm</t></label> </div>
<htk-combo form="lot" column="realm" not-null="false"> <div class="form-group">
<db-model property="model"> <label><t>Realm</t></label>
SELECT id, reino FROM vn2008.reinos <htk-combo form="lot" column="realm" not-null="false">
WHERE display != FALSE ORDER BY reino <db-model property="model">
</db-model> SELECT id, name FROM vn.itemCategory
</htk-combo> WHERE display ORDER BY name
</div> </db-model>
<div class="form-group"> </htk-combo>
<label><t>Rate</t></label> </div>
<select id="rate"> <div class="form-group">
<option>3</option> <label><t>Rate</t></label>
<option>2</option> <select id="rate">
<option>1</option> <option>3</option>
</select> <option>2</option>
</div> <option>1</option>
</div> </select>
</div> </div>
</vn> </div>
</div>
</vn>

View File

@ -6,7 +6,7 @@ export default new Class({
activate() { activate() {
this.$.lot.assign({ this.$.lot.assign({
date: new Date(), date: Date.vnNew(),
useIds: false useIds: false
}); });
}, },

View File

@ -1,105 +1,107 @@
<vn> <vn>
<vn-lot-query id="params"> <vn-lot-query id="params">
<vn-spec name="config" type="Number"/> <vn-spec name="config" type="Number"/>
</vn-lot-query> </vn-lot-query>
<vn-lot id="lot"/> <vn-lot id="lot"/>
<div id="title"> <div id="title">
<h1><t>Shelves</t></h1> <h1><t>Shelves</t></h1>
</div> </div>
<div id="actions" class="action-bar"> <div id="actions" class="action-bar">
<htk-bar-button <htk-bar-button
icon="print" icon="print"
tip="_Preview" tip="_Preview"
on-click="this.onPreviewClick()"/> on-click="this.onPreviewClick()"/>
</div> </div>
<div id="form" class="shelves"> <div id="form" class="shelves">
<div class="form box vn-w-sm vn-pa-lg"> <div class="form box vn-w-sm vn-pa-lg">
<div class="form-group"> <div class="form-group">
<label><t>Configuration</t></label> <label><t>Configuration</t></label>
<htk-combo <htk-combo
id="config" id="config"
placeholder="_Select config" placeholder="_Select config"
form="params" form="params"
column="config" column="config"
on-changed="this.onConfigChange()" on-changed="this.onConfigChange()"
on-ready="this.onConfigChange()"> on-ready="this.onConfigChange()">
<db-model property="model"> <db-model property="model">
SELECT c.id, c.name reportTitle, c.namePrefix, c.warehouse, c.family, SELECT c.id, c.name reportTitle, c.namePrefix, c.warehouse, c.family,
c.shelf, c.maxAmount, c.showPacking, c.stack, t.reino_id realm c.shelf, c.maxAmount, c.showPacking, c.stack, it.categoryFk realm
FROM shelfConfig c FROM shelfConfig c
JOIN vn2008.Tipos t ON t.tipo_id = c.family JOIN vn.itemType it ON it.id = c.family
</db-model> </db-model>
</htk-combo> </htk-combo>
</div> </div>
<div class="form-group"> <div class="form-group">
<label><t>Date</t></label> <label><t>Date</t></label>
<htk-date-chooser form="lot" name="date"/> <htk-date-chooser form="lot" name="date"/>
</div> </div>
<div class="form-group"> <div class="form-group">
<label><t>Reign</t></label> <label><t>Reign</t></label>
<htk-combo form="lot" name="realm"> <htk-combo form="lot" name="realm">
<db-model property="model"> <db-model property="model">
SELECT id, reino FROM vn2008.reinos SELECT id, name FROM vn.itemCategory
WHERE display != FALSE ORDER BY reino WHERE display ORDER BY name
</db-model> </db-model>
</htk-combo> </htk-combo>
</div> </div>
<div class="form-group"> <div class="form-group">
<label><t>Family</t></label> <label><t>Family</t></label>
<htk-combo form="lot" name="family"> <htk-combo form="lot" name="family">
<db-model property="model" lot="lot"> <db-model property="model" lot="lot">
SELECT tipo_id, Tipo FROM vn2008.Tipos SELECT id, name FROM vn.itemType
WHERE reino_id = #realm ORDER BY Tipo WHERE categoryFk = #realm ORDER BY name
</db-model> </db-model>
</htk-combo> </htk-combo>
</div> </div>
<div class="form-group"> <div class="form-group">
<label><t>Store</t></label> <label><t>Store</t></label>
<htk-combo form="lot"> <htk-combo form="lot">
<db-model property="model"> <db-model property="model">
SELECT id, name FROM vn2008.warehouse SELECT id, name
WHERE reserve ORDER BY name FROM vn.warehouse
</db-model> WHERE hasAvailable
</htk-combo> ORDER BY name
</div> </db-model>
<div class="form-group"> </htk-combo>
<label><t>Shelf</t></label> </div>
<htk-combo form="lot" name="shelf"> <div class="form-group">
<db-model property="model"> <label><t>Shelf</t></label>
SELECT id, name FROM shelf <htk-combo form="lot" name="shelf">
</db-model> <db-model property="model">
</htk-combo> SELECT id, name FROM shelf
</div> </db-model>
<div class="form-group"> </htk-combo>
<label><t>Name prefix</t></label> </div>
<htk-entry form="lot" name="namePrefix"/> <div class="form-group">
</div> <label><t>Name prefix</t></label>
<div class="form-group"> <htk-entry form="lot" name="namePrefix"/>
<label><t>Limit amount per item</t></label> </div>
<htk-entry form="lot" name="maxAmount"/> <div class="form-group">
</div> <label><t>Limit amount per item</t></label>
<div class="form-group"> <htk-entry form="lot" name="maxAmount"/>
<label><t>Title</t></label> </div>
<htk-entry form="lot" name="reportTitle"/> <div class="form-group">
</div> <label><t>Title</t></label>
<div class="form-group"> <htk-entry form="lot" name="reportTitle"/>
<label> </div>
<htk-check form="lot" name="showPacking"/> <div class="form-group">
<t>Show packing</t> <label>
</label> <htk-check form="lot" name="showPacking"/>
</div> <t>Show packing</t>
<div class="form-group"> </label>
<label> </div>
<htk-check form="lot" name="stack"/> <div class="form-group">
<t>Stack different items</t> <label>
</label> <htk-check form="lot" name="stack"/>
</div> <t>Stack different items</t>
<div class="form-group"> </label>
<label> </div>
<htk-check form="lot" name="useIds"/> <div class="form-group">
<t>Use ids instead of names</t> <label>
</label> <htk-check form="lot" name="useIds"/>
</div> <t>Use ids instead of names</t>
</div> </label>
</div> </div>
</vn> </div>
</div>
</vn>

View File

@ -40,9 +40,7 @@ export const routes = {
}, },
agencies: { agencies: {
packages: packages:
() => import('agencies/packages'), () => import('agencies/packages')
provinces:
() => import('agencies/provinces')
}, },
cms: { cms: {
about: about:
@ -70,7 +68,9 @@ export const routes = {
orders: orders:
() => import('ecomerce/orders'), () => import('ecomerce/orders'),
ticket: ticket:
() => import('ecomerce/ticket') () => import('ecomerce/ticket'),
pending:
() => import('ecomerce/pending')
}, },
news: { news: {
new: new:

View File

@ -9,6 +9,24 @@ module.exports = new Class({
,get() { ,get() {
return this._conn; return this._conn;
} }
},
hash: {
type: Vn.Hash
,get() {
return this._hash;
}
},
gui: {
type: Gui
,get() {
return this._gui;
}
},
login: {
type: Login
,get() {
return this._login;
}
} }
} }
@ -35,6 +53,7 @@ module.exports = new Class({
,showLogin() { ,showLogin() {
const login = this._login = new Login({ const login = this._login = new Login({
app: this,
conn: this._conn, conn: this._conn,
hash: this._hash hash: this._hash
}); });
@ -47,6 +66,7 @@ module.exports = new Class({
if (this._gui) return; if (this._gui) return;
const gui = this._gui = new Gui({ const gui = this._gui = new Gui({
app: this,
conn: this._conn, conn: this._conn,
hash: this._hash hash: this._hash
}); });
@ -198,11 +218,11 @@ module.exports = new Class({
,async _onConnError(conn, err) { ,async _onConnError(conn, err) {
if (!(err instanceof Vn.JsonException)) return; if (!(err instanceof Vn.JsonException)) return;
switch (err.exception) { switch (err.exception) {
case 'UserDisabled': case 'UserDisabledError':
Htk.Toast.showError(_('User disabled')); Htk.Toast.showError(_('User disabled'));
await this._logout(); await this._logout();
return; return;
case 'OutdatedVersion': case 'OutdatedVersionError':
this._newVersion(); this._newVersion();
return; return;
} }
@ -218,12 +238,13 @@ module.exports = new Class({
if (err instanceof Vn.JsonException) { if (err instanceof Vn.JsonException) {
const statusCode = err.statusCode; const statusCode = err.statusCode;
if (statusCode >= 400 && statusCode < 500) { if (statusCode >= 400 && statusCode < 500) {
if (err.statusCode == 403) if (err.statusCode == 403) {
Htk.Toast.showError(_('You don\'t have enough privileges')); Htk.Toast.showError(err.message ||
else { _('You don\'t have enough privileges'));
} else {
switch (err.exception) { switch (err.exception) {
case 'UserDisabled': case 'UserDisabledError':
case 'OutdatedVersion': case 'OutdatedVersionError':
return; return;
} }
if (err.statusCode == 401) if (err.statusCode == 401)

View File

@ -1,21 +0,0 @@
module.exports = {
async check(conn, hash) {
this.hash = hash;
const resultSet = await conn.execQuery('CALL myBasket_check');
const status = resultSet.fetchValue();
if (!status) return;
const isOk = status == 'UPDATED' || status == 'OK';
if (status == 'UPDATED')
Htk.Toast.showWarning(_('Order items updated'));
if (!isOk)
this.hash.setAll({form: 'ecomerce/checkout'});
return isOk;
}
};

77
js/hedera/basket.js Normal file
View File

@ -0,0 +1,77 @@
module.exports = class {
constructor(app) {
this.app = app;
let orderId = localStorage.getItem('hederaBasket');
if (orderId) orderId = parseInt(orderId);
this.orderId = orderId;
}
async checkOrder(orderId) {
const resultSet = await this.app.conn.execQuery(
'CALL myOrder_checkConfig(#id)',
{id: orderId}
);
resultSet.fetchValue();
}
async check(checkoutContinue) {
if (this.orderId) {
return await this.checkRedirect(checkoutContinue);
} else {
this.redirect();
return false;
}
}
async checkRedirect(checkoutContinue) {
try {
await this.checkOrder(this.orderId);
return true;
} catch(err) {
if (err.exception == 'Vn.Lib.UserError') {
switch(err.code) {
case 'orderConfirmed':
case 'orderNotOwnedByUser':
this.constructor.unload();
await this.redirect();
break;
default:
this.app.hash.setAll({
form: 'ecomerce/checkout',
id: this.orderId,
continue: checkoutContinue
});
Htk.Toast.showError(err.message);
}
return false;
} else
throw err;
}
}
async redirect() {
const resultSet = await this.app.conn.execQuery(
'SELECT COUNT(*) > 0 FROM myOrder');
if (resultSet.fetchValue()) {
this.app.hash.setAll({form: 'ecomerce/pending'});
Htk.Toast.showMessage(_('Load an order'));
} else {
this.app.hash.setAll({form: 'ecomerce/checkout'});
}
}
async load(orderId) {
this.loadIntoBasket(orderId);
if (await this.checkRedirect('catalog'))
this.app.hash.setAll({
form: 'ecomerce/catalog'
});
}
loadIntoBasket(orderId) {
if (this.orderId != orderId) {
localStorage.setItem('hederaBasket', orderId);
this.orderId = orderId;
Htk.Toast.showMessage(_('OrderLoadedIntoBasket'));
}
}
static unload() {
localStorage.removeItem('hederaBasket');
}
};

View File

@ -7,6 +7,7 @@ module.exports = new Class({
,initialize(gui) { ,initialize(gui) {
this.gui = gui; this.gui = gui;
this.app = gui.app;
this.conn = gui.conn; this.conn = gui.conn;
this.hash = gui.hash; this.hash = gui.hash;
} }

View File

@ -50,19 +50,16 @@ module.exports = new Class({
this.doc.body.appendChild(this.node); this.doc.body.appendChild(this.node);
Htk.Toast.pushTop(this.$.formHolder); Htk.Toast.pushTop(this.$.formHolder);
await this.refreshUserData();
Vn.Node.setText(this.$.userName, this.user.nickname);
const resultSet = await this._conn.execQuery( const resultSet = await this._conn.execQuery(
'SELECT id, name, nickname FROM account.myUser;' 'SELECT defaultForm FROM config;'
+'SELECT defaultForm FROM config;'
+'SELECT url FROM imageConfig;' +'SELECT url FROM imageConfig;'
+'SELECT dbproduccion FROM vn.config;' +'SELECT dbproduccion FROM vn.config;'
+'SELECT productionDomain, testDomain FROM config;' +'SELECT productionDomain, testDomain FROM config;'
); );
// Retrieving the user name
this.user = resultSet.fetchObject();
Vn.Node.setText(this.$.userName, this.user.nickname);
// Retrieving configuration parameters // Retrieving configuration parameters
Vn.Config.defaultForm = resultSet.fetchValue(); Vn.Config.defaultForm = resultSet.fetchValue();
@ -119,6 +116,12 @@ module.exports = new Class({
Htk.Toast.showWarning(_('By using this site you accept cookies')); Htk.Toast.showWarning(_('By using this site you accept cookies'));
} }
} }
,async refreshUserData() {
const resultSet = await this._conn.execQuery(
'SELECT id, name, nickname FROM account.myUser');
this.user = resultSet.fetchObject();
}
,async hide() { ,async hide() {
if (!this._shown) if (!this._shown)
@ -463,29 +466,41 @@ module.exports = new Class({
} }
//++++++++++++++++++++++++++++++++++++++++++++++++++++++ Supplant //++++++++++++++++++++++++++++++++++++++++++++++++++++++ Supplant
/**
* Supplants another user.
*
* @param {String} supplantUser The user name
*/
,async supplantUser(supplantUser) {
const json = await this._conn.send('client/supplant', {supplantUser});
this._conn.token = json;
sessionStorage.setItem('supplantUser', supplantUser);
await this.refreshUserData();
Vn.Node.setText(this.$.supplanted, this.user.nickname);
this.$.supplant.classList.toggle('show', true);
await this.loadMenu();
}
/*
* Ends the user supplanting and restores the original login.
*/
,async onSupplantExitClick() {
this._conn.post('Accounts/logout');
this._conn.fetchToken();
sessionStorage.removeItem('supplantUser');
this.$.supplant.classList.toggle('show', false);
await this.refreshUserData();
await this.loadMenu();
this._onFormChange();
}
,async supplantInit() { ,async supplantInit() {
var user = sessionStorage.getItem('supplantUser'); var user = sessionStorage.getItem('supplantUser');
if (user == null) return; if (user == null) return;
await this.supplantUser(user);
await this._conn.supplantUser(user);
sessionStorage.setItem('supplantUser', user);
await this.loadMenu();
const res = await this._conn.execQuery(
'SELECT nickname FROM account.myUser');
const userName = res.fetchValue();
Vn.Node.setText(this.$.supplanted, userName);
this.$.supplant.classList.toggle('show', true);
}
,async onSupplantExitClick() {
this.$.supplant.classList.toggle('show', false);
await this._conn.supplantEnd();
sessionStorage.removeItem('supplantUser');
await this.loadMenu();
this._onFormChange();
} }
//++++++++++++++++++++++++++++++++++++++++++++++++++++++ Destroy //++++++++++++++++++++++++++++++++++++++++++++++++++++++ Destroy

View File

@ -10,6 +10,6 @@ Hedera = module.exports = {
,Report : require('./report') ,Report : require('./report')
,App : require('./app') ,App : require('./app')
,Tpv : require('./tpv') ,Tpv : require('./tpv')
,BasketChecker : require('./basket-checker') ,Basket : require('./basket')
}; };

View File

@ -38,7 +38,8 @@ AppName: Verdnatura
Home: Inici Home: Inici
Orders: Encàrrecs Orders: Encàrrecs
Basket: Cistella Basket: Cistella
Last orders: Últims comandes Pending orders: Pendents
Last orders: Confirmades
Invoices: Factures Invoices: Factures
Catalog: Catàleg Catalog: Catàleg
About: Coneix-nos About: Coneix-nos
@ -62,3 +63,22 @@ Agencies: Agències
Configuration: Configuració Configuration: Configuració
Account: Compte Account: Compte
Addresses: Adreces Addresses: Adreces
Load an order: Si us plau carrega una comanda pendent a la cistella o en comença una de nova
Old password: Contrasenya antiga
New password: Nova contrasenya
Repeat password: Repetir contrasenya
Requirements: Requisits
Modify: Modificar
Password requirements: Requisits de contrasenya
characters long: caràcters de longitud
alphabetic characters: caràcters alfabètics
capital letters: majúscules
digits: dígits
symbols: símbols
Password changed!: Contrasenya modificada!
Password doesn't meet the requirements: ''
Passwords doesn't match: Les contrasenyes no coincideixen!
Passwords empty: Les contrasenyes en blanc
Change password: Canvia la contrasenya

View File

@ -34,7 +34,8 @@ AppName: Verdnatura
Home: Home Home: Home
Orders: Orders Orders: Orders
Basket: Basket Basket: Basket
Last orders: Last orders Pending orders: Pending
Last orders: Confirmed
Invoices: Invoices Invoices: Invoices
Catalog: Catalog Catalog: Catalog
About: About About: About
@ -58,3 +59,5 @@ Agencies: Agencies
Configuration: Configuration Configuration: Configuration
Account: Account Account: Account
Addresses: Addresses Addresses: Addresses
Load an order: Please load a pending order to the cart or start a new one

View File

@ -38,7 +38,8 @@ AppName: Verdnatura
Home: Inicio Home: Inicio
Orders: Pedidos Orders: Pedidos
Basket: Cesta Basket: Cesta
Last orders: Últimos pedidos Pending orders: Pendientes
Last orders: Confirmados
Invoices: Facturas Invoices: Facturas
Catalog: Catálogo Catalog: Catálogo
About: Conócenos About: Conócenos
@ -62,3 +63,24 @@ Agencies: Agencias
Configuration: Configuración Configuration: Configuración
Account: Cuenta Account: Cuenta
Addresses: Direcciones Addresses: Direcciones
Load an order: Por favor carga un pedido pendiente en la cesta o empieza uno nuevo
Old password: Contaseña antigua
New password: Nueva contraseña
Repeat password: Repetir contraseña
Requirements: Requisitos
Modify: Modificar
Password requirements: Requisitos de constraseña
characters long: carácteres de longitud
alphabetic characters: carácteres alfabéticos
capital letters: letras mayúsculas
digits: dígitos
symbols: 'símbolos. Ej: $%&.'
Password changed!: ¡Contraseña modificada!
Password doesn't meet the requirements: >-
La nueva contraseña no reune los requisitos de seguridad necesarios, pulsa en
info para más detalle
Passwords doesn't match: ¡Las contraseñas no coinciden!
Passwords empty: Contraseña vacía
Change password: Cambiar contraseña

View File

@ -5,7 +5,7 @@ Remind me: Retenir mon mot de passe
Log in as guest: Entrez en tant qu'invité Log in as guest: Entrez en tant qu'invité
Login: Se connecter Login: Se connecter
Login mail: info@verdnatura.es Login mail: info@verdnatura.es
Login phone: +33 781 533 900 Login phone: +33 783 285 437
Password forgotten? Push here: Vous avez oublié votre mot de passe? Password forgotten? Push here: Vous avez oublié votre mot de passe?
Yet you are not a customer?: Vous n'êtes pas encore client? Yet you are not a customer?: Vous n'êtes pas encore client?
Sign up: S'inscrire Sign up: S'inscrire
@ -38,7 +38,8 @@ AppName: Verdnatura
Home: Accueil Home: Accueil
Orders: Commandes Orders: Commandes
Basket: Panier Basket: Panier
Last orders: Dernières commandes Pending orders: En attente
Last orders: Confirmées
Invoices: Facturas Invoices: Facturas
Catalog: Catalogue Catalog: Catalogue
About: Nous About: Nous
@ -62,3 +63,22 @@ Agencies: Agences
Configuration: Configuration Configuration: Configuration
Account: Compte Account: Compte
Addresses: Adresses Addresses: Adresses
Load an order: Veuillez télécharger une commande en attente dans le panier ou en démarrer une nouvelle
Old password: Ancien mot de passe
New password: Nouveau mot de passe
Repeat password: Répéter le mot de passe
Requirements: Exigences
Modify: Modifier
Password requirements: Mot de passe exigences
characters long: Longs caractères
alphabetic characters: les caractères alphabétiques
capital letters: lettres majuscules
digits: chiffres
symbols: 'symboles. Ej: $%&.'
Password changed!: Mot de passe modifié!
Password doesn't meet the requirements: ''
Passwords doesn't match: Les mots de passe ne correspondent pas!
Passwords empty: ''
Change password: Changer le mot de passe

View File

@ -36,7 +36,8 @@ AppName: VerdNatura
Home: Principio Home: Principio
Orders: Encomendas Orders: Encomendas
Basket: Cesta Basket: Cesta
Last orders: Últimas encomendas Pending orders: Pendentes
Last orders: Confirmados
Invoices: Facturas Invoices: Facturas
Catalog: Catálogo Catalog: Catálogo
About: Conheça-nos About: Conheça-nos
@ -60,3 +61,22 @@ Agencies: Agências
Configuration: Configuração Configuration: Configuração
Account: Conta Account: Conta
Addresses: Moradas Addresses: Moradas
Load an order: Carregue um pedido pendente no carrinho ou inicie um novo
Old password: Palavra-passe antiga
New password: Nova Palavra-passe
Repeat password: Repetir Palavra-passe
Requirements: Requisitos
Modify: Modificar
Password requirements: Requisitos de Palavra-passe
characters long: caracteres
alphabetic characters: caracteres alfabéticos
capital letters: letras maiúsculas
digits: dígitos
symbols: 'símbolos. Ej: $%&.'
Password changed!: Palavra-passe Modificada!
Password doesn't meet the requirements: Palavra-passe não atende aos requisitos
Passwords doesn't match: As Palavras-Passe não coincidem!
Passwords empty: Palavra-passe vazia
Change password: Mudar Palavra-passe

View File

@ -26,6 +26,12 @@ module.exports = new Class({
self._onSubmit(); self._onSubmit();
return false; return false;
}; };
if(this.hash.$.verificationToken){
this.$.changePassword.conn = this.conn;
this.$.changePassword.token = this.hash.$.verificationToken;
this.$.changePassword.open();
}
} }
,_onConnLoadChange(conn, isLoading) { ,_onConnLoadChange(conn, isLoading) {
@ -94,7 +100,11 @@ module.exports = new Class({
return; return;
} }
await this._conn.send('user/recover-password', {recoverUser}); await this.conn.post('VnUsers/recoverPassword', {
user: recoverUser,
app: 'hedera'
});
Htk.Toast.showMessage(_('A mail has been sent wich you can recover your password')); Htk.Toast.showMessage(_('A mail has been sent wich you can recover your password'));
} }
}); });

View File

@ -54,4 +54,5 @@
</div> </div>
</div> </div>
</div> </div>
<htk-change-password id="change-password"/>
</vn> </vn>

View File

@ -9,11 +9,10 @@ module.exports = new Class({
this.tpvStatus = this.hash.$.tpvStatus; this.tpvStatus = this.hash.$.tpvStatus;
if (this.tpvStatus) { if (this.tpvStatus) {
const query = 'CALL myTpvTransaction_end(#transaction, #status)'; this.conn.post('TpvTransactions/end', {
this.conn.execQuery(query, { orderId: this.tpvOrder,
transaction: this.tpvOrder,
status: this.tpvStatus status: this.tpvStatus
}); })
} }
return this.tpvStatus; return this.tpvStatus;
@ -24,22 +23,18 @@ module.exports = new Class({
} }
,async _realPay(amount, company) { ,async _realPay(amount, company) {
if (!isNumeric(amount) || amount <= 0) if (!isNumeric(amount) || amount <= 0) {
throw new UserError(_('AmountError')); Htk.Toast.showError(_('AmountError'));
return;
let json;
try {
json = await this.conn.send('tpv/transaction', {
amount: parseInt(amount)
,urlOk: this._makeUrl('ok')
,urlKo: this._makeUrl('ko')
,company: company
});
} catch(err) {
throw new UserError(_('PayError'));
} }
const json = await this.conn.post('TpvTransactions/start', {
amount: parseInt(amount),
urlOk: this._makeUrl('ok'),
urlKo: this._makeUrl('ko'),
company
});
const postValues = json.postValues; const postValues = json.postValues;
const form = document.createElement('form'); const form = document.createElement('form');

View File

@ -141,7 +141,7 @@ module.exports = new Class({
} }
,goToCurrentMonth() { ,goToCurrentMonth() {
var date = new Date(); var date = Date.vnNew();
this.goToMonth(date.getFullYear(), date.getMonth()); this.goToMonth(date.getFullYear(), date.getMonth());
} }
@ -179,7 +179,7 @@ module.exports = new Class({
// Marks the current day // Marks the current day
var today = new Date(); var today = Date.vnNew();
if (this.year == today.getFullYear() if (this.year == today.getFullYear()
&& this.month == today.getMonth()) { && this.month == today.getMonth()) {

View File

@ -0,0 +1,111 @@
var Component = require('vn/component');
var Toast = require('../toast');
var Tpl = require('./ui.xml').default;
/**
* A change password popup.
*/
module.exports = new Class({
Extends: Component,
Tag: 'htk-change-password',
Properties: {
/**
* The token url.
*/
token: {
type: String
,set(value) {
this._token = value;
}
,get() {
return this._token;
}
},
conn: {
type: Db.Connection
,set(x) {
this._conn = x
}
,get() {
return this._conn;
}
},
user: {
type: Object
}
},
initialize(props) {
Component.prototype.initialize.call(this, props);
},
async open() {
this.passwordForm = await this.conn.get('UserPasswords/findOne')
this.loadTemplateFromString(Tpl);
this.$.oldPassword.value = '';
this.$.newPassword.value = '';
this.$.repeatPassword.value = '';
this.$.oldPassword.style.display = this.token ? 'none' : 'block';
this.$.changePassword.open();
if (this.token)
this.$.newPassword.focus();
else
this.$.oldPassword.focus();
},
async onPassModifyClick() {
const form = this.$.changePassword.node;
Vn.Node.disableInputs(form);
try {
const oldPassword = this.$.oldPassword.value;
const newPassword = this.$.newPassword.value;
const repeatedPassword = this.$.repeatPassword.value;
try {
if (newPassword == '' && repeatedPassword == '')
throw new Error(_('Passwords empty'));
if (newPassword !== repeatedPassword)
throw new Error(_('Passwords doesn\'t match'));
} catch (err) {
return Toast.showError(err.message);
}
const params = {newPassword};
try {
if (this.token) {
const headers = {
Authorization: this.token
};
await this.conn.post('VnUsers/reset-password', params, {headers});
} else {
params.userId = this.user.id;
params.oldPassword = oldPassword;
await this.conn.patch(`Accounts/change-password`, params);
}
} catch(err) {
Toast.showError(err.message);
if (this.token)
this.$.newPassword.select();
else
this.$.oldPassword.select();
return;
}
if(this.user)
await this.conn.open(this.user.name, newPassword);
this.$.changePassword.hide();
} finally {
Vn.Node.disableInputs(form, false);
}
Toast.showMessage(_('Password changed!'));
}
});

View File

@ -0,0 +1,62 @@
<vn>
<htk-popup
id="change-password"
modal="true">
<div property="child-node" class="htk-dialog vn-w-xs vn-pa-lg">
<div class="form">
<h5 class="vn-mb-md">
<t>Change password</t>
</h5>
<input
id="old-password"
type="password"
placeholder="_Old password"/>
<input
id="new-password"
type="password"
placeholder="_New password"
autocomplete="new-password"/>
<input
id="repeat-password"
type="password"
placeholder="_Repeat password"
autocomplete="new-password"/>
</div>
<div class="button-bar">
<button class="thin" on-click="this.onPassModifyClick()">
<t>Modify</t>
</button>
<button class="thin" on-click="this.$.passwordInfo.show()">
<t>Requirements</t>
</button>
<div class="clear"/>
</div>
</div>
</htk-popup>
<htk-popup
id="password-info"
modal="true">
<div property="child-node" class="htk-dialog pass-info vn-w-xs vn-pa-lg">
<h5 class="vn-mb-md">
<t>Password requirements</t>
</h5>
<ul>
<li>
{{this.passwordForm.length}} <t>characters long</t>
</li>
<li>
{{this.passwordForm.nAlpha}} <t>alphabetic characters</t>
</li>
<li>
{{this.passwordForm.nUpper}} <t>capital letters</t>
</li>
<li>
{{this.passwordForm.nDigits}} <t>digits</t>
</li>
<li>
{{this.passwordForm.nPunct}} <t>symbols</t>
</li>
</ul>
</div>
</htk-popup>
</vn>

View File

@ -10,15 +10,7 @@ module.exports = new Class({
value: { value: {
type: String type: String
,set(x) { ,set(x) {
if (Vn.Value.compare(x, this._value)) this._setValue(x);
return;
if (x instanceof Date)
x = x.clone();
this.valueChanged(x);
this.putValue(x);
this._notifyChanges();
} }
,get() { ,get() {
return this._value; return this._value;
@ -109,11 +101,11 @@ module.exports = new Class({
,_lockField: false ,_lockField: false
,_setValue(newValue) { ,_setValue(newValue) {
if (!this._putValue(newValue)) if (!this._putValue(newValue)) return;
return; newValue = this._value;
if (!this._lockField) if (!this._lockField)
this.putValue(newValue); this.putValue(this._value);
if (this.conditionalFunc) if (this.conditionalFunc)
this.conditionalFunc(this, newValue); this.conditionalFunc(this, newValue);

View File

@ -3,22 +3,23 @@ require('db/db');
require('./style/index.scss'); require('./style/index.scss');
Htk = module.exports = { Htk = module.exports = {
Popup : require('./popup') Popup : require('./popup')
,Dialog : require('./dialog') ,Dialog : require('./dialog')
,Toast : require('./toast') ,Toast : require('./toast')
,Repeater : require('./repeater') ,Repeater : require('./repeater')
,Grid : require('./grid') ,Grid : require('./grid')
,Spinner : require('./spinner') ,Spinner : require('./spinner')
,Icon : require('./icon') ,Icon : require('./icon')
,FullImage : require('./full-image') ,FullImage : require('./full-image')
,ImageEditor : require('./image-editor') ,ImageEditor : require('./image-editor')
,Assistant : require('./assistant') ,Assistant : require('./assistant')
,AssistantBar : require('./assistant-bar') ,AssistantBar : require('./assistant-bar')
,Step : require('./step') ,Step : require('./step')
,Loader : require('./loader') ,Loader : require('./loader')
,List : require('./list') ,List : require('./list')
,Field : require('./field') ,Field : require('./field')
,Column : require('./column') ,Column : require('./column')
,ChangePassword : require('./change-password')
}; };
var Fields = { var Fields = {

View File

@ -192,7 +192,7 @@ module.exports = new Class({
} }
,_onFileUpload(cell) { ,_onFileUpload(cell) {
this._stamp = new Date().getTime(); this._stamp = Date.vnNew().getTime();
this._refreshSrc(cell); this._refreshSrc(cell);
this.popup.hide(); this.popup.hide();
} }

View File

@ -54,7 +54,7 @@ module.exports = new Class({
,render() { ,render() {
var radio = Vn.Browser.createRadio('', this.doc); var radio = Vn.Browser.createRadio('', this.doc);
radio.checked = false; radio.checked = false;
radio.addEventListener('change', this._onChange.bind(this)); radio.addEventListener('change', () => this._onChange());
this._node = radio; this._node = radio;
} }

View File

@ -4,8 +4,6 @@ var htkRadioGroupUid = 0;
module.exports = new Class({ module.exports = new Class({
Extends: Htk.Field Extends: Htk.Field
,Tag: 'htk-radio-group' ,Tag: 'htk-radio-group'
,radioLock: false
,initialize(props) { ,initialize(props) {
this.clear(); this.clear();

View File

@ -3,69 +3,61 @@
*/ */
module.exports = module.exports =
{ {
set: function (key, value, days) set: function(key, value, days) {
{
var strCookie = key + '=' + value + ';'; var strCookie = key + '=' + value + ';';
if (days != undefined) if (days != undefined) {
{ var date = Date.vnNew();
var date = new Date (); date.setTime(date.getTime() + days * 86400000);
date.setTime (date.getTime () + days * 86400000); strCookie += 'expires=' + date.toGMTString();
strCookie += 'expires=' + date.toGMTString ();
} }
document.cookie = strCookie; document.cookie = strCookie;
} }
,unset: function (key) ,unset: function(key) {
{ this.set(key, '', -1);
this.set (key, '', -1);
} }
,get: function (key) ,get: function(key) {
{ var cookie = new String(document.cookie);
var cookie = new String (document.cookie); var start = cookie.indexOf(key + '=');
var start = cookie.indexOf (key + '=');
if (start != -1) if (start != -1) {
{
var end; var end;
start += key.length + 1; start += key.length + 1;
end = cookie.indexOf (';', start); end = cookie.indexOf(';', start);
if (end > 0) if (end > 0)
return cookie.substring (start, end); return cookie.substring(start, end);
else else
return cookie.substring (start); return cookie.substring(start);
} }
return null; return null;
} }
,getInt: function (key) ,getInt: function(key) {
{ var value = this.get(key);
var value = this.get (key);
if (value != null) if (value != null)
return parseInt (value); return parseInt(value);
return null; return null;
} }
,getFloat: function (key) ,getFloat: function(key) {
{ var value = this.get(key);
var value = this.get (key);
if (value != null) if (value != null)
return parseFloat (value); return parseFloat(value);
return null; return null;
} }
,check: function (key) ,check: function(key) {
{ return this.get(key) != null;
return this.get (key) != null;
} }
}; };

View File

@ -6,6 +6,22 @@ Date.prototype.clone = function() {
return new Date(this.getTime()); return new Date(this.getTime());
} }
Date.vnUTC = () => {
const env = process.env.NODE_ENV;
if (!env || env === 'development')
return new Date(Date.UTC(2001, 0, 1, 11));
return new Date();
};
Date.vnNew = () => {
return new Date(Date.vnUTC());
};
Date.vnNow = () => {
return new Date(Date.vnUTC()).getTime();
};
module.exports = module.exports =
{ {
WDays: [ WDays: [
@ -55,7 +71,7 @@ module.exports =
,'Dec' ,'Dec'
] ]
,tokenD: '%A, %B %e' ,tokenD: '%A, %B %e %Y'
,regexp: new RegExp('%[a-zA-Z]', 'g') ,regexp: new RegExp('%[a-zA-Z]', 'g')
@ -101,7 +117,7 @@ module.exports =
// Year with 4 digits // Year with 4 digits
case 'Y': return d.getFullYear(); case 'Y': return d.getFullYear();
// Complete date without year // Complete date
case 'D': return _(this.tokenD).replace(this.regexp, this.regexpFunc.bind(this, d)); case 'D': return _(this.tokenD).replace(this.regexp, this.regexpFunc.bind(this, d));
} }

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