Compare commits

..

407 Commits

Author SHA1 Message Date
Javier Segarra 614b953d63 Merge pull request 'fix: updates vntable2' (!1381) from fix_ticketNegatives into dev
gitea/salix-front/pipeline/head This commit looks good Details
Reviewed-on: #1381
Reviewed-by: Jon Elias <jon@verdnatura.es>
2025-02-12 15:40:05 +00:00
Jon Elias 23e029b225 Merge branch 'dev' into fix_ticketNegatives
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-12 15:30:07 +00:00
Javier Segarra a0dbb63346 fix: updates vntable2
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-12 16:24:34 +01:00
Jon Elias 273cae5df8 Merge pull request '#7451: Deleted module property in CardSummary and each module' (!1378) from 7451-DeleteModuleProp into dev
gitea/salix-front/pipeline/head This commit looks good Details
Reviewed-on: #1378
Reviewed-by: Jorge Penadés <jorgep@verdnatura.es>
2025-02-12 12:11:18 +00:00
Jon Elias 8eb875b5b8 Merge branch 'dev' into 7451-DeleteModuleProp
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-12 09:46:30 +00:00
PAU ROVIRA ROSALENY 4950ca6822 Merge pull request 'fix: #7065 fixed test intermittent error' (!1337) from 7065-testUserPanel into dev
gitea/salix-front/pipeline/head This commit looks good Details
Reviewed-on: #1337
Reviewed-by: Alex Moreno <alexm@verdnatura.es>
2025-02-12 07:43:09 +00:00
PAU ROVIRA ROSALENY fa4802cd6d Merge branch 'dev' into 7065-testUserPanel
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-12 07:41:55 +00:00
Alex Moreno ef2e3c5351 refactor: remove unused defineEmits import in ChangeQuantityDialog.vue
gitea/salix-front/pipeline/head Build queued... Details
2025-02-12 07:56:09 +01:00
Alex Moreno 224d554a37 fix: update import path for ParkingDescriptor in ParkingCard.vue
gitea/salix-front/pipeline/head This commit looks good Details
2025-02-12 07:54:28 +01:00
Pablo Natek b221e56aae Merge pull request '6897-refactorVnTableAndEntryBuys' (!1374) from 6897-refactorVnTableAndEntryBuys into dev
gitea/salix-front/pipeline/head There was a failure building this commit Details
Reviewed-on: #1374
Reviewed-by: Alex Moreno <alexm@verdnatura.es>
2025-02-12 06:49:36 +00:00
Alex Moreno 96d1f76bf2 Merge branch 'dev' into 7065-testUserPanel
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-12 06:41:22 +00:00
Pablo Natek cce9016e4e Merge branch 'dev' into 6897-refactorVnTableAndEntryBuys
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-11 15:50:51 +00:00
Jon Elias 701cb875d3 refactor: refs #7451 deleted module prop in CardSummary and modules
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-11 16:44:55 +01:00
Pablo Natek 7e993cab73 refactor: refs #6897 improve condition checks in VnTable and remove unused emit in VnInputTime for cleaner code
gitea/salix-front/pipeline/pr-dev There was a failure building this commit Details
2025-02-11 16:44:05 +01:00
Carlos Satorres 7b34433898 Merge pull request '7550-refactPagesParking' (!1350) from 7550-refactPagesParking into dev
gitea/salix-front/pipeline/head There was a failure building this commit Details
Reviewed-on: #1350
Reviewed-by: Alex Moreno <alexm@verdnatura.es>
2025-02-11 15:28:05 +00:00
Carlos Satorres a0b7f0083d Merge branch 'dev' into 7550-refactPagesParking
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-11 15:26:23 +00:00
Pablo Natek b403daff0e refactor: refs #6897 update VnFilter and VnTable components to enhance customization and improve styling
gitea/salix-front/pipeline/pr-dev Build queued... Details
2025-02-11 14:34:15 +01:00
Pablo Natek 5605654bb8 refactor: refs #6897 remove unused import statements in VnFilter component for cleaner code
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-11 12:30:35 +01:00
Pablo Natek 61ee7ced54 refactor: refs #6897 update component imports and class names for consistency and clarity
gitea/salix-front/pipeline/head This commit looks good Details
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-11 12:25:42 +01:00
PAU ROVIRA ROSALENY bd7672c1ca Merge branch 'dev' into 7065-testUserPanel
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-11 11:24:35 +00:00
Pablo Natek 9c306e4420 Merge branch '6897-entryBuyListRefactor' of https://gitea.verdnatura.es/verdnatura/salix-front into 6897-entryBuyListRefactor 2025-02-11 12:24:17 +01:00
Pablo Natek 7b2240b01d Merge branch 'dev' of https: refs #6897//gitea.verdnatura.es/verdnatura/salix-front into 6897-entryBuyListRefactor 2025-02-11 12:24:15 +01:00
Alex Moreno fcf6957b74 refactor: refs #6897 update deletion handling in CrudModel component to improve data management 2025-02-11 11:35:34 +01:00
Alex Moreno c04adf0e7d refactor: refs #6897 update SkeletonDescriptor component add image 2025-02-11 11:15:19 +01:00
Alex Moreno 06a07d4fd3 refactor: refs #6897 update checkbox attributes to include toggleIndeterminate in EntryBuys component 2025-02-11 10:11:26 +01:00
Javier Segarra 4a2074dc9d Merge pull request '6321_negative_tickets' (!1371) from 6321_negative_tickets into dev
gitea/salix-front/pipeline/head This commit looks good Details
Reviewed-on: #1371
Reviewed-by: Carlos Satorres <carlossa@verdnatura.es>
2025-02-11 09:04:30 +00:00
Javier Segarra 3a95e22f67 Merge branch 'dev' into 6321_negative_tickets
gitea/salix-front/pipeline/head This commit looks good Details
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-11 08:51:33 +00:00
Jose Antonio Tubau 54585691c3 Merge pull request '#7411 - addInfoOnVnCheckboxAndVnInput' (!1295) from 7411-addInfoOnVnCheckboxAndVnInput into dev
gitea/salix-front/pipeline/head This commit looks good Details
Reviewed-on: #1295
Reviewed-by: Alex Moreno <alexm@verdnatura.es>
2025-02-11 08:50:09 +00:00
Javier Segarra 4bd9e69bf1 Merge branch 'dev' into 6321_negative_tickets
gitea/salix-front/pipeline/head This commit looks good Details
2025-02-11 08:43:22 +00:00
Alex Moreno c975943eb1 Merge branch 'dev' into 7411-addInfoOnVnCheckboxAndVnInput
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-11 08:38:51 +00:00
PAU ROVIRA ROSALENY 722cb938ab Merge branch 'dev' into 7065-testUserPanel
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-11 08:05:55 +00:00
Pablo Natek ce89d4a31b Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix-front into 6897-entryBuyListRefactor 2025-02-11 08:15:30 +01:00
Jon Elias f6c5891e0b Merge pull request 'Fix[InvoiceInBasicData]: fixed basic data e2e' (!1361) from Fix-InvoiceInBasicDataE2E into dev
gitea/salix-front/pipeline/head This commit looks good Details
Reviewed-on: #1361
Reviewed-by: Javier Segarra <jsegarra@verdnatura.es>
2025-02-11 07:14:48 +00:00
Pablo Natek 45f4a1cea8 refactor: refs #6897 update component attributes and improve checkbox integration in tables 2025-02-11 07:58:26 +01:00
Jon Elias 94f1b2d709 Merge branch 'dev' into Fix-InvoiceInBasicDataE2E
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-11 06:49:57 +00:00
Pablo Natek f4e210734b Merge branch '6897-entryBuyListRefactor' of https://gitea.verdnatura.es/verdnatura/salix-front into 6897-entryBuyListRefactor 2025-02-10 16:05:08 +01:00
Pablo Natek 86184b905e refactor: refs #6897 remove 'only' from test cases to ensure all tests run 2025-02-10 16:05:01 +01:00
PAU ROVIRA ROSALENY e9336fe20f Merge branch 'dev' into 7065-testUserPanel
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-10 13:13:41 +00:00
Javier Segarra d4212e6e07 Merge pull request 'fix_customerConsumption_filter' (!1357) from fix_customerConsumption_filter into dev
gitea/salix-front/pipeline/head This commit looks good Details
Reviewed-on: #1357
Reviewed-by: Javi Gallego <jgallego@verdnatura.es>
2025-02-10 12:40:47 +00:00
Javier Segarra b2a50e23bf Merge branch 'dev' into fix_customerConsumption_filter
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-10 12:39:54 +00:00
Alex Moreno 5e167876a9 Merge branch 'test' of https://gitea.verdnatura.es/verdnatura/salix-front into dev
gitea/salix-front/pipeline/head This commit looks good Details
2025-02-10 13:31:09 +01:00
Alex Moreno 8d209c9415 Merge branch 'master' of https://gitea.verdnatura.es/verdnatura/salix-front into test
gitea/salix-front/pipeline/pr-dev This commit looks good Details
gitea/salix-front/pipeline/head There was a failure building this commit Details
2025-02-10 13:30:57 +01:00
Jon Elias c0e03bd467 Merge branch 'Fix-InvoiceInBasicDataE2E' of https://gitea.verdnatura.es/verdnatura/salix-front into Fix-InvoiceInBasicDataE2E
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-10 13:19:01 +01:00
Jon Elias 73f02cf8bd refactor: use data-cy in VnSelectSupplier component and refactored e2e 2025-02-10 13:18:59 +01:00
Jon Elias a3c3a60e98 Merge branch 'dev' into Fix-InvoiceInBasicDataE2E
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-10 11:46:20 +00:00
Jon Elias aa6c6f0e69 refactor: requested changes
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-10 12:44:35 +01:00
PAU ROVIRA ROSALENY 1a2d46ddcc Merge branch 'dev' into 7065-testUserPanel
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-10 11:35:36 +00:00
Guillermo Bonet 2a5eeac8d5 Merge branch 'dev' into 6897-entryBuyListRefactor 2025-02-10 11:30:43 +00:00
Pablo Natek 5f624bbf7f refactor: refs #6897 clean up alignment and improve data attributes for better testing 2025-02-10 11:41:41 +01:00
Javier Segarra cdf600cbd0 fix: replace i18n
gitea/salix-front/pipeline/pr-dev There was a failure building this commit Details
2025-02-10 11:04:42 +01:00
Alex Moreno 0a40dd598e fix: cardDescriptor use userFilter
gitea/salix-front/pipeline/head This commit looks good Details
2025-02-10 10:21:38 +01:00
Jon Elias 8c499e3fc3 fix: fixed basic data e2e
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-10 10:20:40 +01:00
Jose Antonio Tubau 18da0e9922 refactor: refs #7411 bind event listeners to QCheckbox in VnCheckbox component
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-10 09:42:34 +01:00
Carlos Satorres 1c4afcb7cc Merge branch 'dev' into 7550-refactPagesParking
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-10 08:42:22 +00:00
Javier Segarra cc21b74626 Merge branch 'dev' into fix_customerConsumption_filter 2025-02-10 09:31:02 +01:00
Jon Elias 0e1f04323c Merge pull request 'Fix[OrderCatalogItemDialog]: Fixed add item to order' (!1359) from Fix-OrderCatalogAddToOrder into dev
gitea/salix-front/pipeline/head This commit looks good Details
Reviewed-on: #1359
Reviewed-by: Alex Moreno <alexm@verdnatura.es>
2025-02-10 08:08:59 +00:00
Jon Elias 585bb9973e Merge branch 'dev' into Fix-OrderCatalogAddToOrder
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-10 07:57:03 +00:00
Jon Elias 311eab363a Merge pull request '#8246 modified addressFk field to use dashIfEmpty filter' (!1208) from 8246-ZoneAddressFk2 into dev
gitea/salix-front/pipeline/head This commit looks good Details
Reviewed-on: #1208
Reviewed-by: Javi Gallego <jgallego@verdnatura.es>
Reviewed-by: Alex Moreno <alexm@verdnatura.es>
2025-02-10 07:55:54 +00:00
Jon Elias a287844860 Merge branch 'dev' into 8246-ZoneAddressFk2
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-10 07:54:53 +00:00
Jon Elias 73dfce4104 fix: fixed OrderCatalog add item to order
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-10 08:51:51 +01:00
Jose Antonio Tubau b2f011e7cc Merge pull request 'fix: refs #7318 fixed claim summary warnings' (!1347) from 7318-claimSummaryFixWarnings into dev
gitea/salix-front/pipeline/head This commit looks good Details
Reviewed-on: #1347
Reviewed-by: Carlos Satorres <carlossa@verdnatura.es>
2025-02-10 07:17:48 +00:00
Jose Antonio Tubau b95d8f3b44 Merge branch 'dev' into 7318-claimSummaryFixWarnings
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-10 07:16:40 +00:00
Alex Moreno 03ef6f01e5 Merge branch 'dev' into 7550-refactPagesParking
gitea/salix-front/pipeline/pr-dev There was a failure building this commit Details
2025-02-10 06:14:25 +00:00
PAU ROVIRA ROSALENY 6ac24586d0 Merge branch 'dev' into 7065-testUserPanel
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-10 05:51:54 +00:00
Pablo Natek af2cbda077 Merge branch 'dev' of https: refs #6897//gitea.verdnatura.es/verdnatura/salix-front into 6897-entryBuyListRefactor
gitea/salix-front/pipeline/head This commit looks good Details
2025-02-09 18:28:33 +01:00
Pablo Natek b37923e194 feat: refs #6897 add success messages for entry lock and improve data attributes for better testing 2025-02-09 18:24:41 +01:00
Jorge Penadés dc3c800342 Merge pull request 'fix: refs #6919 include entityId in descriptor filter' (!1358) from 6919-fixFilters into dev
gitea/salix-front/pipeline/head This commit looks good Details
Reviewed-on: #1358
Reviewed-by: Javi Gallego <jgallego@verdnatura.es>
2025-02-09 12:24:03 +00:00
Jorge Penadés 1948ee9c52 fix: refs #6919 include entityId in descriptor filter
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-09 10:16:48 +01:00
Javier Segarra 40569b1ede fix: refs #6321 ticket locale en 2025-02-08 16:39:25 +01:00
Javier Segarra ca6cfb4c5e Merge branch 'fix_customerConsumption_filter' of https://gitea.verdnatura.es/verdnatura/salix-front into fix_customerConsumption_filter
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-07 23:42:39 +01:00
Javier Segarra b3fd818b13 feat: improves 2025-02-07 23:42:17 +01:00
Javier Segarra ce17e124a0 Merge branch 'dev' into fix_customerConsumption_filter
gitea/salix-front/pipeline/pr-dev Build queued... Details
2025-02-07 22:23:58 +00:00
Javier Segarra 55719fbce7 style: remove comments
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-07 23:02:45 +01:00
Javier Segarra 9dc22b39e2 feat: add more filters 2025-02-07 23:02:17 +01:00
Javier Segarra 63af730838 Merge branch 'dev' into 6321_negative_tickets 2025-02-07 21:42:21 +00:00
Carlos Satorres f8b41101d3 Merge pull request 'fix: improve method into dev' (!1356) from fix_reload_icon into dev
gitea/salix-front/pipeline/head This commit looks good Details
Reviewed-on: #1356
Reviewed-by: Carlos Satorres <carlossa@verdnatura.es>
2025-02-07 14:19:32 +00:00
Javier Segarra d060e88ebb fix: improve method into dev
gitea/salix-front/pipeline/pr-dev This commit looks good Details
Reviewed-on: #1354
Reviewed-by: Carlos Satorres <carlossa@verdnatura.es>
2025-02-07 14:15:28 +00:00
Javier Segarra a4179eeb0a Merge pull request 'WARMFIX: improve method' (!1354) from warmfix_reload_scriptIsMissing into test
gitea/salix-front/pipeline/pr-dev There was a failure building this commit Details
gitea/salix-front/pipeline/head This commit looks good Details
Reviewed-on: #1354
Reviewed-by: Carlos Satorres <carlossa@verdnatura.es>
2025-02-07 14:13:39 +00:00
Jorge Penadés b75578b6fb Merge pull request '#8388 fixInvoiceIn' (!1321) from 8388-fixInvoiceIn into dev
gitea/salix-front/pipeline/head This commit looks good Details
Reviewed-on: #1321
Reviewed-by: Alex Moreno <alexm@verdnatura.es>
2025-02-07 13:51:46 +00:00
Jorge Penadés 8380808ffa Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix-front into 8388-fixInvoiceIn
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-07 14:49:43 +01:00
Javier Segarra 2a3e807460 fix: improve method
gitea/salix-front/pipeline/pr-test This commit looks good Details
2025-02-07 13:38:06 +00:00
Jon Elias b1f0cc7f1d Merge pull request 'Fix[ItemFixedPrice]: Fixed item name filter' (!1351) from Fix-ItemFixedPriceNameFilter into dev
gitea/salix-front/pipeline/head This commit looks good Details
Reviewed-on: #1351
Reviewed-by: Alex Moreno <alexm@verdnatura.es>
2025-02-07 12:44:37 +00:00
Jon Elias 94849d0cdf Merge branch 'dev' into Fix-ItemFixedPriceNameFilter
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-07 12:43:23 +00:00
Jon Elias 0692de7bfb fix: fixed item name filter
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-07 13:41:34 +01:00
Alex Moreno 2d65811360 Merge branch 'dev' into 8246-ZoneAddressFk2
gitea/salix-front/pipeline/pr-dev There was a failure building this commit Details
2025-02-07 12:04:55 +00:00
Jorge Penadés f01e5b824e fix: refs #8388 adjust table cell properties and remove unused styles in InvoiceInVat.vue
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-07 10:41:42 +01:00
PAU ROVIRA ROSALENY e41ed4eff5 Merge branch 'dev' into 7065-testUserPanel
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-07 09:39:35 +00:00
Jorge Penadés d9897b3ea2 Merge branch 'dev' of https: refs #8388//gitea.verdnatura.es/verdnatura/salix-front into 8388-fixInvoiceIn
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-07 10:05:30 +01:00
Jorge Penadés de6020626f Merge pull request 'feat: refs #7119 show country name' (!1346) from 7119-showCountryName into dev
gitea/salix-front/pipeline/head This commit looks good Details
Reviewed-on: #1346
Reviewed-by: Alex Moreno <alexm@verdnatura.es>
2025-02-07 09:03:52 +00:00
Jorge Penadés 05f6e1ec20 Merge branch '7119-showCountryName' of https://gitea.verdnatura.es/verdnatura/salix-front into 7119-showCountryName
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-07 10:02:46 +01:00
Jorge Penadés 0adb86d4f2 Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix-front into 7119-showCountryName 2025-02-07 10:02:37 +01:00
Carlos Satorres b334807c5b fix: refs #7550 department
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-07 09:59:47 +01:00
Javier Segarra 86b77c2022 Merge pull request '#7601 - Different agency fot future tickets' (!1342) from 7601_futureAgency into dev
gitea/salix-front/pipeline/head This commit looks good Details
Reviewed-on: #1342
Reviewed-by: Javi Gallego <jgallego@verdnatura.es>
2025-02-07 08:36:18 +00:00
Javier Segarra 0901c57b12 Merge branch 'dev' into 7601_futureAgency
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-07 08:32:53 +00:00
Carlos Satorres 154a893580 Merge pull request 'fix: refs #6426 create constants' (!1228) from 6426-refactorConstants into dev
gitea/salix-front/pipeline/head This commit looks good Details
Reviewed-on: #1228
Reviewed-by: Alex Moreno <alexm@verdnatura.es>
2025-02-07 08:22:54 +00:00
Carlos Satorres 780e7839f4 Merge branch 'dev' into 6426-refactorConstants
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-07 08:21:56 +00:00
Carlos Satorres acb1ce39e0 fix: refs #7550 organize parking, shelving 2025-02-07 09:19:11 +01:00
PAU ROVIRA ROSALENY be894f52c1 Merge branch 'dev' into 7065-testUserPanel
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-07 07:51:49 +00:00
Jose Antonio Tubau 1f1fa1e2b6 refactor: refs #7318 update order prop type to string and improve conditional rendering for zone
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-07 08:32:33 +01:00
Alex Moreno 6dd3a7b00d Merge branch 'dev' into 7411-addInfoOnVnCheckboxAndVnInput
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-07 07:26:52 +00:00
Alex Moreno 89df2e837c Merge pull request 'refactor: #8322 changed supplier component to use VnSection/VnCardBeta' (!1216) from 8322-Supplier into dev
gitea/salix-front/pipeline/head This commit looks good Details
Reviewed-on: #1216
Reviewed-by: Alex Moreno <alexm@verdnatura.es>
2025-02-07 07:20:47 +00:00
Alex Moreno c72d4e9f04 fix: refs #8322 supplier use cardBeta correctly
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-07 08:19:51 +01:00
Jon Elias 98bcb2f45b Merge pull request 'Hotfix[InvoiceOutList]: Fixed company filter' (!1349) from Hotfix-InvoiceOutCompanyFilter into master
gitea/salix-front/pipeline/head This commit looks good Details
Reviewed-on: #1349
Reviewed-by: Alex Moreno <alexm@verdnatura.es>
2025-02-07 07:12:36 +00:00
Javier Segarra 2550add549 Merge branch 'dev' into 7601_futureAgency
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-07 07:07:48 +00:00
Jon Elias f93c512e16 Merge branch 'master' into Hotfix-InvoiceOutCompanyFilter
gitea/salix-front/pipeline/pr-master This commit looks good Details
2025-02-07 07:00:43 +00:00
Javier Segarra 314f656965 Merge branch '6321_negative_tickets' of https://gitea.verdnatura.es/verdnatura/salix-front into 6321_negative_tickets 2025-02-07 07:56:29 +01:00
Jon Elias 43b6ff89be fix: fixed company filter
gitea/salix-front/pipeline/pr-master This commit looks good Details
2025-02-07 07:56:08 +01:00
Javier Segarra 14c7ec2e39 Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix-front into 6321_negative_tickets 2025-02-07 07:54:21 +01:00
Javier Segarra eb9ab710c4 Merge branch 'dev' into 6321_negative_tickets 2025-02-07 06:41:08 +00:00
Alex Moreno 1a420abfb2 Merge branch 'dev' of https: refs #8322//gitea.verdnatura.es/verdnatura/salix-front into 8322-Supplier
gitea/salix-front/pipeline/pr-dev There was a failure building this commit Details
2025-02-07 07:39:47 +01:00
Alex Moreno 3021e38ae8 fix: hotfix fetchData not use userFilter
gitea/salix-front/pipeline/head This commit looks good Details
2025-02-07 07:32:28 +01:00
Jose Antonio Tubau f6e53e478f fix: refs #7318 fixed claim summary warnings
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-07 07:27:36 +01:00
Alex Moreno 2fea795bdb fix: hotfix empty observations
gitea/salix-front/pipeline/head This commit looks good Details
2025-02-07 07:21:59 +01:00
PAU ROVIRA ROSALENY e77e96ffed Merge branch 'dev' into 7065-testUserPanel
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-07 06:02:05 +00:00
Alex Moreno fc44424dda Merge branch 'dev' into 7119-showCountryName
gitea/salix-front/pipeline/pr-dev There was a failure building this commit Details
2025-02-07 06:00:54 +00:00
Javier Segarra 220fb057e6 feat: refs #6321 requested changes 2025-02-06 18:00:18 +01:00
Jorge Penadés 5e17af2fae feat: refs #7119 show country name
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-06 16:19:38 +01:00
Javier Segarra d7b9a01c57 Merge branch 'dev' into 6321_negative_tickets 2025-02-06 14:58:28 +00:00
Javier Segarra ceef46eccc feat: refs #6321 remove ticketConfig 2025-02-06 15:18:35 +01:00
Jon Elias 504fee11a0 Merge branch '8246-ZoneAddressFk2' of https://gitea.verdnatura.es/verdnatura/salix-front into 8246-ZoneAddressFk2
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-06 14:21:14 +01:00
Jon Elias 1395c0da80 Merge branch 'dev' of https: refs #8246//gitea.verdnatura.es/verdnatura/salix-front into 8246-ZoneAddressFk2 2025-02-06 14:21:12 +01:00
Robert Ferrús 72e9637ef0 Merge pull request 'feat: refs #6822 change traduction Partial delay' (!1341) from 6822-changeTitlePartialDelay into test
gitea/salix-front/pipeline/pr-dev This commit looks good Details
gitea/salix-front/pipeline/head This commit looks good Details
Reviewed-on: #1341
Reviewed-by: Javier Segarra <jsegarra@verdnatura.es>
2025-02-06 12:51:10 +00:00
Javier Segarra e8a90faa62 feat: add agency icon
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-06 12:33:26 +00:00
Alex Moreno 07eacdcebf fix: refs #6426 constants
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-06 12:42:00 +01:00
PAU ROVIRA ROSALENY 035979cb70 Merge branch 'dev' into 7065-testUserPanel
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-06 11:09:59 +00:00
Carlos Satorres 117ce937fe Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix-front into 6426-refactorConstants
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-06 11:58:01 +01:00
Carlos Satorres 64a52e0183 fix: refs #6426 outLayout
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-06 11:57:27 +01:00
Robert Ferrús 3a7366c91a feat: refs #6822 change traduction Partial delay
gitea/salix-front/pipeline/pr-test This commit looks good Details
2025-02-06 11:47:14 +01:00
PAU ROVIRA ROSALENY 828bb61f52 Merge branch 'dev' into 7065-testUserPanel
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-06 09:51:52 +00:00
PAU ROVIRA ROSALENY 9767668798 Merge branch 'dev' into 7065-testUserPanel
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-06 09:33:05 +00:00
Carlos Satorres 5d7bfec177 Merge branch '6426-refactorConstants' of https://gitea.verdnatura.es/verdnatura/salix-front into 6426-refactorConstants
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-06 09:53:13 +01:00
Carlos Satorres ded1dae481 Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix-front into 6426-refactorConstants 2025-02-06 09:53:09 +01:00
Carlos Satorres 502f41993a Merge branch 'dev' into 6426-refactorConstants
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-06 08:47:50 +00:00
PAU ROVIRA ROSALENY 4ad2f936e8 Merge branch 'dev' into 7065-testUserPanel
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-06 07:44:51 +00:00
PAU ROVIRA ROSALENY 85140999ab Actualizar src/components/__tests__/UserPanel.spec.js
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-06 06:56:29 +00:00
Javier Segarra 852e51c06f feat: refs #6321 fetch ticketConfig for alertLevelCode 2025-02-06 01:06:48 +01:00
Javier Segarra b8f2df59cd feat: refs #6321 updates requested 2025-02-06 00:33:43 +01:00
Carlos Satorres 5cb2b326f1 Merge branch 'dev' into 6426-refactorConstants
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-05 15:08:25 +00:00
Javier Segarra d8bc37b627 style: refs #6321 i18n es 2025-02-05 15:38:54 +01:00
Javier Segarra 4f4071f13b Merge branch 'dev' of https: refs #6321//gitea.verdnatura.es/verdnatura/salix-front into 6321_negative_tickets 2025-02-05 15:38:13 +01:00
Javier Segarra aa53feea39 feat: refs #6321 changes 2025-02-05 15:37:16 +01:00
Jon Elias fac0e21ffd Merge branch 'dev' into 8246-ZoneAddressFk2
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-05 13:42:09 +00:00
Jon Elias 6eae05b7d0 Merge branch '8246-ZoneAddressFk2' of https://gitea.verdnatura.es/verdnatura/salix-front into 8246-ZoneAddressFk2
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-05 14:40:05 +01:00
Jon Elias 41c8760707 refactor: refs #8246 added filter to searchbar due to data key 2025-02-05 14:40:04 +01:00
Carlos Satorres 018327a9ec Merge branch 'dev' into 6426-refactorConstants
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-05 11:51:30 +00:00
Carlos Satorres 896626a1fd Merge branch '6426-refactorConstants' of https://gitea.verdnatura.es/verdnatura/salix-front into 6426-refactorConstants
gitea/salix-front/pipeline/pr-dev There was a failure building this commit Details
2025-02-05 12:51:06 +01:00
Carlos Satorres b45e529879 fix: refs #6426 fix constants 2025-02-05 12:51:04 +01:00
Pablo Natek e121cc5d5c Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix-front into 6897-entryBuyListRefactor 2025-02-05 12:42:00 +01:00
Pablo Natek 962a49868e feat: refs #6897 enhance entry management with new filters and localization updates 2025-02-05 12:41:52 +01:00
Jon Elias 808dfe7122 Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix-front into 8246-ZoneAddressFk2 2025-02-05 08:23:52 +01:00
Pablo Natek abce9c66ee Merge branch 'dev' of https: refs #6897//gitea.verdnatura.es/verdnatura/salix-front into 6897-entryBuyListRefactor 2025-02-05 08:04:42 +01:00
Jon Elias 090814cd29 Merge branch 'dev' into 8246-ZoneAddressFk2
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-05 06:59:07 +00:00
Pablo Natek dc8612fc73 refactor: refs #6897 update VnCheckbox component for improved model handling and replace QCheckbox 2025-02-05 07:35:06 +01:00
Javier Segarra de454313cf feat: refs #6321 remove agency 2025-02-05 00:22:50 +01:00
Javier Segarra c65f1524c6 perf: refs #6321 remove console 2025-02-05 00:02:03 +01:00
Javier Segarra 74c0c64d50 fix: refs #6321 colors with variables 2025-02-04 23:59:17 +01:00
Javier Segarra bdb35e24ee perf: refs #6321 minor changes 2025-02-04 23:44:49 +01:00
Javier Segarra 7b7a8085e7 Merge branch 'dev' into 6321_negative_tickets 2025-02-04 23:43:44 +01:00
Pablo Natek 568f523e36 feat: refs #6897 add VnCheckbox component and enhance route list with dynamic select fields 2025-02-04 14:10:00 +01:00
Javier Segarra de6b1a8d5d fix: refs #6321 param 2025-02-04 13:04:57 +01:00
Javier Segarra 1971534876 Merge branch 'dev' into 6321_negative_tickets 2025-02-04 09:46:27 +01:00
Javier Segarra b7e3401d06 feat: refs #6321 changes 2025-02-03 23:29:56 +01:00
Pablo Natek 30f13b65f0 refactor: refs #6897 streamline supplier selection component and enhance localization entries 2025-02-03 14:19:50 +01:00
Pablo Natek 6b9f9188a2 Merge branch 'dev' of https: refs #6897//gitea.verdnatura.es/verdnatura/salix-front into 6897-entryBuyListRefactor
gitea/salix-front/pipeline/head This commit looks good Details
2025-02-03 13:27:23 +01:00
Pablo Natek b258c4eaac refactor: refs #6897 enhance localization entries, clean up unused code, and improve component structure 2025-02-03 13:16:57 +01:00
Jorge Penadés 13f09f13d2 fix: refs #8388 update translation for VAT and Transaction fields in invoice booking
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-03 13:04:38 +01:00
Jorge Penadés 5147967bc0 feat: refs #8388 add validation for missing VAT and Transaction fields in invoice booking
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-03 12:26:43 +01:00
Jorge Penadés e3706094c2 fix: refs #8388 rollback
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-02-03 12:03:39 +01:00
Jorge Penadés 778d8fbb67 Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix-front into 8388-fixInvoiceIn
gitea/salix-front/pipeline/pr-dev There was a failure building this commit Details
2025-02-03 11:06:39 +01:00
Javier Segarra 859071ca4d Merge branch '6321_negative_tickets' of https://gitea.verdnatura.es/verdnatura/salix-front into 6321_negative_tickets 2025-02-03 10:57:27 +01:00
Javier Segarra 5d71a16ec7 feat: refs #6321 changes after review 2025-02-03 09:30:31 +01:00
Jorge Penadés 97df1d8fd2 feat: refs #8388 add total amount calculation and update invoice insertion logic
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-01-31 18:43:09 +01:00
Jorge Penadés f18da15262 feat: refs #8388 enhance invoice booking validation and user confirmation messages
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-01-31 18:07:20 +01:00
Jorge Penadés c2042276ae fix: refs #8388 locale
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-01-31 16:14:09 +01:00
Jorge Penadés d8073e78ab Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix-front into 8388-fixInvoiceIn
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-01-31 16:02:33 +01:00
Jorge Penadés 66665ba5dd feat: refs #8388 if is number check startsWith wip 2025-01-31 16:01:44 +01:00
Jorge Penadés c83854c4c6 fix: refs #8388 update locale 2025-01-31 14:56:27 +01:00
Jorge Penadés 359e67c734 refactor: refs #8388 improve filter and search functionality 2025-01-31 14:46:42 +01:00
Jorge Penadés 290a7273d0 fix: refs #8388 update the right row 2025-01-31 14:19:48 +01:00
Jorge Penadés 8d0d19d4c7 fix: refs #8388 update the right row 2025-01-31 14:17:08 +01:00
Jorge Penadés 6a7fcd1afe feat: refs #8388 add setCursor 2025-01-31 13:44:30 +01:00
Jorge Penadés 42b86f05ce fix: refs #8388 improve table column widths 2025-01-31 12:53:38 +01:00
Javier Segarra 3e61b93ba3 Merge branch 'dev' into 6321_negative_tickets 2025-01-31 10:20:50 +00:00
Jose Antonio Tubau c8754ae4df refactor: refs #7411 add clearable and clear-icon properties to sync password checkbox
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-01-31 08:51:24 +01:00
Jose Antonio Tubau cc07cc7824 refactor: refs #7411 update VnCheckbox component to use v-bind for attributes 2025-01-31 08:50:35 +01:00
Javier Segarra 107b8a7692 perf: refs #6321 clean code 2025-01-31 01:37:08 +01:00
Javier Segarra 0b084ae371 Merge branch 'dev' into 6321_negative_tickets 2025-01-31 01:08:30 +01:00
Javier Segarra 055a0b8751 feat: refs #6321 updates 2025-01-31 01:08:19 +01:00
Carlos Satorres c97b5bffd2 Merge branch 'dev' into 6426-refactorConstants
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-01-30 07:57:30 +00:00
Javier Segarra 31d829ac05 Merge branch 'dev' into 6321_negative_tickets 2025-01-30 00:08:58 +01:00
Javier Segarra 07ad4b1655 Merge branch 'dev' into 6321_negative_tickets 2025-01-29 23:51:03 +01:00
Javier Segarra 973209abed feat: refs #6321 updates 2025-01-29 16:15:37 +01:00
Javier Segarra a28b2183ad fix: refs #6321 change i18n 2025-01-29 12:27:29 +01:00
Javier Segarra 3bf10aa32a Merge branch 'dev' into 6321_negative_tickets 2025-01-29 09:45:46 +01:00
Javier Segarra bded06082a fix: refs #6321 user-filter 2025-01-28 22:58:13 +01:00
Jose Antonio Tubau c083eba66c Merge branch 'dev' into 7411-addInfoOnVnCheckboxAndVnInput
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-01-28 13:35:37 +00:00
Jose Antonio Tubau 2e0575052c refactor: refs #7411 update VnCheckbox component to use defineModel for modelValue binding
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-01-28 14:23:28 +01:00
Jose Antonio Tubau d0a0d19be2 feat: refs #7411 integrate VnCheckbox component across multiple forms with info support
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-01-28 14:16:59 +01:00
Javier Segarra a46e5b07f9 feat: refs #6321 updates 2025-01-28 14:04:56 +01:00
Javier Segarra 9e6b174ae6 Merge branch 'dev' into 6321_negative_tickets 2025-01-28 13:50:10 +01:00
Carlos Satorres 804fb28e11 Merge branch 'dev' into 6426-refactorConstants
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-01-28 12:16:49 +00:00
Javier Segarra 08f73acc3e feat: refs #6321 updates 2025-01-28 08:41:04 +01:00
Jose Antonio Tubau f7c93c8416 refactor: refs #7411 remove unnecessary $props prefix
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-01-28 08:39:35 +01:00
Jose Antonio Tubau a337bdf474 feat: refs #7411 add VnCheckbox component with info support 2025-01-28 08:30:38 +01:00
Javier Segarra 755fd3a076 feat: refs #6321 handle promises 2025-01-27 23:01:44 +01:00
Javier Segarra 231f67df5c feat: refs #6321 style updates 2025-01-27 19:54:12 +01:00
Jon Elias faacff875a Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix-front into 8246-ZoneAddressFk2 2025-01-27 13:39:47 +01:00
Javier Segarra 805e56b9d3 feat: refs #6321 changes 2025-01-27 12:04:14 +01:00
Carlos Satorres 822058b491 fix: refs #6426 constants
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-01-27 11:37:50 +01:00
Carlos Satorres e413acf85d Merge branch 'dev' of https: refs #6426//gitea.verdnatura.es/verdnatura/salix-front into 6426-refactorConstants
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-01-27 11:33:58 +01:00
Pablo Natek 84c92b8a98 refactor: refs #6897 clean up imports, update labels, and enhance localization entries in Entry components 2025-01-27 08:58:58 +01:00
Pablo Natek ece705b0ae Merge branch 'dev' of https: refs #6897//gitea.verdnatura.es/verdnatura/salix-front into 6897-entryBuyListRefactor 2025-01-27 08:21:06 +01:00
Pablo Natek f33c4d42bf refactor: refs #6897 clean up unused code, enhance input components, and add new localization entries 2025-01-27 08:11:28 +01:00
Javier Segarra 36a67e4c73 perf: refs #6321 clean pr 2025-01-26 03:06:57 +01:00
Javier Segarra 100a380f95 test: refs #6321 itemProposal 2025-01-26 02:36:10 +01:00
Javier Segarra dea3535ad4 feat: refs #6321 itemProposal tags 2025-01-26 02:35:59 +01:00
Javier Segarra 0a4da26d3d feat: refs #6321 remove checkbox isFree 2025-01-26 02:35:13 +01:00
Javier Segarra fa83c2d49c test: refs #6321 improve 2025-01-26 00:37:30 +01:00
Javier Segarra c88be1c6a8 perf: refs #6321 clean code vntable detail 2025-01-26 00:35:27 +01:00
Javier Segarra ebca833d73 test: refs #6321 intercept 2025-01-25 20:24:10 +01:00
Javier Segarra db777bec72 feat: refs #6321 replace ItemProposal by dialog 2025-01-25 14:23:52 +01:00
Javier Segarra 3d18d2d652 feat: refs #6321 merge icon column 2025-01-25 14:23:38 +01:00
Javier Segarra d9237c4a38 feat: refs #6321 lactTable icons 2025-01-25 13:47:31 +01:00
Javier Segarra 85a0e328e3 feat: refs #6321 lackDetail actions 2025-01-25 13:27:29 +01:00
Javier Segarra 21ea6a278d feat: refs #6321 clean ticket lack list 2025-01-25 09:41:19 +01:00
Javier Segarra 266c3d26ad Merge branch 'dev' into 6321_negative_tickets 2025-01-25 09:23:16 +01:00
Javier Segarra 5161aaf53d Merge branch 'dev' into 6321_negative_tickets 2025-01-24 07:38:59 +01:00
Javier Segarra 60e9346333 revert: refs #6321 restore some components 2025-01-22 07:04:22 +01:00
Javier Segarra f97bd98c00 revert: refs #6321 restore some components 2025-01-22 07:01:19 +01:00
Javier Segarra d4fecd8d85 Merge branch 'dev' into 6321_negative_tickets 2025-01-21 23:44:12 +01:00
Javier Segarra 38d1beff5b feat: refs #6321 updates 2025-01-20 14:37:13 +01:00
Javier Segarra 24eaaacb19 feat: refs #6321 updates 2025-01-20 09:43:21 +01:00
Jon Elias 05a310d9af fix: refs #8246 fix list field and modified basic-data to adapt to requirements
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-01-17 13:04:14 +01:00
Jon Elias 907cb87c34 Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix-front into 8246-ZoneAddressFk2 2025-01-17 11:36:32 +01:00
Jon Elias 2f3b0c59ad Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix-front into 8246-ZoneAddressFk2 2025-01-17 08:18:41 +01:00
Carlos Satorres 0338e0ea45 fix: refs #6426 create constants
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-01-16 10:42:58 +01:00
PAU ROVIRA ROSALENY 89947f96cd Merge branch 'dev' into 8322-Supplier
gitea/salix-front/pipeline/pr-dev There was a failure building this commit Details
2025-01-16 08:45:09 +00:00
Javier Segarra 442f74fce0 feat: refs #6321 tags 2025-01-16 07:02:13 +01:00
Javier Segarra 518dc56eb2 fix: refs #6321 solve conflicts 2025-01-15 13:19:30 +01:00
PAU ROVIRA ROSALENY 656b736119 Merge branch 'dev' into 8322-Supplier
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-01-14 12:12:30 +00:00
PAU ROVIRA ROSALENY 8aaab2c25c refactor: refs #8322 changed supplier component to use VnSection/VnCardBeta 2025-01-14 13:12:04 +01:00
Javier Segarra 5c295ebd33 fix: refs #6321 ticket-router 2025-01-14 12:29:31 +01:00
Javier Segarra af56321377 Merge branch 'dev' into 6321_negative_tickets 2025-01-14 12:22:46 +01:00
Jon Elias 4826b681ce refactor: refs #8246 modified addressFk field to use dashIfEmpty filter
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-01-13 14:58:47 +01:00
Pablo Natek 0d146cb3bc Merge branch 'dev' of https: refs #6897//gitea.verdnatura.es/verdnatura/salix-front into 6897-entryBuyListRefactor 2024-12-30 11:33:54 +01:00
Javier Segarra e6c48ce468 fix: refs #6321 solver keys duplicated 2024-12-09 14:35:43 +01:00
Javier Segarra 6573b04dab Merge branch 'dev' into 6321_negative_tickets 2024-12-09 14:34:42 +01:00
Pablo Natek 11e570360d feat: refs #6897 add tabs and string checkbox
gitea/salix-front/pipeline/pr-dev There was a failure building this commit Details
2024-10-26 10:02:12 +02:00
Pablo Natek 54ace8c682 refactor: refs #6897 refactor vnTable for non input editable table
gitea/salix-front/pipeline/pr-dev There was a failure building this commit Details
2024-10-23 10:47:44 +02:00
Pablo Natek 6dd0b32389 feat: refs #6897 editable table on field click 2024-10-19 08:45:46 +02:00
Pablo Natek 70decb68ea refactor: refs #6897 entryBuyList use vnTable 2024-10-08 12:33:48 +02:00
Javier Segarra fea760d2f9 Merge branch 'dev' into 6321_negative_tickets
gitea/salix-front/pipeline/pr-dev There was a failure building this commit Details
2024-09-24 22:14:04 +02:00
Javier Segarra 38967931b9 feat: refs #6321 updates 2024-09-24 22:13:00 +02:00
Javier Segarra d7f37eff32 feat: refs #6321 updates 2024-09-24 22:11:41 +02:00
Javier Segarra 7da3f132ea feat: refs #6321 update 2024-09-24 13:54:58 +02:00
Javier Segarra d0eb1d97ac fet: updates 2024-09-18 13:10:11 +02:00
Javier Segarra 53b522c488 Merge branch 'dev' into 6321_negative_tickets 2024-09-18 09:15:36 +02:00
Javier Segarra 1c7bcc8902 Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix-front into 6321_negative_tickets
gitea/salix-front/pipeline/pr-dev There was a failure building this commit Details
2024-09-17 16:43:42 +02:00
Javier Segarra 01cc2d4e75 fet: updates
gitea/salix-front/pipeline/pr-dev There was a failure building this commit Details
2024-09-17 16:42:22 +02:00
Javier Segarra 71236c0a01 fix: remove slot 2024-09-17 14:29:26 +02:00
Javier Segarra 9379e80df7 fix: routing 2024-09-17 14:20:01 +02:00
Javier Segarra 8c6e399fd2 feat: remove comments 2024-09-17 14:06:14 +02:00
Javier Segarra 26eae51585 Merge branch 'dev' into 6321_negative_tickets
gitea/salix-front/pipeline/pr-dev There was a failure building this commit Details
2024-09-17 11:43:47 +02:00
Javier Segarra 2c81ddb4aa feat: updates 2024-09-17 11:41:29 +02:00
Javier Segarra b5db786b06 feat: upodates 2024-09-16 12:15:15 +02:00
Javier Segarra 0a3703532e feat: itemProposalProxy
gitea/salix-front/pipeline/pr-dev There was a failure building this commit Details
2024-09-16 10:47:41 +02:00
Javier Segarra 8be1a42c53 Merge branch 'dev' into 6321_negative_tickets 2024-09-16 09:48:22 +02:00
Javier Segarra d16786d3e1 feat: updates TicketTable 2024-09-12 08:40:19 +02:00
Javier Segarra ff918b8a1c feat: updates ItemProposal 2024-09-11 23:29:59 +02:00
Javier Segarra 9ec1c5ff4b feat: updates ItemProposal 2024-09-11 23:17:38 +02:00
Javier Segarra 373ca0b3f1 feat:TicketLackTable updates 2024-09-11 14:25:10 +02:00
Javier Segarra 5e89bbe19e fix: remove unnesed imports 2024-09-11 12:55:14 +02:00
Javier Segarra d6bb39236d feat: implement VnTable 2024-09-11 12:43:24 +02:00
Javier Segarra b0a439c26c fix: ticketLackList 2024-09-11 11:26:25 +02:00
Javier Segarra 78c5836431 Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix-front into 6321_negative_tickets
gitea/salix-front/pipeline/pr-dev There was a failure building this commit Details
2024-09-11 08:50:39 +02:00
Javier Segarra 437d70d415 perf: TransferSale and implementations 2024-07-23 12:33:11 +02:00
Javier Segarra a53f4bd957 feat: QPopupProxy updateNegativeOrigin 2024-07-22 20:22:32 +02:00
Javier Segarra 3979a328e9 WIP: 28213bcc minor i18n updates 2024-07-22 17:30:15 +02:00
Javier Segarra 28213bcce6 minor i18n updates
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2024-07-20 00:37:13 +02:00
Javier Segarra 7c8ddf9c2b Merge branch 'dev' into 6321_negative_tickets 2024-07-20 00:22:37 +02:00
Javier Segarra c45ff7009c Merge branch 'dev' into 6321_negative_tickets
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2024-07-18 22:04:30 +02:00
Javier Segarra a6cd75a210 feat: Julia icon proposal
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2024-07-04 17:27:59 +02:00
Javier Segarra 189784872f feat: substitution icons
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2024-07-04 09:39:27 +02:00
Javier Segarra 8714be1fa7 feat: define new CustomerDescriptorMenu action. Pending reactivity
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2024-07-03 23:07:50 +02:00
Javier Segarra 87928ea7b6 feat: add new icons. Pending to define icon name 2024-07-03 23:07:44 +02:00
Javier Segarra f52ba11f42 Merge remote-tracking branch 'origin/dev' into 6321_negative_tickets 2024-07-03 23:07:25 +02:00
Javier Segarra 9c8094a3d8 Merge branch 'dev' into 6321_negative_tickets
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2024-07-02 20:31:44 +02:00
Javier Segarra 32fe76aaab feat: Vndescriptor 2024-07-02 20:28:13 +02:00
Javier Segarra c3d97231d2 Merge branch 'dev' into 6321_negative_tickets 2024-07-02 12:20:58 +02:00
Javier Segarra e76daac3be feat: cherryPick TicketTransfer
gitea/salix-front/pipeline/pr-dev There was a failure building this commit Details
2024-06-20 00:06:00 +02:00
Javier Segarra 3ff0d2139a feat: call latestBuysFilter 2024-06-20 00:01:33 +02:00
Javier Segarra bb92d75e00 test: #6321 boilerplate tests 2024-06-20 00:01:12 +02:00
Javier Segarra 1367c372e3 handle replaceItem 2024-06-19 15:25:57 +02:00
Javier Segarra 86cfbace72 feat: #6321 remove row 2024-06-19 13:18:32 +02:00
Javier Segarra 185160aeba feat: use Popover instead dialog 2024-06-18 22:49:55 +02:00
Javier Segarra cd5a64fcc6 fat: #6321 handle events through components 2024-06-17 22:32:39 +02:00
Javier Segarra 20e439f31e feat: ItemProposal difference column
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2024-06-17 12:37:52 +02:00
Javier Segarra 6ef53e790a feat: itemProposal and LackDetail 2024-06-17 12:19:57 +02:00
Javier Segarra 7b047e1637 updates
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2024-06-14 13:44:33 +02:00
Javier Segarra 679710eb4d updates 2024-06-13 14:55:49 +02:00
Javier Segarra bb58f72e3f updates 2024-06-13 09:37:39 +02:00
Javier Segarra 1641ad396c Merge branch 'dev' into 6321_negative_tickets 2024-06-12 23:07:14 +02:00
Javier Segarra f816cb9240 perf: TicketLackLit 2024-06-12 23:06:56 +02:00
Javier Segarra 4226c52fc5 perf: ItemProposal 2024-06-12 22:23:58 +02:00
Javier Segarra 8d9bfd8f1d Merge branch 'dev' into 6321_negative_tickets
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2024-06-11 13:52:48 +02:00
Javier Segarra b370fe673b updates 2024-06-10 17:06:20 +02:00
Javier Segarra fd4ff94f4c feat: #6321 Update handleSplitted form
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2024-06-04 14:14:16 +02:00
Javier Segarra 5b1819f7da Merge branch 'dev' into 6321_negative_tickets 2024-06-04 09:27:46 +02:00
Javier Segarra 79548f5041 updates
gitea/salix-front/pipeline/pr-dev There was a failure building this commit Details
2024-05-30 06:46:30 +02:00
Javier Segarra d3b93b710d updates 2024-05-28 13:07:22 +02:00
Javier Segarra 577c21e601 Merge branch 'dev' into 6321_negative_tickets
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2024-05-28 12:48:00 +02:00
Javier Segarra 36d166ab44 feat: #6321 Split tickets
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2024-05-24 13:52:51 +02:00
Javier Segarra 1eedb6f79b perf: #6321 updates 2024-05-24 11:54:31 +02:00
Javier Segarra ceae5eaa9e Merge branch 'dev' into 6321_negative_tickets 2024-05-24 11:21:06 +02:00
Javier Segarra f0333dfd01 feat: Refactor negativeDetail 2024-05-16 12:01:56 +02:00
Javier Segarra 372e797059 feat: recover split
gitea/salix-front/pipeline/pr-dev There was a failure building this commit Details
2024-05-15 16:25:25 +02:00
Javier Segarra b03578eb65 feat: header itemProposal dialog 2024-05-15 16:09:26 +02:00
Javier Segarra 1c15a02a5f perf: i18n ItemProposal 2024-05-15 15:45:24 +02:00
Javier Segarra bb6a8c0052 feat: remove alertLevelCode column 2024-05-15 15:45:08 +02:00
Javier Segarra 58597bdddf Merge branch 'dev' into 6321_negative_tickets
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2024-05-15 08:55:47 +02:00
Javier Segarra 1ca7420207 feat: replace item 2024-05-15 08:54:22 +02:00
Javier Segarra fffd662cee feat: reload ticket detail when update state/qty 2024-05-15 08:14:50 +02:00
Javier Segarra e07e62abb4 updates 2024-05-14 14:41:34 +02:00
Javier Segarra df911e0210 feat: itemProposal selection 2024-05-14 09:55:36 +02:00
Javier Segarra ad64ee4755 feat: change Qdialog sizing 2024-05-14 08:45:46 +02:00
Javier Segarra 3e39ab7fc2 Merge branch '6321_negative_tickets' of https://gitea.verdnatura.es/verdnatura/salix-front into 6321_negative_tickets
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2024-05-13 13:51:18 +02:00
Javier Segarra e6b360ee4b fix: vnfilterPanel 2024-05-13 13:51:15 +02:00
Jorge Penadés 99ea8e843c Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix-front into 6321_negative_tickets
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2024-05-13 13:22:39 +02:00
Javier Segarra ebdc1e9906 updates
gitea/salix-front/pipeline/pr-dev There was a failure building this commit Details
2024-05-13 13:18:22 +02:00
Javier Segarra 0eab0a9a98 feat: #6321 Modals change qty and state
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2024-05-08 15:35:04 +02:00
Javier Segarra 881e059121 feat: #6321 Show Free lines 2024-05-08 14:06:23 +02:00
Javier Segarra 0984d05220 Merge branch 'fix_minor_styles' into 6321_negative_tickets 2024-05-08 13:44:40 +02:00
Javier Segarra 61519595a9 Merge branch 'dev' into 6321_negative_tickets
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2024-05-08 12:30:01 +02:00
Javier Segarra c03875838f feat: minor updates
gitea/salix-front/pipeline/pr-dev There was a failure building this commit Details
2024-05-02 15:18:14 +02:00
Javier Segarra 6323f165a0 perf: updates 2024-05-02 13:53:40 +02:00
Javier Segarra 1907301852 Merge branch 'dev' into 6321_negative_tickets 2024-05-02 12:48:45 +02:00
Javier Segarra 2c59e6acc3 Merge branch 'dev' into 6321_negative_tickets
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2024-04-30 15:25:10 +02:00
Javier Segarra 1929545e5b feat: itemProposal table
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2024-04-30 15:23:49 +02:00
Javier Segarra 0988936884 feat: frmItemProposal show 2024-04-30 14:51:49 +02:00
Javier Segarra 1d4549439c feat: remove agName
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2024-04-29 15:09:10 +02:00
Javier Segarra b7bfb4b056 feat: updates 2024-04-29 15:08:12 +02:00
Javier Segarra 56a6f24071 feat: family filter 2024-04-29 14:21:39 +02:00
Javier Segarra 1ccad36020 feat: remove unnused filters 2024-04-29 13:25:18 +02:00
Javier Segarra df29ad31fd minor changes 2024-04-29 13:22:31 +02:00
Javier Segarra 7108444a44 fix: 1. Warehouse default 2024-04-29 13:22:23 +02:00
Javier Segarra 5425902918 Merge branch 'dev' into 6321_negative_tickets
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2024-04-29 11:55:56 +02:00
Javier Segarra 4049fa5c4a feat: #6321 replace dialog into layout 2024-04-23 12:50:34 +02:00
Javier Segarra 46aefa67d1 Merge remote-tracking branch 'origin/dev' into 6321_negative_tickets 2024-04-23 11:45:00 +02:00
Javier Segarra cc241c6a4e feat: #6321 new route
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2024-04-22 14:24:23 +02:00
Javier Segarra 5779d37bbd feat: #6321 i18n to yml 2024-04-22 14:08:58 +02:00
Javier Segarra 91c5d7092d Merge remote-tracking branch 'origin/dev' into 6321_negative_tickets 2024-04-22 13:34:00 +02:00
Javier Segarra a5350f686d refs #6321 fix: comments
gitea/salix-front/pipeline/pr-dev There was a failure building this commit Details
2024-04-15 12:28:01 +02:00
Javier Segarra cf0454669a refs #6321 fix: split disabled 2024-04-15 12:24:45 +02:00
Javier Segarra 6804196dbb warnings
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2024-04-08 09:35:17 +02:00
Javier Segarra 6c2c3b8f60 Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix-front into 6321_negative_tickets 2024-04-08 09:22:52 +02:00
Javier Segarra f6eaa99aeb refs #6321 fix: warnings
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2024-04-03 10:04:47 +02:00
Javier Segarra 2951e69a6a refs #6321 feat updateQuantity
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2024-04-03 09:58:04 +02:00
Javier Segarra 85fa394be0 refs #6321 perf: i18n
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2024-04-03 09:49:09 +02:00
Javier Segarra 5a497289da refs #6321 perf: i18n
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2024-04-03 08:41:20 +02:00
Javier Segarra 75e02bf328 change icon 2024-04-03 08:33:14 +02:00
Javier Segarra 370e52f7c4 refs #6321 perf: i18n 2024-04-02 13:25:51 +02:00
Javier Segarra 6b4dea6bf9 refs #6321 fix: filter menu 2024-04-02 13:13:29 +02:00
Javier Segarra 648a98d49d refs #6321 remove bad files 2024-04-02 09:57:59 +02:00
Javier Segarra 207097fa98 refs #6321 remove bad files 2024-04-02 09:56:31 +02:00
Javier Segarra f56934fcc4 refs #6321 perf change response object 2024-04-02 09:44:09 +02:00
Javier Segarra 48f88b5871 refs #6321 remove comments
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2024-04-02 08:17:44 +02:00
Javier Segarra 130c98ef17 refs #6321 remove comments
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2024-04-02 08:14:11 +02:00
Javier Segarra c16cc78ce6 refs #6321 remove bad files 2024-04-02 08:08:50 +02:00
Javier Segarra 0c88efc291 refs #6321 feat: status response after split
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2024-03-29 01:29:45 +01:00
Javier Segarra 967fb4592b Merge branch 'dev' into 6321_negative_tickets 2024-03-29 00:56:23 +01:00
Javier Segarra 697c467006 refs #6321 i18n: buttons tooltip 2024-03-29 00:56:10 +01:00
Javier Segarra 737ab9e99b updates
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2024-03-28 11:54:47 +01:00
Javier Segarra 30a32ad17d refs #6321 updates
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2024-03-28 07:17:06 +01:00
Javier Segarra 3a024e81b5 refs #6321 updates
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2024-03-27 15:20:15 +01:00
Javier Segarra fe12968dd6 refs #6321 fix: rowsSelected 2024-03-27 14:08:25 +01:00
Javier Segarra 81436a1641 refs #6321 feat changeState 2024-03-27 12:02:57 +01:00
Javier Segarra d65caaad07 refs #6321 perf: rename files 2024-03-27 10:19:49 +01:00
Javier Segarra 48aa8dad79 refs #6321 perf: i18n 2024-03-27 10:12:10 +01:00
Javier Segarra 1e09e9e4bb refs #6321 perf: move dialogs to new files 2024-03-27 10:07:27 +01:00
Javier Segarra 6b564bb648 refs #6321 feat: use tokenMultimedia 2024-03-27 10:06:57 +01:00
Javier Segarra 41cf7d242b Merge branch 'dev' into 6321_negative_tickets 2024-03-27 09:53:14 +01:00
Javier Segarra 174d159d04 refs #6321 i18n 2024-03-22 11:46:40 +01:00
Javier Segarra 6e701bd455 refs #6321 updates 2024-03-21 10:14:44 +01:00
Javier Segarra 527c845356 Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix-front into 6321_negative_tickets 2024-03-21 07:48:07 +01:00
Javier Segarra c51feab746 Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix-front into 6321_negative_tickets 2024-03-15 12:22:01 +01:00
Javier Segarra b3cbc64efb refs #6321 perf: i18n
gitea/salix-front/pipeline/pr-dev There was a failure building this commit Details
2024-03-15 12:15:03 +01:00
Javier Segarra 92555f8ddb refs #6321 feat: negativeOrigin modal 2024-03-15 11:31:19 +01:00
Javier Segarra 674b8bb1dc refs #6321 perf: updates 2024-03-15 09:36:30 +01:00
Javier Segarra e264a13234 warnings 2024-03-15 09:36:15 +01:00
Javier Segarra 5326d9db88 refs #6321 perf: update
gitea/salix-front/pipeline/pr-dev There was a failure building this commit Details
2024-03-14 15:26:07 +01:00
Javier Segarra 79e2bddeea Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix-front into 6321_negative_tickets 2024-03-14 15:01:58 +01:00
Javier Segarra 2436db1c28 refs #6321 perf: update 2024-03-14 14:21:02 +01:00
Javier Segarra bffc496965 Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix-front into 6321_negative_tickets 2024-03-14 13:04:05 +01:00
Javier Segarra 322c195175 refs #6321 feat: i18n improves 2024-03-13 14:27:21 +01:00
Javier Segarra 80b881edb5 refs #6321 fix: bug when retrieve token 2024-03-07 09:50:19 +01:00
Javier Segarra d10c04d4f2 refs #6321 feat: change dialog header
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2024-03-06 20:46:13 +01:00
Javier Segarra 0dd89ec3f0 refs #6321 perf: rename files 2024-03-06 20:45:53 +01:00
Javier Segarra 51b8667938 Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix-front into 6321_negative_tickets 2024-03-06 13:51:59 +01:00
Javier Segarra 7254f91645 refs #6321 feat: updates i18n dialog
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2024-03-05 12:59:59 +01:00
Javier Segarra 59e260d448 refs #6321 feat: updates dialog 2024-03-05 12:59:45 +01:00
Javier Segarra 3a7e092efe Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix-front into 6321_negative_tickets
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2024-03-05 08:06:05 +01:00
Javier Segarra 67eb21b707 refs #6321 feat: updates 2024-03-05 08:05:16 +01:00
Javier Segarra f44643fc61 refs #6664 perf: show dialog
gitea/salix-front/pipeline/head This commit looks good Details
gitea/salix-front/pipeline/pr-dev Build started... Details
2024-01-26 13:22:23 +01:00
Javier Segarra 1c51faaff4 Merge branch '6321_negative_tickets' of https://gitea.verdnatura.es/verdnatura/salix-front into 6321_negative_tickets
gitea/salix-front/pipeline/head This commit looks good Details
2024-01-23 11:14:50 +01:00
Javier Segarra f6f84e191b refs #6321 feat dialog approach 2024-01-23 11:14:46 +01:00
Alex Moreno d78c20d14b Merge branch 'dev' into 6321_negative_tickets
gitea/salix-front/pipeline/head This commit looks good Details
2024-01-22 10:41:04 +00:00
Javier Segarra c95b738e0c refs #6321 feat: create new section for ticket module
gitea/salix-front/pipeline/head This commit looks good Details
2024-01-20 12:23:51 +01:00
183 changed files with 6474 additions and 2369 deletions

