diff --git a/CHANGELOG.md b/CHANGELOG.md index 1dbc270b9..0573a6790 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,10 +6,17 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2340.01] - 2023-10-05 + +### Added +### Changed + +### Fixed + ## [2338.01] - 2023-09-21 ### Added - +- (Ticket -> Servicios) Se pueden abonar servicios ### Changed - (Trabajadores -> Calendario) Icono de check arreglado cuando pulsas un tipo de dia diff --git a/back/model-config.json b/back/model-config.json index b88956dee..ebc0e321b 100644 --- a/back/model-config.json +++ b/back/model-config.json @@ -15,6 +15,9 @@ }, "Bank": { "dataSource": "vn" + }, + "Buyer": { + "dataSource": "vn" }, "Campaign": { "dataSource": "vn" diff --git a/back/models/buyer.json b/back/models/buyer.json new file mode 100644 index 000000000..a17d3b538 --- /dev/null +++ b/back/models/buyer.json @@ -0,0 +1,28 @@ +{ + "name": "Buyer", + "base": "VnModel", + "options": { + "mysql": { + "table": "buyer" + } + }, + "properties": { + "userFk": { + "type": "number", + "required": true, + "id": true + }, + "nickname": { + "type": "string", + "required": true + } + }, + "acls": [ + { + "accessType": "READ", + "principalType": "ROLE", + "principalId": "employee", + "permission": "ALLOW" + } + ] +} diff --git a/db/changes/233601/00-createClaimReader.sql b/db/changes/233601/00-createClaimReader.sql index 666bf232e..e913c0ed9 100644 --- a/db/changes/233601/00-createClaimReader.sql +++ b/db/changes/233601/00-createClaimReader.sql @@ -1,4 +1,4 @@ -INSERT INTO `account`.`role` (`id`, `name`, `description`, `hasLogin`) +INSERT INTO `account`.`role` (`name`, `description`, `hasLogin`) VALUES ('claimViewer','Trabajadores que consulta las reclamaciones ',1); INSERT INTO `account`.`roleInherit` (`role`,`inheritsFrom`) @@ -10,7 +10,7 @@ INSERT INTO `account`.`roleInherit` (`role`,`inheritsFrom`) 'buyer', 'deliveryBoss', 'handmadeBoss' - ) + ); DELETE FROM `salix`.`ACL` WHERE `model`= 'claim' @@ -28,5 +28,4 @@ INSERT INTO `salix`.`ACL` (`model`,`property`,`accessType`,`permission`,`princip INSERT INTO `salix`.`ACL` (`model`,`property`,`accessType`,`permission`,`principalType`,`principalid`) VALUES ('Claim','findById','READ','ALLOW','ROLE','claimViewer'); INSERT INTO `salix`.`ACL` (`model`,`property`,`accessType`,`permission`,`principalType`,`principalid`) - VALUES ('Claim','getSummary','READ','ALLOW','ROLE','claimViewer'); - + VALUES ('Claim','getSummary','READ','ALLOW','ROLE','claimViewer'); \ No newline at end of file diff --git a/db/changes/233801/00-firstScript.sql b/db/changes/233801/00-firstScript.sql new file mode 100644 index 000000000..47b96b3bc --- /dev/null +++ b/db/changes/233801/00-firstScript.sql @@ -0,0 +1 @@ +ALTER TABLE `vn`.`province` ADD CONSTRAINT `countryName_UN` UNIQUE KEY (`countryFk`,`name`); diff --git a/db/changes/233801/00-item_setVisibleDiscard.sql b/db/changes/233801/00-item_setVisibleDiscard.sql new file mode 100644 index 000000000..6ee66a947 --- /dev/null +++ b/db/changes/233801/00-item_setVisibleDiscard.sql @@ -0,0 +1,62 @@ + +DELIMITER $$ +CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`item_setVisibleDiscard`( + vItemFk INT, + vWarehouseFk INT, + vQuantity INT, + vAddressFk INT) + +BEGIN + DECLARE vTicketFk INT; + DECLARE vClientFk INT; + DECLARE vCompanyVnlFk INT; + DECLARE vCalc INT; + + SELECT barcodeToItem(vItemFk) INTO vItemFk; + + SELECT DEFAULT(companyFk) INTO vCompanyVnlFk + FROM vn.ticket LIMIT 1; + + SELECT a.clientFk INTO vClientFk + FROM address a + WHERE a.id = vAddressFk; + + SELECT t.id INTO vTicketFk + FROM ticket t + JOIN address a ON a.id = t.addressFk + WHERE t.warehouseFk = vWarehouseFk + AND a.id = vAddressFk + AND DATE(t.shipped) = util.VN_CURDATE(); + + CALL cache.visible_refresh(vCalc, TRUE, vWarehouseFk); + + IF vTicketFk IS NULL THEN + CALL ticket_add( + vClientFk, + util.VN_CURDATE(), + vWarehouseFk, + vCompanyVnlFk, + vAddressFk, + NULL, + NULL, + util.VN_CURDATE(), + account.myUser_getId(), + FALSE, + vTicketFk); + END IF; + + INSERT INTO sale(ticketFk, itemFk, concept, quantity) + SELECT vTicketFk, + vItemFk, + CONCAT(longName,' ', getWorkerCode(), ' ', LEFT(CAST(util.VN_NOW() AS TIME),5)), + vQuantity + FROM item + WHERE id = vItemFk; + + UPDATE cache.visible + SET visible = visible - vQuantity + WHERE calc_id = vCalc + AND item_id = vItemFk; +END$$ +DELIMITER ; + diff --git a/db/changes/233801/00-ticketConfig.sql b/db/changes/233801/00-ticketConfig.sql new file mode 100644 index 000000000..5429878b4 --- /dev/null +++ b/db/changes/233801/00-ticketConfig.sql @@ -0,0 +1,7 @@ + + INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId) + VALUES('Item', 'setVisibleDiscard', 'WRITE', 'ALLOW', 'ROLE', 'employee'); + + INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId) + VALUES('Address', 'getAddress', 'READ', 'ALLOW', 'ROLE', 'employee'); + diff --git a/db/changes/233401/01-deviceLog_acl.sql b/db/changes/233801/01-deviceLog_acl.sql similarity index 100% rename from db/changes/233401/01-deviceLog_acl.sql rename to db/changes/233801/01-deviceLog_acl.sql diff --git a/db/changes/234001/.gitkeep b/db/changes/234001/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index 7a126d4cc..9be9d69f6 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -358,20 +358,20 @@ INSERT INTO `vn`.`contactChannel`(`id`, `name`) (4, 'GCN Channel'), (5, 'The Newspaper'); -INSERT INTO `vn`.`client`(`id`,`name`,`fi`,`socialName`,`contact`,`street`,`city`,`postcode`,`phone`,`mobile`,`isRelevant`,`email`,`iban`,`dueDay`,`accountingAccount`,`isEqualizated`,`provinceFk`,`hasToInvoice`,`credit`,`countryFk`,`isActive`,`gestdocFk`,`quality`,`payMethodFk`,`created`,`isToBeMailed`,`contactChannelFk`,`hasSepaVnl`,`hasCoreVnl`,`hasCoreVnh`,`riskCalculated`,`clientTypeFk`, `hasToInvoiceByAddress`,`isTaxDataChecked`,`isFreezed`,`creditInsurance`,`isCreatedAsServed`,`hasInvoiceSimplified`,`salesPersonFk`,`isVies`,`eypbc`, `businessTypeFk`) +INSERT INTO `vn`.`client`(`id`,`name`,`fi`,`socialName`,`contact`,`street`,`city`,`postcode`,`phone`,`mobile`,`isRelevant`,`email`,`iban`,`dueDay`,`accountingAccount`,`isEqualizated`,`provinceFk`,`hasToInvoice`,`credit`,`countryFk`,`isActive`,`gestdocFk`,`quality`,`payMethodFk`,`created`,`isToBeMailed`,`contactChannelFk`,`hasSepaVnl`,`hasCoreVnl`,`hasCoreVnh`,`riskCalculated`,`clientTypeFk`, `hasToInvoiceByAddress`,`isTaxDataChecked`,`isFreezed`,`creditInsurance`,`isCreatedAsServed`,`hasInvoiceSimplified`,`salesPersonFk`,`isVies`,`eypbc`, `businessTypeFk`,`typeFk`) VALUES - (1101, 'Bruce Wayne', '84612325V', 'BATMAN', 'Alfred', '1007 MOUNTAIN DRIVE, GOTHAM', 'Gotham', 46460, 1111111111, 222222222, 1, 'BruceWayne@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist'), - (1102, 'Petter Parker', '87945234L', 'SPIDER MAN', 'Aunt May', '20 INGRAM STREET, QUEENS, USA', 'Gotham', 46460, 1111111111, 222222222, 1, 'PetterParker@mydomain.com', NULL, 0, 1234567890, 0, 2, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist'), - (1103, 'Clark Kent', '06815934E', 'SUPER MAN', 'lois lane', '344 CLINTON STREET, APARTAMENT 3-D', 'Gotham', 46460, 1111111111, 222222222, 1, 'ClarkKent@mydomain.com', NULL, 0, 1234567890, 0, 3, 1, 0, 19, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist'), - (1104, 'Tony Stark', '06089160W', 'IRON MAN', 'Pepper Potts', '10880 MALIBU POINT, 90265', 'Gotham', 46460, 1111111111, 222222222, 1, 'TonyStark@mydomain.com', NULL, 0, 1234567890, 0, 2, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist'), - (1105, 'Max Eisenhardt', '251628698', 'MAGNETO', 'Rogue', 'UNKNOWN WHEREABOUTS', 'Gotham', 46460, 1111111111, 222222222, 1, 'MaxEisenhardt@mydomain.com', NULL, 0, 1234567890, 0, 3, 1, 300, 8, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 1, NULL, 0, 0, 18, 0, 1, 'florist'), - (1106, 'DavidCharlesHaller', '53136686Q', 'LEGION', 'Charles Xavier', 'CITY OF NEW YORK, NEW YORK, USA', 'Gotham', 46460, 1111111111, 222222222, 1, 'DavidCharlesHaller@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 0, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 0, NULL, 0, 0, 19, 0, 1, 'florist'), - (1107, 'Hank Pym', '09854837G', 'ANT MAN', 'Hawk', 'ANTHILL, SAN FRANCISCO, CALIFORNIA', 'Gotham', 46460, 1111111111, 222222222, 1, 'HankPym@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 0, 0, NULL, 0, 0, 19, 0, 1, 'florist'), - (1108, 'Charles Xavier', '22641921P', 'PROFESSOR X', 'Beast', '3800 VICTORY PKWY, CINCINNATI, OH 45207, USA', 'Gotham', 46460, 1111111111, 222222222, 1, 'CharlesXavier@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 1, NULL, 0, 0, 19, 0, 1, 'florist'), - (1109, 'Bruce Banner', '16104829E', 'HULK', 'Black widow', 'SOMEWHERE IN NEW YORK', 'Gotham', 46460, 1111111111, 222222222, 1, 'BruceBanner@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 0, 0, NULL, 0, 0, 9, 0, 1, 'florist'), - (1110, 'Jessica Jones', '58282869H', 'JESSICA JONES', 'Luke Cage', 'NYCC 2015 POSTER', 'Gotham', 46460, 1111111111, 222222222, 1, 'JessicaJones@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 0, 0, NULL, 0, 0, NULL, 0, 1, 'florist'), - (1111, 'Missing', NULL, 'MISSING MAN', 'Anton', 'THE SPACE, UNIVERSE FAR AWAY', 'Gotham', 46460, 1111111111, 222222222, 1, NULL, NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 4, 0, 1, 0, NULL, 1, 0, NULL, 0, 1, 'others'), - (1112, 'Trash', NULL, 'GARBAGE MAN', 'Unknown name', 'NEW YORK CITY, UNDERGROUND', 'Gotham', 46460, 1111111111, 222222222, 1, NULL, NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 4, 0, 1, 0, NULL, 1, 0, NULL, 0, 1, 'others'); + (1101, 'Bruce Wayne', '84612325V', 'BATMAN', 'Alfred', '1007 MOUNTAIN DRIVE, GOTHAM', 'Gotham', 46460, 1111111111, 222222222, 1, 'BruceWayne@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist','loses'), + (1102, 'Petter Parker', '87945234L', 'SPIDER MAN', 'Aunt May', '20 INGRAM STREET, QUEENS, USA', 'Gotham', 46460, 1111111111, 222222222, 1, 'PetterParker@mydomain.com', NULL, 0, 1234567890, 0, 2, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist','normal'), + (1103, 'Clark Kent', '06815934E', 'SUPER MAN', 'lois lane', '344 CLINTON STREET, APARTAMENT 3-D', 'Gotham', 46460, 1111111111, 222222222, 1, 'ClarkKent@mydomain.com', NULL, 0, 1234567890, 0, 3, 1, 0, 19, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist','normal'), + (1104, 'Tony Stark', '06089160W', 'IRON MAN', 'Pepper Potts', '10880 MALIBU POINT, 90265', 'Gotham', 46460, 1111111111, 222222222, 1, 'TonyStark@mydomain.com', NULL, 0, 1234567890, 0, 2, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist','normal'), + (1105, 'Max Eisenhardt', '251628698', 'MAGNETO', 'Rogue', 'UNKNOWN WHEREABOUTS', 'Gotham', 46460, 1111111111, 222222222, 1, 'MaxEisenhardt@mydomain.com', NULL, 0, 1234567890, 0, 3, 1, 300, 8, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 1, NULL, 0, 0, 18, 0, 1, 'florist','normal'), + (1106, 'DavidCharlesHaller', '53136686Q', 'LEGION', 'Charles Xavier', 'CITY OF NEW YORK, NEW YORK, USA', 'Gotham', 46460, 1111111111, 222222222, 1, 'DavidCharlesHaller@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 0, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 0, NULL, 0, 0, 19, 0, 1, 'florist','normal'), + (1107, 'Hank Pym', '09854837G', 'ANT MAN', 'Hawk', 'ANTHILL, SAN FRANCISCO, CALIFORNIA', 'Gotham', 46460, 1111111111, 222222222, 1, 'HankPym@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 0, 0, NULL, 0, 0, 19, 0, 1, 'florist','normal'), + (1108, 'Charles Xavier', '22641921P', 'PROFESSOR X', 'Beast', '3800 VICTORY PKWY, CINCINNATI, OH 45207, USA', 'Gotham', 46460, 1111111111, 222222222, 1, 'CharlesXavier@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 1, NULL, 0, 0, 19, 0, 1, 'florist','normal'), + (1109, 'Bruce Banner', '16104829E', 'HULK', 'Black widow', 'SOMEWHERE IN NEW YORK', 'Gotham', 46460, 1111111111, 222222222, 1, 'BruceBanner@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 0, 0, NULL, 0, 0, 9, 0, 1, 'florist','normal'), + (1110, 'Jessica Jones', '58282869H', 'JESSICA JONES', 'Luke Cage', 'NYCC 2015 POSTER', 'Gotham', 46460, 1111111111, 222222222, 1, 'JessicaJones@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 0, 0, NULL, 0, 0, NULL, 0, 1, 'florist','normal'), + (1111, 'Missing', NULL, 'MISSING MAN', 'Anton', 'THE SPACE, UNIVERSE FAR AWAY', 'Gotham', 46460, 1111111111, 222222222, 1, NULL, NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 4, 0, 1, 0, NULL, 1, 0, NULL, 0, 1, 'others','normal'), + (1112, 'Trash', NULL, 'GARBAGE MAN', 'Unknown name', 'NEW YORK CITY, UNDERGROUND', 'Gotham', 46460, 1111111111, 222222222, 1, NULL, NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 4, 0, 1, 0, NULL, 1, 0, NULL, 0, 1, 'others','normal'); INSERT INTO `vn`.`client`(`id`, `name`, `fi`, `socialName`, `contact`, `street`, `city`, `postcode`, `isRelevant`, `email`, `iban`,`dueDay`,`accountingAccount`, `isEqualizated`, `provinceFk`, `hasToInvoice`, `credit`, `countryFk`, `isActive`, `gestdocFk`, `quality`, `payMethodFk`,`created`, `isTaxDataChecked`) SELECT id, name, CONCAT(RPAD(CONCAT(id,9),8,id),'A'), CONCAT(name, 'Social'), CONCAT(name, 'Contact'), CONCAT(name, 'Street'), 'GOTHAM', 46460, 1, CONCAT(name,'@mydomain.com'), NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1,NULL, 10, 5, util.VN_CURDATE(), 1 @@ -2780,11 +2780,13 @@ INSERT INTO `util`.`notification` (`id`, `name`, `description`) (2, 'invoice-electronic', 'A electronic invoice has been generated'), (3, 'not-main-printer-configured', 'A printer distinct than main has been configured'), (4, 'supplier-pay-method-update', 'A supplier pay method has been updated'), - (5, 'modified-entry', 'An entry has been modified'); + (5, 'modified-entry', 'An entry has been modified'), + (6, 'book-entry-deleted', 'accounting entries deleted'); INSERT INTO `util`.`notificationAcl` (`notificationFk`, `roleFk`) VALUES - (1, 9); + (1, 9), + (6, 9); INSERT INTO `util`.`notificationQueue` (`id`, `notificationFk`, `params`, `authorFk`, `status`, `created`) VALUES @@ -2797,8 +2799,9 @@ INSERT INTO `util`.`notificationSubscription` (`notificationFk`, `userFk`) (1, 1109), (1, 1110), (2, 1109), - (1,9), - (1,3); + (1, 9), + (1, 3), + (6, 9); INSERT INTO `vn`.`routeConfig` (`id`, `defaultWorkCenterFk`) @@ -2962,3 +2965,14 @@ INSERT INTO `vn`.`invoiceInSerial` (`code`, `description`, `cplusTerIdNifFk`, `t INSERT INTO `hedera`.`imageConfig` (`id`, `maxSize`, `useXsendfile`, `url`) VALUES (1, 0, 0, 'marvel.com'); + +INSERT INTO vn.XDiario (id, ASIEN, FECHA, SUBCTA, CONTRA, CONCEPTO, EURODEBE, EUROHABER, BASEEURO, SERIE, FACTURA, IVA, RECEQUIV, CLAVE, CAMBIO, DEBEME, HABERME, AUXILIAR, MONEDAUSO, TIPOOPE, NFACTICK, TERIDNIF, TERNIF, TERNOM, OPBIENES, L340, enlazado, FECHA_EX, LRECT349, empresa_id, LDIFADUAN, METAL, METALIMP, CLIENTE, METALEJE, FECHA_OP, FACTURAEX, TIPOCLAVE, TIPOEXENCI, TIPONOSUJE, TIPOFACT, TIPORECTIF, SERIE_RT, FACTU_RT, BASEIMP_RT, BASEIMP_RF, RECTIFICA, FECHA_RT, FECREGCON, enlazadoSage) + VALUES + (1, 1.0, util.VN_CURDATE(), '4300001104', NULL, 'n/fra T3333333', 8.88, NULL, NULL, NULL, '0', NULL, 0.00, NULL, NULL, NULL, NULL, NULL, '2', NULL, 1, 2, 'I.F.', 'Nombre Importador', 1, 0, 0, util.VN_CURDATE(), 0, 442, 0, 0, 0.00, NULL, NULL, util.VN_CURDATE(), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, 1), + (2, 1.0, util.VN_CURDATE(), '2000000000', '4300001104', 'n/fra T3333333 Tony Stark', NULL, 8.07, NULL, NULL, '0', NULL, 0.00, NULL, NULL, NULL, NULL, NULL, '2', NULL, 1, 2, 'I.F.', 'Nombre Importador', 1, 0, 0, util.VN_CURDATE(), 0, 442, 0, 0, 0.00, NULL, NULL, util.VN_CURDATE(), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, 1), + (3, 1.0, util.VN_CURDATE(), '4770000010', '4300001104', 'Inmovilizado pendiente : n/fra T3333333 Tony Stark', NULL, 0.81, 8.07, 'T', '3333333', 10.00, NULL, NULL, NULL, NULL, NULL, '', '2', '', 1, 1, '06089160W', 'IRON MAN', 1, 1, 0, util.VN_CURDATE(), 0, 442, 0, 0, 0.00, NULL, NULL, util.VN_CURDATE(), NULL, 1, 1, 1, 1, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, 1), + (4, 2.0, util.VN_CURDATE(), '4300001104', NULL, 'n/fra T4444444', 8.88, NULL, NULL, NULL, '0', NULL, 0.00, NULL, NULL, NULL, NULL, NULL, '2', NULL, 1, 2, 'I.F.', 'Nombre Importador', 1, 0, 0, util.VN_CURDATE(), 0, 442, 0, 0, 0.00, NULL, NULL, util.VN_CURDATE(), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, 0), + (5, 2.0, util.VN_CURDATE(), '2000000000', '4300001104', 'n/fra T4444444 Tony Stark', NULL, 8.07, NULL, NULL, '0', NULL, 0.00, NULL, NULL, NULL, NULL, NULL, '2', NULL, 1, 2, 'I.F.', 'Nombre Importador', 1, 0, 0, util.VN_CURDATE(), 0, 442, 0, 0, 0.00, NULL, NULL, util.VN_CURDATE(), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, 0), + (6, 2.0, util.VN_CURDATE(), '4770000010', '4300001104', 'Inmovilizado pendiente : n/fra T4444444 Tony Stark', NULL, 0.81, 8.07, 'T', '4444444', 10.00, NULL, NULL, NULL, NULL, NULL, '', '2', '', 1, 1, '06089160W', 'IRON MAN', 1, 1, 0, util.VN_CURDATE(), 0, 442, 0, 0, 0.00, NULL, NULL, util.VN_CURDATE(), NULL, 1, 1, 1, 1, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, 0); + + \ No newline at end of file diff --git a/e2e/helpers/selectors.js b/e2e/helpers/selectors.js index fe3633723..1b18eb866 100644 --- a/e2e/helpers/selectors.js +++ b/e2e/helpers/selectors.js @@ -671,8 +671,8 @@ export default { firstAddServiceTypeButton: 'vn-ticket-service vn-icon-button[vn-tooltip="New service type"]', firstServiceType: 'vn-ticket-service vn-autocomplete[ng-model="service.ticketServiceTypeFk"]', firstQuantity: 'vn-ticket-service vn-input-number[ng-model="service.quantity"]', - firstPrice: 'vn-ticket-service vn-horizontal:nth-child(1) vn-input-number[ng-model="service.price"]', - fistDeleteServiceButton: 'vn-ticket-service form vn-horizontal:nth-child(1) vn-icon-button[icon="delete"]', + firstPrice: 'vn-ticket-service vn-horizontal:nth-child(2) vn-input-number[ng-model="service.price"]', + fistDeleteServiceButton: 'vn-ticket-service form vn-horizontal:nth-child(2) vn-icon-button[icon="delete"]', newServiceTypeName: '.vn-dialog.shown vn-textfield[ng-model="newServiceType.name"]', serviceLine: 'vn-ticket-service > form > vn-card > vn-one:nth-child(2) > vn-horizontal', saveServiceButton: 'button[type=submit]', diff --git a/e2e/paths/09-invoice-in/03_basic_data.spec.js b/e2e/paths/09-invoice-in/03_basic_data.spec.js index 778b5949c..50fe18830 100644 --- a/e2e/paths/09-invoice-in/03_basic_data.spec.js +++ b/e2e/paths/09-invoice-in/03_basic_data.spec.js @@ -82,32 +82,24 @@ describe('InvoiceIn basic data path', () => { await page.waitToClick(selectors.invoiceInBasicData.confirm); let message = await page.waitForSnackbar(); - expect(message.text).toContain('The company can\'t be empty'); - await page.clearInput(selectors.invoiceInBasicData.companyId); await page.autocompleteSearch(selectors.invoiceInBasicData.companyId, 'VNL'); await page.waitToClick(selectors.invoiceInBasicData.confirm); message = await page.waitForSnackbar(); - expect(message.text).toContain('The warehouse can\'t be empty'); - await page.clearInput(selectors.invoiceInBasicData.warehouseId); await page.autocompleteSearch(selectors.invoiceInBasicData.warehouseId, 'Warehouse One'); await page.waitToClick(selectors.invoiceInBasicData.confirm); message = await page.waitForSnackbar(); - expect(message.text).toContain('The DMS Type can\'t be empty'); - await page.clearInput(selectors.invoiceInBasicData.dmsTypeId); await page.autocompleteSearch(selectors.invoiceInBasicData.dmsTypeId, 'Ticket'); await page.waitToClick(selectors.invoiceInBasicData.confirm); message = await page.waitForSnackbar(); - expect(message.text).toContain('The description can\'t be empty'); - await page.waitToClick(selectors.invoiceInBasicData.description); await page.write(selectors.invoiceInBasicData.description, 'Dms without edition.'); diff --git a/front/core/lib/validator.js b/front/core/lib/validator.js index b0b8f7389..51134f30a 100644 --- a/front/core/lib/validator.js +++ b/front/core/lib/validator.js @@ -5,6 +5,10 @@ export const validators = { if (validator.isEmpty(value ? String(value) : '')) throw new Error(_($translate, `Value can't be empty`)); }, + negative: $translate => { + if (validator < 0) + throw new Error(_($translate, `Negative numbers are not allowed. Please enter a valid number.`)); + }, absence: ($translate, value) => { if (!validator.isEmpty(value)) throw new Error(_($translate, `Value should be empty`)); @@ -104,9 +108,8 @@ export function checkNull($translate, value, conf) { export function _($translate, text, params = []) { text = $translate.instant(text); - for (let i = 0; i < params.length; i++) { + for (let i = 0; i < params.length; i++) text = text.replace('%s', params[i]); - } return text; } diff --git a/front/core/locale/es.yml b/front/core/locale/es.yml index e9c2311b4..96c34d98c 100644 --- a/front/core/locale/es.yml +++ b/front/core/locale/es.yml @@ -16,6 +16,7 @@ Value can't be empty: El valor no puede estar vacío Value should be empty: El valor debe estar vacío Value should be integer: El valor debe ser entero Value should be a number: El valor debe ser numérico +Negative numbers are not allowed. Please enter a valid number: No se permiten números negativos. Por favor, ingrese un número válido Invalid value: Valor incorrecto Value can't be blank: El valor no puede estar en blanco Value can't be null: El valor no puede ser nulo diff --git a/loopback/locale/es.json b/loopback/locale/es.json index ccd63e0ff..73a3920d2 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -307,7 +307,7 @@ "Negative basis of tickets": "Base negativa para los tickets: {{ticketsIds}}", "You cannot assign an alias that you are not assigned to": "No puede asignar un alias que no tenga asignado", "This ticket cannot be left empty.": "Este ticket no se puede dejar vacío. %s", - "The company has not informed the supplier account for bank transfers": "La empresa no tiene informado la cuenta de proveedor para transferencias bancarias", + "The company has not informed the supplier account for bank transfers": "La empresa no tiene informado la cuenta de proveedor para transferencias bancarias", "You cannot assign/remove an alias that you are not assigned to": "No puede asignar/eliminar un alias que no tenga asignado", "This invoice has a linked vehicle.": "Esta factura tiene un vehiculo vinculado", "You don't have enough privileges.": "No tienes suficientes permisos.", diff --git a/modules/client/back/methods/address/getAddress.js b/modules/client/back/methods/address/getAddress.js new file mode 100644 index 000000000..a62a0ec6f --- /dev/null +++ b/modules/client/back/methods/address/getAddress.js @@ -0,0 +1,24 @@ +module.exports = Self => { + Self.remoteMethod('getAddress', { + description: 'Get all activated address with loses client activated', + accessType: 'READ', + accepts: [], + returns: { + type: ['object'], + root: true + }, + http: { + path: `/getAddress`, + verb: 'GET' + } + }); + Self.getAddress = async() => { + let getAddressQuery = ` + SELECT a.id, a.nickname + FROM vn.address a + JOIN vn.client c ON a.clientFk = c.id AND c.isActive <> FALSE + WHERE c.typeFk = 'loses' AND a.isActive <> FALSE;`; + + return result = await Self.rawSql(getAddressQuery); + }; +}; diff --git a/modules/client/back/methods/address/specs/getAddress.spec.js b/modules/client/back/methods/address/specs/getAddress.spec.js new file mode 100644 index 000000000..a86e1007c --- /dev/null +++ b/modules/client/back/methods/address/specs/getAddress.spec.js @@ -0,0 +1,9 @@ +const {models} = require('vn-loopback/server/server'); + +describe('getAddress()', () => { + it('return list of activated address with loses client activated', async() => { + let response = await models.Address.getAddress(); + + expect(response.length).toEqual(2); + }); +}); diff --git a/modules/client/back/model-config.json b/modules/client/back/model-config.json index bc48ec360..296b5e6a7 100644 --- a/modules/client/back/model-config.json +++ b/modules/client/back/model-config.json @@ -136,5 +136,8 @@ }, "Incoterms": { "dataSource": "vn" + }, + "Xdiario": { + "dataSource": "vn" } } diff --git a/modules/client/back/models/XDiario.json b/modules/client/back/models/XDiario.json index be2d258f9..be543393d 100644 --- a/modules/client/back/models/XDiario.json +++ b/modules/client/back/models/XDiario.json @@ -1,5 +1,5 @@ { - "name": "XDiario", + "name": "Xdiario", "base": "VnModel", "options": { "mysql": { @@ -7,10 +7,12 @@ } }, "properties": { - "ASIEN": { + "id": { "type": "number", - "id": true, - "description": "Identifier" + "id": true + }, + "ASIEN": { + "type": "number" }, "FECHA": { "type": "date" @@ -71,6 +73,9 @@ }, "MONEDAUSO": { "type": "string" + }, + "enlazadoSage": { + "type": "boolean" } }, "relations": { diff --git a/modules/client/back/models/address.js b/modules/client/back/models/address.js index 3a1157add..4a93b5d5c 100644 --- a/modules/client/back/models/address.js +++ b/modules/client/back/models/address.js @@ -3,6 +3,8 @@ let getFinalState = require('vn-loopback/util/hook').getFinalState; let isMultiple = require('vn-loopback/util/hook').isMultiple; module.exports = Self => { + require('../methods/address/getAddress')(Self); + Self.validateAsync('isEqualizated', cannotHaveET, { message: 'Cannot check Equalization Tax in this NIF/CIF' }); diff --git a/modules/client/front/summary/index.html b/modules/client/front/summary/index.html index a0c83ded1..e8418b860 100644 --- a/modules/client/front/summary/index.html +++ b/modules/client/front/summary/index.html @@ -262,7 +262,7 @@ value="{{$ctrl.summary.averageInvoiced.invoiced | currency: 'EUR':2}}"> + value="{{$ctrl.claimingRate($ctrl.summary.claimsRatio.claimingRate / 100) | percentage}}"> diff --git a/modules/entry/back/locale/entry/es.yml b/modules/entry/back/locale/entry/es.yml index 3a0c3d9c1..a892b05d2 100644 --- a/modules/entry/back/locale/entry/es.yml +++ b/modules/entry/back/locale/entry/es.yml @@ -4,14 +4,14 @@ columns: dated: fecha reference: referencia invoiceNumber: número factura - isBooked: reservado + isBooked: contabilizado isExcludedFromAvailable: excluido del disponible notes: notas isConfirmed: confirmado isVirtual: virtual - isRaid: incursión + isRaid: redada commission: comisión - isOrdered: precio3 + isOrdered: pedida created: creado observation: observación isBlocked: bloqueado diff --git a/modules/invoiceIn/front/basic-data/index.js b/modules/invoiceIn/front/basic-data/index.js index 8747fc4f2..246f1b16f 100644 --- a/modules/invoiceIn/front/basic-data/index.js +++ b/modules/invoiceIn/front/basic-data/index.js @@ -67,17 +67,22 @@ class Controller extends Section { } openCreateDialog() { - this.dms = { - reference: null, - warehouseId: null, - companyId: null, - dmsTypeId: null, - description: null, - hasFile: true, - hasFileAttached: true, - files: null - }; - this.$.dmsCreateDialog.show(); + const params = {filter: { + where: {code: 'invoiceIn'} + }}; + this.$http.get('DmsTypes/findOne', {params}).then(res => { + this.dms = { + reference: this.invoiceIn.supplierRef, + warehouseId: this.vnConfig.warehouseFk, + companyId: this.vnConfig.companyFk, + dmsTypeId: res.data.id, + description: this.invoiceIn.supplier.name, + hasFile: true, + hasFileAttached: true, + files: null + }; + this.$.dmsCreateDialog.show(); + }); } downloadFile(dmsId) { diff --git a/modules/invoiceIn/front/create/index.js b/modules/invoiceIn/front/create/index.js index 186f5d478..885d55359 100644 --- a/modules/invoiceIn/front/create/index.js +++ b/modules/invoiceIn/front/create/index.js @@ -6,6 +6,7 @@ class Controller extends Section { this.invoiceIn = {}; if (this.$params && this.$params.supplierFk) this.invoiceIn.supplierFk = this.$params.supplierFk; + this.invoiceIn.issued = Date.vnNew(); } get companyFk() { diff --git a/modules/invoiceIn/front/create/index.spec.js b/modules/invoiceIn/front/create/index.spec.js deleted file mode 100644 index 93109346c..000000000 --- a/modules/invoiceIn/front/create/index.spec.js +++ /dev/null @@ -1,52 +0,0 @@ -import './index.js'; -import watcher from 'core/mocks/watcher'; - -describe('InvoiceIn', () => { - describe('Component vnInvoiceInCreate', () => { - let controller; - let $element; - - beforeEach(ngModule('invoiceIn')); - - beforeEach(inject(($componentController, $rootScope) => { - const $scope = $rootScope.$new(); - $scope.watcher = watcher; - $element = angular.element(''); - controller = $componentController('vnInvoiceInCreate', {$element, $scope}); - controller.$params = {}; - })); - - afterEach(() => { - $element.remove(); - }); - - describe('onInit()', () => { - it(`should defined the controller's invoiceIn property`, () => { - expect(controller.invoiceIn).toBeUndefined(); - - controller.$onInit(); - - expect(controller.invoiceIn).toEqual({}); - }); - - it(`should define invoiceIn and it's supplierFk when received via params`, () => { - controller.$params.supplierFk = 'supplierId'; - - controller.$onInit(); - - expect(controller.invoiceIn.supplierFk).toEqual('supplierId'); - }); - }); - - describe('onSubmit()', () => { - it(`should redirect to basic data by calling the $state.go function`, () => { - jest.spyOn(controller.$state, 'go'); - - controller.onSubmit(); - - expect(controller.$state.go).toHaveBeenCalledWith('invoiceIn.card.basicData', {id: 1234}); - }); - }); - }); -}); - diff --git a/modules/invoiceOut/back/methods/invoiceOut/delete.js b/modules/invoiceOut/back/methods/invoiceOut/delete.js index d8b9d309b..d6efd9961 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/delete.js +++ b/modules/invoiceOut/back/methods/invoiceOut/delete.js @@ -1,4 +1,3 @@ - module.exports = Self => { Self.remoteMethod('delete', { description: 'Delete a invoiceOut', @@ -34,19 +33,41 @@ module.exports = Self => { try { const invoiceOut = await Self.findById(id, {}, myOptions); - const tickets = await Self.app.models.Ticket.find({ + const models = Self.app.models; + const tickets = await models.Ticket.find({ where: {refFk: invoiceOut.ref} }, myOptions); - + + const [bookEntry] = await models.Xdiario.find({ + where: { + SERIE: invoiceOut.ref[0], + FACTURA: invoiceOut.ref.slice(1) + } + }, myOptions); const promises = []; for (let ticket of tickets) promises.push(ticket.updateAttribute('refFk', null, myOptions)); await Promise.all(promises); - await invoiceOut.destroy(myOptions); + if (bookEntry) { + if (bookEntry.enlazadoSage) { + const params = { + bookEntry: bookEntry.ASIEN, + invoiceOutRef: invoiceOut.ref + } + await Self.rawSql(`SELECT util.notification_send('book-entry-deleted', ?, NULL)`, + [JSON.stringify(params)], + myOptions); + }; + + await models.Xdiario.destroyAll({ + ASIEN: bookEntry.ASIEN + }); + } + if (tx) await tx.commit(); return tickets; diff --git a/modules/invoiceOut/back/methods/invoiceOut/specs/delete.spec.js b/modules/invoiceOut/back/methods/invoiceOut/specs/delete.spec.js index a662cb318..9d638ecf4 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/specs/delete.spec.js +++ b/modules/invoiceOut/back/methods/invoiceOut/specs/delete.spec.js @@ -2,18 +2,24 @@ const models = require('vn-loopback/server/server').models; const LoopBackContext = require('loopback-context'); describe('invoiceOut delete()', () => { - const invoiceOutId = 2; - const userId = 1106; + const invoiceOutId = 2; + const userId = 106; const activeCtx = { accessToken: {userId: userId}, }; + + beforeEach(() => { + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: activeCtx + }); + }); it('should check that there is one ticket in the target invoiceOut', async() => { const tx = await models.InvoiceOut.beginTransaction({}); const options = {transaction: tx}; try { - const invoiceOut = await models.InvoiceOut.findById(invoiceOutId, {}, options); + const invoiceOut = await models.InvoiceOut.findById(invoiceOutId , {}, options); const tickets = await models.Ticket.find({where: {refFk: invoiceOut.ref}}, options); expect(tickets.length).toEqual(1); @@ -31,12 +37,7 @@ describe('invoiceOut delete()', () => { const options = {transaction: tx}; try { - spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ - active: activeCtx - }); - await models.InvoiceOut.delete(invoiceOutId, options); - const originalTicket = await models.Ticket.findById(3, {}, options); const deletedInvoiceOut = await models.InvoiceOut.findById(invoiceOutId, {}, options); @@ -50,4 +51,107 @@ describe('invoiceOut delete()', () => { throw e; } }); + + it('should delete the corresponding bookEntry and not notify', async () => { + const tx = await models.InvoiceOut.beginTransaction({}); + const options = {transaction: tx}; + + try { + const filter = { + where: { + ASIEN: 2 + }, + fields: ['id', 'enlazadoSage'] + }; + + const [beforeXdiario] = await models.Xdiario.find(filter, options) + + const [beforeNotification] = await models.NotificationQueue.find({ + where: { + notificationFk: 'book-entry-deleted', + status: 'pending' + } + }, options); + + expect(beforeXdiario).toBeDefined(); + expect(beforeXdiario.enlazadoSage).toBeFalsy; + expect(beforeNotification).not.toBeDefined(); + + await models.InvoiceOut.delete(4, options); + + const [afterXdiario] = await models.Xdiario.find({ + where: { + ASIEN: 2 + } + }, options); + + const [afterNotification] = await models.NotificationQueue.find({ + where: { + notificationFk: 'book-entry-deleted', + params: '{"bookEntry":2,"invoiceOutRef":"T4444444"}', + status: 'pending' + } + }, options); + + expect(afterXdiario).not.toBeDefined(); + expect(afterNotification).not.toBeDefined(); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); + + it('should delete the corresponding bookEntry and notify', async () => { + const tx = await models.InvoiceOut.beginTransaction({}); + const options = {transaction: tx}; + + try { + const filter = { + where: { + ASIEN: 1 + }, + fields: ['id', 'enlazadoSage'] + }; + + const [beforeXdiario] = await models.Xdiario.find(filter, options) + + const [beforeNotification] = await models.NotificationQueue.find({ + where: { + notificationFk: 'book-entry-deleted', + status: 'pending' + } + }, options); + + expect(beforeXdiario).toBeDefined(); + expect(beforeXdiario.enlazadoSage).toBeTruthy(); + expect(beforeNotification).not.toBeDefined(); + + await models.InvoiceOut.delete(3, options); + + const [afterXdiario] = await models.Xdiario.find({ + where: { + ASIEN: 1 + } + }, options); + + const [afterNotification] = await models.NotificationQueue.find({ + where: { + notificationFk: 'book-entry-deleted', + params: '{"bookEntry":1,"invoiceOutRef":"T3333333"}', + status: 'pending' + } + }, options); + + expect(afterXdiario).not.toBeDefined(); + expect(afterNotification).toBeDefined(); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); + }); diff --git a/modules/item/back/methods/item/setVisibleDiscard.js b/modules/item/back/methods/item/setVisibleDiscard.js new file mode 100644 index 000000000..bcdda1ced --- /dev/null +++ b/modules/item/back/methods/item/setVisibleDiscard.js @@ -0,0 +1,37 @@ +module.exports = Self => { + Self.remoteMethodCtx('setVisibleDiscard', { + description: 'Change visible for item', + accessType: 'WRITE', + accepts: [{ + arg: 'itemFk', + type: 'Number', + required: false, + description: 'The item id' + }, { + arg: 'warehouseFk', + type: 'Number', + required: true, + description: 'The warehouse of item' + }, { + arg: 'quantity', + type: 'Number', + required: true, + description: 'The quantity to modify' + }, + { + arg: 'addressFk', + type: 'Number', + required: true, + description: 'The address id' + }], + http: { + path: `/setVisibleDiscard`, + verb: 'POST' + } + }); + + Self.setVisibleDiscard = async(ctx, itemFk, warehouseFk, quantity, addressFk) => { + const query = `CALL vn.item_setVisibleDiscard(?, ?, ?, ?)`; + await Self.rawSql(query, [itemFk, warehouseFk, quantity, addressFk]); + }; +}; diff --git a/modules/item/back/models/item.js b/modules/item/back/models/item.js index 61c5c2588..eac1ecb7d 100644 --- a/modules/item/back/models/item.js +++ b/modules/item/back/models/item.js @@ -16,6 +16,7 @@ module.exports = Self => { require('../methods/item/createIntrastat')(Self); require('../methods/item/buyerWasteEmail')(Self); require('../methods/item/labelPdf')(Self); + require('../methods/item/setVisibleDiscard')(Self); Self.validatesPresenceOf('originFk', {message: 'Cannot be blank'}); diff --git a/modules/monitor/back/methods/sales-monitor/specs/salesFilter.spec.js b/modules/monitor/back/methods/sales-monitor/specs/salesFilter.spec.js index 4e0fb85b7..c3da7f08b 100644 --- a/modules/monitor/back/methods/sales-monitor/specs/salesFilter.spec.js +++ b/modules/monitor/back/methods/sales-monitor/specs/salesFilter.spec.js @@ -39,7 +39,7 @@ describe('SalesMonitor salesFilter()', () => { const filter = {}; const result = await models.SalesMonitor.salesFilter(ctx, filter, options); - expect(result.length).toBeGreaterThan(15); + expect(result.length).toBeGreaterThan(11); await tx.rollback(); } catch (e) { @@ -151,7 +151,7 @@ describe('SalesMonitor salesFilter()', () => { const result = await models.SalesMonitor.salesFilter(ctx, filter, options); const firstRow = result[0]; - expect(result.length).toEqual(12); + expect(result.length).toEqual(15); expect(firstRow.alertLevel).not.toEqual(0); await tx.rollback(); diff --git a/modules/supplier/back/models/supplier-account.js b/modules/supplier/back/models/supplier-account.js index 691e72580..7c68e2c98 100644 --- a/modules/supplier/back/models/supplier-account.js +++ b/modules/supplier/back/models/supplier-account.js @@ -13,7 +13,7 @@ module.exports = Self => { const bankEntity = await Self.app.models.BankEntity.findById(this.bankEntityFk); const filter = { fields: ['code'], - where: {id: bankEntity.countryFk} + where: {id: bankEntity?.countryFk} }; const country = await Self.app.models.Country.findOne(filter); diff --git a/modules/ticket/back/methods/sale/refund.js b/modules/ticket/back/methods/sale/refund.js index 12f240ae2..3c41aab1e 100644 --- a/modules/ticket/back/methods/sale/refund.js +++ b/modules/ticket/back/methods/sale/refund.js @@ -5,8 +5,7 @@ module.exports = Self => { accepts: [ { arg: 'salesIds', - type: ['number'], - required: true + type: ['number'] }, { arg: 'servicesIds', @@ -41,6 +40,7 @@ module.exports = Self => { myOptions.transaction = tx; } + let refundTicket = null; try { const refundAgencyMode = await models.AgencyMode.findOne({ include: { @@ -55,42 +55,55 @@ module.exports = Self => { const refoundZoneId = refundAgencyMode.zones()[0].id; - const salesFilter = { - where: {id: {inq: salesIds}}, - include: { - relation: 'components', - scope: { - fields: ['saleFk', 'componentFk', 'value'] + if (salesIds) { + const salesFilter = { + where: {id: {inq: salesIds}}, + include: { + relation: 'components', + scope: { + fields: ['saleFk', 'componentFk', 'value'] + } } + }; + const sales = await models.Sale.find(salesFilter, myOptions); + const ticketsIds = [...new Set(sales.map(sale => sale.ticketFk))]; + + const now = Date.vnNew(); + const [firstTicketId] = ticketsIds; + + // eslint-disable-next-line max-len + refundTicket = await createTicketRefund(firstTicketId, now, refundAgencyMode, refoundZoneId, withWarehouse, myOptions); + + for (const sale of sales) { + const createdSale = await models.Sale.create({ + ticketFk: refundTicket.id, + itemFk: sale.itemFk, + quantity: - sale.quantity, + concept: sale.concept, + price: sale.price, + discount: sale.discount, + }, myOptions); + + const components = sale.components(); + for (const component of components) + component.saleFk = createdSale.id; + + await models.SaleComponent.create(components, myOptions); } - }; - const sales = await models.Sale.find(salesFilter, myOptions); - const ticketsIds = [...new Set(sales.map(sale => sale.ticketFk))]; - - let [firstTicketId] = ticketsIds; - if (!firstTicketId) { - [ticketServices] = await models.TicketService.find({where: {id: {inq: servicesIds}}}, myOptions); - firstTicketId = ticketServices.ticketFk; } - const now = Date.vnNew(); - const refundTicket = await createTicketRefund(firstTicketId, now, refundAgencyMode, refoundZoneId, withWarehouse, myOptions); + if (!refundTicket) { + const servicesFilter = { + where: {id: {inq: servicesIds}} + }; + const services = await models.TicketService.find(servicesFilter, myOptions); + const ticketsIds = [...new Set(services.map(service => service.ticketFk))]; - for (const sale of sales) { - const createdSale = await models.Sale.create({ - ticketFk: refundTicket.id, - itemFk: sale.itemFk, - quantity: - sale.quantity, - concept: sale.concept, - price: sale.price, - discount: sale.discount, - }, myOptions); + const now = Date.vnNew(); + const [firstTicketId] = ticketsIds; - const components = sale.components(); - for (const component of components) - component.saleFk = createdSale.id; - - await models.SaleComponent.create(components, myOptions); + // eslint-disable-next-line max-len + refundTicket = await createTicketRefund(firstTicketId, now, refundAgencyMode, refoundZoneId, withWarehouse, myOptions); } if (servicesIds && servicesIds.length > 0) { @@ -101,8 +114,8 @@ module.exports = Self => { for (const service of services) { await models.TicketService.create({ description: service.description, - quantity: - service.quantity, - price: service.price, + quantity: service.quantity, + price: - service.price, taxClassFk: service.taxClassFk, ticketFk: refundTicket.id, ticketServiceTypeFk: service.ticketServiceTypeFk, diff --git a/modules/ticket/back/methods/ticket/specs/filter.spec.js b/modules/ticket/back/methods/ticket/specs/filter.spec.js index 510446cab..2e5730980 100644 --- a/modules/ticket/back/methods/ticket/specs/filter.spec.js +++ b/modules/ticket/back/methods/ticket/specs/filter.spec.js @@ -68,7 +68,7 @@ describe('ticket filter()', () => { const filter = {}; const result = await models.Ticket.filter(ctx, filter, options); - expect(result.length).toEqual(6); + expect(result.length).toEqual(9); await tx.rollback(); } catch (e) { @@ -154,7 +154,7 @@ describe('ticket filter()', () => { const secondRow = result[1]; const thirdRow = result[2]; - expect(result.length).toBeGreaterThan(15); + expect(result.length).toBeGreaterThan(11); expect(firstRow.state).toEqual('Entregado'); expect(secondRow.state).toEqual('Entregado'); expect(thirdRow.state).toEqual('Entregado'); diff --git a/modules/ticket/front/services/index.html b/modules/ticket/front/services/index.html index bb5505ce6..bc288a8a2 100644 --- a/modules/ticket/front/services/index.html +++ b/modules/ticket/front/services/index.html @@ -1,4 +1,4 @@ -
- + + + + + + + + rule="TicketService" + min="0"> - + - - - - \ No newline at end of file + diff --git a/modules/ticket/front/services/index.js b/modules/ticket/front/services/index.js index 4866fd8bb..d8c209ea4 100644 --- a/modules/ticket/front/services/index.js +++ b/modules/ticket/front/services/index.js @@ -6,6 +6,8 @@ class Controller extends Section { $onInit() { this.services = []; this.getDefaultTaxClass(); + this.isDataSaved = false; + this.checkeds = []; } getDefaultTaxClass() { @@ -49,6 +51,26 @@ class Controller extends Section { .then(() => this.$.model.refresh()) .then(() => this.$.watcher.notifySaved()); } + + createRefund() { + if (!this.checkeds.length) return; + + const params = {servicesIds: this.checkeds, withWarehouse: false}; + const query = 'Sales/refund'; + this.$http.post(query, params).then(res => { + const refundTicket = res.data; + this.vnApp.showSuccess(this.$t('The following refund ticket have been created', { + ticketId: refundTicket.id + })); + this.$state.go('ticket.card.sale', {id: refundTicket.id}); + }); + } + + addChecked(id) { + if (this.checkeds.includes(id)) + return this.checkeds = this.checkeds.filter(check => check != id); + this.checkeds.push(id); + } } ngModule.vnComponent('vnTicketService', { diff --git a/modules/ticket/front/services/index.spec.js b/modules/ticket/front/services/index.spec.js index affe8a6e7..9293d4c65 100644 --- a/modules/ticket/front/services/index.spec.js +++ b/modules/ticket/front/services/index.spec.js @@ -19,12 +19,11 @@ describe('Ticket component vnTicketService', () => { describe('getDefaultTaxClass', () => { it('should set the default tax class in the controller', () => { - $httpBackend.whenRoute('GET', `TaxClasses/findOne`) - .respond({ - id: 4000, - name: 'Whatever', - code: 'GG' - }); + $httpBackend.whenRoute('GET', `TaxClasses/findOne`).respond({ + id: 4000, + name: 'Whatever', + code: 'GG', + }); controller.getDefaultTaxClass(); $httpBackend.flush(); @@ -49,15 +48,15 @@ describe('Ticket component vnTicketService', () => { it('should set the description of the selected service upon service type creation', () => { const service = { id: 1, - quantity: 10 + quantity: 10, }; $scope.newServiceType = { - name: 'Totally new stuff' + name: 'Totally new stuff', }; $httpBackend.when('POST', 'TicketServiceTypes').respond({ id: 4001, - name: 'Totally new stuff' + name: 'Totally new stuff', }); controller.onNewServiceTypeAccept(service); $httpBackend.flush(); @@ -65,4 +64,20 @@ describe('Ticket component vnTicketService', () => { expect(service.ticketServiceTypeFk).toEqual(4001); }); }); + + describe('addChecked', () => { + it('should add an item to the checkeds array', () => { + controller.checkeds = []; + controller.addChecked(1); + + expect(controller.checkeds).toEqual([1]); + }); + + it('should remove an item if it is already in the checkeds array', () => { + controller.checkeds = [1, 2, 3]; + controller.addChecked(2); + + expect(controller.checkeds).toEqual([1, 3]); + }); + }); }); diff --git a/modules/ticket/front/services/locale/es.yml b/modules/ticket/front/services/locale/es.yml index 08788fc09..08e6c968c 100644 --- a/modules/ticket/front/services/locale/es.yml +++ b/modules/ticket/front/services/locale/es.yml @@ -2,4 +2,6 @@ Service: Servicios Tax class: Tipo IVA Add service: Añadir servicio Remove service: Quitar servicio -New service type: Nuevo tipo de servicio \ No newline at end of file +New service type: Nuevo tipo de servicio +Pay: Abonar +To create services with negative amounts mark the service on the source ticket and press the pay button.: Para crear sevicios con cantidades negativas marcar servicio en el ticket origen y apretar el boton abonar. \ No newline at end of file diff --git a/package.json b/package.json index 44a651af4..d250071a6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "salix-back", - "version": "23.38.01", + "version": "23.40.01", "author": "Verdnatura Levante SL", "description": "Salix backend", "license": "GPL-3.0", diff --git a/print/templates/email/book-entry-deleted/assets/css/import.js b/print/templates/email/book-entry-deleted/assets/css/import.js new file mode 100644 index 000000000..1582b82c5 --- /dev/null +++ b/print/templates/email/book-entry-deleted/assets/css/import.js @@ -0,0 +1,12 @@ +const Stylesheet = require(`vn-print/core/stylesheet`); + +const path = require('path'); +const vnPrintPath = path.resolve('print'); + +module.exports = new Stylesheet([ + `${vnPrintPath}/common/css/spacing.css`, + `${vnPrintPath}/common/css/misc.css`, + `${vnPrintPath}/common/css/layout.css`, + `${vnPrintPath}/common/css/email.css`]) + .mergeStyles(); + diff --git a/print/templates/email/book-entry-deleted/book-entry-deleted.html b/print/templates/email/book-entry-deleted/book-entry-deleted.html new file mode 100644 index 000000000..9a9f2a93e --- /dev/null +++ b/print/templates/email/book-entry-deleted/book-entry-deleted.html @@ -0,0 +1,8 @@ + +
+
+

{{ $t('title') }}

+

+
+
+
diff --git a/print/templates/email/book-entry-deleted/book-entry-deleted.js b/print/templates/email/book-entry-deleted/book-entry-deleted.js new file mode 100644 index 000000000..cd29f5ddb --- /dev/null +++ b/print/templates/email/book-entry-deleted/book-entry-deleted.js @@ -0,0 +1,19 @@ +const Component = require(`vn-print/core/component`); +const emailBody = new Component(); + +module.exports = { + name: 'book-entry-deleted', + components: { + 'email-body': emailBody.build(), + }, + props: { + bookEntry: { + type: Number, + required: true + }, + invoiceOutRef: { + type: String, + required: true + } + } +}; diff --git a/print/templates/email/book-entry-deleted/locale/en.yml b/print/templates/email/book-entry-deleted/locale/en.yml new file mode 100644 index 000000000..11c18f2c9 --- /dev/null +++ b/print/templates/email/book-entry-deleted/locale/en.yml @@ -0,0 +1,5 @@ +Subject: Linked Accounting Entry Deleted +Title: Linked Accounting Entry Deleted +Description: The linked accounting entry that was associated with SAGE has been deleted.

+Entry No. {0}

+This entry has been deleted because the associated invoice {1} has been removed. diff --git a/print/templates/email/book-entry-deleted/locale/es.yml b/print/templates/email/book-entry-deleted/locale/es.yml new file mode 100644 index 000000000..c40cf25fd --- /dev/null +++ b/print/templates/email/book-entry-deleted/locale/es.yml @@ -0,0 +1,5 @@ +subject: Asiento contable enlazado eliminado +title: Asiento contable enlazado eliminado +description: Se ha borrado el asiento contable que se encuentraba enlazado a SAGE

+ Asientos nº {0}

+ Este asiento se ha borrado porque se ha eliminado la factura asociada {1} diff --git a/print/templates/email/printer-setup/locale/es.yml b/print/templates/email/printer-setup/locale/es.yml index b96d6d5f4..39e83b1a8 100644 --- a/print/templates/email/printer-setup/locale/es.yml +++ b/print/templates/email/printer-setup/locale/es.yml @@ -8,8 +8,8 @@ description: https://www.youtube.com/watch?v=qhb0kgQF3o8. También necesitarás el GoLabel, el programa para imprimir las cintas. - downloadFrom: Puedes descargarlo desde este enlace https://godex.s3-accelerate.amazonaws.com/_6f5glRrVhQAEBGhdUsqJA.file?v01 + downloadFrom: Puedes descargarlo desde este enlace https://cdn.verdnatura.es/public/GoLabel.zip downloadDriver: En este enlace puedes descargar el driver de la impresora https://es.seagullscientific.com/support/downloads/drivers/godex/download/ sections: @@ -40,4 +40,4 @@ help: Cualquier duda que te surja, no dudes en consultarla, ¡estamos pa atenderte! salesPersonName: Soy tu comercial y mi nombre es salesPersonPhone: Teléfono y whatsapp -salesPersonEmail: Dirección de e-mail \ No newline at end of file +salesPersonEmail: Dirección de e-mail