View File

@ -14,8 +14,8 @@ export default defineConfig({
downloadsFolder: 'test/cypress/downloads',
video: false,
specPattern: 'test/cypress/integration/**/*.spec.js',
experimentalRunAllSpecs: true,
watchForFileChanges: true,
experimentalRunAllSpecs: false,
watchForFileChanges: false,
reporter: 'cypress-mochawesome-reporter',
reporterOptions: {
charts: true,

View File

@ -30,7 +30,6 @@ export default configure(function (/* ctx */) {
// --> boot files are part of "main.js"
// https://v2.quasar.dev/quasar-cli/boot-files
boot: ['i18n', 'axios', 'vnDate', 'validations', 'quasar', 'quasar.defaults'],
// https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#css
css: ['app.scss'],

View File

@ -0,0 +1,2 @@
export const langs = ['en', 'es'];
export const decimalPlaces = 2;

View File

@ -51,4 +51,5 @@ export default boot(({ app }) => {
await useCau(response, message);
};
app.provide('app', app);
});

View File

@ -64,6 +64,10 @@ const $props = defineProps({
type: Function,
default: null,
},
beforeSaveFn: {
type: Function,
default: null,
},
goTo: {
type: String,
default: '',
@ -176,7 +180,11 @@ async function saveChanges(data) {
hasChanges.value = false;
return;
}
const changes = data || getChanges();
let changes = data || getChanges();
if ($props.beforeSaveFn) {
changes = await $props.beforeSaveFn(changes, getChanges);
}
try {
await axios.post($props.saveUrl || $props.url + '/crud', changes);
} finally {
@ -229,12 +237,12 @@ async function remove(data) {
componentProps: {
title: t('globals.confirmDeletion'),
message: t('globals.confirmDeletionMessage'),
newData,
data: { deletes: ids },
ids,
promise: saveChanges,
},
})
.onOk(async () => {
await saveChanges({ deletes: ids });
newData = newData.filter((form) => !ids.some((id) => id == form[pk]));
fetch(newData);
});
@ -374,6 +382,8 @@ watch(formUrl, async () => {
@click="onSubmit"
:disable="!hasChanges"
:title="t('globals.save')"
v-shortcut="'s'"
shortcut="s"
data-cy="crudModelDefaultSaveBtn"
/>
<slot name="moreAfterActions" />

View File

@ -181,6 +181,7 @@ const selectTravel = ({ id }) => {
color="primary"
:disabled="isLoading"
:loading="isLoading"
data-cy="save-filter-travel-form"
/>
</div>
<QTable
@ -191,9 +192,10 @@ const selectTravel = ({ id }) => {
:no-data-label="t('Enter a new search')"
class="q-mt-lg"
@row-click="(_, row) => selectTravel(row)"
data-cy="table-filter-travel-form"
>
<template #body-cell-id="{ row }">
<QTd auto-width @click.stop>
<QTd auto-width @click.stop data-cy="travelFk-travel-form">
<QBtn flat color="blue">{{ row.id }}</QBtn>
<TravelDescriptorProxy :id="row.id" />
</QTd>

View File

@ -1,5 +1,5 @@
<script setup>
import { ref, computed } from 'vue';
import { ref, computed, onMounted } from 'vue';
import { useI18n } from 'vue-i18n';
import FormModel from 'components/FormModel.vue';
@ -15,23 +15,30 @@ defineProps({
type: String,
default: '',
},
showSaveAndContinueBtn: {
type: Boolean,
default: false,
},
});
const { t } = useI18n();
const formModelRef = ref(null);
const closeButton = ref(null);
const isSaveAndContinue = ref(false);
const onDataSaved = (formData, requestResponse) => {
if (closeButton.value) closeButton.value.click();
if (closeButton.value && isSaveAndContinue) closeButton.value.click();
emit('onDataSaved', formData, requestResponse);
};
const isLoading = computed(() => formModelRef.value?.isLoading);
const reset = computed(() => formModelRef.value?.reset);
defineExpose({
isLoading,
onDataSaved,
isSaveAndContinue,
reset,
});
</script>
@ -51,6 +58,19 @@ defineExpose({
<p>{{ subtitle }}</p>
<slot name="form-inputs" :data="data" :validate="validate" />
<div class="q-mt-lg row justify-end">
<QBtn
v-if="showSaveAndContinueBtn"
:label="t('globals.isSaveAndContinue')"
:title="t('globals.isSaveAndContinue')"
type="submit"
color="primary"
class="q-ml-sm"
:disabled="isLoading"
:loading="isLoading"
data-cy="FormModelPopup_isSaveAndContinue"
z-max
@click="() => (isSaveAndContinue = true)"
/>
<QBtn
:label="t('globals.cancel')"
:title="t('globals.cancel')"
@ -59,10 +79,15 @@ defineExpose({
flat
:disabled="isLoading"
:loading="isLoading"
@click="emit('onDataCanceled')"
v-close-popup
data-cy="FormModelPopup_cancel"
v-close-popup
z-max
@click="
() => {
isSaveAndContinue = false;
emit('onDataCanceled');
}
"
/>
<QBtn
:label="t('globals.save')"
@ -74,6 +99,7 @@ defineExpose({
:loading="isLoading"
data-cy="FormModelPopup_save"
z-max
@click="() => (isSaveAndContinue = false)"
/>
</div>
</template>

View File

@ -328,7 +328,6 @@ en:
active: Is active
visible: Is visible
floramondo: Is floramondo
salesPersonFk: Buyer
categoryFk: Category
es:
@ -339,7 +338,6 @@ es:
active: Activo
visible: Visible
floramondo: Floramondo
salesPersonFk: Comprador
categoryFk: Categoría
Plant: Planta natural
Flower: Flor fresca

View File

@ -26,6 +26,7 @@ const itemComputed = computed(() => {
:to="{ name: itemComputed.name }"
clickable
v-ripple
:data-cy="`${itemComputed.name}-menu-item`"
>
<QItemSection avatar v-if="itemComputed.icon">
<QIcon :name="itemComputed.icon" />

View File

@ -9,6 +9,7 @@ import VnSelect from 'components/common/VnSelect.vue';
import FormPopup from './FormPopup.vue';
import axios from 'axios';
import useNotify from 'src/composables/useNotify.js';
import VnCheckbox from 'src/components/common/VnCheckbox.vue';
const $props = defineProps({
invoiceOutData: {
@ -131,15 +132,11 @@ const refund = async () => {
:required="true"
/> </VnRow
><VnRow>
<div>
<QCheckbox
:label="t('Inherit warehouse')"
<VnCheckbox
v-model="invoiceParams.inheritWarehouse"
:label="t('Inherit warehouse')"
:info="t('Inherit warehouse tooltip')"
/>
<QIcon name="info" class="cursor-info q-ml-sm" size="sm">
<QTooltip>{{ t('Inherit warehouse tooltip') }}</QTooltip>
</QIcon>
</div>
</VnRow>
</template>
</FormPopup>

View File

@ -10,6 +10,7 @@ import VnSelect from 'components/common/VnSelect.vue';
import FormPopup from './FormPopup.vue';
import axios from 'axios';
import useNotify from 'src/composables/useNotify.js';
import VnCheckbox from './common/VnCheckbox.vue';
const $props = defineProps({
invoiceOutData: {
@ -186,15 +187,11 @@ const makeInvoice = async () => {
/>
</VnRow>
<VnRow>
<div>
<QCheckbox
:label="t('Bill destination client')"
<VnCheckbox
v-model="checked"
:label="t('Bill destination client')"
:info="t('transferInvoiceInfo')"
/>
<QIcon name="info" class="cursor-info q-ml-sm" size="sm">
<QTooltip>{{ t('transferInvoiceInfo') }}</QTooltip>
</QIcon>
</div>
</VnRow>
</template>
</FormPopup>

View File

@ -1,9 +1,8 @@
<script setup>
import { markRaw, computed } from 'vue';
import { QIcon, QCheckbox } from 'quasar';
import { QIcon, QCheckbox, QToggle } from 'quasar';
import { dashIfEmpty } from 'src/filters';
/* basic input */
import VnSelect from 'components/common/VnSelect.vue';
import VnSelectCache from 'components/common/VnSelectCache.vue';
import VnInput from 'components/common/VnInput.vue';
@ -12,8 +11,11 @@ import VnInputDate from 'components/common/VnInputDate.vue';
import VnInputTime from 'components/common/VnInputTime.vue';
import VnComponent from 'components/common/VnComponent.vue';
import VnUserLink from 'components/ui/VnUserLink.vue';
import VnSelectEnum from '../common/VnSelectEnum.vue';
import VnCheckbox from '../common/VnCheckbox.vue';
const model = defineModel(undefined, { required: true });
const emit = defineEmits(['blur']);
const $props = defineProps({
column: {
type: Object,
@ -39,10 +41,18 @@ const $props = defineProps({
type: Object,
default: null,
},
autofocus: {
type: Boolean,
default: false,
},
showLabel: {
type: Boolean,
default: null,
},
eventHandlers: {
type: Object,
default: null,
},
});
const defaultSelect = {
@ -99,7 +109,8 @@ const defaultComponents = {
},
},
checkbox: {
component: markRaw(QCheckbox),
ref: 'checkbox',
component: markRaw(VnCheckbox),
attrs: ({ model }) => {
const defaultAttrs = {
disable: !$props.isEditable,
@ -115,6 +126,10 @@ const defaultComponents = {
},
forceAttrs: {
label: $props.showLabel && $props.column.label,
autofocus: true,
},
events: {
blur: () => emit('blur'),
},
},
select: {
@ -125,12 +140,19 @@ const defaultComponents = {
component: markRaw(VnSelect),
...defaultSelect,
},
selectEnum: {
component: markRaw(VnSelectEnum),
...defaultSelect,
},
icon: {
component: markRaw(QIcon),
},
userLink: {
component: markRaw(VnUserLink),
},
toggle: {
component: markRaw(QToggle),
},
};
const value = computed(() => {
@ -160,7 +182,28 @@ const col = computed(() => {
return newColumn;
});
const components = computed(() => $props.components ?? defaultComponents);
const components = computed(() => {
const sourceComponents = $props.components ?? defaultComponents;
return Object.keys(sourceComponents).reduce((acc, key) => {
const component = sourceComponents[key];
if (!component || typeof component !== 'object') {
acc[key] = component;
return acc;
}
acc[key] = {
...component,
attrs: {
...(component.attrs || {}),
autofocus: $props.autofocus,
},
event: { ...component?.event, ...$props?.eventHandlers },
};
return acc;
}, {});
});
</script>
<template>
<div class="row no-wrap">

View File

@ -1,14 +1,12 @@
<script setup>
import { markRaw, computed } from 'vue';
import { QCheckbox } from 'quasar';
import { QCheckbox, QToggle } from 'quasar';
import { useArrayData } from 'composables/useArrayData';
/* basic input */
import VnSelect from 'components/common/VnSelect.vue';
import VnInput from 'components/common/VnInput.vue';
import VnInputDate from 'components/common/VnInputDate.vue';
import VnInputTime from 'components/common/VnInputTime.vue';
import VnTableColumn from 'components/VnTable/VnColumn.vue';
import VnColumn from 'components/VnTable/VnColumn.vue';
const $props = defineProps({
column: {
@ -27,6 +25,10 @@ const $props = defineProps({
type: String,
default: 'table',
},
customClass: {
type: String,
default: '',
},
});
defineExpose({ addFilter, props: $props });
@ -34,7 +36,7 @@ defineExpose({ addFilter, props: $props });
const model = defineModel(undefined, { required: true });
const arrayData = useArrayData(
$props.dataKey,
$props.searchUrl ? { searchUrl: $props.searchUrl } : null
$props.searchUrl ? { searchUrl: $props.searchUrl } : null,
);
const columnFilter = computed(() => $props.column?.columnFilter);
@ -46,19 +48,18 @@ const enterEvent = {
const defaultAttrs = {
filled: !$props.showTitle,
class: 'q-px-xs q-pb-xs q-pt-none fit',
dense: true,
};
const forceAttrs = {
label: $props.showTitle ? '' : columnFilter.value?.label ?? $props.column.label,
label: $props.showTitle ? '' : (columnFilter.value?.label ?? $props.column.label),
};
const selectComponent = {
component: markRaw(VnSelect),
event: updateEvent,
attrs: {
class: 'q-px-sm q-pb-xs q-pt-none fit',
class: `q-pt-none fit ${$props.customClass}`,
dense: true,
filled: !$props.showTitle,
},
@ -109,14 +110,24 @@ const components = {
component: markRaw(QCheckbox),
event: updateEvent,
attrs: {
dense: true,
class: $props.showTitle ? 'q-py-sm q-mt-md' : 'q-px-md q-py-xs fit',
class: $props.showTitle ? 'q-py-sm' : 'q-px-md q-py-xs fit',
'toggle-indeterminate': true,
size: 'sm',
},
forceAttrs,
},
select: selectComponent,
rawSelect: selectComponent,
toggle: {
component: markRaw(QToggle),
event: updateEvent,
attrs: {
class: $props.showTitle ? 'q-py-sm' : 'q-px-md q-py-xs fit',
'toggle-indeterminate': true,
size: 'sm',
},
forceAttrs,
},
};
async function addFilter(value, name) {
@ -132,19 +143,8 @@ async function addFilter(value, name) {
await arrayData.addFilter({ params: { [field]: value } });
}
function alignRow() {
switch ($props.column.align) {
case 'left':
return 'justify-start items-start';
case 'right':
return 'justify-end items-end';
default:
return 'flex-center';
}
}
const showFilter = computed(
() => $props.column?.columnFilter !== false && $props.column.name != 'tableActions'
() => $props.column?.columnFilter !== false && $props.column.name != 'tableActions',
);
const onTabPressed = async () => {
@ -152,13 +152,8 @@ const onTabPressed = async () => {
};
</script>
<template>
<div
v-if="showFilter"
class="full-width"
:class="alignRow()"
style="max-height: 45px; overflow: hidden"
>
<VnTableColumn
<div v-if="showFilter" class="full-width flex-center" style="overflow: hidden">
<VnColumn
:column="$props.column"
default="input"
v-model="model"
@ -168,3 +163,8 @@ const onTabPressed = async () => {
/>
</div>
</template>
<style lang="scss" scoped>
label.vn-label-padding > .q-field__inner > .q-field__control {
padding: inherit !important;
}
</style>

View File

@ -41,6 +41,7 @@ async function orderBy(name, direction) {
break;
}
if (!direction) return await arrayData.deleteOrder(name);
await arrayData.addOrder(name, direction);
}
@ -51,11 +52,11 @@ defineExpose({ orderBy });
@mouseenter="hover = true"
@mouseleave="hover = false"
@click="orderBy(name, model?.direction)"
class="row items-center no-wrap cursor-pointer"
class="row items-center no-wrap cursor-pointer title"
>
<span :title="label">{{ label }}</span>
<sup v-if="name && model?.index">
<QChip
v-if="name"
:label="!vertical ? model?.index : ''"
:icon="
(model?.index || hover) && !vertical
@ -71,7 +72,7 @@ defineExpose({ orderBy });
]"
class="no-box-shadow"
:clickable="true"
style="min-width: 40px"
style="min-width: 40px; max-height: 30px"
>
<div
class="column flex-center"
@ -91,5 +92,20 @@ defineExpose({ orderBy });
/>
</div>
</QChip>
</sup>
</div>
</template>
<style lang="scss" scoped>
.title {
display: flex;
justify-content: center;
align-items: center;
height: 30px;
width: 100%;
color: var(--vn-label-color);
}
sup {
vertical-align: super; /* Valor predeterminado */
/* También puedes usar otros valores como "baseline", "top", "text-top", etc. */
}
</style>

View File

@ -1,22 +1,37 @@
<script setup>
import { ref, onBeforeMount, onMounted, computed, watch, useAttrs } from 'vue';
import {
ref,
onBeforeMount,
onMounted,
onUnmounted,
computed,
watch,
h,
render,
inject,
useAttrs,
} from 'vue';
import { useArrayData } from 'src/composables/useArrayData';
import { useI18n } from 'vue-i18n';
import { useRoute, useRouter } from 'vue-router';
import { useQuasar } from 'quasar';
import { useStateStore } from 'stores/useStateStore';
import { useFilterParams } from 'src/composables/useFilterParams';
import { dashIfEmpty } from 'src/filters';
import CrudModel from 'src/components/CrudModel.vue';
import FormModelPopup from 'components/FormModelPopup.vue';
import VnTableColumn from 'components/VnTable/VnColumn.vue';
import VnColumn from 'components/VnTable/VnColumn.vue';
import VnFilter from 'components/VnTable/VnFilter.vue';
import VnTableChip from 'components/VnTable/VnChip.vue';
import VnVisibleColumn from 'src/components/VnTable/VnVisibleColumn.vue';
import VnLv from 'components/ui/VnLv.vue';
import VnTableOrder from 'src/components/VnTable/VnOrder.vue';
import VnTableFilter from './VnTableFilter.vue';
import { getColAlign } from 'src/composables/getColAlign';
const arrayData = useArrayData(useAttrs()['data-key']);
const $props = defineProps({
columns: {
type: Array,
@ -42,10 +57,6 @@ const $props = defineProps({
type: [Function, Boolean],
default: null,
},
rowCtrlClick: {
type: [Function, Boolean],
default: null,
},
redirect: {
type: String,
default: null,
@ -114,7 +125,19 @@ const $props = defineProps({
type: Boolean,
default: false,
},
withFilters: {
type: Boolean,
default: true,
},
overlay: {
type: Boolean,
default: false,
},
createComplement: {
type: Object,
},
});
const { t } = useI18n();
const stateStore = useStateStore();
const route = useRoute();
@ -132,10 +155,18 @@ const showForm = ref(false);
const splittedColumns = ref({ columns: [] });
const columnsVisibilitySkipped = ref();
const createForm = ref();
const createRef = ref(null);
const tableRef = ref();
const params = ref(useFilterParams($attrs['data-key']).params);
const orders = ref(useFilterParams($attrs['data-key']).orders);
const app = inject('app');
const editingRow = ref(null);
const editingField = ref(null);
const isTableMode = computed(() => mode.value == TABLE_MODE);
const showRightIcon = computed(() => $props.rightSearch || $props.rightSearchIcon);
const selectRegex = /select/;
const emit = defineEmits(['onFetch', 'update:selected', 'saveChanges']);
const tableModes = [
{
icon: 'view_column',
@ -156,7 +187,8 @@ onBeforeMount(() => {
hasParams.value = urlParams && Object.keys(urlParams).length !== 0;
});
onMounted(() => {
onMounted(async () => {
if ($props.isEditable) document.addEventListener('click', clickHandler);
mode.value =
quasar.platform.is.mobile && !$props.disableOption?.card
? CARD_MODE
@ -178,14 +210,25 @@ onMounted(() => {
}
});
onUnmounted(async () => {
if ($props.isEditable) document.removeEventListener('click', clickHandler);
});
watch(
() => $props.columns,
(value) => splitColumns(value),
{ immediate: true },
);
const isTableMode = computed(() => mode.value == TABLE_MODE);
const showRightIcon = computed(() => $props.rightSearch || $props.rightSearchIcon);
defineExpose({
create: createForm,
reload,
redirect: redirectFn,
selected,
CrudModelRef,
params,
tableRef,
});
function splitColumns(columns) {
splittedColumns.value = {
@ -231,16 +274,6 @@ const rowClickFunction = computed(() => {
return () => {};
});
const rowCtrlClickFunction = computed(() => {
if ($props.rowCtrlClick != undefined) return $props.rowCtrlClick;
if ($props.redirect)
return (evt, { id }) => {
stopEventPropagation(evt);
window.open(`/#/${$props.redirect}/${id}`, '_blank');
};
return () => {};
});
function redirectFn(id) {
router.push({ path: `/${$props.redirect}/${id}` });
}
@ -262,21 +295,6 @@ function columnName(col) {
return name;
}
function getColAlign(col) {
return 'text-' + (col.align ?? 'left');
}
const emit = defineEmits(['onFetch', 'update:selected', 'saveChanges']);
defineExpose({
create: createForm,
reload,
redirect: redirectFn,
selected,
CrudModelRef,
params,
tableRef,
});
function handleOnDataSaved(_) {
if (_.onDataSaved) _.onDataSaved({ CrudModelRef: CrudModelRef.value });
else $props.create.onDataSaved(_);
@ -304,6 +322,214 @@ function handleSelection({ evt, added, rows: selectedRows }, rows) {
}
}
}
function isEditableColumn(column) {
const isEditableCol = column?.isEditable ?? true;
const isVisible = column?.visible ?? true;
const hasComponent = column?.component;
return $props.isEditable && isVisible && hasComponent && isEditableCol;
}
function hasEditableFormat(column) {
if (isEditableColumn(column)) return 'editable-text';
}
const clickHandler = async (event) => {
const clickedElement = event.target.closest('td');
const isDateElement = event.target.closest('.q-date');
const isTimeElement = event.target.closest('.q-time');
if (isDateElement || isTimeElement) return;
if (clickedElement === null) {
destroyInput(editingRow.value, editingField.value);
return;
}
const rowIndex = clickedElement.getAttribute('data-row-index');
const colField = clickedElement.getAttribute('data-col-field');
const column = $props.columns.find((col) => col.name === colField);
if (editingRow.value !== null && editingField.value !== null) {
if (editingRow.value === rowIndex && editingField.value === colField) {
return;
}
destroyInput(editingRow.value, editingField.value);
}
if (isEditableColumn(column))
await renderInput(Number(rowIndex), colField, clickedElement);
};
async function handleTabKey(event, rowIndex, colField) {
if (editingRow.value == rowIndex && editingField.value == colField)
destroyInput(editingRow.value, editingField.value);
const direction = event.shiftKey ? -1 : 1;
const { nextRowIndex, nextColumnName } = await handleTabNavigation(
rowIndex,
colField,
direction,
);
if (nextRowIndex < 0 || nextRowIndex >= arrayData.store.data.length) return;
event.preventDefault();
await renderInput(nextRowIndex, nextColumnName, null);
}
async function renderInput(rowId, field, clickedElement) {
editingField.value = field;
editingRow.value = rowId;
const originalColumn = $props.columns.find((col) => col.name === field);
const column = { ...originalColumn, ...{ label: '' } };
const row = CrudModelRef.value.formData[rowId];
const oldValue = CrudModelRef.value.formData[rowId][column?.name];
if (!clickedElement)
clickedElement = document.querySelector(
`[data-row-index="${rowId}"][data-col-field="${field}"]`,
);
Array.from(clickedElement.childNodes).forEach((child) => {
child.style.visibility = 'hidden';
child.style.position = 'relative';
});
const isSelect = selectRegex.test(column?.component);
if (isSelect) column.attrs = { ...column.attrs, 'emit-value': false };
const node = h(VnColumn, {
row: row,
class: 'temp-input',
column: column,
modelValue: row[column.name],
componentProp: 'columnField',
autofocus: true,
focusOnMount: true,
eventHandlers: {
'update:modelValue': async (value) => {
if (isSelect) {
row[column.name] = value[column.attrs?.optionValue ?? 'id'];
row[column?.name + 'TextValue'] =
value[column.attrs?.optionLabel ?? 'name'];
await column?.cellEvent?.['update:modelValue']?.(
value,
oldValue,
row,
);
} else row[column.name] = value;
await column?.cellEvent?.['update:modelValue']?.(value, oldValue, row);
},
keyup: async (event) => {
if (event.key === 'Enter') handleBlur(rowId, field, clickedElement);
},
keydown: async (event) => {
switch (event.key) {
case 'Tab':
await handleTabKey(event, rowId, field);
event.stopPropagation();
break;
case 'Escape':
destroyInput(rowId, field, clickedElement);
break;
default:
break;
}
},
click: (event) => {
column?.cellEvent?.['click']?.(event, row);
},
},
});
node.appContext = app._context;
render(node, clickedElement);
if (['checkbox', 'toggle', undefined].includes(column?.component))
node.el?.querySelector('span > div').focus();
}
function destroyInput(rowIndex, field, clickedElement) {
if (!clickedElement)
clickedElement = document.querySelector(
`[data-row-index="${rowIndex}"][data-col-field="${field}"]`,
);
if (clickedElement) {
render(null, clickedElement);
Array.from(clickedElement.childNodes).forEach((child) => {
child.style.visibility = 'visible';
child.style.position = '';
});
}
if (editingRow.value !== rowIndex || editingField.value !== field) return;
editingRow.value = null;
editingField.value = null;
}
function handleBlur(rowIndex, field, clickedElement) {
destroyInput(rowIndex, field, clickedElement);
}
async function handleTabNavigation(rowIndex, colName, direction) {
const columns = $props.columns;
const totalColumns = columns.length;
let currentColumnIndex = columns.findIndex((col) => col.name === colName);
let iterations = 0;
let newColumnIndex = currentColumnIndex;
do {
iterations++;
newColumnIndex = (newColumnIndex + direction + totalColumns) % totalColumns;
if (isEditableColumn(columns[newColumnIndex])) break;
} while (iterations < totalColumns);
if (iterations >= totalColumns) {
return;
}
if (direction === 1 && newColumnIndex <= currentColumnIndex) {
rowIndex++;
} else if (direction === -1 && newColumnIndex >= currentColumnIndex) {
rowIndex--;
}
return { nextRowIndex: rowIndex, nextColumnName: columns[newColumnIndex].name };
}
function getCheckboxIcon(value) {
switch (typeof value) {
case 'boolean':
return value ? 'check' : 'close';
case 'number':
return value === 0 ? 'close' : 'check';
case 'undefined':
return 'indeterminate_check_box';
default:
return 'indeterminate_check_box';
}
}
function getToggleIcon(value) {
if (value === null) return 'help_outline';
return value ? 'toggle_on' : 'toggle_off';
}
function formatColumnValue(col, row, dashIfEmpty) {
if (col?.format) {
if (selectRegex.test(col?.component) && row[col?.name + 'TextValue']) {
return dashIfEmpty(row[col?.name + 'TextValue']);
} else {
return col.format(row, dashIfEmpty);
}
} else {
return dashIfEmpty(row[col?.name]);
}
}
const checkbox = ref(null);
</script>
<template>
<QDrawer
@ -311,7 +537,7 @@ function handleSelection({ evt, added, rows: selectedRows }, rows) {
v-model="stateStore.rightDrawer"
side="right"
:width="256"
show-if-above
:overlay="$props.overlay"
>
<QScrollArea class="fit">
<VnTableFilter
@ -332,7 +558,7 @@ function handleSelection({ evt, added, rows: selectedRows }, rows) {
<CrudModel
v-bind="$attrs"
:class="$attrs['class'] ?? 'q-px-md'"
:limit="$attrs['limit'] ?? 20"
:limit="$attrs['limit'] ?? 100"
ref="CrudModelRef"
@on-fetch="(...args) => emit('onFetch', ...args)"
:search-url="searchUrl"
@ -348,8 +574,12 @@ function handleSelection({ evt, added, rows: selectedRows }, rows) {
<QTable
ref="tableRef"
v-bind="table"
class="vnTable"
:class="{ 'last-row-sticky': $props.footer }"
:class="[
'vnTable',
table ? 'selection-cell' : '',
$props.footer ? 'last-row-sticky' : '',
]"
wrap-cells
:columns="splittedColumns.columns"
:rows="rows"
v-model:selected="selected"
@ -365,9 +595,10 @@ function handleSelection({ evt, added, rows: selectedRows }, rows) {
@selection="(details) => handleSelection(details, rows)"
>
<template #top-left v-if="!$props.withoutHeader">
<slot name="top-left"></slot>
<slot name="top-left"> </slot>
</template>
<template #top-right v-if="!$props.withoutHeader">
<slot name="top-right"></slot>
<VnVisibleColumn
v-if="isTableMode"
v-model="splittedColumns.columns"
@ -381,6 +612,7 @@ function handleSelection({ evt, added, rows: selectedRows }, rows) {
dense
:options="tableModes.filter((mode) => !mode.disable)"
/>
<QBtn
v-if="showRightIcon"
icon="filter_alt"
@ -392,32 +624,38 @@ function handleSelection({ evt, added, rows: selectedRows }, rows) {
<template #header-cell="{ col }">
<QTh
v-if="col.visible ?? true"
:style="col.headerStyle"
:class="col.headerClass"
class="body-cell"
:style="col?.width ? `max-width: ${col?.width}` : ''"
style="padding: inherit"
>
<div
class="column ellipsis"
:class="`text-${col?.align ?? 'left'}`"
:style="$props.columnSearch ? 'height: 75px' : ''"
class="no-padding"
:style="
withFilters && $props.columnSearch ? 'height: 75px' : ''
"
>
<div class="row items-center no-wrap" style="height: 30px">
<div class="text-center" style="height: 30px">
<QTooltip v-if="col.toolTip">{{ col.toolTip }}</QTooltip>
<VnTableOrder
v-model="orders[col.orderBy ?? col.name]"
:name="col.orderBy ?? col.name"
:label="col?.label"
:label="col?.labelAbbreviation ?? col?.label"
:data-key="$attrs['data-key']"
:search-url="searchUrl"
/>
</div>
<VnFilter
v-if="$props.columnSearch"
v-if="
$props.columnSearch &&
col.columnSearch !== false &&
withFilters
"
:column="col"
:show-title="true"
:data-key="$attrs['data-key']"
v-model="params[columnName(col)]"
:search-url="searchUrl"
class="full-width"
customClass="header-filter"
/>
</div>
</QTh>
@ -435,16 +673,27 @@ function handleSelection({ evt, added, rows: selectedRows }, rows) {
</QTd>
</template>
<template #body-cell="{ col, row, rowIndex }">
<!-- Columns -->
<QTd
auto-width
class="no-margin"
:class="[getColAlign(col), col.columnClass]"
:style="col.style"
class="no-margin q-px-xs"
v-if="col.visible ?? true"
@click.ctrl="
($event) =>
rowCtrlClickFunction && rowCtrlClickFunction($event, row)
:style="{
'max-width': col?.width ?? false,
position: 'relative',
}"
:class="[
col.columnClass,
'body-cell no-margin no-padding',
getColAlign(col),
]"
:data-row-index="rowIndex"
:data-col-field="col?.name"
>
<div
class="no-padding no-margin peter"
style="
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
"
>
<slot
@ -453,14 +702,34 @@ function handleSelection({ evt, added, rows: selectedRows }, rows) {
:row="row"
:row-index="rowIndex"
>
<VnTableColumn
:column="col"
:row="row"
:is-editable="col.isEditable ?? isEditable"
v-model="row[col.name]"
component-prop="columnField"
<QIcon
v-if="col?.component === 'toggle'"
:name="
col?.getIcon
? col.getIcon(row[col?.name])
: getToggleIcon(row[col?.name])
"
style="color: var(--vn-text-color)"
:class="hasEditableFormat(col)"
size="14px"
/>
<QIcon
v-else-if="col?.component === 'checkbox'"
:name="getCheckboxIcon(row[col?.name])"
style="color: var(--vn-text-color)"
:class="hasEditableFormat(col)"
size="14px"
/>
<span
v-else
:class="hasEditableFormat(col)"
:style="col?.style ? col.style(row) : null"
style="bottom: 0"
>
{{ formatColumnValue(col, row, dashIfEmpty) }}
</span>
</slot>
</div>
</QTd>
</template>
<template #body-cell-tableActions="{ col, row }">
@ -563,7 +832,7 @@ function handleSelection({ evt, added, rows: selectedRows }, rows) {
:row="row"
:row-index="index"
>
<VnTableColumn
<VnColumn
:column="col"
:row="row"
:is-editable="false"
@ -603,14 +872,17 @@ function handleSelection({ evt, added, rows: selectedRows }, rows) {
</component>
</template>
<template #bottom-row="{ cols }" v-if="$props.footer">
<QTr v-if="rows.length" style="height: 30px">
<QTr v-if="rows.length" style="height: 45px">
<QTh v-if="table.selection" />
<QTh
v-for="col of cols.filter((cols) => cols.visible ?? true)"
:key="col?.id"
class="text-center"
:class="getColAlign(col)"
>
<slot :name="`column-footer-${col.name}`" />
<slot
:name="`column-footer-${col.name}`"
:isEditableColumn="isEditableColumn(col)"
/>
</QTh>
</QTr>
</template>
@ -654,14 +926,33 @@ function handleSelection({ evt, added, rows: selectedRows }, rows) {
{{ createForm?.title }}
</QTooltip>
</QPageSticky>
<QDialog v-model="showForm" transition-show="scale" transition-hide="scale">
<QDialog
v-model="showForm"
transition-show="scale"
transition-hide="scale"
:full-width="createComplement?.isFullWidth ?? false"
@before-hide="
() => {
if (createRef.isSaveAndContinue) {
showForm = true;
createForm.formInitialData = { ...create.formInitialData };
}
}
"
data-cy="vn-table-create-dialog"
>
<FormModelPopup
ref="createRef"
v-bind="createForm"
:model="$attrs['data-key'] + 'Create'"
@on-data-saved="(_, res) => createForm.onDataSaved(res)"
>
<template #form-inputs="{ data }">
<div class="grid-create">
<div :style="createComplement?.containerStyle">
<div>
<slot name="previous-create-dialog" :data="data" />
</div>
<div class="grid-create" :style="createComplement?.columnGridStyle">
<slot
v-for="column of splittedColumns.create"
:key="column.name"
@ -670,17 +961,19 @@ function handleSelection({ evt, added, rows: selectedRows }, rows) {
:column-name="column.name"
:label="column.label"
>
<VnTableColumn
<VnColumn
:column="column"
:row="{}"
default="input"
v-model="data[column.name]"
:show-label="true"
component-prop="columnCreate"
:data-cy="`${column.name}-create-popup`"
/>
</slot>
<slot name="more-create-dialog" :data="data" />
</div>
</div>
</template>
</FormModelPopup>
</QDialog>
@ -697,6 +990,42 @@ es:
</i18n>
<style lang="scss">
.selection-cell {
table td:first-child {
padding: 0px;
}
}
.side-padding {
padding-left: 1px;
padding-right: 1px;
}
.editable-text:hover {
border-bottom: 1px dashed var(--q-primary);
@extend .side-padding;
}
.editable-text {
border-bottom: 1px dashed var(--vn-label-color);
@extend .side-padding;
}
.cell-input {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
padding-top: 0px !important;
}
.q-field--labeled .q-field__native,
.q-field--labeled .q-field__prefix,
.q-field--labeled .q-field__suffix {
padding-top: 20px;
}
.body-cell {
padding-left: 2px !important;
padding-right: 2px !important;
position: relative;
}
.bg-chip-secondary {
background-color: var(--vn-page-color);
color: var(--vn-text-color);
@ -713,7 +1042,7 @@ es:
.grid-three {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(350px, max-content));
grid-template-columns: repeat(auto-fit, minmax(150px, max-content));
max-width: 100%;
grid-gap: 20px;
margin: 0 auto;
@ -722,7 +1051,6 @@ es:
.grid-create {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, max-content));
max-width: 100%;
grid-gap: 20px;
margin: 0 auto;
}
@ -738,7 +1066,9 @@ es:
}
}
}
.q-table tbody tr td {
position: relative;
}
.q-table {
th {
padding: 0;
@ -838,4 +1168,15 @@ es:
.q-table__middle.q-virtual-scroll.q-virtual-scroll--vertical.scroll {
background-color: var(--vn-section-color);
}
.temp-input {
top: 0;
position: absolute;
width: 100%;
height: 100%;
display: flex;
}
label.header-filter > .q-field__inner > .q-field__control {
padding: inherit;
}
</style>

View File

@ -27,12 +27,13 @@ function columnName(col) {
</script>
<template>
<VnFilterPanel v-bind="$attrs" :search-button="true" :disable-submit-event="true">
<template #body="{ params, orders }">
<template #body="{ params, orders, searchFn }">
<div
class="row no-wrap flex-center"
class="container"
v-for="col of columns.filter((c) => c.columnFilter ?? true)"
:key="col.id"
>
<div class="filter">
<VnFilter
ref="tableFilterRef"
:column="col"
@ -40,6 +41,8 @@ function columnName(col) {
v-model="params[columnName(col)]"
:search-url="searchUrl"
/>
</div>
<div class="order">
<VnTableOrder
v-if="col?.columnFilter !== false && col?.name !== 'tableActions'"
v-model="orders[col.orderBy ?? col.name]"
@ -49,9 +52,11 @@ function columnName(col) {
:vertical="true"
/>
</div>
</div>
<slot
name="moreFilterPanel"
:params="params"
:search-fn="searchFn"
:orders="orders"
:columns="columns"
/>
@ -67,3 +72,21 @@ function columnName(col) {
</template>
</VnFilterPanel>
</template>
<style lang="scss" scoped>
.container {
display: flex;
justify-content: center;
align-items: center;
height: 45px;
gap: 10px;
}
.filter {
width: 70%;
height: 40px;
text-align: center;
}
.order {
width: 10%;
}
</style>

View File

@ -32,16 +32,21 @@ const areAllChecksMarked = computed(() => {
function setUserConfigViewData(data, isLocal) {
if (!data) return;
// Importante: El name de las columnas de la tabla debe conincidir con el name de las variables que devuelve la view config
if (!isLocal) localColumns.value = [];
// Array to Object
const skippeds = $props.skip.reduce((a, v) => ({ ...a, [v]: v }), {});
for (let column of columns.value) {
const { label, name } = column;
const { label, name, labelAbbreviation } = column;
if (skippeds[name]) continue;
column.visible = data[name] ?? true;
if (!isLocal) localColumns.value.push({ name, label, visible: column.visible });
if (!isLocal)
localColumns.value.push({
name,
label,
labelAbbreviation,
visible: column.visible,
});
}
}
@ -152,7 +157,11 @@ onMounted(async () => {
<QCheckbox
v-for="col in localColumns"
:key="col.name"
:label="col.label ?? col.name"
:label="
col?.labelAbbreviation
? col.labelAbbreviation + ` (${col.label ?? col.name})`
: (col.label ?? col.name)
"
v-model="col.visible"
/>
</div>

View File

@ -1,9 +1,13 @@
import { vi, describe, expect, it, beforeEach, beforeAll, afterEach } from 'vitest';
import { vi, describe, expect, it, beforeEach, afterEach } from 'vitest';
import { createWrapper } from 'app/test/vitest/helper';
import UserPanel from 'src/components/UserPanel.vue';
import axios from 'axios';
import { useState } from 'src/composables/useState';
vi.mock('src/utils/quasarLang', () => ({
default: vi.fn(),
}));
describe('UserPanel', () => {
let wrapper;
let vm;
@ -39,7 +43,7 @@ describe('UserPanel', () => {
await vm.saveDarkMode(true);
expect(axios.patch).toHaveBeenCalledWith('/UserConfigs/115', { darkMode: true });
expect(vm.user.darkMode).toBe(true);
vm.updatePreferences();
await vm.updatePreferences();
expect(vm.darkMode).toBe(true);
});
@ -48,7 +52,7 @@ describe('UserPanel', () => {
await vm.saveLanguage(userLanguage);
expect(axios.patch).toHaveBeenCalledWith('/VnUsers/115', { lang: userLanguage });
expect(vm.user.lang).toBe(userLanguage);
vm.updatePreferences();
await vm.updatePreferences();
expect(vm.locale).toBe(userLanguage);
});

View File

@ -0,0 +1,43 @@
<script setup>
import { computed } from 'vue';
const model = defineModel({ type: [Number, Boolean] });
const $props = defineProps({
info: {
type: String,
default: null,
},
});
const checkboxModel = computed({
get() {
if (typeof model.value === 'number') {
return model.value !== 0;
}
return model.value;
},
set(value) {
if (typeof model.value === 'number') {
model.value = value ? 1 : 0;
} else {
model.value = value;
}
},
});
</script>
<template>
<div>
<QCheckbox v-bind="$attrs" v-on="$attrs" v-model="checkboxModel" />
<QIcon
v-if="info"
v-bind="$attrs"
class="cursor-info q-ml-sm"
name="info"
size="sm"
>
<QTooltip>
{{ info }}
</QTooltip>
</QIcon>
</div>
</template>

View File

@ -0,0 +1,32 @@
<script setup>
const $props = defineProps({
colors: {
type: String,
default: '{"value":[]}',
},
});
const colorArray = JSON.parse($props.colors)?.value;
const maxHeight = 30;
const colorHeight = maxHeight / colorArray?.length;
</script>
<template>
<div class="color-div" :style="{ height: `${maxHeight}px` }">
<div
v-for="(color, index) in colorArray"
:key="index"
:style="{
backgroundColor: `#${color}`,
height: `${colorHeight}px`,
}"
>
&nbsp;
</div>
</div>
</template>
<style scoped>
.color-div {
display: flex;
flex-direction: column;
}
</style>

View File

@ -17,6 +17,8 @@ const $props = defineProps({
},
});
const emit = defineEmits(['blur']);
const componentArray = computed(() => {
if (typeof $props.prop === 'object') return [$props.prop];
return $props.prop;
@ -54,6 +56,7 @@ function toValueAttrs(attrs) {
v-bind="mix(toComponent).attrs"
v-on="mix(toComponent).event ?? {}"
v-model="model"
@blur="emit('blur')"
/>
</span>
</template>

View File

@ -11,6 +11,7 @@ const emit = defineEmits([
'update:options',
'keyup.enter',
'remove',
'blur',
]);
const $props = defineProps({
@ -136,6 +137,7 @@ const handleUppercase = () => {
:type="$attrs.type"
:class="{ required: isRequired }"
@keyup.enter="emit('keyup.enter')"
@blur="emit('blur')"
@keydown="handleKeydown"
:clearable="false"
:rules="mixinRules"
@ -143,7 +145,7 @@ const handleUppercase = () => {
hide-bottom-space
:data-cy="$attrs.dataCy ?? $attrs.label + '_input'"
>
<template #prepend>
<template #prepend v-if="$slots.prepend">
<slot name="prepend" />
</template>
<template #append>
@ -172,7 +174,7 @@ const handleUppercase = () => {
<QIcon
name="match_case"
size="xs"
v-if="!$attrs.disabled && !($attrs.readonly) && $props.uppercase"
v-if="!$attrs.disabled && !$attrs.readonly && $props.uppercase"
@click="handleUppercase"
class="uppercase-icon"
>
@ -194,7 +196,9 @@ const handleUppercase = () => {
<style>
.uppercase-icon {
transition: color 0.3s, transform 0.2s;
transition:
color 0.3s,
transform 0.2s;
cursor: pointer;
}

View File

@ -42,7 +42,7 @@ const formattedDate = computed({
if (value.at(2) == '/') value = value.split('/').reverse().join('/');
value = date.formatDate(
new Date(value).toISOString(),
'YYYY-MM-DDTHH:mm:ss.SSSZ'
'YYYY-MM-DDTHH:mm:ss.SSSZ',
);
}
const [year, month, day] = value.split('-').map((e) => parseInt(e));
@ -55,7 +55,7 @@ const formattedDate = computed({
orgDate.getHours(),
orgDate.getMinutes(),
orgDate.getSeconds(),
orgDate.getMilliseconds()
orgDate.getMilliseconds(),
);
}
}
@ -64,7 +64,7 @@ const formattedDate = computed({
});
const popupDate = computed(() =>
model.value ? date.formatDate(new Date(model.value), 'YYYY/MM/DD') : model.value
model.value ? date.formatDate(new Date(model.value), 'YYYY/MM/DD') : model.value,
);
onMounted(() => {
// fix quasar bug
@ -73,7 +73,7 @@ onMounted(() => {
watch(
() => model.value,
(val) => (formattedDate.value = val),
{ immediate: true }
{ immediate: true },
);
const styleAttrs = computed(() => {

View File

@ -8,6 +8,7 @@ defineProps({
});
const model = defineModel({ type: [Number, String] });
const emit = defineEmits(['blur']);
</script>
<template>
<VnInput
@ -24,5 +25,6 @@ const model = defineModel({ type: [Number, String] });
model = parseFloat(val).toFixed(decimalPlaces);
}
"
@blur="emit('blur')"
/>
</template>

View File

@ -0,0 +1,38 @@
<script setup>
import { ref } from 'vue';
defineProps({
label: {
type: String,
default: '',
},
icon: {
type: String,
required: true,
default: null,
},
color: {
type: String,
default: 'primary',
},
tooltip: {
type: String,
default: null,
},
});
const popupProxyRef = ref(null);
</script>
<template>
<QBtn :color="$props.color" :icon="$props.icon" :label="$t($props.label)">
<template #default>
<slot name="extraIcon"></slot>
<QPopupProxy ref="popupProxyRef" style="max-width: none">
<QCard>
<slot :popup="popupProxyRef"></slot>
</QCard>
</QPopupProxy>
<QTooltip>{{ $t($props.tooltip) }}</QTooltip>
</template>
</QBtn>
</template>

View File

@ -106,7 +106,14 @@ function checkIsMain() {
:data-key="dataKey"
:array-data="arrayData"
:columns="columns"
>
<template #moreFilterPanel="{ params, orders, searchFn }">
<slot
name="moreFilterPanel"
v-bind="{ params, orders, searchFn }"
/>
</template>
</VnTableFilter>
</slot>
</template>
</RightAdvancedMenu>

View File

@ -171,7 +171,8 @@ onMounted(() => {
});
const arrayDataKey =
$props.dataKey ?? ($props.url?.length > 0 ? $props.url : $attrs.name ?? $attrs.label);
$props.dataKey ??
($props.url?.length > 0 ? $props.url : ($attrs.name ?? $attrs.label));
const arrayData = useArrayData(arrayDataKey, {
url: $props.url,
@ -220,7 +221,7 @@ async function fetchFilter(val) {
optionFilterValue.value ??
(new RegExp(/\d/g).test(val)
? optionValue.value
: optionFilter.value ?? optionLabel.value);
: (optionFilter.value ?? optionLabel.value));
let defaultWhere = {};
if ($props.filterOptions.length) {
@ -239,7 +240,7 @@ async function fetchFilter(val) {
const { data } = await arrayData.applyFilter(
{ filter: filterOptions },
{ updateRouter: false }
{ updateRouter: false },
);
setOptions(data);
return data;
@ -272,7 +273,7 @@ async function filterHandler(val, update) {
ref.setOptionIndex(-1);
ref.moveOptionSelection(1, true);
}
}
},
);
}
@ -308,7 +309,7 @@ function handleKeyDown(event) {
if (inputValue) {
const matchingOption = myOptions.value.find(
(option) =>
option[optionLabel.value].toLowerCase() === inputValue.toLowerCase()
option[optionLabel.value].toLowerCase() === inputValue.toLowerCase(),
);
if (matchingOption) {
@ -320,11 +321,11 @@ function handleKeyDown(event) {
}
const focusableElements = document.querySelectorAll(
'a:not([disabled]), button:not([disabled]), input:not([disabled]), textarea:not([disabled]), select:not([disabled]), details:not([disabled]), [tabindex]:not([tabindex="-1"]):not([disabled])'
'a:not([disabled]), button:not([disabled]), input:not([disabled]), textarea:not([disabled]), select:not([disabled]), details:not([disabled]), [tabindex]:not([tabindex="-1"]):not([disabled])',
);
const currentIndex = Array.prototype.indexOf.call(
focusableElements,
event.target
event.target,
);
if (currentIndex >= 0 && currentIndex < focusableElements.length - 1) {
focusableElements[currentIndex + 1].focus();

View File

@ -14,7 +14,7 @@ const $props = defineProps({
},
});
const options = ref([]);
const emit = defineEmits(['blur']);
onBeforeMount(async () => {
const { url, optionValue, optionLabel } = useAttrs();
const findBy = $props.find ?? url?.charAt(0)?.toLocaleLowerCase() + url?.slice(1, -1);
@ -35,5 +35,5 @@ onBeforeMount(async () => {
});
</script>
<template>
<VnSelect v-bind="$attrs" :options="$attrs.options ?? options" />
<VnSelect v-bind="$attrs" :options="$attrs.options ?? options" @blur="emit('blur')" />
</template>

View File

@ -37,7 +37,6 @@ const isAllowedToCreate = computed(() => {
defineExpose({ vnSelectDialogRef: select });
</script>
<template>
<VnSelect
ref="select"
@ -67,7 +66,6 @@ defineExpose({ vnSelectDialogRef: select });
</template>
</VnSelect>
</template>
<style lang="scss" scoped>
.default-icon {
cursor: pointer;

View File

@ -1,9 +1,7 @@
<script setup>
import { computed } from 'vue';
import VnSelect from 'components/common/VnSelect.vue';
const model = defineModel({ type: [String, Number, Object] });
const url = 'Suppliers';
</script>
<template>
@ -11,11 +9,13 @@ const url = 'Suppliers';
:label="$t('globals.supplier')"
v-bind="$attrs"
v-model="model"
:url="url"
url="Suppliers"
option-value="id"
option-label="nickname"
:fields="['id', 'name', 'nickname', 'nif']"
:filter-options="['id', 'name', 'nickname', 'nif']"
sort-by="name ASC"
data-cy="vnSupplierSelect"
>
<template #option="scope">
<QItem v-bind="scope.itemProps">

View File

@ -0,0 +1,50 @@
<script setup>
import VnSelectDialog from './VnSelectDialog.vue';
import FilterTravelForm from 'src/components/FilterTravelForm.vue';
import { useI18n } from 'vue-i18n';
import { toDate } from 'src/filters';
const { t } = useI18n();
const $props = defineProps({
data: {
type: Object,
required: true,
},
onFilterTravelSelected: {
type: Function,
required: true,
},
});
</script>
<template>
<VnSelectDialog
:label="t('entry.basicData.travel')"
v-bind="$attrs"
url="Travels/filter"
:fields="['id', 'warehouseInName']"
option-value="id"
option-label="warehouseInName"
map-options
hide-selected
:required="true"
action-icon="filter_alt"
:roles-allowed-to-create="['buyer']"
>
<template #form>
<FilterTravelForm @travel-selected="onFilterTravelSelected(data, $event)" />
</template>
<template #option="scope">
<QItem v-bind="scope.itemProps">
<QItemSection>
<QItemLabel>
{{ scope.opt?.agencyModeName }} -
{{ scope.opt?.warehouseInName }}
({{ toDate(scope.opt?.shipped) }})
{{ scope.opt?.warehouseOutName }}
({{ toDate(scope.opt?.landed) }})
</QItemLabel>
</QItemSection>
</QItem>
</template>
</VnSelectDialog>
</template>

View File

@ -1,81 +0,0 @@
<script setup>
import { ref } from 'vue';
import VnSelect from 'src/components/common/VnSelect.vue';
import FetchData from 'components/FetchData.vue';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const model = defineModel({ type: String, required: true });
const countriesOption = ref([]);
const countriesOptionCopy = ref([]);
const lastVal = ref();
function handleBlur() {
if (lastVal.value == '') lastVal.value = null;
model.value = lastVal.value && lastVal.value.toUpperCase().slice(0, 2);
}
function filterFn(val, update) {
update(
() => {
if (val === '') {
countriesOptionCopy.value = JSON.parse(
JSON.stringify(countriesOption.value)
);
return;
}
const exist = countriesOption.value.filter((c) =>
c.code.toLowerCase().includes(val.toLowerCase())
);
if (exist) return (countriesOptionCopy.value = exist);
countriesOptionCopy.value = JSON.parse(JSON.stringify([{ code: val }]));
},
(ref) => {
if (val !== '' && ref.options.length > 0) {
ref.setOptionIndex(-1);
ref.moveOptionSelection(1, true);
}
}
);
}
</script>
<template>
<FetchData auto-load @on-fetch="(data) => (countriesOption = data)" url="Countries" />
<VnSelect
:label="t('Vies')"
v-model="model"
:input-debounce="0"
:options="countriesOptionCopy"
@input-value="(evt) => (lastVal = evt) && handleBlur()"
@filter="filterFn"
option-label="code"
option-value="code"
v-bind="$attrs"
>
<template #option="scope">
<QItem v-bind="scope.itemProps">
<QItemSection>
<QItemLabel>{{ scope.opt?.code }}</QItemLabel>
<QItemLabel caption>
{{ scope.opt?.code }},
{{ scope.opt?.name }}
</QItemLabel>
</QItemSection>
</QItem>
</template>
<template #after>
<QIcon name="info" class="cursor-pointer">
<QTooltip>{{ t('viesTip') }}</QTooltip>
</QIcon>
</template>
</VnSelect>
</template>
<i18n>
es:
viesTip: El campo puede contener valores que no este en la lista
en:
viesTip: The field may contain value that are not in the list
</i18n>

View File

@ -29,10 +29,6 @@ const $props = defineProps({
type: String,
default: null,
},
module: {
type: String,
default: null,
},
summary: {
type: Object,
default: null,
@ -57,7 +53,7 @@ defineExpose({ getData });
onBeforeMount(async () => {
arrayData = useArrayData($props.dataKey, {
url: $props.url,
filter: $props.filter,
userFilter: $props.filter,
skip: 0,
oneRecord: true,
});
@ -148,7 +144,9 @@ const toModule = computed(() =>
{{ t('components.smartCard.openSummary') }}
</QTooltip>
</QBtn>
<RouterLink :to="{ name: `${module}Summary`, params: { id: entity.id } }">
<RouterLink
:to="{ name: `${dataKey}Summary`, params: { id: entity.id } }"
>
<QBtn
class="link"
color="white"

View File

@ -1,53 +1,32 @@
<script setup>
defineProps({
hasImage: {
type: Boolean,
default: false,
},
});
</script>
<template>
<div id="descriptor-skeleton">
<div id="descriptor-skeleton" class="bg-vn-page">
<div class="row justify-between q-pa-sm">
<QSkeleton square size="40px" />
<QSkeleton square size="40px" />
<QSkeleton square height="40px" width="20px" />
<QSkeleton square size="30px" v-for="i in 3" :key="i" />
</div>
<div class="col justify-between q-pa-sm q-gutter-y-xs">
<QSkeleton square height="40px" width="150px" />
<QSkeleton square height="30px" width="70px" />
<div class="q-pa-xs" v-if="hasImage">
<QSkeleton square height="200px" width="100%" />
</div>
<div class="col q-pl-sm q-pa-sm q-mb-md">
<div class="row justify-between">
<QSkeleton type="text" square height="30px" width="20%" />
<QSkeleton type="text" square height="30px" width="60%" />
<div class="col justify-between q-pa-md q-gutter-y-xs">
<QSkeleton square height="25px" width="150px" />
<QSkeleton square height="15px" width="70px" />
</div>
<div class="row justify-between">
<QSkeleton type="text" square height="30px" width="20%" />
<QSkeleton type="text" square height="30px" width="60%" />
</div>
<div class="row justify-between">
<QSkeleton type="text" square height="30px" width="20%" />
<QSkeleton type="text" square height="30px" width="60%" />
</div>
<div class="row justify-between">
<QSkeleton type="text" square height="30px" width="20%" />
<QSkeleton type="text" square height="30px" width="60%" />
</div>
<div class="row justify-between">
<QSkeleton type="text" square height="30px" width="20%" />
<QSkeleton type="text" square height="30px" width="60%" />
</div>
<div class="row justify-between">
<QSkeleton type="text" square height="30px" width="20%" />
<QSkeleton type="text" square height="30px" width="60%" />
<div class="q-pl-sm q-pa-sm q-mb-md">
<div class="row q-gutter-x-sm q-pa-none q-ma-none" v-for="i in 5" :key="i">
<QSkeleton type="text" square height="20px" width="30%" />
<QSkeleton type="text" square height="20px" width="60%" />
</div>
</div>
<QCardActions>
<QSkeleton size="40px" />
<QSkeleton size="40px" />
<QSkeleton size="40px" />
<QSkeleton size="40px" />
<QSkeleton size="40px" />
<QCardActions class="q-gutter-x-sm justify-between">
<QSkeleton size="40px" v-for="i in 5" :key="i" />
</QCardActions>
</div>
</template>
<style lang="scss" scoped>
#descriptor-skeleton .q-card__actions {
justify-content: space-between;
}
</style>

View File

@ -82,7 +82,7 @@ function cancel() {
@click="cancel()"
/>
</QCardSection>
<QCardSection class="q-pb-none">
<QCardSection class="q-pb-none" data-cy="VnConfirm_message">
<span v-if="message !== false" v-html="message" />
</QCardSection>
<QCardSection class="row items-center q-pt-none">
@ -95,6 +95,7 @@ function cancel() {
:disable="isLoading"
flat
@click="cancel()"
data-cy="VnConfirm_cancel"
/>
<QBtn
:label="t('globals.confirm')"

View File

@ -293,6 +293,9 @@ const getLocale = (label) => {
/>
</template>
<style scoped lang="scss">
.q-field__label.no-pointer-events.absolute.ellipsis {
margin-left: 6px !important;
}
.list {
width: 256px;
}

View File

@ -11,7 +11,7 @@
<QTooltip>
{{ $t('components.cardDescriptor.moreOptions') }}
</QTooltip>
<QMenu ref="menuRef">
<QMenu ref="menuRef" data-cy="descriptor-more-opts-menu">
<QList>
<slot name="menu" :menu-ref="$refs.menuRef" />
</QList>

View File

@ -18,7 +18,12 @@ import VnInput from 'components/common/VnInput.vue';
const emit = defineEmits(['onFetch']);
const $attrs = useAttrs();
const originalAttrs = useAttrs();
const $attrs = computed(() => {
const { style, ...rest } = originalAttrs;
return rest;
});
const isRequired = computed(() => {
return Object.keys($attrs).includes('required')

View File

@ -0,0 +1,41 @@
<script setup>
import { toPercentage } from 'filters/index';
import { computed } from 'vue';
const props = defineProps({
value: {
type: Number,
required: true,
},
});
const valueClass = computed(() =>
props.value === 0 ? 'neutral' : props.value > 0 ? 'positive' : 'negative',
);
const iconName = computed(() =>
props.value === 0 ? 'equal' : props.value > 0 ? 'arrow_upward' : 'arrow_downward',
);
const formattedValue = computed(() => props.value);
</script>
<template>
<span :class="valueClass">
<QIcon :name="iconName" size="sm" class="value-icon" />
{{ toPercentage(formattedValue) }}
</span>
</template>
<style lang="scss" scoped>
.positive {
color: $secondary;
}
.negative {
color: $negative;
}
.neutral {
color: $primary;
}
.value-icon {
margin-right: 4px;
}
</style>

View File

@ -0,0 +1,65 @@
import { useQuasar } from 'quasar';
import { useI18n } from 'vue-i18n';
import { useRouter } from 'vue-router';
import axios from 'axios';
import VnConfirm from 'components/ui/VnConfirm.vue';
export async function checkEntryLock(entryFk, userFk) {
const { t } = useI18n();
const quasar = useQuasar();
const { push } = useRouter();
const { data } = await axios.get(`Entries/${entryFk}`, {
params: {
filter: JSON.stringify({
fields: ['id', 'locked', 'lockerUserFk'],
include: { relation: 'user', scope: { fields: ['id', 'nickname'] } },
}),
},
});
const entryConfig = await axios.get('EntryConfigs/findOne');
if (data?.lockerUserFk && data?.locked) {
const now = new Date(Date.vnNow()).getTime();
const lockedTime = new Date(data.locked).getTime();
const timeDiff = (now - lockedTime) / 1000;
const isMaxTimeLockExceeded = entryConfig.data.maxLockTime > timeDiff;
if (data?.lockerUserFk !== userFk && isMaxTimeLockExceeded) {
quasar
.dialog({
component: VnConfirm,
componentProps: {
'data-cy': 'entry-lock-confirm',
title: t('entry.lock.title'),
message: t('entry.lock.message', {
userName: data?.user?.nickname,
time: timeDiff / 60,
}),
},
})
.onOk(
async () =>
await axios.patch(`Entries/${entryFk}`, {
locked: Date.vnNow(),
lockerUserFk: userFk,
}),
)
.onCancel(() => {
push({ path: `summary` });
});
}
} else {
await axios
.patch(`Entries/${entryFk}`, {
locked: Date.vnNow(),
lockerUserFk: userFk,
})
.then(
quasar.notify({
message: t('entry.lock.success'),
color: 'positive',
group: false,
}),
);
}
}

View File

@ -0,0 +1,21 @@
export function getColAlign(col) {
let align;
switch (col.component) {
case 'select':
align = 'left';
break;
case 'number':
align = 'right';
break;
case 'date':
case 'checkbox':
align = 'center';
break;
default:
align = col?.align;
}
if (/^is[A-Z]/.test(col.name) || /^has[A-Z]/.test(col.name)) align = 'center';
return 'text-' + (align ?? 'center');
}

View File

@ -27,6 +27,15 @@ export function useRole() {
return false;
}
function likeAny(roles) {
const roleStore = state.getRoles();
for (const role of roles) {
if (!roleStore.value.findIndex((rs) => rs.startsWith(role)) !== -1)
return true;
}
return false;
}
function isEmployee() {
return hasAny(['employee']);
}
@ -35,6 +44,7 @@ export function useRole() {
isEmployee,
fetch,
hasAny,
likeAny,
state,
};
}

View File

@ -21,7 +21,10 @@ body.body--light {
.q-header .q-toolbar {
color: var(--vn-text-color);
}
--vn-color-negative: $negative;
}
body.body--dark {
--vn-header-color: #5d5d5d;
--vn-page-color: #222;
@ -37,6 +40,8 @@ body.body--dark {
--vn-text-color-contrast: black;
background-color: var(--vn-page-color);
--vn-color-negative: $negative;
}
a {
@ -75,7 +80,6 @@ a {
text-decoration: underline;
}
// Removes chrome autofill background
input:-webkit-autofill,
select:-webkit-autofill {
color: var(--vn-text-color);
@ -149,11 +153,6 @@ select:-webkit-autofill {
cursor: pointer;
}
.vn-table-separation-row {
height: 16px !important;
background-color: var(--vn-section-color) !important;
}
/* Estilo para el asterisco en campos requeridos */
.q-field.required .q-field__label:after {
content: ' *';
@ -230,10 +229,12 @@ input::-webkit-inner-spin-button {
max-width: 100%;
}
.q-table__container {
/* ===== Scrollbar CSS ===== /
/ Firefox */
.remove-bg {
filter: brightness(1.1);
mix-blend-mode: multiply;
}
.q-table__container {
* {
scrollbar-width: auto;
scrollbar-color: var(--vn-label-color) transparent;
@ -274,8 +275,6 @@ input::-webkit-inner-spin-button {
font-size: 11pt;
}
td {
font-size: 11pt;
border-top: 1px solid var(--vn-page-color);
border-collapse: collapse;
}
}
@ -319,9 +318,6 @@ input::-webkit-inner-spin-button {
max-width: fit-content;
}
.row > .column:has(.q-checkbox) {
max-width: fit-content;
}
.q-field__inner {
.q-field__control {
min-height: auto !important;

View File

@ -13,7 +13,7 @@
// Tip: Use the "Theme Builder" on Quasar's documentation website.
// Tip: to add new colors https://quasar.dev/style/color-palette/#adding-your-own-colors
$primary: #ec8916;
$secondary: $primary;
$secondary: #89be34;
$positive: #c8e484;
$negative: #fb5252;
$info: #84d0e2;
@ -30,7 +30,9 @@ $color-spacer: #7979794d;
$border-thin-light: 1px solid $color-spacer-light;
$primary-light: #f5b351;
$dark-shadow-color: black;
$layout-shadow-dark: 0 0 10px 2px #00000033, 0 0px 10px #0000003d;
$layout-shadow-dark:
0 0 10px 2px #00000033,
0 0px 10px #0000003d;
$spacing-md: 16px;
$color-font-secondary: #777;
$width-xs: 400px;

View File

@ -33,6 +33,7 @@ globals:
reset: Reset
close: Close
cancel: Cancel
isSaveAndContinue: Save and continue
clone: Clone
confirm: Confirm
assign: Assign
@ -167,6 +168,7 @@ globals:
workCenters: Work centers
modes: Modes
zones: Zones
negative: Negative
zonesList: List
deliveryDays: Delivery days
upcomingDeliveries: Upcoming deliveries
@ -174,6 +176,7 @@ globals:
alias: Alias
aliasUsers: Users
subRoles: Subroles
myAccount: Mi cuenta
inheritedRoles: Inherited Roles
customers: Customers
customerCreate: New customer
@ -406,6 +409,106 @@ cau:
subtitle: By sending this ticket, all the data related to the error, the section, the user, etc., are already sent.
inputLabel: Explain why this error should not appear
askPrivileges: Ask for privileges
entry:
list:
newEntry: New entry
tableVisibleColumns:
isExcludedFromAvailable: Exclude from inventory
isOrdered: Ordered
isConfirmed: Ready to label
isReceived: Received
isRaid: Raid
landed: Date
supplierFk: Supplier
reference: Ref/Alb/Guide
invoiceNumber: Invoice
agencyModeId: Agency
isBooked: Booked
companyFk: Company
evaNotes: Notes
warehouseOutFk: Origin
warehouseInFk: Destiny
entryTypeDescription: Entry type
invoiceAmount: Import
travelFk: Travel
summary:
invoiceAmount: Amount
commission: Commission
currency: Currency
invoiceNumber: Invoice number
ordered: Ordered
booked: Booked
excludedFromAvailable: Inventory
travelReference: Reference
travelAgency: Agency
travelShipped: Shipped
travelDelivered: Delivered
travelLanded: Landed
travelReceived: Received
buys: Buys
stickers: Stickers
package: Package
packing: Pack.
grouping: Group.
buyingValue: Buying value
import: Import
pvp: PVP
basicData:
travel: Travel
currency: Currency
commission: Commission
observation: Observation
booked: Booked
excludedFromAvailable: Inventory
buys:
observations: Observations
packagingFk: Box
color: Color
printedStickers: Printed stickers
notes:
observationType: Observation type
latestBuys:
tableVisibleColumns:
image: Picture
itemFk: Item ID
weightByPiece: Weight/Piece
isActive: Active
family: Family
entryFk: Entry
freightValue: Freight value
comissionValue: Commission value
packageValue: Package value
isIgnored: Is ignored
price2: Grouping
price3: Packing
minPrice: Min
ektFk: Ekt
packingOut: Package out
landing: Landing
isExcludedFromAvailable: Exclude from inventory
isRaid: Raid
invoiceNumber: Invoice
reference: Ref/Alb/Guide
params:
isExcludedFromAvailable: Excluir del inventario
isOrdered: Pedida
isConfirmed: Lista para etiquetar
isReceived: Recibida
isRaid: Redada
landed: Fecha
supplierFk: Proveedor
invoiceNumber: Nº Factura
reference: Ref/Alb/Guía
agencyModeId: Agencia
isBooked: Asentado
companyFk: Empresa
travelFk: Envio
evaNotes: Notas
warehouseOutFk: Origen
warehouseInFk: Destino
entryTypeDescription: Tipo entrada
invoiceAmount: Importe
dated: Fecha
ticket:
params:
ticketFk: Ticket ID
@ -635,6 +738,8 @@ wagon:
name: Name
supplier:
search: Search supplier
searchInfo: Search supplier by id or name
list:
payMethod: Pay method
account: Account

View File

@ -33,9 +33,11 @@ globals:
reset: Restaurar
close: Cerrar
cancel: Cancelar
isSaveAndContinue: Guardar y continuar
clone: Clonar
confirm: Confirmar
assign: Asignar
replace: Sustituir
back: Volver
yes: Si
no: No
@ -48,6 +50,7 @@ globals:
rowRemoved: Fila eliminada
pleaseWait: Por favor espera...
noPinnedModules: No has fijado ningún módulo
split: Split
summary:
basicData: Datos básicos
daysOnward: Días adelante
@ -55,8 +58,8 @@ globals:
today: Hoy
yesterday: Ayer
dateFormat: es-ES
microsip: Abrir en MicroSIP
noSelectedRows: No tienes ninguna línea seleccionada
microsip: Abrir en MicroSIP
downloadCSVSuccess: Descarga de CSV exitosa
reference: Referencia
agency: Agencia
@ -76,8 +79,10 @@ globals:
requiredField: Campo obligatorio
class: clase
type: Tipo
reason: motivo
reason: Motivo
removeSelection: Eliminar selección
noResults: Sin resultados
results: resultados
system: Sistema
notificationSent: Notificación enviada
warehouse: Almacén
@ -166,6 +171,7 @@ globals:
agency: Agencia
workCenters: Centros de trabajo
modes: Modos
negative: Tickets negativos
zones: Zonas
zonesList: Listado
deliveryDays: Días de entrega
@ -286,9 +292,9 @@ globals:
buyRequest: Peticiones de compra
wasteBreakdown: Deglose de mermas
itemCreate: Nuevo artículo
tax: 'IVA'
botanical: 'Botánico'
barcode: 'Código de barras'
tax: IVA
botanical: Botánico
barcode: Código de barras
itemTypeCreate: Nueva familia
family: Familia
lastEntries: Últimas entradas
@ -352,7 +358,7 @@ globals:
from: Desde
to: Hasta
supplierFk: Proveedor
supplierRef: Ref. proveedor
supplierRef: Nº factura
serial: Serie
amount: Importe
awbCode: AWB
@ -397,6 +403,87 @@ cau:
subtitle: Al enviar este cau ya se envían todos los datos relacionados con el error, la sección, el usuario, etc
inputLabel: Explique el motivo por el que no deberia aparecer este fallo
askPrivileges: Solicitar permisos
entry:
list:
newEntry: Nueva entrada
tableVisibleColumns:
isExcludedFromAvailable: Excluir del inventario
isOrdered: Pedida
isConfirmed: Lista para etiquetar
isReceived: Recibida
isRaid: Redada
landed: Fecha
supplierFk: Proveedor
invoiceNumber: Nº Factura
reference: Ref/Alb/Guía
agencyModeId: Agencia
isBooked: Asentado
companyFk: Empresa
travelFk: Envio
evaNotes: Notas
warehouseOutFk: Origen
warehouseInFk: Destino
entryTypeDescription: Tipo entrada
invoiceAmount: Importe
summary:
invoiceAmount: Importe
commission: Comisión
currency: Moneda
invoiceNumber: Núm. factura
ordered: Pedida
booked: Contabilizada
excludedFromAvailable: Inventario
travelReference: Referencia
travelAgency: Agencia
travelShipped: F. envio
travelWarehouseOut: Alm. salida
travelDelivered: Enviada
travelLanded: F. entrega
travelReceived: Recibida
buys: Compras
stickers: Etiquetas
package: Embalaje
packing: Pack.
grouping: Group.
buyingValue: Coste
import: Importe
pvp: PVP
basicData:
travel: Envío
currency: Moneda
observation: Observación
commission: Comisión
booked: Asentado
excludedFromAvailable: Inventario
buys:
observations: Observaciónes
packagingFk: Embalaje
color: Color
printedStickers: Etiquetas impresas
notes:
observationType: Tipo de observación
latestBuys:
tableVisibleColumns:
image: Foto
itemFk: Id Artículo
weightByPiece: Peso (gramos)/tallo
isActive: Activo
family: Familia
entryFk: Entrada
freightValue: Porte
comissionValue: Comisión
packageValue: Embalaje
isIgnored: Ignorado
price2: Grouping
price3: Packing
minPrice: Min
ektFk: Ekt
packingOut: Embalaje envíos
landing: Llegada
isExcludedFromAvailable: Excluir del inventario
isRaid: Redada
invoiceNumber: Nº Factura
reference: Ref/Alb/Guía
ticket:
params:
ticketFk: ID de ticket
@ -410,6 +497,38 @@ ticket:
freightItemName: Nombre
packageItemName: Embalaje
longName: Descripción
pageTitles:
tickets: Tickets
list: Listado
ticketCreate: Nuevo ticket
summary: Resumen
basicData: Datos básicos
boxing: Encajado
sms: Sms
notes: Notas
sale: Lineas del pedido
dms: Gestión documental
negative: Tickets negativos
volume: Volumen
observation: Notas
ticketAdvance: Adelantar tickets
futureTickets: Tickets a futuro
expedition: Expedición
purchaseRequest: Petición de compra
weeklyTickets: Tickets programados
saleTracking: Líneas preparadas
services: Servicios
tracking: Estados
components: Componentes
pictures: Fotos
packages: Bultos
list:
nickname: Alias
state: Estado
shipped: Enviado
landed: Entregado
salesPerson: Comercial
total: Total
card:
customerId: ID cliente
customerCard: Ficha del cliente
@ -456,15 +575,11 @@ ticket:
consigneeStreet: Dirección
create:
address: Dirección
order:
field:
salesPersonFk: Comercial
form:
clientFk: Cliente
addressFk: Dirección
agencyModeFk: Agencia
list:
newOrder: Nuevo Pedido
invoiceOut:
card:
issued: Fecha emisión
customerCard: Ficha del cliente
ticketList: Listado de tickets
summary:
issued: Fecha
dued: Fecha límite
@ -475,6 +590,71 @@ order:
fee: Cuota
tickets: Tickets
totalWithVat: Importe
globalInvoices:
errors:
chooseValidClient: Selecciona un cliente válido
chooseValidCompany: Selecciona una empresa válida
chooseValidPrinter: Selecciona una impresora válida
chooseValidSerialType: Selecciona una tipo de serie válida
fillDates: La fecha de la factura y la fecha máxima deben estar completas
invoiceDateLessThanMaxDate: La fecha de la factura no puede ser menor que la fecha máxima
invoiceWithFutureDate: Existe una factura con una fecha futura
noTicketsToInvoice: No existen tickets para facturar
criticalInvoiceError: Error crítico en la facturación proceso detenido
invalidSerialTypeForAll: El tipo de serie debe ser global cuando se facturan todos los clientes
table:
addressId: Id dirección
streetAddress: Dirección fiscal
statusCard:
percentageText: '{getPercentage}% {getAddressNumber} de {getNAddresses}'
pdfsNumberText: '{nPdfs} de {totalPdfs} PDFs'
negativeBases:
clientId: Id cliente
base: Base
active: Activo
hasToInvoice: Facturar
verifiedData: Datos comprobados
comercial: Comercial
errors:
downloadCsvFailed: Error al descargar CSV
order:
field:
salesPersonFk: Comercial
form:
clientFk: Cliente
addressFk: Dirección
agencyModeFk: Agencia
list:
newOrder: Nuevo Pedido
summary:
basket: Cesta
notConfirmed: No confirmada
created: Creado
createdFrom: Creado desde
address: Dirección
total: Total
vat: IVA
state: Estado
alias: Alias
items: Artículos
orderTicketList: Tickets del pedido
amount: Monto
confirm: Confirmar
confirmLines: Confirmar lineas
shelving:
list:
parking: Parking
priority: Prioridad
newShelving: Nuevo Carro
summary:
recyclable: Reciclable
parking:
pickingOrder: Orden de recogida
row: Fila
column: Columna
searchBar:
info: Puedes buscar por código de parking
label: Buscar parking...
department:
chat: Chat
bossDepartment: Jefe de departamento
@ -635,8 +815,8 @@ wagon:
volumeNotEmpty: El volumen no puede estar vacío
typeNotEmpty: El tipo no puede estar vacío
maxTrays: Has alcanzado el número máximo de bandejas
minHeightBetweenTrays: 'La distancia mínima entre bandejas es '
maxWagonHeight: 'La altura máxima del vagón es '
minHeightBetweenTrays: La distancia mínima entre bandejas es
maxWagonHeight: La altura máxima del vagón es
uncompleteTrays: Hay bandejas sin completar
params:
label: Etiqueta
@ -644,6 +824,8 @@ wagon:
volume: Volumen
name: Nombre
supplier:
search: Buscar proveedor
searchInfo: Buscar proveedor por id o nombre
list:
payMethod: Método de pago
account: Cuenta
@ -781,7 +963,7 @@ components:
cardDescriptor:
mainList: Listado principal
summary: Resumen
moreOptions: 'Más opciones'
moreOptions: Más opciones
leftMenu:
addToPinned: Añadir a fijados
removeFromPinned: Eliminar de fijados

View File

@ -1,12 +1,12 @@
<script setup>
import { Dark, Quasar } from 'quasar';
import { computed } from 'vue';
import { computed, onMounted } from 'vue';
import { useI18n } from 'vue-i18n';
import { localeEquivalence } from 'src/i18n/index';
import quasarLang from 'src/utils/quasarLang';
import { langs } from 'src/boot/defaults/constants.js';
const { t, locale } = useI18n();
const userLocale = computed({
get() {
return locale.value;
@ -28,7 +28,6 @@ const darkMode = computed({
Dark.set(value);
},
});
const langs = ['en', 'es'];
</script>
<template>

View File

@ -51,7 +51,6 @@ const removeAlias = () => {
<CardDescriptor
ref="descriptor"
:url="`MailAliases/${entityId}`"
module="Alias"
data-key="Alias"
title="alias"
>

View File

@ -23,8 +23,7 @@ onMounted(async () => {
<CardDescriptor
ref="descriptor"
:url="`VnUsers/preview`"
:filter="filter"
module="Account"
:filter="{ ...filter, where: { id: entityId } }"
data-key="Account"
title="nickname"
>

View File

@ -12,6 +12,7 @@ import VnInputPassword from 'src/components/common/VnInputPassword.vue';
import VnChangePassword from 'src/components/common/VnChangePassword.vue';
import { useQuasar } from 'quasar';
import { useRouter } from 'vue-router';
import VnCheckbox from 'src/components/common/VnCheckbox.vue';
const $props = defineProps({
hasAccount: {
@ -121,18 +122,14 @@ onMounted(() => {
:promise="sync"
>
<template #customHTML>
{{ shouldSyncPassword }}
<QCheckbox
:label="t('account.card.actions.sync.checkbox')"
<VnCheckbox
v-model="shouldSyncPassword"
class="full-width"
:label="t('account.card.actions.sync.checkbox')"
:info="t('account.card.actions.sync.tooltip')"
clearable
clear-icon="close"
>
<QIcon style="padding-left: 10px" color="primary" name="info" size="sm">
<QTooltip>{{ t('account.card.actions.sync.tooltip') }}</QTooltip>
</QIcon></QCheckbox
>
color="primary"
/>
<VnInputPassword
v-if="shouldSyncPassword"
:label="t('login.password')"

View File

@ -35,7 +35,6 @@ const removeRole = async () => {
<CardDescriptor
url="VnRoles"
:filter="{ where: { id: entityId } }"
module="Role"
data-key="Role"
:summary="$props.summary"
>

View File

@ -46,7 +46,6 @@ onMounted(async () => {
<CardDescriptor
:url="`Claims/${entityId}`"
:filter="filter"
module="Claim"
title="client.name"
data-key="Claim"
>
@ -86,7 +85,7 @@ onMounted(async () => {
/>
</template>
</VnLv>
<VnLv :label="t('claim.zone')">
<VnLv v-if="entity.ticket?.zone?.id" :label="t('claim.zone')">
<template #value>
<span class="link">
{{ entity.ticket?.zone?.name }}
@ -98,11 +97,10 @@ onMounted(async () => {
:label="t('claim.province')"
:value="entity.ticket?.address?.province?.name"
/>
<VnLv :label="t('claim.ticketId')">
<VnLv v-if="entity.ticketFk" :label="t('claim.ticketId')">
<template #value>
<span class="link">
{{ entity.ticketFk }}
<TicketDescriptorProxy :id="entity.ticketFk" />
</span>
</template>

View File

@ -1,5 +1,5 @@
<script setup>
import { computed } from 'vue';
import { computed, useAttrs } from 'vue';
import { useRoute } from 'vue-router';
import { useState } from 'src/composables/useState';
import VnNotes from 'src/components/ui/VnNotes.vue';
@ -7,6 +7,7 @@ import VnNotes from 'src/components/ui/VnNotes.vue';
const route = useRoute();
const state = useState();
const user = state.getUser();
const $attrs = useAttrs();
const $props = defineProps({
id: { type: [Number, String], default: null },

View File

@ -131,7 +131,7 @@ const STATE_COLOR = {
prefix="claim"
:array-data-props="{
url: 'Claims/filter',
order: ['cs.priority ASC', 'created ASC'],
order: 'cs.priority ASC, created ASC',
}"
>
<template #advanced-menu>

View File

@ -117,7 +117,7 @@ const toCustomerAddressEdit = (addressId) => {
data-key="CustomerAddresses"
order="id DESC"
ref="vnPaginateRef"
:user-filter="addressFilter"
:filter="addressFilter"
:url="`Clients/${route.params.id}/addresses`"
/>
<div class="full-width flex justify-center">
@ -189,11 +189,11 @@ const toCustomerAddressEdit = (addressId) => {
<QSeparator
class="q-mx-lg"
v-if="item.observations.length"
v-if="item?.observations?.length"
vertical
/>
<div v-if="item.observations.length">
<div v-if="item?.observations?.length">
<div
:key="obIndex"
class="flex q-mb-sm"

View File

@ -61,6 +61,23 @@ const columns = computed(() => [
columnFilter: false,
cardVisible: true,
},
{
align: 'left',
name: 'buyerId',
label: t('customer.params.buyerId'),
component: 'select',
attrs: {
url: 'TicketRequests/getItemTypeWorker',
optionLabel: 'nickname',
optionValue: 'id',
fields: ['id', 'nickname'],
sortBy: ['nickname ASC'],
optionFilter: 'firstName',
},
cardVisible: false,
visible: false,
},
{
name: 'description',
align: 'left',
@ -74,6 +91,7 @@ const columns = computed(() => [
name: 'quantity',
label: t('globals.quantity'),
cardVisible: true,
visible: true,
columnFilter: {
inWhere: true,
},
@ -119,7 +137,7 @@ const openSendEmailDialog = async () => {
openConfirmationModal(
t('The consumption report will be sent'),
t('Please, confirm'),
() => sendCampaignMetricsEmail({ address: arrayData.store.data.email })
() => sendCampaignMetricsEmail({ address: arrayData.store.data.email }),
);
};
const sendCampaignMetricsEmail = ({ address }) => {
@ -138,11 +156,11 @@ const updateDateParams = (value, params) => {
const campaign = campaignList.value.find((c) => c.id === value);
if (!campaign) return;
const { dated, previousDays, scopeDays } = campaign;
const _date = new Date(dated);
const [from, to] = dateRange(_date);
params.from = new Date(from.setDate(from.getDate() - previousDays)).toISOString();
params.to = new Date(to.setDate(to.getDate() + scopeDays)).toISOString();
const { dated, scopeDays } = campaign;
const from = new Date(dated);
from.setDate(from.getDate() - scopeDays);
params.from = from;
params.to = dated;
return params;
};
</script>
@ -200,29 +218,62 @@ const updateDateParams = (value, params) => {
<div v-if="row.subName" class="subName">
{{ row.subName }}
</div>
<FetchedTags :item="row" :max-length="3" />
<FetchedTags :item="row" />
</template>
<template #moreFilterPanel="{ params }">
<div class="column no-wrap flex-center q-gutter-y-md q-mt-xs q-pr-xl">
<VnSelect
:filled="true"
class="q-px-sm q-pt-none fit"
url="ItemTypes"
v-model="params.typeId"
:label="t('item.list.typeName')"
:fields="['id', 'name', 'categoryFk']"
:include="'category'"
:sortBy="'name ASC'"
dense
@update:model-value="(data) => updateDateParams(data, params)"
>
<template #option="scope">
<QItem v-bind="scope.itemProps">
<QItemSection>
<QItemLabel>{{ scope.opt?.name }}</QItemLabel>
<QItemLabel caption>{{
scope.opt?.category?.name
}}</QItemLabel>
</QItemSection>
</QItem>
</template>
</VnSelect>
<VnSelect
:filled="true"
class="q-px-sm q-pt-none fit"
url="ItemCategories"
v-model="params.categoryId"
:label="t('item.list.category')"
:fields="['id', 'name']"
:sortBy="'name ASC'"
dense
@update:model-value="(data) => updateDateParams(data, params)"
/>
<VnSelect
v-model="params.campaign"
:options="campaignList"
:label="t('globals.campaign')"
:filled="true"
class="q-px-sm q-pt-none fit"
dense
option-label="code"
:option-label="(opt) => t(opt.code)"
:fields="['id', 'code', 'dated', 'scopeDays']"
@update:model-value="(data) => updateDateParams(data, params)"
dense
>
<template #option="scope">
<QItem v-bind="scope.itemProps">
<QItemSection>
<QItemLabel>
{{ scope.opt?.code }}
{{
new Date(scope.opt?.dated).getFullYear()
}}</QItemLabel
>
<QItemLabel> {{ t(scope.opt?.code) }} </QItemLabel>
<QItemLabel caption>
{{ new Date(scope.opt?.dated).getFullYear() }}
</QItemLabel>
</QItemSection>
</QItem>
</template>
@ -247,7 +298,19 @@ const updateDateParams = (value, params) => {
</template>
<i18n>
en:
valentinesDay: Valentine's Day
mothersDay: Mother's Day
allSaints: All Saints' Day
es:
Enter a new search: Introduce una nueva búsqueda
Group by items: Agrupar por artículos
valentinesDay: Día de San Valentín
mothersDay: Día de la Madre
allSaints: Día de Todos los Santos
Campaign consumption: Consumo campaña
Campaign: Campaña
From: Desde
To: Hasta
</i18n>

View File

@ -55,7 +55,6 @@ const debtWarning = computed(() => {
<template>
<CardDescriptor
module="Customer"
:url="`Clients/${entityId}/getCard`"
:summary="$props.summary"
data-key="Customer"
@ -110,7 +109,21 @@ const debtWarning = computed(() => {
>
<QTooltip>{{ t('customer.card.isDisabled') }}</QTooltip>
</QIcon>
<QIcon v-if="entity.isFreezed" name="vn:frozen" size="xs" color="primary">
<QIcon
v-if="entity?.substitutionAllowed"
name="help"
size="xs"
color="primary"
>
<QTooltip>{{ t('Allowed substitution') }}</QTooltip>
</QIcon>
<QIcon
v-if="customer?.isFreezed"
name="vn:frozen"
size="xs"
color="primary"
>
<QTooltip>{{ t('customer.card.isFrozen') }}</QTooltip>
</QIcon>
<QIcon

View File

@ -61,6 +61,16 @@ const openCreateForm = (type) => {
.join('&');
useOpenURL(`/#/${type}/list?${params}`);
};
const updateSubstitutionAllowed = async () => {
try {
await axios.patch(`Clients/${route.params.id}`, {
substitutionAllowed: !$props.customer.substitutionAllowed,
});
notify('globals.notificationSent', 'positive');
} catch (error) {
notify(error.message, 'positive');
}
};
</script>
<template>
@ -69,6 +79,13 @@ const openCreateForm = (type) => {
{{ t('globals.pageTitles.createTicket') }}
</QItemSection>
</QItem>
<QItem v-ripple clickable>
<QItemSection @click="updateSubstitutionAllowed()">{{
$props.customer.substitutionAllowed
? t('Disable substitution')
: t('Allow substitution')
}}</QItemSection>
</QItem>
<QItem v-ripple clickable>
<QItemSection @click="showSmsDialog()">{{ t('Send SMS') }}</QItemSection>
</QItem>

View File

@ -8,8 +8,8 @@ import FormModel from 'components/FormModel.vue';
import VnRow from 'components/ui/VnRow.vue';
import VnInput from 'src/components/common/VnInput.vue';
import VnSelect from 'src/components/common/VnSelect.vue';
import VnSelectVies from 'src/components/common/VnSelectVies.vue';
import VnLocation from 'src/components/common/VnLocation.vue';
import VnCheckbox from 'src/components/common/VnCheckbox.vue';
const { t } = useI18n();
const route = useRoute();
@ -104,7 +104,6 @@ function handleLocation(data, location) {
:required="true"
@update:model-value="(location) => handleLocation(data, location)"
/>
<VnSelectVies v-model="data.viesCode" style="max-width: 30%" />
</VnRow>
<VnRow>
<QCheckbox :label="t('Active')" v-model="data.isActive" />
@ -112,7 +111,11 @@ function handleLocation(data, location) {
</VnRow>
<VnRow>
<QCheckbox :label="t('Has to invoice')" v-model="data.hasToInvoice" />
<QCheckbox :label="t('Verified data')" v-model="data.isTaxDataChecked" />
<VnCheckbox
v-model="data.isVies"
:label="t('globals.isVies')"
:info="t('whenActivatingIt')"
/>
</VnRow>
<VnRow>
@ -124,17 +127,11 @@ function handleLocation(data, location) {
</VnRow>
<VnRow>
<div>
<QCheckbox
:label="t('Is equalizated')"
<VnCheckbox
v-model="data.isEqualizated"
:label="t('Is equalizated')"
:info="t('inOrderToInvoice')"
/>
<QIcon class="cursor-info q-ml-sm" name="info" size="sm">
<QTooltip>
{{ t('inOrderToInvoice') }}
</QTooltip>
</QIcon>
</div>
<QCheckbox :label="t('Daily invoice')" v-model="data.hasDailyInvoice" />
</VnRow>
@ -142,6 +139,9 @@ function handleLocation(data, location) {
<QCheckbox
:label="t('Electronic invoice')"
v-model="data.hasElectronicInvoice"
/><QCheckbox
:label="t('Verified data')"
v-model="data.isTaxDataChecked"
/>
</VnRow>
</template>
@ -169,9 +169,11 @@ es:
Incoterms authorization: Autorización incoterms
Electronic invoice: Factura electrónica
onlyLetters: Sólo se pueden usar letras, números y espacios
whenActivatingIt: Al activarlo, no informar el código del país en el campo nif
inOrderToInvoice: Para facturar no se consulta este campo, sino el RE de consignatario. Al modificar este campo si no esta marcada la casilla Facturar por consignatario, se propagará automaticamente el cambio a todos lo consignatarios, en caso contrario preguntará al usuario si quiere o no propagar
Daily invoice: Facturación diaria
en:
onlyLetters: Only letters, numbers and spaces can be used
whenActivatingIt: When activating it, do not enter the country code in the ID field
inOrderToInvoice: In order to invoice, this field is not contulted, but the consignee's ET. When modifiying this field if the invoice by address option is not checked, the change will be automatically propagated to all addresses, otherwise the user will be asked if he wants to propagate it or not
</i18n>

View File

@ -1,4 +1,3 @@
<script setup>
import { useI18n } from 'vue-i18n';
import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
@ -52,11 +51,7 @@ const exprBuilder = (param, value) => {
</QItem>
<QItem class="q-mb-sm">
<QItemSection>
<VnInput
:label="t('globals.name')"
v-model="params.name"
is-outlined
/>
<VnInput :label="t('Name')" v-model="params.name" is-outlined />
</QItemSection>
</QItem>
<QItem class="q-mb-sm">

View File

@ -264,6 +264,7 @@ const columns = computed(() => [
align: 'left',
name: 'isActive',
label: t('customer.summary.isActive'),
component: 'checkbox',
chip: {
color: null,
condition: (value) => !value,
@ -302,6 +303,7 @@ const columns = computed(() => [
align: 'left',
name: 'isFreezed',
label: t('customer.extendedList.tableVisibleColumns.isFreezed'),
component: 'checkbox',
chip: {
color: null,
condition: (value) => value,
@ -419,7 +421,7 @@ function handleLocation(data, location) {
<VnTable
ref="tableRef"
:data-key="dataKey"
url="Clients/filter"
url="Clients/extendedListFilter"
:create="{
urlCreate: 'Clients/createWithUser',
title: t('globals.pageTitles.customerCreate'),

View File

@ -9,7 +9,7 @@ import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.v
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
import VnInput from 'src/components/common/VnInput.vue';
import CustomerDefaulterAddObservation from './CustomerDefaulterAddObservation.vue';
import DepartmentDescriptorProxy from 'src/pages/Department/Card/DepartmentDescriptorProxy.vue';
import DepartmentDescriptorProxy from 'src/pages/Worker/Department/Card/DepartmentDescriptorProxy.vue';
import VnTable from 'src/components/VnTable/VnTable.vue';
import { useArrayData } from 'src/composables/useArrayData';

View File

@ -107,6 +107,9 @@ customer:
defaulterSinced: Defaulted Since
hasRecovery: Has Recovery
socialName: Social name
typeId: Type
buyerId: Buyer
categoryId: Category
city: City
phone: Phone
postcode: Postcode

View File

@ -108,6 +108,9 @@ customer:
hasRecovery: Tiene recobro
socialName: Razón social
campaign: Campaña
typeId: Familia
buyerId: Comprador
categoryId: Reino
city: Ciudad
phone: Teléfono
postcode: Código postal

View File

@ -1,30 +1,32 @@
<script setup>
import { ref } from 'vue';
import { onMounted, ref } from 'vue';
import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
import { useRole } from 'src/composables/useRole';
import { useState } from 'src/composables/useState';
import { checkEntryLock } from 'src/composables/checkEntryLock';
import FetchData from 'components/FetchData.vue';
import FormModel from 'components/FormModel.vue';
import VnRow from 'components/ui/VnRow.vue';
import VnInput from 'src/components/common/VnInput.vue';
import VnSelect from 'src/components/common/VnSelect.vue';
import VnSelectDialog from 'src/components/common/VnSelectDialog.vue';
import FilterTravelForm from 'src/components/FilterTravelForm.vue';
import VnInputNumber from 'src/components/common/VnInputNumber.vue';
import { toDate } from 'src/filters';
import VnSelectTravelExtended from 'src/components/common/VnSelectTravelExtended.vue';
import VnSelectSupplier from 'src/components/common/VnSelectSupplier.vue';
const route = useRoute();
const { t } = useI18n();
const { hasAny } = useRole();
const isAdministrative = () => hasAny(['administrative']);
const state = useState();
const user = state.getUser().fn();
const companiesOptions = ref([]);
const currenciesOptions = ref([]);
const onFilterTravelSelected = (formData, id) => {
formData.travelFk = id;
};
onMounted(() => {
checkEntryLock(route.params.id, user.id);
});
</script>
<template>
@ -52,46 +54,24 @@ const onFilterTravelSelected = (formData, id) => {
>
<template #form="{ data }">
<VnRow>
<VnSelectTravelExtended
:data="data"
v-model="data.travelFk"
:onFilterTravelSelected="(data, result) => (data.travelFk = result)"
/>
<VnSelectSupplier
v-model="data.supplierFk"
hide-selected
:required="true"
map-options
/>
<VnSelectDialog
:label="t('entry.basicData.travel')"
v-model="data.travelFk"
url="Travels/filter"
:fields="['id', 'warehouseInName']"
option-value="id"
option-label="warehouseInName"
map-options
hide-selected
:required="true"
action-icon="filter_alt"
>
<template #form>
<FilterTravelForm
@travel-selected="onFilterTravelSelected(data, $event)"
/>
</template>
<template #option="scope">
<QItem v-bind="scope.itemProps">
<QItemSection>
<QItemLabel>
{{ scope.opt?.agencyModeName }} -
{{ scope.opt?.warehouseInName }}
({{ toDate(scope.opt?.shipped) }})
{{ scope.opt?.warehouseOutName }}
({{ toDate(scope.opt?.landed) }})
</QItemLabel>
</QItemSection>
</QItem>
</template>
</VnSelectDialog>
</VnRow>
<VnRow>
<VnInput v-model="data.reference" :label="t('globals.reference')" />
<VnInputNumber
v-model="data.invoiceAmount"
:label="t('entry.summary.invoiceAmount')"
:positive="false"
/>
</VnRow>
<VnRow>
<VnInput
@ -113,8 +93,7 @@ const onFilterTravelSelected = (formData, id) => {
<VnInputNumber
:label="t('entry.summary.commission')"
v-model="data.commission"
step="1"
autofocus
:step="1"
:positive="false"
/>
<VnSelect
@ -161,7 +140,7 @@ const onFilterTravelSelected = (formData, id) => {
:label="t('entry.summary.excludedFromAvailable')"
/>
<QCheckbox
v-if="isAdministrative()"
:disable="!isAdministrative()"
v-model="data.isBooked"
:label="t('entry.basicData.booked')"
/>

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +1,19 @@
<script setup>
import { ref, computed, onMounted } from 'vue';
import { useRoute } from 'vue-router';
import { useRoute, useRouter } from 'vue-router';
import { useI18n } from 'vue-i18n';
import CardDescriptor from 'components/ui/CardDescriptor.vue';
import VnLv from 'src/components/ui/VnLv.vue';
import { toDate } from 'src/filters';
import { getUrl } from 'src/composables/getUrl';
import EntryDescriptorMenu from './EntryDescriptorMenu.vue';
import { useQuasar } from 'quasar';
import { usePrintService } from 'composables/usePrintService';
import CardDescriptor from 'components/ui/CardDescriptor.vue';
import VnLv from 'src/components/ui/VnLv.vue';
import TravelDescriptorProxy from 'src/pages/Travel/Card/TravelDescriptorProxy.vue';
import axios from 'axios';
const quasar = useQuasar();
const { push } = useRouter();
const { openReport } = usePrintService();
const $props = defineProps({
id: {
@ -83,12 +90,63 @@ const getEntryRedirectionFilter = (entry) => {
to,
});
};
function showEntryReport() {
openReport(`Entries/${entityId.value}/entry-order-pdf`);
}
function showNotification(type, message) {
quasar.notify({
type: type,
message: t(message),
});
}
async function recalculateRates(entity) {
try {
const entryConfig = await axios.get('EntryConfigs/findOne');
if (entryConfig.data?.inventorySupplierFk === entity.supplierFk) {
showNotification(
'negative',
'Cannot recalculate prices because this is an inventory entry',
);
return;
}
await axios.post(`Entries/${entityId.value}/recalcEntryPrices`);
showNotification('positive', 'Entry prices recalculated');
} catch (error) {
showNotification('negative', 'Failed to recalculate rates');
console.error(error);
}
}
async function cloneEntry() {
try {
const response = await axios.post(`Entries/${entityId.value}/cloneEntry`);
push({ path: `/entry/${response.data}` });
showNotification('positive', 'Entry cloned');
} catch (error) {
showNotification('negative', 'Failed to clone entry');
console.error(error);
}
}
async function deleteEntry() {
try {
await axios.post(`Entries/${entityId.value}/deleteEntry`);
push({ path: `/entry/list` });
showNotification('positive', 'Entry deleted');
} catch (error) {
showNotification('negative', 'Failed to delete entry');
console.error(error);
}
}
</script>
<template>
<CardDescriptor
ref="entryDescriptorRef"
module="Entry"
:url="`Entries/${entityId}`"
:userFilter="entryFilter"
title="supplier.nickname"
@ -96,15 +154,56 @@ const getEntryRedirectionFilter = (entry) => {
width="lg-width"
>
<template #menu="{ entity }">
<EntryDescriptorMenu :id="entity.id" />
<QItem
v-ripple
clickable
@click="showEntryReport(entity)"
data-cy="show-entry-report"
>
<QItemSection>{{ t('Show entry report') }}</QItemSection>
</QItem>
<QItem
v-ripple
clickable
@click="recalculateRates(entity)"
data-cy="recalculate-rates"
>
<QItemSection>{{ t('Recalculate rates') }}</QItemSection>
</QItem>
<QItem v-ripple clickable @click="cloneEntry(entity)" data-cy="clone-entry">
<QItemSection>{{ t('Clone') }}</QItemSection>
</QItem>
<QItem v-ripple clickable @click="deleteEntry(entity)" data-cy="delete-entry">
<QItemSection>{{ t('Delete') }}</QItemSection>
</QItem>
</template>
<template #body="{ entity }">
<VnLv :label="t('globals.agency')" :value="entity.travel?.agency?.name" />
<VnLv :label="t('shipped')" :value="toDate(entity.travel?.shipped)" />
<VnLv :label="t('landed')" :value="toDate(entity.travel?.landed)" />
<VnLv :label="t('Travel')">
<template #value>
<span class="link" v-if="entity?.travelFk">
{{ entity.travel?.agency?.name }}
{{ entity.travel?.warehouseOut?.code }} &rarr;
{{ entity.travel?.warehouseIn?.code }}
<TravelDescriptorProxy :id="entity?.travelFk" />
</span>
</template>
</VnLv>
<VnLv
:label="t('globals.warehouseOut')"
:value="entity.travel?.warehouseOut?.name"
:label="t('entry.summary.travelShipped')"
:value="toDate(entity.travel?.shipped)"
/>
<VnLv
:label="t('entry.summary.travelLanded')"
:value="toDate(entity.travel?.landed)"
/>
<VnLv :label="t('entry.summary.currency')" :value="entity?.currency?.code" />
<VnLv
:label="t('entry.summary.invoiceAmount')"
:value="entity?.invoiceAmount"
/>
<VnLv
:label="t('entry.summary.entryType')"
:value="entity?.entryType?.description"
/>
</template>
<template #icons="{ entity }">
@ -131,6 +230,14 @@ const getEntryRedirectionFilter = (entry) => {
}}</QTooltip
>
</QIcon>
<QIcon
v-if="!entity?.travelFk"
name="vn:deletedTicket"
size="xs"
color="primary"
>
<QTooltip>{{ t('This entry is deleted') }}</QTooltip>
</QIcon>
</QCardActions>
</template>
<template #actions="{ entity }">
@ -143,21 +250,6 @@ const getEntryRedirectionFilter = (entry) => {
>
<QTooltip>{{ t('Supplier card') }}</QTooltip>
</QBtn>
<QBtn
:to="{
name: 'TravelMain',
query: {
params: JSON.stringify({
agencyModeFk: entity.travel?.agencyModeFk,
}),
},
}"
size="md"
icon="local_airport"
color="primary"
>
<QTooltip>{{ t('All travels with current agency') }}</QTooltip>
</QBtn>
<QBtn
:to="{
name: 'EntryMain',
@ -177,10 +269,24 @@ const getEntryRedirectionFilter = (entry) => {
</template>
<i18n>
es:
Travel: Envío
Supplier card: Ficha del proveedor
All travels with current agency: Todos los envíos con la agencia actual
All entries with current supplier: Todas las entradas con el proveedor actual
Show entry report: Ver informe del pedido
Inventory entry: Es inventario
Virtual entry: Es una redada
shipped: Enviado
landed: Recibido
This entry is deleted: Esta entrada está eliminada
Cannot recalculate prices because this is an inventory entry: No se pueden recalcular los precios porque es una entrada de inventario
Entry deleted: Entrada eliminada
Entry cloned: Entrada clonada
Entry prices recalculated: Precios de la entrada recalculados
Failed to recalculate rates: No se pudieron recalcular las tarifas
Failed to clone entry: No se pudo clonar la entrada
Failed to delete entry: No se pudo eliminar la entrada
Recalculate rates: Recalcular tarifas
Clone: Clonar
Delete: Eliminar
</i18n>

View File

@ -54,8 +54,8 @@ const transferEntry = async () => {
<i18n>
en:
transferEntryDialog: The entries will be transferred to the next day
transferEntry: Transfer Entry
transferEntry: Partial delay
es:
transferEntryDialog: Se van a transferir las compras al dia siguiente
transferEntry: Transferir Entrada
transferEntry: Retraso parcial
</i18n>

View File

@ -9,6 +9,7 @@ export default {
'shipped',
'agencyModeFk',
'warehouseOutFk',
'warehouseInFk',
'daysInForward',
],
include: [
@ -21,13 +22,13 @@ export default {
{
relation: 'warehouseOut',
scope: {
fields: ['name'],
fields: ['name', 'code'],
},
},
{
relation: 'warehouseIn',
scope: {
fields: ['name'],
fields: ['name', 'code'],
},
},
],
@ -39,5 +40,17 @@ export default {
fields: ['id', 'nickname'],
},
},
{
relation: 'currency',
scope: {
fields: ['id', 'code'],
},
},
{
relation: 'entryType',
scope: {
fields: ['code', 'description'],
},
},
],
};

View File

@ -2,19 +2,17 @@
import { onMounted, ref, computed } from 'vue';
import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
import { toDate } from 'src/filters';
import { getUrl } from 'src/composables/getUrl';
import axios from 'axios';
import CardSummary from 'components/ui/CardSummary.vue';
import VnLv from 'src/components/ui/VnLv.vue';
import TravelDescriptorProxy from 'src/pages/Travel/Card/TravelDescriptorProxy.vue';
import { toDate, toCurrency, toCelsius } from 'src/filters';
import { getUrl } from 'src/composables/getUrl';
import axios from 'axios';
import FetchedTags from 'src/components/ui/FetchedTags.vue';
import VnToSummary from 'src/components/ui/VnToSummary.vue';
import EntryDescriptorMenu from './EntryDescriptorMenu.vue';
import VnRow from 'src/components/ui/VnRow.vue';
import EntryBuys from './EntryBuys.vue';
import VnTitle from 'src/components/common/VnTitle.vue';
import VnCheckbox from 'src/components/common/VnCheckbox.vue';
import VnToSummary from 'src/components/ui/VnToSummary.vue';
const route = useRoute();
const { t } = useI18n();
@ -33,117 +31,6 @@ const entry = ref();
const entryBuys = ref([]);
const entryUrl = ref();
onMounted(async () => {
entryUrl.value = (await getUrl('entry/')) + entityId.value;
});
const tableColumnComponents = {
quantity: {
component: () => 'span',
props: () => {},
},
stickers: {
component: () => 'span',
props: () => {},
event: () => {},
},
packagingFk: {
component: () => 'span',
props: () => {},
event: () => {},
},
weight: {
component: () => 'span',
props: () => {},
event: () => {},
},
packing: {
component: () => 'span',
props: () => {},
event: () => {},
},
grouping: {
component: () => 'span',
props: () => {},
event: () => {},
},
buyingValue: {
component: () => 'span',
props: () => {},
event: () => {},
},
amount: {
component: () => 'span',
props: () => {},
event: () => {},
},
pvp: {
component: () => 'span',
props: () => {},
event: () => {},
},
};
const entriesTableColumns = computed(() => {
return [
{
label: t('globals.quantity'),
field: 'quantity',
name: 'quantity',
align: 'left',
},
{
label: t('entry.summary.stickers'),
field: 'stickers',
name: 'stickers',
align: 'left',
},
{
label: t('entry.summary.package'),
field: 'packagingFk',
name: 'packagingFk',
align: 'left',
},
{
label: t('globals.weight'),
field: 'weight',
name: 'weight',
align: 'left',
},
{
label: t('entry.summary.packing'),
field: 'packing',
name: 'packing',
align: 'left',
},
{
label: t('entry.summary.grouping'),
field: 'grouping',
name: 'grouping',
align: 'left',
},
{
label: t('entry.summary.buyingValue'),
field: 'buyingValue',
name: 'buyingValue',
align: 'left',
format: (value) => toCurrency(value),
},
{
label: t('entry.summary.import'),
name: 'amount',
align: 'left',
format: (_, row) => toCurrency(row.buyingValue * row.quantity),
},
{
label: t('entry.summary.pvp'),
name: 'pvp',
align: 'left',
format: (_, row) => toCurrency(row.price2) + ' / ' + toCurrency(row.price3),
},
];
});
async function setEntryData(data) {
if (data) entry.value = data;
await fetchEntryBuys();
@ -153,14 +40,18 @@ const fetchEntryBuys = async () => {
const { data } = await axios.get(`Entries/${entry.value.id}/getBuys`);
if (data) entryBuys.value = data;
};
</script>
onMounted(async () => {
entryUrl.value = (await getUrl('entry/')) + entityId.value;
});
</script>
<template>
<CardSummary
ref="summaryRef"
:url="`Entries/${entityId}/getEntry`"
@on-fetch="(data) => setEntryData(data)"
data-key="EntrySummary"
data-cy="entry-summary"
>
<template #header-left>
<VnToSummary
@ -173,40 +64,67 @@ const fetchEntryBuys = async () => {
<template #header>
<span>{{ entry.id }} - {{ entry.supplier.nickname }}</span>
</template>
<template #menu="{ entity }">
<EntryDescriptorMenu :id="entity.id" />
</template>
<template #body>
<QCard class="vn-one">
<VnTitle
:url="`#/entry/${entityId}/basic-data`"
:text="t('globals.summary.basicData')"
/>
<VnLv :label="t('entry.summary.commission')" :value="entry.commission" />
<div class="card-group">
<div class="card-content">
<VnLv
:label="t('entry.summary.commission')"
:value="entry?.commission"
/>
<VnLv
:label="t('entry.summary.currency')"
:value="entry.currency?.name"
:value="entry?.currency?.name"
/>
<VnLv :label="t('globals.company')" :value="entry.company.code" />
<VnLv :label="t('globals.reference')" :value="entry.reference" />
<VnLv
:label="t('globals.company')"
:value="entry?.company?.code"
/>
<VnLv :label="t('globals.reference')" :value="entry?.reference" />
<VnLv
:label="t('entry.summary.invoiceNumber')"
:value="entry.invoiceNumber"
:value="entry?.invoiceNumber"
/>
<VnLv
:label="t('entry.basicData.initialTemperature')"
:value="toCelsius(entry.initialTemperature)"
</div>
<div class="card-content">
<VnCheckbox
:label="t('entry.summary.ordered')"
v-model="entry.isOrdered"
:disable="true"
size="xs"
/>
<VnLv
:label="t('entry.basicData.finalTemperature')"
:value="toCelsius(entry.finalTemperature)"
<VnCheckbox
:label="t('globals.confirmed')"
v-model="entry.isConfirmed"
:disable="true"
size="xs"
/>
<VnCheckbox
:label="t('entry.summary.booked')"
v-model="entry.isBooked"
:disable="true"
size="xs"
/>
<VnCheckbox
:label="t('entry.summary.excludedFromAvailable')"
v-model="entry.isExcludedFromAvailable"
:disable="true"
size="xs"
/>
</div>
</div>
</QCard>
<QCard class="vn-one">
<QCard class="vn-one" v-if="entry?.travelFk">
<VnTitle
:url="`#/entry/${entityId}/basic-data`"
:text="t('globals.summary.basicData')"
:url="`#/travel/${entry.travel.id}/summary`"
:text="t('Travel')"
/>
<div class="card-group">
<div class="card-content">
<VnLv :label="t('entry.summary.travelReference')">
<template #value>
<span class="link">
@ -220,7 +138,7 @@ const fetchEntryBuys = async () => {
:value="entry.travel.agency?.name"
/>
<VnLv
:label="t('globals.shipped')"
:label="t('entry.summary.travelShipped')"
:value="toDate(entry.travel.shipped)"
/>
<VnLv
@ -228,104 +146,72 @@ const fetchEntryBuys = async () => {
:value="entry.travel.warehouseOut?.name"
/>
<VnLv
:label="t('entry.summary.travelDelivered')"
:value="entry.travel.isDelivered"
:label="t('entry.summary.travelLanded')"
:value="toDate(entry.travel.landed)"
/>
<VnLv :label="t('globals.landed')" :value="toDate(entry.travel.landed)" />
<VnLv
:label="t('globals.warehouseIn')"
:value="entry.travel.warehouseIn?.name"
/>
<VnLv
</div>
<div class="card-content">
<VnCheckbox
:label="t('entry.summary.travelDelivered')"
v-model="entry.travel.isDelivered"
:disable="true"
size="xs"
/>
<VnCheckbox
:label="t('entry.summary.travelReceived')"
:value="entry.travel.isReceived"
v-model="entry.travel.isReceived"
:disable="true"
size="xs"
/>
</QCard>
<QCard class="vn-one">
<VnTitle :url="`#/travel/${entityId}/summary`" :text="t('Travel data')" />
<VnRow class="block">
<VnLv :label="t('entry.summary.ordered')" :value="entry.isOrdered" />
<VnLv :label="t('globals.confirmed')" :value="entry.isConfirmed" />
<VnLv :label="t('entry.summary.booked')" :value="entry.isBooked" />
<VnLv
:label="t('entry.summary.excludedFromAvailable')"
:value="entry.isExcludedFromAvailable"
/>
</VnRow>
</div>
</div>
</QCard>
<QCard class="vn-max">
<VnTitle
:url="`#/entry/${entityId}/buys`"
:text="t('entry.summary.buys')"
/>
<QTable
:rows="entryBuys"
:columns="entriesTableColumns"
row-key="index"
class="full-width q-mt-md"
:no-data-label="t('globals.noResults')"
>
<template #body="{ cols, row, rowIndex }">
<QTr no-hover>
<QTd v-for="col in cols" :key="col?.name">
<component
:is="tableColumnComponents[col?.name].component()"
v-bind="tableColumnComponents[col?.name].props()"
@click="tableColumnComponents[col?.name].event()"
class="col-content"
>
<template
v-if="
col?.name !== 'observation' &&
col?.name !== 'isConfirmed'
"
>{{ col.value }}</template
>
<QTooltip v-if="col.toolTip">{{
col.toolTip
}}</QTooltip>
</component>
</QTd>
</QTr>
<QTr no-hover>
<QTd>
<span>{{ row.item.itemType.code }}</span>
</QTd>
<QTd>
<span>{{ row.item.id }}</span>
</QTd>
<QTd>
<span>{{ row.item.size }}</span>
</QTd>
<QTd>
<span>{{ toCurrency(row.item.minPrice) }}</span>
</QTd>
<QTd colspan="6">
<span>{{ row.item.concept }}</span>
<span v-if="row.item.subName" class="subName">
{{ row.item.subName }}
</span>
<FetchedTags :item="row.item" />
</QTd>
</QTr>
<!-- Esta última row es utilizada para agregar un espaciado y así marcar una diferencia visual entre los diferentes buys -->
<QTr v-if="rowIndex !== entryBuys.length - 1">
<QTd colspan="10" class="vn-table-separation-row" />
</QTr>
</template>
</QTable>
<EntryBuys
v-if="entityId"
:id="Number(entityId)"
:editable-mode="false"
table-height="49vh"
/>
</QCard>
</template>
</CardSummary>
</template>
<style lang="scss" scoped>
.separation-row {
background-color: var(--vn-section-color) !important;
.card-group {
display: flex;
flex-direction: column;
}
.card-content {
display: flex;
flex-direction: column;
text-overflow: ellipsis;
> div {
max-height: 24px;
}
}
@media (min-width: 1010px) {
.card-group {
flex-direction: row;
}
.card-content {
flex: 1;
margin-right: 16px;
}
}
</style>
<i18n>
es:
Travel data: Datos envío
Travel: Envío
InvoiceIn data: Datos factura
</i18n>

View File

@ -19,6 +19,7 @@ const props = defineProps({
const currenciesOptions = ref([]);
const companiesOptions = ref([]);
const entryFilterPanel = ref();
</script>
<template>
@ -38,7 +39,7 @@ const companiesOptions = ref([]);
@on-fetch="(data) => (currenciesOptions = data)"
auto-load
/>
<VnFilterPanel :data-key="props.dataKey" :search-button="true">
<VnFilterPanel ref="entryFilterPanel" :data-key="props.dataKey" :search-button="true">
<template #tags="{ tag, formatFn }">
<div class="q-gutter-x-xs">
<strong>{{ t(`entryFilter.params.${tag.label}`) }}: </strong>
@ -48,70 +49,65 @@ const companiesOptions = ref([]);
<template #body="{ params, searchFn }">
<QItem>
<QItemSection>
<VnInput
v-model="params.search"
:label="t('entryFilter.params.search')"
is-outlined
/>
<QCheckbox
:label="t('params.isExcludedFromAvailable')"
v-model="params.isExcludedFromAvailable"
toggle-indeterminate
>
<QTooltip>
{{ t('params.isExcludedFromAvailable') }}
</QTooltip>
</QCheckbox>
</QItemSection>
<QItemSection>
<QCheckbox
:label="t('params.isOrdered')"
v-model="params.isOrdered"
toggle-indeterminate
>
<QTooltip>
{{ t('entry.list.tableVisibleColumns.isOrdered') }}
</QTooltip>
</QCheckbox>
</QItemSection>
</QItem>
<QItem>
<QItemSection>
<VnInput
v-model="params.reference"
:label="t('entryFilter.params.reference')"
is-outlined
/>
<QCheckbox
:label="t('params.isReceived')"
v-model="params.isReceived"
toggle-indeterminate
>
<QTooltip>
{{ t('entry.list.tableVisibleColumns.isReceived') }}
</QTooltip>
</QCheckbox>
</QItemSection>
<QItemSection>
<QCheckbox
:label="t('entry.list.tableVisibleColumns.isConfirmed')"
v-model="params.isConfirmed"
toggle-indeterminate
>
<QTooltip>
{{ t('entry.list.tableVisibleColumns.isConfirmed') }}
</QTooltip>
</QCheckbox>
</QItemSection>
</QItem>
<QItem>
<QItemSection>
<VnInput
v-model="params.invoiceNumber"
:label="t('entryFilter.params.invoiceNumber')"
is-outlined
/>
</QItemSection>
</QItem>
<QItem>
<QItemSection>
<VnInput
v-model="params.travelFk"
:label="t('entryFilter.params.travelFk')"
is-outlined
/>
</QItemSection>
</QItem>
<QItem>
<QItemSection>
<VnSelect
:label="t('entryFilter.params.companyFk')"
v-model="params.companyFk"
<VnInputDate
:label="t('params.landed')"
v-model="params.landed"
@update:model-value="searchFn()"
:options="companiesOptions"
option-value="id"
option-label="code"
hide-selected
dense
outlined
rounded
is-outlined
/>
</QItemSection>
</QItem>
<QItem>
<QItemSection>
<VnSelect
:label="t('entryFilter.params.currencyFk')"
v-model="params.currencyFk"
@update:model-value="searchFn()"
:options="currenciesOptions"
option-value="id"
option-label="name"
hide-selected
dense
outlined
rounded
/>
<VnInput v-model="params.id" label="Id" is-outlined />
</QItemSection>
</QItem>
<QItem>
@ -125,62 +121,165 @@ const companiesOptions = ref([]);
rounded
/>
</QItemSection>
</QItem>
<QItem>
<QItemSection>
<VnInputDate
:label="t('entryFilter.params.created')"
v-model="params.created"
@update:model-value="searchFn()"
<VnInput
v-model="params.invoiceNumber"
:label="t('params.invoiceNumber')"
is-outlined
/>
</QItemSection>
</QItem>
<QItem>
<QItemSection>
<VnInputDate
:label="t('entryFilter.params.from')"
v-model="params.from"
@update:model-value="searchFn()"
<VnInput
v-model="params.reference"
:label="t('entry.list.tableVisibleColumns.reference')"
is-outlined
/>
</QItemSection>
</QItem>
<QItem>
<QItemSection>
<VnInputDate
:label="t('entryFilter.params.to')"
v-model="params.to"
<VnSelect
:label="t('params.agencyModeId')"
v-model="params.agencyModeId"
@update:model-value="searchFn()"
url="AgencyModes"
:fields="['id', 'name']"
hide-selected
dense
outlined
rounded
/>
</QItemSection>
</QItem>
<QItem>
<QItemSection>
<VnInput
v-model="params.evaNotes"
:label="t('params.evaNotes')"
is-outlined
/>
</QItemSection>
</QItem>
<QItem>
<QItemSection>
<QCheckbox
:label="t('entryFilter.params.isBooked')"
v-model="params.isBooked"
toggle-indeterminate
/>
</QItemSection>
<QItemSection>
<QCheckbox
:label="t('entryFilter.params.isConfirmed')"
v-model="params.isConfirmed"
toggle-indeterminate
<VnSelect
:label="t('params.warehouseOutFk')"
v-model="params.warehouseOutFk"
@update:model-value="searchFn()"
url="Warehouses"
:fields="['id', 'name']"
hide-selected
dense
outlined
rounded
/>
</QItemSection>
</QItem>
<QItem>
<QItemSection>
<QCheckbox
:label="t('entryFilter.params.isOrdered')"
v-model="params.isOrdered"
toggle-indeterminate
<VnSelect
:label="t('params.warehouseInFk')"
v-model="params.warehouseInFk"
@update:model-value="searchFn()"
url="Warehouses"
:fields="['id', 'name']"
hide-selected
dense
outlined
rounded
>
<template #option="scope">
<QItem v-bind="scope.itemProps">
<QItemSection>
<QItemLabel>
{{ scope.opt?.name }}
</QItemLabel>
<QItemLabel caption>
{{ `#${scope.opt?.id} , ${scope.opt?.nickname}` }}
</QItemLabel>
</QItemSection>
</QItem>
</template>
</VnSelect>
</QItemSection>
</QItem>
<QItem>
<QItemSection>
<VnInput
v-model="params.invoiceNumber"
:label="t('params.invoiceNumber')"
is-outlined
/>
</QItemSection>
</QItem>
<QItem>
<QItemSection>
<VnSelect
:label="t('params.entryTypeCode')"
v-model="params.entryTypeCode"
@update:model-value="searchFn()"
url="EntryTypes"
:fields="['code', 'description']"
option-value="code"
option-label="description"
hide-selected
dense
outlined
rounded
/>
</QItemSection>
</QItem>
<QItem>
<QItemSection>
<VnInput
v-model="params.evaNotes"
:label="t('params.evaNotes')"
is-outlined
/>
</QItemSection>
</QItem>
</template>
</VnFilterPanel>
</template>
<i18n>
en:
params:
isExcludedFromAvailable: Inventory
isOrdered: Ordered
isReceived: Received
isConfirmed: Confirmed
isRaid: Raid
landed: Date
id: Id
supplierFk: Supplier
invoiceNumber: Invoice number
reference: Ref/Alb/Guide
agencyModeId: Agency mode
evaNotes: Notes
warehouseOutFk: Origin
warehouseInFk: Destiny
entryTypeCode: Entry type
hasToShowDeletedEntries: Show deleted entries
es:
params:
isExcludedFromAvailable: Inventario
isOrdered: Pedida
isConfirmed: Confirmado
isReceived: Recibida
isRaid: Raid
landed: Fecha
id: Id
supplierFk: Proveedor
invoiceNumber: Núm. factura
reference: Ref/Alb/Guía
agencyModeId: Modo agencia
evaNotes: Notas
warehouseOutFk: Origen
warehouseInFk: Destino
entryTypeCode: Tipo de entrada
hasToShowDeletedEntries: Mostrar entradas eliminadas
</i18n>

View File

@ -1,21 +1,25 @@
<script setup>
import axios from 'axios';
import VnSection from 'src/components/common/VnSection.vue';
import { ref, computed } from 'vue';
import { useI18n } from 'vue-i18n';
import { useState } from 'src/composables/useState';
import { onBeforeMount } from 'vue';
import EntryFilter from './EntryFilter.vue';
import VnTable from 'components/VnTable/VnTable.vue';
import { toCelsius, toDate } from 'src/filters';
import { useSummaryDialog } from 'src/composables/useSummaryDialog';
import EntrySummary from './Card/EntrySummary.vue';
import SupplierDescriptorProxy from 'src/pages/Supplier/Card/SupplierDescriptorProxy.vue';
import TravelDescriptorProxy from 'src/pages/Travel/Card/TravelDescriptorProxy.vue';
import VnSection from 'src/components/common/VnSection.vue';
import VnSelectTravelExtended from 'src/components/common/VnSelectTravelExtended.vue';
import { toDate } from 'src/filters';
const { t } = useI18n();
const tableRef = ref();
const defaultEntry = ref({});
const state = useState();
const user = state.getUser();
const dataKey = 'EntryList';
const { viewSummary } = useSummaryDialog();
const entryFilter = {
const entryQueryFilter = {
include: [
{
relation: 'suppliers',
@ -40,44 +44,53 @@ const entryFilter = {
const columns = computed(() => [
{
name: 'status',
columnFilter: false,
label: 'Ex',
toolTip: t('entry.list.tableVisibleColumns.isExcludedFromAvailable'),
name: 'isExcludedFromAvailable',
component: 'checkbox',
width: '35px',
},
{
label: 'Pe',
toolTip: t('entry.list.tableVisibleColumns.isOrdered'),
name: 'isOrdered',
component: 'checkbox',
width: '35px',
},
{
label: 'Le',
toolTip: t('entry.list.tableVisibleColumns.isConfirmed'),
name: 'isConfirmed',
component: 'checkbox',
width: '35px',
},
{
label: 'Re',
toolTip: t('entry.list.tableVisibleColumns.isReceived'),
name: 'isReceived',
component: 'checkbox',
width: '35px',
},
{
label: t('entry.list.tableVisibleColumns.landed'),
name: 'landed',
component: 'date',
columnField: {
component: null,
},
format: (row, dashIfEmpty) => dashIfEmpty(toDate(row.landed)),
width: '105px',
},
{
align: 'left',
label: t('globals.id'),
name: 'id',
isId: true,
component: 'number',
chip: {
condition: () => true,
},
},
{
align: 'left',
label: t('globals.reference'),
name: 'reference',
isTitle: true,
component: 'input',
columnField: {
component: null,
},
create: true,
cardVisible: true,
},
{
align: 'left',
label: t('entry.list.tableVisibleColumns.created'),
name: 'created',
create: true,
cardVisible: true,
component: 'date',
columnField: {
component: null,
},
format: (row, dashIfEmpty) => dashIfEmpty(toDate(row.created)),
},
{
align: 'left',
label: t('entry.list.tableVisibleColumns.supplierFk'),
name: 'supplierFk',
create: true,
@ -87,164 +100,205 @@ const columns = computed(() => [
url: 'suppliers',
fields: ['id', 'name'],
},
columnField: {
component: null,
},
format: (row, dashIfEmpty) => dashIfEmpty(row.supplierName),
},
{
align: 'left',
label: t('entry.list.tableVisibleColumns.isBooked'),
name: 'isBooked',
cardVisible: true,
create: true,
component: 'checkbox',
label: t('entry.list.tableVisibleColumns.invoiceNumber'),
name: 'invoiceNumber',
component: 'input',
},
{
align: 'left',
label: t('entry.list.tableVisibleColumns.isConfirmed'),
name: 'isConfirmed',
label: t('entry.list.tableVisibleColumns.reference'),
name: 'reference',
isTitle: true,
component: 'input',
columnField: {
component: null,
},
cardVisible: true,
create: true,
component: 'checkbox',
},
{
align: 'left',
label: t('entry.list.tableVisibleColumns.isOrdered'),
name: 'isOrdered',
cardVisible: true,
create: true,
component: 'checkbox',
label: 'AWB',
name: 'awbCode',
component: 'input',
},
{
align: 'left',
label: t('entry.list.tableVisibleColumns.companyFk'),
label: t('entry.list.tableVisibleColumns.agencyModeId'),
name: 'agencyModeId',
cardVisible: true,
component: 'select',
attrs: {
url: 'agencyModes',
fields: ['id', 'name'],
},
columnField: {
component: null,
},
format: (row, dashIfEmpty) => dashIfEmpty(row.agencyModeName),
},
{
align: 'left',
label: t('entry.list.tableVisibleColumns.evaNotes'),
name: 'evaNotes',
component: 'input',
},
{
align: 'left',
label: t('entry.list.tableVisibleColumns.warehouseOutFk'),
name: 'warehouseOutFk',
cardVisible: true,
component: 'select',
attrs: {
url: 'warehouses',
fields: ['id', 'name'],
},
columnField: {
component: null,
},
format: (row, dashIfEmpty) => dashIfEmpty(row.warehouseOutName),
},
{
align: 'left',
label: t('entry.list.tableVisibleColumns.warehouseInFk'),
name: 'warehouseInFk',
cardVisible: true,
component: 'select',
attrs: {
url: 'warehouses',
fields: ['id', 'name'],
},
columnField: {
component: null,
},
format: (row, dashIfEmpty) => dashIfEmpty(row.warehouseInName),
},
{
align: 'left',
label: t('entry.list.tableVisibleColumns.entryTypeDescription'),
name: 'entryTypeCode',
cardVisible: true,
},
{
name: 'dated',
label: t('entry.list.tableVisibleColumns.dated'),
component: 'date',
cardVisible: false,
visible: false,
create: true,
},
{
name: 'companyFk',
label: t('entry.list.tableVisibleColumns.companyFk'),
cardVisible: false,
visible: false,
create: true,
component: 'select',
attrs: {
url: 'companies',
fields: ['id', 'code'],
optionValue: 'id',
optionLabel: 'code',
optionValue: 'id',
url: 'Companies',
},
columnField: {
component: null,
},
create: true,
format: (row, dashIfEmpty) => dashIfEmpty(row.companyCode),
},
{
align: 'left',
label: t('entry.list.tableVisibleColumns.travelFk'),
name: 'travelFk',
component: 'select',
attrs: {
url: 'travels',
fields: ['id', 'ref'],
optionLabel: 'ref',
optionValue: 'id',
},
columnField: {
component: null,
},
label: t('entry.list.tableVisibleColumns.travelFk'),
cardVisible: false,
visible: false,
create: true,
format: (row, dashIfEmpty) => dashIfEmpty(row.travelRef),
},
{
align: 'left',
label: t('entry.list.tableVisibleColumns.invoiceAmount'),
name: 'invoiceAmount',
cardVisible: true,
},
{
align: 'left',
name: 'initialTemperature',
label: t('entry.basicData.initialTemperature'),
field: 'initialTemperature',
format: (row) => toCelsius(row.initialTemperature),
},
{
align: 'left',
name: 'finalTemperature',
label: t('entry.basicData.finalTemperature'),
field: 'finalTemperature',
format: (row) => toCelsius(row.finalTemperature),
},
{
label: t('entry.list.tableVisibleColumns.isExcludedFromAvailable'),
name: 'isExcludedFromAvailable',
columnFilter: {
inWhere: true,
},
},
{
align: 'right',
name: 'tableActions',
actions: [
{
title: t('components.smartCard.viewSummary'),
icon: 'preview',
action: (row) => viewSummary(row.id, EntrySummary),
isPrimary: true,
},
],
},
]);
function getBadgeAttrs(row) {
const date = row.landed;
let today = Date.vnNew();
today.setHours(0, 0, 0, 0);
let timeTicket = new Date(date);
timeTicket.setHours(0, 0, 0, 0);
let timeDiff = today - timeTicket;
if (timeDiff > 0) return { color: 'warning', 'text-color': 'black' };
switch (row.entryTypeCode) {
case 'regularization':
case 'life':
case 'internal':
case 'inventory':
if (!row.isOrdered || !row.isConfirmed)
return { color: 'negative', 'text-color': 'black' };
break;
case 'product':
case 'packaging':
case 'devaluation':
case 'payment':
case 'transport':
if (
row.invoiceAmount === null ||
(row.invoiceNumber === null && row.reference === null) ||
!row.isOrdered ||
!row.isConfirmed
)
return { color: 'negative', 'text-color': 'black' };
break;
default:
break;
}
if (timeDiff < 0) return { color: 'info', 'text-color': 'black' };
return { color: 'transparent' };
}
onBeforeMount(async () => {
defaultEntry.value = (await axios.get('EntryConfigs/findOne')).data;
});
</script>
<template>
<VnSection
:data-key="dataKey"
:columns="columns"
prefix="entry"
url="Entries/filter"
:array-data-props="{
url: 'Entries/filter',
order: 'id DESC',
userFilter: entryFilter,
order: 'landed DESC',
userFilter: EntryFilter,
}"
>
<template #advanced-menu>
<EntryFilter data-key="EntryList" />
<EntryFilter :data-key="dataKey" />
</template>
<template #body>
<VnTable
v-if="defaultEntry.defaultSupplierFk"
ref="tableRef"
:data-key="dataKey"
url="Entries/filter"
:filter="entryQueryFilter"
order="landed DESC"
:create="{
urlCreate: 'Entries',
title: t('entry.list.newEntry'),
title: t('Create entry'),
onDataSaved: ({ id }) => tableRef.redirect(id),
formInitialData: {},
formInitialData: {
supplierFk: defaultEntry.defaultSupplierFk,
dated: Date.vnNew(),
companyFk: user?.companyFk,
},
}"
:columns="columns"
redirect="entry"
:right-search="false"
>
<template #column-status="{ row }">
<div class="row q-gutter-xs">
<QIcon
v-if="!!row.isExcludedFromAvailable"
name="vn:inventory"
color="primary"
<template #column-landed="{ row }">
<QBadge
v-if="row?.travelFk"
v-bind="getBadgeAttrs(row)"
class="q-pa-sm"
style="font-size: 14px"
>
<QTooltip>{{
t(
'entry.list.tableVisibleColumns.isExcludedFromAvailable',
)
}}</QTooltip>
</QIcon>
<QIcon v-if="!!row.isRaid" name="vn:net" color="primary">
<QTooltip>
{{
t('globals.raid', {
daysInForward: row.daysInForward,
})
}}</QTooltip
>
</QIcon>
</div>
{{ toDate(row.landed) }}
</QBadge>
</template>
<template #column-supplierFk="{ row }">
<span class="link" @click.stop>
@ -252,13 +306,26 @@ const columns = computed(() => [
<SupplierDescriptorProxy :id="row.supplierFk" />
</span>
</template>
<template #column-travelFk="{ row }">
<span class="link" @click.stop>
{{ row.travelRef }}
<TravelDescriptorProxy :id="row.travelFk" />
</span>
<template #column-create-travelFk="{ data }">
<VnSelectTravelExtended
:data="data"
v-model="data.travelFk"
:onFilterTravelSelected="
(data, result) => (data.travelFk = result)
"
data-cy="entry-travel-select"
/>
</template>
</VnTable>
</template>
</VnSection>
</template>
<i18n>
es:
Inventory entry: Es inventario
Virtual entry: Es una redada
Search entries: Buscar entradas
You can search by entry reference: Puedes buscar por referencia de la entrada
Create entry: Crear entrada
</i18n>

View File

@ -1,21 +1,36 @@
entry:
lock:
title: Lock entry
message: This entry has been locked by {userName} for {time} minutes. Do you want to unlock it?
success: The entry has been locked successfully
list:
newEntry: New entry
tableVisibleColumns:
created: Creation
supplierFk: Supplier
isBooked: Booked
isConfirmed: Confirmed
isExcludedFromAvailable: Exclude from inventory
isOrdered: Ordered
isConfirmed: Ready to label
isReceived: Received
isRaid: Raid
landed: Date
supplierFk: Supplier
reference: Ref/Alb/Guide
invoiceNumber: Invoice
agencyModeId: Agency
isBooked: Booked
companyFk: Company
travelFk: Travel
isExcludedFromAvailable: Inventory
evaNotes: Notes
warehouseOutFk: Origin
warehouseInFk: Destiny
entryTypeDescription: Entry type
invoiceAmount: Import
travelFk: Travel
dated: Dated
inventoryEntry: Inventory entry
summary:
commission: Commission
currency: Currency
invoiceNumber: Invoice number
invoiceAmount: Invoice amount
ordered: Ordered
booked: Booked
excludedFromAvailable: Inventory
@ -33,6 +48,7 @@ entry:
buyingValue: Buying value
import: Import
pvp: PVP
entryType: Entry type
basicData:
travel: Travel
currency: Currency
@ -69,17 +85,55 @@ entry:
landing: Landing
isExcludedFromAvailable: Es inventory
params:
toShipped: To
fromShipped: From
daysOnward: Days onward
daysAgo: Days ago
warehouseInFk: Warehouse in
isExcludedFromAvailable: Exclude from inventory
isOrdered: Ordered
isConfirmed: Ready to label
isReceived: Received
isIgnored: Ignored
isRaid: Raid
landed: Date
supplierFk: Supplier
reference: Ref/Alb/Guide
invoiceNumber: Invoice
agencyModeId: Agency
isBooked: Booked
companyFk: Company
evaNotes: Notes
warehouseOutFk: Origin
warehouseInFk: Destiny
entryTypeDescription: Entry type
invoiceAmount: Import
travelFk: Travel
dated: Dated
itemFk: Item id
hex: Color
name: Item name
size: Size
stickers: Stickers
packagingFk: Packaging
weight: Kg
groupingMode: Grouping selector
grouping: Grouping
quantity: Quantity
buyingValue: Buying value
price2: Package
price3: Box
minPrice: Minumum price
hasMinPrice: Has minimum price
packingOut: Packing out
comment: Comment
subName: Supplier name
tags: Tags
company_name: Company name
itemTypeFk: Item type
workerFk: Worker id
search: Search entries
searchInfo: You can search by entry reference
descriptorMenu:
showEntryReport: Show entry report
entryFilter:
params:
isExcludedFromAvailable: Exclude from inventory
invoiceNumber: Invoice number
travelFk: Travel
companyFk: Company
@ -91,8 +145,16 @@ entryFilter:
isBooked: Booked
isConfirmed: Confirmed
isOrdered: Ordered
isReceived: Received
search: General search
reference: Reference
landed: Landed
id: Id
agencyModeId: Agency
evaNotes: Notes
warehouseOutFk: Origin
warehouseInFk: Destiny
entryTypeCode: Entry type
myEntries:
id: ID
landed: Landed

View File

@ -1,21 +1,36 @@
entry:
lock:
title: Entrada bloqueada
message: Esta entrada ha sido bloqueada por {userName} hace {time} minutos. ¿Quieres desbloquearla?
success: La entrada ha sido bloqueada correctamente
list:
newEntry: Nueva entrada
tableVisibleColumns:
created: Creación
supplierFk: Proveedor
isBooked: Asentado
isConfirmed: Confirmado
isExcludedFromAvailable: Excluir del inventario
isOrdered: Pedida
isConfirmed: Lista para etiquetar
isReceived: Recibida
isRaid: Redada
landed: Fecha
supplierFk: Proveedor
invoiceNumber: Nº Factura
reference: Ref/Alb/Guía
agencyModeId: Agencia
isBooked: Asentado
companyFk: Empresa
travelFk: Envio
isExcludedFromAvailable: Inventario
evaNotes: Notas
warehouseOutFk: Origen
warehouseInFk: Destino
entryTypeDescription: Tipo entrada
invoiceAmount: Importe
dated: Fecha
inventoryEntry: Es inventario
summary:
commission: Comisión
currency: Moneda
invoiceNumber: Núm. factura
invoiceAmount: Importe
ordered: Pedida
booked: Contabilizada
excludedFromAvailable: Inventario
@ -34,12 +49,13 @@ entry:
buyingValue: Coste
import: Importe
pvp: PVP
entryType: Tipo entrada
basicData:
travel: Envío
currency: Moneda
observation: Observación
commission: Comisión
booked: Asentado
booked: Contabilizada
excludedFromAvailable: Inventario
initialTemperature: Ini °C
finalTemperature: Fin °C
@ -69,31 +85,70 @@ entry:
packingOut: Embalaje envíos
landing: Llegada
isExcludedFromAvailable: Es inventario
params:
toShipped: Hasta
fromShipped: Desde
warehouseInFk: Alm. entrada
daysOnward: Días adelante
daysAgo: Días atras
descriptorMenu:
showEntryReport: Ver informe del pedido
search: Buscar entradas
searchInfo: Puedes buscar por referencia de entrada
params:
isExcludedFromAvailable: Excluir del inventario
isOrdered: Pedida
isConfirmed: Lista para etiquetar
isReceived: Recibida
isRaid: Redada
isIgnored: Ignorado
landed: Fecha
supplierFk: Proveedor
invoiceNumber: Nº Factura
reference: Ref/Alb/Guía
agencyModeId: Agencia
isBooked: Asentado
companyFk: Empresa
travelFk: Envio
evaNotes: Notas
warehouseOutFk: Origen
warehouseInFk: Destino
entryTypeDescription: Tipo entrada
invoiceAmount: Importe
dated: Fecha
itemFk: Id artículo
hex: Color
name: Nombre artículo
size: Medida
stickers: Etiquetas
packagingFk: Embalaje
weight: Kg
groupinMode: Selector de grouping
grouping: Grouping
quantity: Quantity
buyingValue: Precio de compra
price2: Paquete
price3: Caja
minPrice: Precio mínimo
hasMinPrice: Tiene precio mínimo
packingOut: Packing out
comment: Referencia
subName: Nombre proveedor
tags: Etiquetas
company_name: Nombre empresa
itemTypeFk: Familia
workerFk: Comprador
entryFilter:
params:
invoiceNumber: Núm. factura
travelFk: Envío
companyFk: Empresa
currencyFk: Moneda
supplierFk: Proveedor
from: Desde
to: Hasta
created: Fecha creación
isBooked: Asentado
isConfirmed: Confirmado
isExcludedFromAvailable: Inventario
isOrdered: Pedida
search: Búsqueda general
reference: Referencia
isConfirmed: Confirmado
isReceived: Recibida
isRaid: Raid
landed: Fecha
id: Id
supplierFk: Proveedor
invoiceNumber: Núm. factura
reference: Ref/Alb/Guía
agencyModeId: Modo agencia
evaNotes: Notas
warehouseOutFk: Origen
warehouseInFk: Destino
entryTypeCode: Tipo de entrada
hasToShowDeletedEntries: Mostrar entradas eliminadas
myEntries:
id: ID
landed: F. llegada

View File

@ -125,7 +125,7 @@ function deleteFile(dmsFk) {
<VnInput
clearable
clear-icon="close"
:label="t('Supplier ref')"
:label="t('invoiceIn.supplierRef')"
v-model="data.supplierRef"
/>
</VnRow>
@ -149,6 +149,7 @@ function deleteFile(dmsFk) {
option-value="id"
option-label="id"
:filter-options="['id', 'name']"
data-cy="UnDeductibleVatSelect"
>
<template #option="scope">
<QItem v-bind="scope.itemProps">
@ -310,7 +311,6 @@ function deleteFile(dmsFk) {
supplierFk: Supplier
es:
supplierFk: Proveedor
Supplier ref: Ref. proveedor
Expedition date: Fecha expedición
Operation date: Fecha operación
Undeductible VAT: Iva no deducible

View File

@ -90,7 +90,6 @@ async function setInvoiceCorrection(id) {
<template>
<CardDescriptor
ref="cardDescriptorRef"
module="InvoiceIn"
data-key="InvoiceIn"
:url="`InvoiceIns/${entityId}`"
:filter="filter"

View File

@ -186,7 +186,7 @@ const createInvoiceInCorrection = async () => {
clickable
@click="book(entityId)"
>
<QItemSection>{{ t('invoiceIn.descriptorMenu.toBook') }}</QItemSection>
<QItemSection>{{ t('invoiceIn.descriptorMenu.book') }}</QItemSection>
</QItem>
</template>
</InvoiceInToBook>
@ -197,7 +197,7 @@ const createInvoiceInCorrection = async () => {
@click="triggerMenu('unbook')"
>
<QItemSection>
{{ t('invoiceIn.descriptorMenu.toUnbook') }}
{{ t('invoiceIn.descriptorMenu.unbook') }}
</QItemSection>
</QItem>
<QItem

View File

@ -1,5 +1,5 @@
<script setup>
import { ref, computed } from 'vue';
import { ref, computed, onBeforeMount } from 'vue';
import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
import axios from 'axios';
@ -12,6 +12,7 @@ import VnSelect from 'src/components/common/VnSelect.vue';
import useNotify from 'src/composables/useNotify.js';
import VnInputDate from 'src/components/common/VnInputDate.vue';
import VnInputNumber from 'src/components/common/VnInputNumber.vue';
import { toCurrency } from 'filters/index';
const route = useRoute();
const { notify } = useNotify();
@ -26,7 +27,7 @@ const invoiceInFormRef = ref();
const invoiceId = +route.params.id;
const filter = { where: { invoiceInFk: invoiceId } };
const areRows = ref(false);
const totals = ref();
const columns = computed(() => [
{
name: 'duedate',
@ -66,6 +67,8 @@ const columns = computed(() => [
},
]);
const totalAmount = computed(() => getTotal(invoiceInFormRef.value.formData, 'amount'));
const isNotEuro = (code) => code != 'EUR';
async function insert() {
@ -73,6 +76,10 @@ async function insert() {
await invoiceInFormRef.value.reload();
notify(t('globals.dataSaved'), 'positive');
}
onBeforeMount(async () => {
totals.value = (await axios.get(`InvoiceIns/${invoiceId}/getTotals`)).data;
});
</script>
<template>
<FetchData
@ -153,7 +160,7 @@ async function insert() {
<QTd />
<QTd />
<QTd>
{{ getTotal(rows, 'amount', { currency: 'default' }) }}
{{ toCurrency(totalAmount) }}
</QTd>
<QTd>
<template v-if="isNotEuro(invoiceIn.currency.code)">
@ -235,7 +242,16 @@ async function insert() {
v-shortcut="'+'"
size="lg"
round
@click="!areRows ? insert() : invoiceInFormRef.insert()"
@click="
() => {
if (!areRows) insert();
else
invoiceInFormRef.insert({
amount: (totals.totalTaxableBase - totalAmount).toFixed(2),
invoiceInFk: invoiceId,
});
}
"
/>
</QPageSticky>
</template>

View File

@ -193,7 +193,7 @@ const getLink = (param) => `#/invoice-in/${entityId.value}/${param}`;
<InvoiceIntoBook>
<template #content="{ book }">
<QBtn
:label="t('To book')"
:label="t('Book')"
color="orange-11"
text-color="black"
@click="book(entityId)"
@ -224,10 +224,7 @@ const getLink = (param) => `#/invoice-in/${entityId.value}/${param}`;
</span>
</template>
</VnLv>
<VnLv
:label="t('invoiceIn.list.supplierRef')"
:value="entity.supplierRef"
/>
<VnLv :label="t('invoiceIn.supplierRef')" :value="entity.supplierRef" />
<VnLv
:label="t('invoiceIn.summary.currency')"
:value="entity.currency?.code"
@ -357,7 +354,7 @@ const getLink = (param) => `#/invoice-in/${entityId.value}/${param}`;
entity.totals.totalTaxableBaseForeignValue &&
toCurrency(
entity.totals.totalTaxableBaseForeignValue,
currency
currency,
)
}}</QTd>
</QTr>
@ -392,7 +389,7 @@ const getLink = (param) => `#/invoice-in/${entityId.value}/${param}`;
entity.totals.totalDueDayForeignValue &&
toCurrency(
entity.totals.totalDueDayForeignValue,
currency
currency,
)
}}
</QTd>
@ -472,5 +469,5 @@ const getLink = (param) => `#/invoice-in/${entityId.value}/${param}`;
Search invoice: Buscar factura recibida
You can search by invoice reference: Puedes buscar por referencia de la factura
Totals: Totales
To book: Contabilizar
Book: Contabilizar
</i18n>

View File

@ -1,5 +1,5 @@
<script setup>
import { ref, computed } from 'vue';
import { ref, computed, nextTick } from 'vue';
import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
import { useArrayData } from 'src/composables/useArrayData';
@ -25,7 +25,6 @@ const sageTaxTypes = ref([]);
const sageTransactionTypes = ref([]);
const rowsSelected = ref([]);
const invoiceInFormRef = ref();
const expenseRef = ref();
defineProps({
actionIcon: {
@ -97,6 +96,20 @@ const columns = computed(() => [
},
]);
const taxableBaseTotal = computed(() => {
return getTotal(invoiceInFormRef.value.formData, 'taxableBase');
});
const taxRateTotal = computed(() => {
return getTotal(invoiceInFormRef.value.formData, null, {
cb: taxRate,
});
});
const combinedTotal = computed(() => {
return +taxableBaseTotal.value + +taxRateTotal.value;
});
const filter = {
fields: [
'id',
@ -125,7 +138,7 @@ function taxRate(invoiceInTax) {
return ((taxTypeSage / 100) * taxableBase).toFixed(2);
}
function autocompleteExpense(evt, row, col) {
function autocompleteExpense(evt, row, col, ref) {
const val = evt.target.value;
if (!val) return;
@ -134,22 +147,17 @@ function autocompleteExpense(evt, row, col) {
({ id }) => id == useAccountShortToStandard(param),
);
expenseRef.value.vnSelectDialogRef.vnSelectRef.toggleOption(lookup);
ref.vnSelectDialogRef.vnSelectRef.toggleOption(lookup);
}
const taxableBaseTotal = computed(() => {
return getTotal(invoiceInFormRef.value.formData, 'taxableBase');
});
const taxRateTotal = computed(() => {
return getTotal(invoiceInFormRef.value.formData, null, {
cb: taxRate,
function setCursor(ref) {
nextTick(() => {
const select = ref.vnSelectDialogRef
? ref.vnSelectDialogRef.vnSelectRef
: ref.vnSelectRef;
select.$el.querySelector('input').setSelectionRange(0, 0);
});
});
const combinedTotal = computed(() => {
return +taxableBaseTotal.value + +taxRateTotal.value;
});
}
</script>
<template>
<FetchData
@ -187,14 +195,24 @@ const combinedTotal = computed(() => {
<template #body-cell-expense="{ row, col }">
<QTd>
<VnSelectDialog
ref="expenseRef"
:ref="`expenseRef-${row.$index}`"
v-model="row[col.model]"
:options="col.options"
:option-value="col.optionValue"
:option-label="col.optionLabel"
:filter-options="['id', 'name']"
:tooltip="t('Create a new expense')"
@keydown.tab="autocompleteExpense($event, row, col)"
@keydown.tab="
autocompleteExpense(
$event,
row,
col,
$refs[`expenseRef-${row.$index}`],
)
"
@update:model-value="
setCursor($refs[`expenseRef-${row.$index}`])
"
>
<template #option="scope">
<QItem v-bind="scope.itemProps">
@ -210,7 +228,7 @@ const combinedTotal = computed(() => {
</QTd>
</template>
<template #body-cell-taxablebase="{ row }">
<QTd>
<QTd shrink>
<VnInputNumber
clear-icon="close"
v-model="row.taxableBase"
@ -221,12 +239,16 @@ const combinedTotal = computed(() => {
<template #body-cell-sageiva="{ row, col }">
<QTd>
<VnSelect
:ref="`sageivaRef-${row.$index}`"
v-model="row[col.model]"
:options="col.options"
:option-value="col.optionValue"
:option-label="col.optionLabel"
:filter-options="['id', 'vat']"
data-cy="vat-sageiva"
@update:model-value="
setCursor($refs[`sageivaRef-${row.$index}`])
"
>
<template #option="scope">
<QItem v-bind="scope.itemProps">
@ -244,11 +266,15 @@ const combinedTotal = computed(() => {
<template #body-cell-sagetransaction="{ row, col }">
<QTd>
<VnSelect
:ref="`sagetransactionRef-${row.$index}`"
v-model="row[col.model]"
:options="col.options"
:option-value="col.optionValue"
:option-label="col.optionLabel"
:filter-options="['id', 'transaction']"
@update:model-value="
setCursor($refs[`sagetransactionRef-${row.$index}`])
"
>
<template #option="scope">
<QItem v-bind="scope.itemProps">
@ -266,7 +292,7 @@ const combinedTotal = computed(() => {
</QTd>
</template>
<template #body-cell-foreignvalue="{ row }">
<QTd>
<QTd shrink>
<VnInputNumber
:class="{
'no-pointer-events': !isNotEuro(currency),

View File

@ -29,6 +29,7 @@ const cols = computed(() => [
name: 'isBooked',
label: t('invoiceIn.isBooked'),
columnFilter: false,
component: 'checkbox',
},
{
align: 'left',
@ -56,7 +57,7 @@ const cols = computed(() => [
{
align: 'left',
name: 'supplierRef',
label: t('invoiceIn.list.supplierRef'),
label: t('invoiceIn.supplierRef'),
},
{
align: 'left',
@ -177,7 +178,7 @@ const cols = computed(() => [
:required="true"
/>
<VnInput
:label="t('invoiceIn.list.supplierRef')"
:label="t('invoiceIn.supplierRef')"
v-model="data.supplierRef"
/>
<VnSelect

View File

@ -4,6 +4,7 @@ import { useQuasar } from 'quasar';
import { useI18n } from 'vue-i18n';
import VnConfirm from 'src/components/ui/VnConfirm.vue';
import { useArrayData } from 'src/composables/useArrayData';
import qs from 'qs';
const { notify, dialog } = useQuasar();
const { t } = useI18n();
@ -12,29 +13,51 @@ defineExpose({ checkToBook });
const { store } = useArrayData();
async function checkToBook(id) {
let directBooking = true;
let messages = [];
const hasProblemWithTax = (
await axios.get('InvoiceInTaxes/count', {
params: {
where: JSON.stringify({
invoiceInFk: id,
or: [{ taxTypeSageFk: null }, { transactionTypeSageFk: null }],
}),
},
})
).data?.count;
if (hasProblemWithTax)
messages.push(t('The VAT and Transaction fields have not been informed'));
const { data: totals } = await axios.get(`InvoiceIns/${id}/getTotals`);
const taxableBaseNotEqualDueDay = totals.totalDueDay != totals.totalTaxableBase;
const vatNotEqualDueDay = totals.totalDueDay != totals.totalVat;
if (taxableBaseNotEqualDueDay && vatNotEqualDueDay) directBooking = false;
if (taxableBaseNotEqualDueDay && vatNotEqualDueDay)
messages.push(t('The sum of the taxable bases does not match the due dates'));
const { data: dueDaysCount } = await axios.get('InvoiceInDueDays/count', {
where: {
const dueDaysCount = (
await axios.get('InvoiceInDueDays/count', {
params: {
where: JSON.stringify({
invoiceInFk: id,
dueDated: { gte: Date.vnNew() },
}),
},
});
})
).data?.count;
if (dueDaysCount) directBooking = false;
if (directBooking) return toBook(id);
if (dueDaysCount) messages.push(t('Some due dates are less than or equal to today'));
if (!messages.length) toBook(id);
else
dialog({
component: VnConfirm,
componentProps: { title: t('Are you sure you want to book this invoice?') },
}).onOk(async () => await toBook(id));
componentProps: {
title: t('Are you sure you want to book this invoice?'),
message: messages.reduce((acc, msg) => `${acc}<p>${msg}</p>`, ''),
},
}).onOk(() => toBook(id));
}
async function toBook(id) {
@ -59,4 +82,7 @@ async function toBook(id) {
es:
Are you sure you want to book this invoice?: ¿Estás seguro de querer asentar esta factura?
It was not able to book the invoice: No se pudo contabilizar la factura
Some due dates are less than or equal to today: Algún vencimiento tiene una fecha menor o igual que hoy
The sum of the taxable bases does not match the due dates: La suma de las bases imponibles no coincide con la de los vencimientos
The VAT and Transaction fields have not been informed: No se han informado los campos de iva y/o transacción
</i18n>

View File

@ -3,10 +3,10 @@ invoiceIn:
searchInfo: Search incoming invoices by ID or supplier fiscal name
serial: Serial
isBooked: Is booked
supplierRef: Invoice nº
list:
ref: Reference
supplier: Supplier
supplierRef: Supplier ref.
file: File
issued: Issued
dueDated: Due dated
@ -19,8 +19,6 @@ invoiceIn:
unbook: Unbook
delete: Delete
clone: Clone
toBook: To book
toUnbook: To unbook
deleteInvoice: Delete invoice
invoiceDeleted: invoice deleted
cloneInvoice: Clone invoice
@ -70,4 +68,3 @@ invoiceIn:
isBooked: Is booked
account: Ledger account
correctingFk: Rectificative

View File

@ -3,10 +3,10 @@ invoiceIn:
searchInfo: Buscar facturas recibidas por ID o nombre fiscal del proveedor
serial: Serie
isBooked: Contabilizada
supplierRef: Nº factura
list:
ref: Referencia
supplier: Proveedor
supplierRef: Ref. proveedor
issued: F. emisión
dueDated: F. vencimiento
file: Fichero
@ -15,12 +15,10 @@ invoiceIn:
descriptor:
ticketList: Listado de tickets
descriptorMenu:
book: Asentar
unbook: Desasentar
book: Contabilizar
unbook: Descontabilizar
delete: Eliminar
clone: Clonar
toBook: Contabilizar
toUnbook: Descontabilizar
deleteInvoice: Eliminar factura
invoiceDeleted: Factura eliminada
cloneInvoice: Clonar factura
@ -68,4 +66,3 @@ invoiceIn:
isBooked: Contabilizada
account: Cuenta contable
correctingFk: Rectificativa

View File

@ -36,7 +36,6 @@ function ticketFilter(invoice) {
<template>
<CardDescriptor
ref="descriptor"
module="InvoiceOut"
:url="`InvoiceOuts/${entityId}`"
:filter="filter"
title="ref"

View File

@ -97,12 +97,19 @@ const columns = computed(() => [
},
{
align: 'left',
name: 'companyCode',
name: 'companyFk',
label: t('globals.company'),
cardVisible: true,
component: 'select',
attrs: { url: 'Companies', optionLabel: 'code', optionValue: 'id' },
columnField: { component: null },
attrs: {
url: 'Companies',
optionLabel: 'code',
optionValue: 'id',
},
columnField: {
component: null,
},
format: (row, dashIfEmpty) => dashIfEmpty(row.companyCode),
},
{
align: 'left',

View File

@ -11,6 +11,7 @@ import VnSelect from 'src/components/common/VnSelect.vue';
import VnSelectDialog from 'src/components/common/VnSelectDialog.vue';
import FilterItemForm from 'src/components/FilterItemForm.vue';
import CreateIntrastatForm from './CreateIntrastatForm.vue';
import VnCheckbox from 'src/components/common/VnCheckbox.vue';
const route = useRoute();
const { t } = useI18n();
@ -208,30 +209,20 @@ const onIntrastatCreated = (response, formData) => {
/>
</VnRow>
<VnRow class="row q-gutter-md q-mb-md">
<div>
<QCheckbox
<VnCheckbox
v-model="data.isFragile"
:label="t('item.basicData.isFragile')"
:info="t('item.basicData.isFragileTooltip')"
class="q-mr-sm"
size="xs"
/>
<QIcon name="info" class="cursor-pointer" size="xs">
<QTooltip max-width="300px">
{{ t('item.basicData.isFragileTooltip') }}
</QTooltip>
</QIcon>
</div>
<div>
<QCheckbox
<VnCheckbox
v-model="data.isPhotoRequested"
:label="t('item.basicData.isPhotoRequested')"
:info="t('item.basicData.isPhotoRequestedTooltip')"
class="q-mr-sm"
size="xs"
/>
<QIcon name="info" class="cursor-pointer" size="xs">
<QTooltip>
{{ t('item.basicData.isPhotoRequestedTooltip') }}
</QTooltip>
</QIcon>
</div>
</VnRow>
<VnRow>
<VnInput

View File

@ -7,8 +7,8 @@ import FetchData from 'components/FetchData.vue';
import FormModel from 'components/FormModel.vue';
import VnRow from 'components/ui/VnRow.vue';
import VnSelectDialog from 'src/components/common/VnSelectDialog.vue';
import CreateGenusForm from './CreateGenusForm.vue';
import CreateSpecieForm from './CreateSpecieForm.vue';
import CreateGenusForm from '../components/CreateGenusForm.vue';
import CreateSpecieForm from '../components/CreateSpecieForm.vue';
const route = useRoute();
const { t } = useI18n();

View File

@ -34,6 +34,10 @@ const $props = defineProps({
type: Number,
default: null,
},
proxyRender: {
type: Boolean,
default: false,
},
});
const route = useRoute();
@ -88,7 +92,6 @@ const updateStock = async () => {
<template>
<CardDescriptor
data-key="Item"
module="Item"
:summary="$props.summary"
:url="`Items/${entityId}/getCard`"
@on-fetch="setData"
@ -112,7 +115,7 @@ const updateStock = async () => {
<template #value>
<span class="link">
{{ entity.itemType?.worker?.user?.name }}
<WorkerDescriptorProxy :id="entity.itemType?.worker?.id" />
<WorkerDescriptorProxy :id="entity.itemType?.worker?.id ?? NaN" />
</span>
</template>
</VnLv>
@ -147,7 +150,7 @@ const updateStock = async () => {
</QCardActions>
</template>
<template #actions="{}">
<QCardActions class="row justify-center">
<QCardActions class="row justify-center" v-if="proxyRender">
<QBtn
:to="{
name: 'ItemDiary',
@ -160,6 +163,16 @@ const updateStock = async () => {
>
<QTooltip>{{ t('item.descriptor.itemDiary') }}</QTooltip>
</QBtn>
<QBtn
:to="{
name: 'ItemLastEntries',
}"
size="md"
icon="vn:regentry"
color="primary"
>
<QTooltip>{{ t('item.descriptor.itemLastEntries') }}</QTooltip>
</QBtn>
</QCardActions>
</template>
</CardDescriptor>

View File

@ -4,7 +4,7 @@ import ItemSummary from './ItemSummary.vue';
const $props = defineProps({
id: {
type: Number,
type: [Number, String],
required: true,
},
dated: {
@ -21,9 +21,8 @@ const $props = defineProps({
},
});
</script>
<template>
<QPopupProxy>
<QPopupProxy style="max-width: 10px">
<ItemDescriptor
v-if="$props.id"
:id="$props.id"
@ -31,6 +30,7 @@ const $props = defineProps({
:dated="dated"
:sale-fk="saleFk"
:warehouse-fk="warehouseFk"
:proxy-render="true"
/>
</QPopupProxy>
</template>

View File

@ -65,10 +65,19 @@ const columns = computed(() => [
name: 'name',
...defaultColumnAttrs,
create: true,
columnFilter: {
component: 'select',
attrs: {
url: 'Items',
fields: ['id', 'name', 'subName'],
optionLabel: 'name',
optionValue: 'name',
uppercase: false,
},
},
},
{
label: t('item.fixedPrice.groupingPrice'),
field: 'rate2',
name: 'rate2',
...defaultColumnAttrs,
component: 'input',
@ -76,7 +85,6 @@ const columns = computed(() => [
},
{
label: t('item.fixedPrice.packingPrice'),
field: 'rate3',
name: 'rate3',
...defaultColumnAttrs,
component: 'input',
@ -85,7 +93,6 @@ const columns = computed(() => [
{
label: t('item.fixedPrice.minPrice'),
field: 'minPrice',
name: 'minPrice',
...defaultColumnAttrs,
component: 'input',
@ -108,7 +115,6 @@ const columns = computed(() => [
},
{
label: t('item.fixedPrice.ended'),
field: 'ended',
name: 'ended',
...defaultColumnAttrs,
columnField: {
@ -124,7 +130,6 @@ const columns = computed(() => [
{
label: t('globals.warehouse'),
field: 'warehouseFk',
name: 'warehouseFk',
...defaultColumnAttrs,
columnClass: 'shrink',
@ -415,7 +420,6 @@ function handleOnDataSave({ CrudModelRef }) {
'row-key': 'id',
selection: 'multiple',
}"
:use-model="true"
v-model:selected="rowsSelected"
:create-as-dialog="false"
:create="{

View File

@ -26,7 +26,6 @@ const entityId = computed(() => {
</script>
<template>
<CardDescriptor
module="ItemType"
:url="`ItemTypes/${entityId}`"
:filter="filter"
title="code"

View File

@ -0,0 +1,332 @@
<script setup>
import { ref, computed } from 'vue';
import { useI18n } from 'vue-i18n';
import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
import { toCurrency } from 'filters/index';
import VnStockValueDisplay from 'src/components/ui/VnStockValueDisplay.vue';
import VnTable from 'src/components/VnTable/VnTable.vue';
import axios from 'axios';
import notifyResults from 'src/utils/notifyResults';
import FetchData from 'components/FetchData.vue';
const MATCH = 'match';
const { t } = useI18n();
const $props = defineProps({
itemLack: {
type: Object,
required: true,
default: () => {},
},
replaceAction: {
type: Boolean,
required: false,
default: false,
},
sales: {
type: Array,
required: false,
default: () => [],
},
});
const proposalSelected = ref([]);
const ticketConfig = ref({});
const proposalTableRef = ref(null);
const sale = computed(() => $props.sales[0]);
const saleFk = computed(() => sale.value.saleFk);
const filter = computed(() => ({
itemFk: $props.itemLack.itemFk,
sales: saleFk.value,
}));
const defaultColumnAttrs = {
align: 'center',
sortable: false,
};
const emit = defineEmits(['onDialogClosed', 'itemReplaced']);
const conditionalValuePrice = (price) =>
price > 1 + ticketConfig.value.lackAlertPrice / 100 ? 'match' : 'not-match';
const columns = computed(() => [
{
...defaultColumnAttrs,
label: t('proposal.available'),
name: 'available',
field: 'available',
columnFilter: {
component: 'input',
type: 'number',
columnClass: 'shrink',
},
columnClass: 'shrink',
},
{
...defaultColumnAttrs,
label: t('proposal.counter'),
name: 'counter',
field: 'counter',
columnClass: 'shrink',
style: 'max-width: 75px',
columnFilter: {
component: 'input',
type: 'number',
columnClass: 'shrink',
},
},
{
align: 'left',
sortable: true,
label: t('proposal.longName'),
name: 'longName',
field: 'longName',
columnClass: 'expand',
},
{
align: 'left',
sortable: true,
label: t('item.list.color'),
name: 'tag5',
field: 'value5',
columnClass: 'expand',
},
{
align: 'left',
sortable: true,
label: t('item.list.stems'),
name: 'tag6',
field: 'value6',
columnClass: 'expand',
},
{
align: 'left',
sortable: true,
label: t('item.list.producer'),
name: 'tag7',
field: 'value7',
columnClass: 'expand',
},
{
...defaultColumnAttrs,
label: t('proposal.price2'),
name: 'price2',
style: 'max-width: 75px',
columnFilter: {
component: 'input',
type: 'number',
columnClass: 'shrink',
},
},
{
...defaultColumnAttrs,
label: t('proposal.minQuantity'),
name: 'minQuantity',
field: 'minQuantity',
style: 'max-width: 75px',
columnFilter: {
component: 'input',
type: 'number',
columnClass: 'shrink',
},
},
{
...defaultColumnAttrs,
label: t('proposal.located'),
name: 'located',
field: 'located',
},
{
align: 'right',
label: '',
name: 'tableActions',
actions: [
{
title: t('Replace'),
icon: 'change_circle',
show: (row) => isSelectionAvailable(row),
action: change,
isPrimary: true,
},
],
},
]);
function extractMatchValues(obj) {
return Object.keys(obj)
.filter((key) => key.startsWith(MATCH))
.map((key) => parseInt(key.replace(MATCH, ''), 10));
}
const gradientStyle = (value) => {
let color = 'white';
const perc = parseFloat(value);
switch (true) {
case perc >= 0 && perc < 33:
color = 'primary';
break;
case perc >= 33 && perc < 66:
color = 'warning';
break;
default:
color = 'secondary';
break;
}
return color;
};
const statusConditionalValue = (row) => {
const matches = extractMatchValues(row);
const value = matches.reduce((acc, i) => acc + row[`${MATCH}${i}`], 0);
return 100 * (value / matches.length);
};
const isSelectionAvailable = (itemProposal) => {
const { price2 } = itemProposal;
const salePrice = sale.value.price;
const byPrice = (100 * price2) / salePrice > ticketConfig.value.lackAlertPrice;
if (byPrice) {
return byPrice;
}
const byQuantity =
(100 * itemProposal.available) / Math.abs($props.itemLack.lack) <
ticketConfig.value.lackAlertPrice;
return byQuantity;
};
async function change({ itemFk: substitutionFk }) {
try {
const promises = $props.sales.map(({ saleFk, quantity }) => {
const params = {
saleFk,
substitutionFk,
quantity,
};
return axios.post('Sales/replaceItem', params);
});
const results = await Promise.allSettled(promises);
notifyResults(results, 'saleFk');
emit('itemReplaced', {
type: 'refresh',
quantity: quantity.value,
itemProposal: proposalSelected.value[0],
});
proposalSelected.value = [];
} catch (error) {
console.error(error);
}
}
async function handleTicketConfig(data) {
ticketConfig.value = data[0];
}
</script>
<template>
<FetchData
url="TicketConfigs"
:filter="{ fields: ['lackAlertPrice'] }"
@on-fetch="handleTicketConfig"
auto-load
/>
<VnTable
v-if="ticketConfig"
auto-load
data-cy="proposalTable"
ref="proposalTableRef"
data-key="ItemsGetSimilar"
url="Items/getSimilar"
:user-filter="filter"
:columns="columns"
class="full-width q-mt-md"
row-key="id"
:row-click="change"
:is-editable="false"
:right-search="false"
:without-header="true"
:disable-option="{ card: true, table: true }"
>
<template #column-longName="{ row }">
<QTd
class="flex"
style="max-width: 100%; flex-shrink: 50px; flex-wrap: nowrap"
>
<div
class="middle full-width"
:class="[`proposal-${gradientStyle(statusConditionalValue(row))}`]"
>
<QTooltip> {{ statusConditionalValue(row) }}% </QTooltip>
</div>
<div style="flex: 2 0 100%; align-content: center">
<div>
<span class="link">{{ row.longName }}</span>
<ItemDescriptorProxy :id="row.id" />
</div>
</div>
</QTd>
</template>
<template #column-tag5="{ row }">
<span :class="{ match: !row.match5 }">{{ row.value5 }}</span>
</template>
<template #column-tag6="{ row }">
<span :class="{ match: !row.match6 }">{{ row.value6 }}</span>
</template>
<template #column-tag7="{ row }">
<span :class="{ match: !row.match7 }">{{ row.value7 }}</span>
</template>
<template #column-counter="{ row }">
<span
:class="{
match: row.counter === 1,
'not-match': row.counter !== 1,
}"
>{{ row.counter }}</span
>
</template>
<template #column-minQuantity="{ row }">
{{ row.minQuantity }}
</template>
<template #column-price2="{ row }">
<div class="flex column items-center content-center">
<VnStockValueDisplay :value="(sales[0].price - row.price2) / 100" />
<span :class="[conditionalValuePrice(row.price2)]">{{
toCurrency(row.price2)
}}</span>
</div>
</template>
</VnTable>
</template>
<style lang="scss" scoped>
@import 'src/css/quasar.variables.scss';
.middle {
float: left;
margin-right: 2px;
flex: 2 0 5px;
}
.match {
color: $negative;
}
.not-match {
color: inherit;
}
.proposal-warning {
background-color: $warning;
}
.proposal-secondary {
background-color: $secondary;
}
.proposal-primary {
background-color: $primary;
}
.text {
margin: 0.05rem;
padding: 1px;
border: 1px solid var(--vn-label-color);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-size: smaller;
}
</style>

View File

@ -0,0 +1,56 @@
<script setup>
import ItemProposal from './ItemProposal.vue';
import { useDialogPluginComponent } from 'quasar';
const $props = defineProps({
itemLack: {
type: Object,
required: true,
default: () => {},
},
replaceAction: {
type: Boolean,
required: false,
default: false,
},
sales: {
type: Array,
required: false,
default: () => [],
},
});
const { dialogRef } = useDialogPluginComponent();
const emit = defineEmits([
'onDialogClosed',
'itemReplaced',
...useDialogPluginComponent.emits,
]);
defineExpose({ show: () => dialogRef.value.show(), hide: () => dialogRef.value.hide() });
</script>
<template>
<QDialog ref="dialogRef" transition-show="scale" transition-hide="scale">
<QCard class="dialog-width">
<QCardSection class="row items-center q-pb-none">
<span class="text-h6 text-grey">{{ $t('Item proposal') }}</span>
<QSpace />
<QBtn icon="close" flat round dense v-close-popup />
</QCardSection>
<QCardSection>
<ItemProposal
v-bind="$props"
@item-replaced="
(data) => {
emit('itemReplaced', data);
dialogRef.hide();
}
"
></ItemProposal
></QCardSection>
</QCard>
</QDialog>
</template>
<style lang="scss" scoped>
.dialog-width {
max-width: $width-lg;
}
</style>

View File

@ -112,6 +112,7 @@ item:
available: Available
warehouseText: 'Calculated on the warehouse of { warehouseName }'
itemDiary: Item diary
itemLastEntries: Last entries
producer: Producer
clone:
title: All its properties will be copied
@ -130,6 +131,7 @@ item:
origin: Orig.
userName: Buyer
weight: Weight
color: Color
weightByPiece: Weight/stem
stemMultiplier: Multiplier
producer: Producer
@ -216,3 +218,23 @@ item:
search: 'Search item'
searchInfo: 'You can search by id'
regularizeStock: Regularize stock
itemProposal: Items proposal
proposal:
difference: Difference
title: Items proposal
itemFk: Item
longName: Name
subName: Producer
value5: value5
value6: value6
value7: value7
value8: value8
available: Available
minQuantity: minQuantity
price2: Price
located: Located
counter: Counter
groupingPrice: Grouping Price
itemOldPrice: itemOld Price
status: State
quantityToReplace: Quanity to replace

View File

@ -118,6 +118,7 @@ item:
available: Disponible
warehouseText: 'Calculado sobre el almacén de { warehouseName }'
itemDiary: Registro de compra-venta
itemLastEntries: Últimas entradas
producer: Productor
clone:
title: Todas sus propiedades serán copiadas
@ -135,6 +136,7 @@ item:
size: Medida
origin: Orig.
weight: Peso
color: Color
weightByPiece: Peso/tallo
userName: Comprador
stemMultiplier: Multiplicador
@ -220,5 +222,30 @@ item:
achieved: 'Conseguido'
concept: 'Concepto'
state: 'Estado'
search: 'Buscar artículo'
searchInfo: 'Puedes buscar por id'
itemProposal: Artículos similares
proposal:
substitutionAvailable: Sustitución disponible
notSubstitutionAvailableByPrice: Sustitución no disponible, 30% de diferencia por precio o cantidad
compatibility: Compatibilidad
title: Items de sustitución para los tickets seleccionados
itemFk: Item
longName: Nombre
subName: Productor
value5: value5
value6: value6
value7: value7
value8: value8
available: Disponible
minQuantity: Min. cantidad
price2: Precio
located: Ubicado
counter: Contador
difference: Diferencial
groupingPrice: Precio Grouping
itemOldPrice: Precio itemOld
status: Estado
quantityToReplace: Cantidad a reemplazar
replace: Sustituir
replaceAndConfirm: Sustituir y confirmar precio
search: 'Buscar artículo'
searchInfo: 'Puedes buscar por id'

View File

@ -157,7 +157,7 @@ const openTab = (id) =>
openConfirmationModal(
$t('globals.deleteConfirmTitle'),
$t('salesOrdersTable.deleteConfirmMessage'),
removeOrders
removeOrders,
)
"
>

View File

@ -43,10 +43,9 @@ const addToOrder = async () => {
);
state.set('orderTotal', orderTotal);
const rows = orderData.value.rows.push(...items) || [];
state.set('Order', {
...orderData.value,
rows,
items,
});
notify(t('globals.dataSaved'), 'positive');
emit('added', -totalQuantity(items));

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