Merge branch 'dev' into 3261-ticket_request
gitea/salix/pipeline/head This commit looks good Details

This commit is contained in:
Joan Sanchez 2021-11-15 09:14:55 +00:00
commit fac1122438
63 changed files with 3155 additions and 1928 deletions

View File

@ -25,6 +25,9 @@
}, },
"isAutoConciliated": { "isAutoConciliated": {
"type": "boolean" "type": "boolean"
},
"maxAmount": {
"type": "number"
} }
}, },
"acls": [{ "acls": [{

View File

@ -0,0 +1,3 @@
ALTER TABLE vn.accountingType ADD maxAmount INT DEFAULT NULL NULL;
UPDATE vn.accountingType SET maxAmount = 1000 WHERE code = 'cash';

View File

@ -0,0 +1,4 @@
ALTER TABLE vn.payMethod CHANGE ibanRequired ibanRequiredForClients tinyint(3) DEFAULT 0 NULL;
ALTER TABLE vn.payMethod ADD ibanRequiredForSuppliers tinyint(3) DEFAULT 0 NULL;
ALTER TABLE vn.payMethod CHANGE ibanRequiredForSuppliers ibanRequiredForSuppliers tinyint(3) DEFAULT 0 NULL AFTER ibanRequiredForClients;
UPDATE vn.payMethod SET ibanRequiredForSuppliers = 1 WHERE code = 'wireTransfer';

View File

@ -19,7 +19,7 @@ USE `util`;
-- --
-- Dumping data for table `config` -- Dumping data for table `config`
-- --
LOCK TABLES `config` WRITE; LOCK TABLES `config` WRITE;
/*!40000 ALTER TABLE `config` DISABLE KEYS */; /*!40000 ALTER TABLE `config` DISABLE KEYS */;
INSERT INTO `config` VALUES (1,'10360',0,'production',NULL); INSERT INTO `config` VALUES (1,'10360',0,'production',NULL);
@ -34,7 +34,7 @@ UNLOCK TABLES;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
-- Dump completed on 2021-10-20 8:38:20 -- Dump completed on 2021-11-08 8:19:54
USE `account`; USE `account`;
-- MariaDB dump 10.19 Distrib 10.6.4-MariaDB, for Linux (x86_64) -- MariaDB dump 10.19 Distrib 10.6.4-MariaDB, for Linux (x86_64)
-- --
@ -72,7 +72,7 @@ INSERT INTO `roleInherit` VALUES (1,1,2),(2,1,3),(3,1,70),(4,2,11),(5,3,11),(6,5
/*!40000 ALTER TABLE `roleInherit` ENABLE KEYS */; /*!40000 ALTER TABLE `roleInherit` ENABLE KEYS */;
UNLOCK TABLES; UNLOCK TABLES;
-- --
-- Dumping data for table `roleRole` -- Dumping data for table `roleRole`
-- --
@ -120,7 +120,7 @@ UNLOCK TABLES;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
-- Dump completed on 2021-10-20 8:38:22 -- Dump completed on 2021-11-08 8:19:55
USE `salix`; USE `salix`;
-- MariaDB dump 10.19 Distrib 10.6.4-MariaDB, for Linux (x86_64) -- MariaDB dump 10.19 Distrib 10.6.4-MariaDB, for Linux (x86_64)
-- --
@ -176,7 +176,7 @@ UNLOCK TABLES;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
-- Dump completed on 2021-10-20 8:38:23 -- Dump completed on 2021-11-08 8:19:56
USE `vn`; USE `vn`;
-- MariaDB dump 10.19 Distrib 10.6.4-MariaDB, for Linux (x86_64) -- MariaDB dump 10.19 Distrib 10.6.4-MariaDB, for Linux (x86_64)
-- --
@ -432,7 +432,7 @@ UNLOCK TABLES;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
-- Dump completed on 2021-10-20 8:38:27 -- Dump completed on 2021-11-08 8:20:01
USE `cache`; USE `cache`;
-- MariaDB dump 10.19 Distrib 10.6.4-MariaDB, for Linux (x86_64) -- MariaDB dump 10.19 Distrib 10.6.4-MariaDB, for Linux (x86_64)
-- --
@ -468,7 +468,7 @@ UNLOCK TABLES;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
-- Dump completed on 2021-10-20 8:38:28 -- Dump completed on 2021-11-08 8:20:02
USE `hedera`; USE `hedera`;
-- MariaDB dump 10.19 Distrib 10.6.4-MariaDB, for Linux (x86_64) -- MariaDB dump 10.19 Distrib 10.6.4-MariaDB, for Linux (x86_64)
-- --
@ -534,7 +534,7 @@ UNLOCK TABLES;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
-- Dump completed on 2021-10-20 8:38:29 -- Dump completed on 2021-11-08 8:20:03
USE `postgresql`; USE `postgresql`;
-- MariaDB dump 10.19 Distrib 10.6.4-MariaDB, for Linux (x86_64) -- MariaDB dump 10.19 Distrib 10.6.4-MariaDB, for Linux (x86_64)
-- --
@ -608,7 +608,7 @@ UNLOCK TABLES;
LOCK TABLES `workcenter` WRITE; LOCK TABLES `workcenter` WRITE;
/*!40000 ALTER TABLE `workcenter` DISABLE KEYS */; /*!40000 ALTER TABLE `workcenter` DISABLE KEYS */;
INSERT INTO `workcenter` VALUES (1,'Silla',20,NULL,1,'Av espioca 100',552703),(2,'Mercaflor',19,NULL,NULL,NULL,NULL),(3,'Marjales',26,20008,NULL,NULL,NULL),(4,'VNH',NULL,NULL,3,NULL,NULL),(5,'Madrid',28,2867,5,'Av constitución 3',554145),(6,'Vilassar',88,88038,2,'Cami del Crist, 33',556412),(7,'Tenerife',NULL,NULL,10,NULL,NULL),(8,NULL,NULL,NULL,NULL,NULL,NULL),(9,'Algemesi',20,1348,60,'Fenollars, 2',523549),(10,NULL,NULL,NULL,NULL,NULL,NULL); INSERT INTO `workcenter` VALUES (1,'Silla',20,NULL,1,'Av espioca 100',552703),(2,'Mercaflor',19,NULL,NULL,NULL,NULL),(3,'Marjales',26,20008,NULL,NULL,NULL),(4,'VNH',NULL,NULL,3,NULL,NULL),(5,'Madrid',28,2868,5,'Av constitución 3',554145),(6,'Vilassar',88,88038,2,'Cami del Crist, 33',556412),(7,'Tenerife',NULL,NULL,10,NULL,NULL),(8,NULL,NULL,NULL,NULL,NULL,NULL),(9,'Algemesi',20,1351,60,'Fenollars, 2',523549),(10,NULL,NULL,NULL,NULL,NULL,NULL);
/*!40000 ALTER TABLE `workcenter` ENABLE KEYS */; /*!40000 ALTER TABLE `workcenter` ENABLE KEYS */;
UNLOCK TABLES; UNLOCK TABLES;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
@ -620,7 +620,7 @@ UNLOCK TABLES;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
-- Dump completed on 2021-10-20 8:38:30 -- Dump completed on 2021-11-08 8:20:05
USE `sage`; USE `sage`;
-- MariaDB dump 10.19 Distrib 10.6.4-MariaDB, for Linux (x86_64) -- MariaDB dump 10.19 Distrib 10.6.4-MariaDB, for Linux (x86_64)
-- --
@ -676,4 +676,4 @@ UNLOCK TABLES;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
-- Dump completed on 2021-10-20 8:38:31 -- Dump completed on 2021-11-08 8:20:06

View File

@ -7,7 +7,7 @@ ALTER TABLE `vn`.`zoneGeo` AUTO_INCREMENT = 1;
ALTER TABLE `vn`.`ticket` AUTO_INCREMENT = 1; ALTER TABLE `vn`.`ticket` AUTO_INCREMENT = 1;
INSERT INTO `salix`.`AccessToken` (`id`, `ttl`, `created`, `userId`) INSERT INTO `salix`.`AccessToken` (`id`, `ttl`, `created`, `userId`)
VALUES VALUES
('TOTALLY_SECURE_TOKEN', '1209600', CURDATE(), 66); ('TOTALLY_SECURE_TOKEN', '1209600', CURDATE(), 66);
@ -154,16 +154,16 @@ INSERT INTO `vn`.`shelving` (`code`, `parkingFk`, `isPrinted`, `priority`, `park
('GVC', '1', '0', '1', '0', '1106'), ('GVC', '1', '0', '1', '0', '1106'),
('HEJ', '2', '0', '1', '0', '1106'); ('HEJ', '2', '0', '1', '0', '1106');
INSERT INTO `vn`.`accountingType`(`id`, `description`, `receiptDescription`,`code`) INSERT INTO `vn`.`accountingType`(`id`, `description`, `receiptDescription`,`code`, `maxAmount`)
VALUES VALUES
(1, 'CC y Polizas de crédito', NULL, NULL), (1, 'CC y Polizas de crédito', NULL, NULL, NULL),
(2, 'Cash', 'Cash', 'cash'), (2, 'Cash', 'Cash', 'cash', 1000),
(3, 'Credit card', 'Credit Card', 'creditCard'), (3, 'Credit card', 'Credit Card', 'creditCard', NULL),
(4, 'Finalcial lines', NULL, NULL), (4, 'Finalcial lines', NULL, NULL, NULL),
(5, 'Other products', NULL, NULL), (5, 'Other products', NULL, NULL, NULL),
(6, 'Loans', NULL, NULL), (6, 'Loans', NULL, NULL, NULL),
(7, 'Leasing', NULL, NULL), (7, 'Leasing', NULL, NULL, NULL),
(8, 'Compensations', 'Compensations', 'compensation'); (8, 'Compensations', 'Compensations', 'compensation', NULL);
INSERT INTO `vn`.`bank`(`id`, `bank`, `account`, `cash`, `entityFk`, `isActive`, `currencyFk`) INSERT INTO `vn`.`bank`(`id`, `bank`, `account`, `cash`, `entityFk`, `isActive`, `currencyFk`)
VALUES VALUES
@ -217,14 +217,14 @@ UPDATE `vn`.`agencyMode` SET `web` = 1, `reportMail` = 'no-reply@gothamcity.com'
UPDATE `vn`.`agencyMode` SET `code` = 'refund' WHERE `id` = 23; UPDATE `vn`.`agencyMode` SET `code` = 'refund' WHERE `id` = 23;
INSERT INTO `vn`.`payMethod`(`id`,`code`, `name`, `graceDays`, `outstandingDebt`, `ibanRequired`) INSERT INTO `vn`.`payMethod`(`id`,`code`, `name`, `graceDays`, `outstandingDebt`, `ibanRequiredForClients`, `ibanRequiredForSuppliers`)
VALUES VALUES
(1, NULL, 'PayMethod one', 0, 001, 0), (1, NULL, 'PayMethod one', 0, 001, 0, 0),
(2, NULL, 'PayMethod two', 10, 001, 0), (2, NULL, 'PayMethod two', 10, 001, 0, 0),
(3, 'compensation', 'PayMethod three', 0, 001, 0), (3, 'compensation', 'PayMethod three', 0, 001, 0, 0),
(4, NULL, 'PayMethod with IBAN', 0, 001, 1), (4, NULL, 'PayMethod with IBAN', 0, 001, 1, 0),
(5, NULL, 'PayMethod five', 10, 001, 0), (5, NULL, 'PayMethod five', 10, 001, 0, 0),
(8,'wireTransfer', 'WireTransfer', 5, 001, 1); (8,'wireTransfer', 'WireTransfer', 5, 001, 1, 1);
INSERT INTO `vn`.`payDem`(`id`, `payDem`) INSERT INTO `vn`.`payDem`(`id`, `payDem`)
VALUES VALUES
@ -1285,11 +1285,11 @@ INSERT INTO `vn`.`supplierAddress`(`id`, `supplierFk`, `nickname`, `street`, `pr
(5, 442, 'GCR building', 'Bristol district', 1, '46000', 'Gotham', '111111111', '222222222'), (5, 442, 'GCR building', 'Bristol district', 1, '46000', 'Gotham', '111111111', '222222222'),
(6, 442, 'The Gotham Tonight building', 'Bristol district', 1, '46000', 'Gotham', '111111111', '222222222'); (6, 442, 'The Gotham Tonight building', 'Bristol district', 1, '46000', 'Gotham', '111111111', '222222222');
INSERT INTO `vn`.`supplier`(`id`, `name`, `nickname`,`account`,`countryFk`,`nif`,`isFarmer`,`commission`, `created`, `isActive`, `street`, `city`, `provinceFk`, `postCode`, `payMethodFk`, `payDemFk`, `payDay`, `taxTypeSageFk`, `withholdingSageFk`, `transactionTypeSageFk`, `workerFk`, `supplierActivityFk`) INSERT INTO `vn`.`supplier`(`id`, `name`, `nickname`,`account`,`countryFk`,`nif`,`isFarmer`,`commission`, `created`, `isActive`, `street`, `city`, `provinceFk`, `postCode`, `payMethodFk`, `payDemFk`, `payDay`, `taxTypeSageFk`, `withholdingSageFk`, `transactionTypeSageFk`, `workerFk`, `supplierActivityFk`, `isPayMethodChecked`)
VALUES VALUES
(1, 'Plants SL', 'Plants nick', 4100000001, 1, '06089160W', 0, 0, CURDATE(), 1, 'supplier address 1', 'PONTEVEDRA', 1, 15214, 1, 1, 15, 4, 1, 1, 18, 'flowerPlants'), (1, 'Plants SL', 'Plants nick', 4100000001, 1, '06089160W', 0, 0, CURDATE(), 1, 'supplier address 1', 'PONTEVEDRA', 1, 15214, 1, 1, 15, 4, 1, 1, 18, 'flowerPlants', 1),
(2, 'Farmer King', 'The farmer', 4000020002, 1, '87945234L', 1, 0, CURDATE(), 1, 'supplier address 2', 'SILLA', 2, 43022, 1, 2, 10, 93, 2, 8, 18, 'animals'), (2, 'Farmer King', 'The farmer', 4000020002, 1, '87945234L', 1, 0, CURDATE(), 1, 'supplier address 2', 'SILLA', 2, 43022, 1, 2, 10, 93, 2, 8, 18, 'animals', 1),
(442, 'Verdnatura Levante SL', 'Verdnatura', 5115000442, 1, '06815934E', 0, 0, CURDATE(), 1, 'supplier address 3', 'SILLA', 1, 43022, 1, 2, 15, 6, 9, 3, 18, 'flowerPlants'); (442, 'Verdnatura Levante SL', 'Verdnatura', 5115000442, 1, '06815934E', 0, 0, CURDATE(), 1, 'supplier address 3', 'SILLA', 1, 43022, 1, 2, 15, 6, 9, 3, 18, 'flowerPlants', 1);
INSERT INTO `vn`.`supplierContact`(`id`, `supplierFk`, `phone`, `mobile`, `email`, `observation`, `name`) INSERT INTO `vn`.`supplierContact`(`id`, `supplierFk`, `phone`, `mobile`, `email`, `observation`, `name`)
VALUES VALUES

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,4 @@
/* eslint max-len: ["error", { "ignoreStrings": true }]*/
export default { export default {
globalItems: { globalItems: {
@ -273,6 +274,7 @@ export default {
deliveredAmount: '.vn-dialog vn-input-number[ng-model="$ctrl.deliveredAmount"]', deliveredAmount: '.vn-dialog vn-input-number[ng-model="$ctrl.deliveredAmount"]',
refundAmount: '.vn-dialog vn-input-number[ng-model="$ctrl.amountToReturn"]', refundAmount: '.vn-dialog vn-input-number[ng-model="$ctrl.amountToReturn"]',
saveButton: '.vn-dialog.shown [response="accept"]', saveButton: '.vn-dialog.shown [response="accept"]',
anyBalanceLine: 'vn-client-balance-index vn-tbody > vn-tr',
firstLineBalance: 'vn-client-balance-index vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(8)', firstLineBalance: 'vn-client-balance-index vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(8)',
firstLineReference: 'vn-client-balance-index vn-tbody > vn-tr:nth-child(1) > vn-td-editable', firstLineReference: 'vn-client-balance-index vn-tbody > vn-tr:nth-child(1) > vn-td-editable',
firstLineReferenceInput: 'vn-client-balance-index vn-tbody > vn-tr:nth-child(1) > vn-td-editable > div > field > vn-textfield' firstLineReferenceInput: 'vn-client-balance-index vn-tbody > vn-tr:nth-child(1) > vn-td-editable > div > field > vn-textfield'
@ -470,6 +472,7 @@ export default {
firstTicketCheckbox: 'vn-ticket-index vn-tbody > a:nth-child(1) > vn-td:nth-child(1) > vn-check', firstTicketCheckbox: 'vn-ticket-index vn-tbody > a:nth-child(1) > vn-td:nth-child(1) > vn-check',
secondTicketCheckbox: 'vn-ticket-index vn-tbody > a:nth-child(2) > vn-td:nth-child(1) > vn-check', secondTicketCheckbox: 'vn-ticket-index vn-tbody > a:nth-child(2) > vn-td:nth-child(1) > vn-check',
thirdTicketCheckbox: 'vn-ticket-index vn-tbody > a:nth-child(3) > vn-td:nth-child(1) > vn-check', thirdTicketCheckbox: 'vn-ticket-index vn-tbody > a:nth-child(3) > vn-td:nth-child(1) > vn-check',
fifthTicketCheckbox: 'vn-ticket-index vn-tbody > a:nth-child(5) > vn-td:nth-child(1) > vn-check',
sixthTicketCheckbox: 'vn-ticket-index vn-tbody > a:nth-child(6) > vn-td:nth-child(1) > vn-check', sixthTicketCheckbox: 'vn-ticket-index vn-tbody > a:nth-child(6) > vn-td:nth-child(1) > vn-check',
payoutButton: 'vn-ticket-index vn-button[icon="icon-recovery"]', payoutButton: 'vn-ticket-index vn-button[icon="icon-recovery"]',
payoutCompany: '.vn-dialog vn-autocomplete[ng-model="$ctrl.companyFk"]', payoutCompany: '.vn-dialog vn-autocomplete[ng-model="$ctrl.companyFk"]',
@ -1144,6 +1147,7 @@ export default {
alias: 'vn-supplier-basic-data vn-textfield[ng-model="$ctrl.supplier.nickname"]', alias: 'vn-supplier-basic-data vn-textfield[ng-model="$ctrl.supplier.nickname"]',
isSerious: 'vn-supplier-basic-data vn-check[ng-model="$ctrl.supplier.isSerious"]', isSerious: 'vn-supplier-basic-data vn-check[ng-model="$ctrl.supplier.isSerious"]',
isActive: 'vn-supplier-basic-data vn-check[ng-model="$ctrl.supplier.isActive"]', isActive: 'vn-supplier-basic-data vn-check[ng-model="$ctrl.supplier.isActive"]',
isPayMethodChecked: 'vn-supplier-basic-data vn-check[ng-model="$ctrl.supplier.isPayMethodChecked"]',
notes: 'vn-supplier-basic-data vn-textarea[ng-model="$ctrl.supplier.note"]', notes: 'vn-supplier-basic-data vn-textarea[ng-model="$ctrl.supplier.note"]',
saveButton: 'vn-supplier-basic-data button[type="submit"]', saveButton: 'vn-supplier-basic-data button[type="submit"]',
}, },

View File

@ -105,7 +105,23 @@ describe('Client balance path', () => {
expect(result).toContain('-€100.00'); expect(result).toContain('-€100.00');
}); });
it('should create a new payment and check the cash exceeded the maximum', async() => {
const amountPaid = '1001';
await page.closePopup();
await page.waitToClick(selectors.clientBalance.newPaymentButton);
await page.autocompleteSearch(selectors.clientBalance.newPaymentBank, 'Cash');
await page.write(selectors.clientBalance.newPaymentAmount, amountPaid);
await page.clearInput(selectors.clientBalance.newDescription);
await page.write(selectors.clientBalance.newDescription, 'Payment');
await page.waitToClick(selectors.clientBalance.saveButton);
const message = await page.waitForSnackbar();
expect(message.text).toContain('Amount exceeded');
});
it('should create a new payment that sets the balance back to the original negative value', async() => { it('should create a new payment that sets the balance back to the original negative value', async() => {
await page.closePopup();
await page.waitToClick(selectors.clientBalance.newPaymentButton); await page.waitToClick(selectors.clientBalance.newPaymentButton);
await page.autocompleteSearch(selectors.clientBalance.newPaymentBank, 'Pay on receipt'); await page.autocompleteSearch(selectors.clientBalance.newPaymentBank, 'Pay on receipt');
await page.overwrite(selectors.clientBalance.newPaymentAmount, '-150'); await page.overwrite(selectors.clientBalance.newPaymentAmount, '-150');

View File

@ -21,8 +21,8 @@ describe('Ticket index payout path', () => {
it('should check the second ticket from a client and 1 of another', async() => { it('should check the second ticket from a client and 1 of another', async() => {
await page.waitToClick(selectors.globalItems.searchButton); await page.waitToClick(selectors.globalItems.searchButton);
await page.waitToClick(selectors.ticketsIndex.secondTicketCheckbox);
await page.waitToClick(selectors.ticketsIndex.thirdTicketCheckbox); await page.waitToClick(selectors.ticketsIndex.thirdTicketCheckbox);
await page.waitToClick(selectors.ticketsIndex.fifthTicketCheckbox);
await page.waitToClick(selectors.ticketsIndex.payoutButton); await page.waitToClick(selectors.ticketsIndex.payoutButton);
const message = await page.waitForSnackbar(); const message = await page.waitForSnackbar();
@ -58,9 +58,11 @@ describe('Ticket index payout path', () => {
await page.selectModule('client'); await page.selectModule('client');
await page.accessToSearchResult('1101'); await page.accessToSearchResult('1101');
await page.accessToSection('client.card.balance.index'); await page.accessToSection('client.card.balance.index');
await page.waitForSelector('vn-client-balance-index vn-tbody > vn-tr'); await page.waitForSelector(selectors.clientBalance.anyBalanceLine);
let result = await page.countElement('vn-client-balance-index vn-tbody > vn-tr'); const count = await page.countElement(selectors.clientBalance.anyBalanceLine);
const reference = await page.waitToGetProperty(selectors.clientBalance.firstLineReference, 'innerText');
expect(result).toEqual(4); expect(count).toEqual(4);
expect(reference).toContain('Cash, Albaran: 7, 8Payment');
}); });
}); });

View File

@ -22,6 +22,7 @@ describe('Supplier basic data path', () => {
await page.write(selectors.supplierBasicData.alias, 'Plants Nick SL'); await page.write(selectors.supplierBasicData.alias, 'Plants Nick SL');
await page.waitToClick(selectors.supplierBasicData.isSerious); await page.waitToClick(selectors.supplierBasicData.isSerious);
await page.waitToClick(selectors.supplierBasicData.isActive); await page.waitToClick(selectors.supplierBasicData.isActive);
await page.waitToClick(selectors.supplierBasicData.isPayMethodChecked);
await page.write(selectors.supplierBasicData.notes, 'Some notes'); await page.write(selectors.supplierBasicData.notes, 'Some notes');
await page.waitToClick(selectors.supplierBasicData.saveButton); await page.waitToClick(selectors.supplierBasicData.saveButton);
@ -52,6 +53,12 @@ describe('Supplier basic data path', () => {
expect(result).toBe('unchecked'); expect(result).toBe('unchecked');
}); });
it('should check the isPayMethodChecked checkbox is now unchecked', async() => {
const result = await page.checkboxState(selectors.supplierBasicData.isPayMethodChecked);
expect(result).toBe('unchecked');
});
it('should check the notes were edited', async() => { it('should check the notes were edited', async() => {
const result = await page.waitToGetProperty(selectors.supplierBasicData.notes, 'value'); const result = await page.waitToGetProperty(selectors.supplierBasicData.notes, 'value');

View File

@ -28,7 +28,7 @@
url="Workers/activeWithRole" url="Workers/activeWithRole"
search-function="{firstName: $search}" search-function="{firstName: $search}"
value-field="id" value-field="id"
where="{role: 'salesPerson'}" where="{role: {inq: ['salesPerson', 'officeBoss']}}"
label="Salesperson"> label="Salesperson">
<tpl-item>{{firstName}} {{name}}</tpl-item> <tpl-item>{{firstName}} {{name}}</tpl-item>
</vn-autocomplete> </vn-autocomplete>

View File

@ -129,7 +129,7 @@ module.exports = Self => {
function hasIban(err, done) { function hasIban(err, done) {
Self.app.models.PayMethod.findById(this.payMethodFk, (_, instance) => { Self.app.models.PayMethod.findById(this.payMethodFk, (_, instance) => {
if (instance && instance.ibanRequired && !this.iban) if (instance && instance.ibanRequiredForClients && !this.iban)
err(); err();
done(); done();
}); });

View File

@ -25,7 +25,10 @@
"outstandingDebt": { "outstandingDebt": {
"type": "Number" "type": "Number"
}, },
"ibanRequired": { "ibanRequiredForClients": {
"type": "boolean"
},
"ibanRequiredForSuppliers": {
"type": "boolean" "type": "boolean"
} }
} }

View File

@ -44,7 +44,8 @@
label="Amount" label="Amount"
ng-model="$ctrl.amountPaid" ng-model="$ctrl.amountPaid"
step="0.01" step="0.01"
required="true"> required="true"
max="$ctrl.maxAmount">
</vn-input-number> </vn-input-number>
</vn-horizontal> </vn-horizontal>
<vn-horizontal> <vn-horizontal>

View File

@ -45,6 +45,7 @@ class Controller extends Dialog {
set description(value) { set description(value) {
this.receipt.description = value; this.receipt.description = value;
this.originalDescription = value;
} }
get description() { get description() {
@ -60,7 +61,14 @@ class Controller extends Dialog {
if (value) { if (value) {
const accountingType = value.accountingType; const accountingType = value.accountingType;
this.receipt.description = accountingType && accountingType.receiptDescription; if (this.originalDescription) {
this.receipt.description =
`${accountingType && accountingType.receiptDescription}, ${this.originalDescription}`;
} else {
this.receipt.description =
`${accountingType && accountingType.receiptDescription}`;
}
this.maxAmount = accountingType && accountingType.maxAmount;
} }
} }
@ -121,6 +129,11 @@ class Controller extends Dialog {
if (response !== 'accept') if (response !== 'accept')
return super.responseHandler(response); return super.responseHandler(response);
const exceededAmount = this.receipt.amountPaid > this.maxAmount;
if (this.bankSelection.accountingType.code == 'cash' && exceededAmount)
return this.vnApp.showError(this.$t('Amount exceeded', {maxAmount: this.maxAmount}));
let receiptId; let receiptId;
return this.$http.post(`Clients/${this.clientFk}/createReceipt`, this.receipt) return this.$http.post(`Clients/${this.clientFk}/createReceipt`, this.receipt)
.then(res => { .then(res => {

View File

@ -23,10 +23,12 @@ describe('Client', () => {
clientFk: 1101, clientFk: 1101,
companyFk: 442 companyFk: 442
}; };
controller.bankSelection = {accountingType: {code: 'myCode'}};
})); }));
describe('bankSelection() setter', () => { describe('bankSelection() setter', () => {
it('should set the receipt description property', () => { it('should set the receipt description property', () => {
controller.originalDescription = 'Albaran: 1, 2';
controller.bankSelection = { controller.bankSelection = {
id: 1, id: 1,
bank: 'Cash', bank: 'Cash',
@ -36,7 +38,7 @@ describe('Client', () => {
} }
}; };
expect(controller.receipt.description).toEqual('Cash'); expect(controller.receipt.description).toEqual('Cash, Albaran: 1, 2');
}); });
}); });

View File

@ -1 +1,2 @@
View receipt: Ver recibo View receipt: Ver recibo
Amount exceeded: Según ley contra el fraude no se puede recibir cobros por importe igual o superior a {{maxAmount}}

View File

@ -19,7 +19,7 @@
vn-acl="salesAssistant" vn-acl="salesAssistant"
ng-model="$ctrl.client.payMethodFk" ng-model="$ctrl.client.payMethodFk"
data="paymethods" data="paymethods"
fields="['ibanRequired']" fields="['ibanRequiredForClients']"
initial-data="$ctrl.client.payMethod"> initial-data="$ctrl.client.payMethod">
</vn-autocomplete> </vn-autocomplete>
<vn-input-number <vn-input-number

View File

@ -34,13 +34,20 @@
</div> </div>
<div class="quicklinks"> <div class="quicklinks">
<div ng-transclude="btnOne"> <div ng-transclude="btnOne">
<vn-quick-link
tooltip="Supplier card"
state="['supplier.card.summary', {id: $ctrl.entry.supplier.id}]"
icon="icon-supplier">
</vn-quick-link>
</div>
<div ng-transclude="btnTwo">
<vn-quick-link <vn-quick-link
tooltip="All travels with current agency" tooltip="All travels with current agency"
state="['travel.index', {q: $ctrl.travelFilter}]" state="['travel.index', {q: $ctrl.travelFilter}]"
icon="local_airport"> icon="local_airport">
</vn-quick-link> </vn-quick-link>
</div> </div>
<div ng-transclude="btnTwo"> <div ng-transclude="btnThree">
<vn-quick-link <vn-quick-link
tooltip="All entries with current supplier" tooltip="All entries with current supplier"
state="['entry.index', {q: $ctrl.entryFilter}]" state="['entry.index', {q: $ctrl.entryFilter}]"

View File

@ -1,4 +1,5 @@
Reference: Referencia Reference: Referencia
Supplier card: Ficha del proveedor
All travels with current agency: Todos los envios con la agencia actual All travels with current agency: Todos los envios con la agencia actual
All entries with current supplier: Todas las entradas con el proveedor actual All entries with current supplier: Todas las entradas con el proveedor actual
Show entry report: Ver informe del pedido Show entry report: Ver informe del pedido

View File

@ -56,7 +56,7 @@ module.exports = Self => {
{ {
relation: 'client', relation: 'client',
scope: { scope: {
fields: ['id', 'socialName'] fields: ['id', 'socialName', 'email']
} }
} }
] ]

View File

@ -0,0 +1,139 @@
<vn-icon-button
icon="more_vert"
vn-popover="menu">
</vn-icon-button>
<vn-menu vn-id="menu">
<vn-list>
<vn-item class="dropdown"
vn-click-stop="showInvoiceMenu.show($event, 'left')"
name="showInvoicePdf"
translate>
Show invoice...
<vn-menu vn-id="showInvoiceMenu">
<vn-list>
<a class="vn-item"
href="api/InvoiceOuts/{{$ctrl.id}}/download?access_token={{$ctrl.vnToken.token}}"
target="_blank"
name="showInvoicePdf"
translate>
Show as PDF
</a>
<vn-item
ng-click="$ctrl.showCsvInvoice()"
translate>
Show as CSV
</vn-item>
</vn-list>
</vn-menu>
</vn-item>
<vn-item class="dropdown"
vn-click-stop="sendInvoiceMenu.show($event, 'left')"
name="sendInvoice"
translate>
Send invoice...
<vn-menu vn-id="sendInvoiceMenu">
<vn-list>
<vn-item
ng-click="sendPdfConfirmation.show({email: $ctrl.invoiceOut.client.email})"
translate>
Send PDF
</vn-item>
<vn-item
ng-click="sendCsvConfirmation.show({email: $ctrl.invoiceOut.client.email})"
translate>
Send CSV
</vn-item>
</vn-list>
</vn-menu>
</vn-item>
<vn-item
ng-click="deleteConfirmation.show()"
vn-acl="invoicing"
vn-acl-action="remove"
name="deleteInvoice"
translate>
Delete Invoice
</vn-item>
<vn-item
ng-click="bookConfirmation.show()"
vn-acl="invoicing"
vn-acl-action="remove"
name="bookInvoice"
translate>
Book invoice
</vn-item>
<vn-item
ng-click="createInvoicePdfConfirmation.show()"
ng-show="$ctrl.hasInvoicing || !$ctrl.invoiceOut.hasPdf"
name="regenerateInvoice"
translate>
{{!$ctrl.invoiceOut.hasPdf ? 'Generate PDF invoice': 'Regenerate PDF invoice'}}
</vn-item>
<vn-item
ng-click="$ctrl.showExportationLetter()"
ng-show="$ctrl.invoiceOut.serial == 'E'"
translate>
Show CIES letter
</vn-item>
</vn-list>
</vn-menu>
<vn-confirm
vn-id="deleteConfirmation"
on-accept="$ctrl.deleteInvoiceOut()"
question="Are you sure you want to delete this invoice?">
</vn-confirm>
<vn-confirm
vn-id="bookConfirmation"
on-accept="$ctrl.bookInvoiceOut()"
question="Are you sure you want to book this invoice?">
</vn-confirm>
<vn-client-descriptor-popover
vn-id="clientDescriptor">
</vn-client-descriptor-popover>
<!-- Create invoice PDF confirmation dialog -->
<vn-confirm
vn-id="createInvoicePdfConfirmation"
on-accept="$ctrl.createPdfInvoice()"
question="Are you sure you want to generate/regenerate the PDF invoice?"
message="Generate PDF invoice document">
</vn-confirm>
<!-- Send PDF invoice confirmation popup -->
<vn-dialog
vn-id="sendPdfConfirmation"
on-accept="$ctrl.sendPdfInvoice($data)"
message="Send PDF invoice">
<tpl-body>
<span translate>Are you sure you want to send it?</span>
<vn-textfield vn-one
label="Email"
ng-model="sendPdfConfirmation.data.email">
</vn-textfield>
</tpl-body>
<tpl-buttons>
<input type="button" response="cancel" translate-attr="{value: 'Cancel'}"/>
<button response="accept" translate>Confirm</button>
</tpl-buttons>
</vn-dialog>
<!-- Send CSV invoice confirmation popup -->
<vn-dialog
vn-id="sendCsvConfirmation"
on-accept="$ctrl.sendCsvInvoice($data)"
message="Send CSV invoice">
<tpl-body>
<span translate>Are you sure you want to send it?</span>
<vn-textfield vn-one
label="Email"
ng-model="sendCsvConfirmation.data.email">
</vn-textfield>
</tpl-body>
<tpl-buttons>
<input type="button" response="cancel" translate-attr="{value: 'Cancel'}"/>
<button response="accept" translate>Confirm</button>
</tpl-buttons>
</vn-dialog>

View File

@ -0,0 +1,121 @@
import ngModule from '../module';
import Section from 'salix/components/section';
import './style.scss';
class Controller extends Section {
constructor($element, $, vnReport, vnEmail) {
super($element, $);
this.vnReport = vnReport;
this.vnEmail = vnEmail;
}
get invoiceOut() {
return this._invoiceOut;
}
set invoiceOut(value) {
this._invoiceOut = value;
if (value)
this.id = value.id;
}
loadData() {
const filter = {
include: [
{
relation: 'company',
scope: {
fields: ['id', 'code']
}
}, {
relation: 'client',
scope: {
fields: ['id', 'name', 'email']
}
}
]
};
return this.$http.get(`InvoiceOuts/${this.invoiceOut.id}`, {filter})
.then(res => this.invoiceOut = res.data);
}
reload() {
return this.loadData().then(() => {
if (this.parentReload)
this.parentReload();
});
}
cardReload() {
// Prevents error when not defined
}
deleteInvoiceOut() {
return this.$http.post(`InvoiceOuts/${this.invoiceOut.id}/delete`)
.then(() => this.$state.go('invoiceOut.index'))
.then(() => this.$state.reload())
.then(() => this.vnApp.showSuccess(this.$t('InvoiceOut deleted')));
}
bookInvoiceOut() {
return this.$http.post(`InvoiceOuts/${this.invoiceOut.ref}/book`)
.then(() => this.$state.reload())
.then(() => this.vnApp.showSuccess(this.$t('InvoiceOut booked')));
}
createPdfInvoice() {
return this.$http.post(`InvoiceOuts/${this.id}/createPdf`)
.then(() => this.reload())
.then(() => {
const snackbarMessage = this.$t(
`The invoice PDF document has been regenerated`);
this.vnApp.showSuccess(snackbarMessage);
});
}
showCsvInvoice() {
this.vnReport.showCsv('invoice', {
recipientId: this.invoiceOut.client.id,
invoiceId: this.id
});
}
sendPdfInvoice($data) {
if (!$data.email)
return this.vnApp.showError(this.$t(`The email can't be empty`));
return this.vnEmail.send('invoice', {
recipientId: this.invoiceOut.client.id,
recipient: $data.email,
invoiceId: this.id
});
}
sendCsvInvoice($data) {
if (!$data.email)
return this.vnApp.showError(this.$t(`The email can't be empty`));
return this.vnEmail.sendCsv('invoice', {
recipientId: this.invoiceOut.client.id,
recipient: $data.email,
invoiceId: this.id
});
}
showExportationLetter() {
this.vnReport.show('exportation', {
recipientId: this.invoiceOut.client.id,
invoiceId: this.id
});
}
}
Controller.$inject = ['$element', '$scope', 'vnReport', 'vnEmail'];
ngModule.vnComponent('vnInvoiceOutDescriptorMenu', {
template: require('./index.html'),
controller: Controller,
bindings: {
invoiceOut: '<',
parentReload: '&'
}
});

View File

@ -0,0 +1,96 @@
import './index';
describe('vnInvoiceOutDescriptorMenu', () => {
let controller;
let $httpBackend;
let $httpParamSerializer;
const invoiceOut = {
id: 1,
client: {id: 1101}
};
beforeEach(ngModule('invoiceOut'));
beforeEach(inject(($componentController, _$httpParamSerializer_, _$httpBackend_) => {
$httpBackend = _$httpBackend_;
$httpParamSerializer = _$httpParamSerializer_;
controller = $componentController('vnInvoiceOutDescriptorMenu', {$element: null});
}));
describe('createPdfInvoice()', () => {
it('should make a query to the createPdf() endpoint and show a success snackbar', () => {
jest.spyOn(controller.vnApp, 'showSuccess');
controller.invoiceOut = invoiceOut;
$httpBackend.whenGET(`InvoiceOuts/${invoiceOut.id}`).respond();
$httpBackend.expectPOST(`InvoiceOuts/${invoiceOut.id}/createPdf`).respond();
controller.createPdfInvoice();
$httpBackend.flush();
expect(controller.vnApp.showSuccess).toHaveBeenCalled();
});
});
describe('showCsvInvoice()', () => {
it('should make a query to the csv invoice download endpoint and show a message snackbar', () => {
jest.spyOn(window, 'open').mockReturnThis();
controller.invoiceOut = invoiceOut;
const expectedParams = {
invoiceId: invoiceOut.id,
recipientId: invoiceOut.client.id
};
const serializedParams = $httpParamSerializer(expectedParams);
const expectedPath = `api/csv/invoice/download?${serializedParams}`;
controller.showCsvInvoice();
expect(window.open).toHaveBeenCalledWith(expectedPath);
});
});
describe('sendPdfInvoice()', () => {
it('should make a query to the email invoice endpoint and show a message snackbar', () => {
jest.spyOn(controller.vnApp, 'showMessage');
controller.invoiceOut = invoiceOut;
const $data = {email: 'brucebanner@gothamcity.com'};
const expectedParams = {
invoiceId: invoiceOut.id,
recipient: $data.email,
recipientId: invoiceOut.client.id
};
const serializedParams = $httpParamSerializer(expectedParams);
$httpBackend.expectGET(`email/invoice?${serializedParams}`).respond();
controller.sendPdfInvoice($data);
$httpBackend.flush();
expect(controller.vnApp.showMessage).toHaveBeenCalled();
});
});
describe('sendCsvInvoice()', () => {
it('should make a query to the csv invoice send endpoint and show a message snackbar', () => {
jest.spyOn(controller.vnApp, 'showMessage');
controller.invoiceOut = invoiceOut;
const $data = {email: 'brucebanner@gothamcity.com'};
const expectedParams = {
invoiceId: invoiceOut.id,
recipient: $data.email,
recipientId: invoiceOut.client.id
};
const serializedParams = $httpParamSerializer(expectedParams);
$httpBackend.expectGET(`csv/invoice/send?${serializedParams}`).respond();
controller.sendCsvInvoice($data);
$httpBackend.flush();
expect(controller.vnApp.showMessage).toHaveBeenCalled();
});
});
});

View File

@ -0,0 +1,17 @@
Show invoice...: Ver factura...
Send invoice...: Enviar factura...
Send PDF invoice: Enviar factura en PDF
Send CSV invoice: Enviar factura en CSV
Delete Invoice: Eliminar factura
Clone Invoice: Clonar factura
Book invoice: Asentar factura
Generate PDF invoice: Generar PDF factura
Show CIES letter: Ver carta CIES
InvoiceOut deleted: Factura eliminada
Are you sure you want to delete this invoice?: Estas seguro de eliminar esta factura?
Are you sure you want to clone this invoice?: Estas seguro de clonar esta factura?
InvoiceOut booked: Factura asentada
Are you sure you want to book this invoice?: Estas seguro de querer asentar esta factura?
Regenerate PDF invoice: Regenerar PDF factura
The invoice PDF document has been regenerated: El documento PDF de la factura ha sido regenerado
The email can't be empty: El correo no puede estar vacío

View File

@ -0,0 +1,24 @@
@import "./effects";
@import "variables";
vn-invoice-out-descriptor-menu {
& > vn-icon-button[icon="more_vert"] {
display: flex;
min-width: 45px;
height: 45px;
box-sizing: border-box;
align-items: center;
justify-content: center;
}
& > vn-icon-button[icon="more_vert"] {
@extend %clickable;
color: inherit;
& > vn-icon {
padding: 10px;
}
vn-icon {
font-size: 1.75rem;
}
}
}

View File

@ -1,81 +1,12 @@
<vn-descriptor-content <vn-descriptor-content
module="invoiceOut" module="invoiceOut"
description="$ctrl.invoiceOut.ref"> description="$ctrl.invoiceOut.ref">
<slot-menu> <slot-dot-menu>
<vn-item class="dropdown" <vn-invoice-out-descriptor-menu
vn-click-stop="showInvoiceMenu.show($event, 'left')" invoice-out="$ctrl.invoiceOut"
name="showInvoicePdf" parent-reload="$ctrl.reload()"
translate> />
Show invoice... </slot-dot-menu>
<vn-menu vn-id="showInvoiceMenu">
<vn-list>
<a class="vn-item"
href="api/InvoiceOuts/{{$ctrl.id}}/download?access_token={{$ctrl.vnToken.token}}"
target="_blank"
name="showInvoicePdf"
translate>
Show as PDF
</a>
<vn-item
ng-click="$ctrl.showCsvInvoice()"
translate>
Show as CSV
</vn-item>
</vn-list>
</vn-menu>
</vn-item>
<vn-item class="dropdown"
vn-click-stop="sendInvoiceMenu.show($event, 'left')"
name="sendInvoice"
translate>
Send invoice...
<vn-menu vn-id="sendInvoiceMenu">
<vn-list>
<vn-item
ng-click="sendPdfConfirmation.show({email: $ctrl.invoiceOut.client.email})"
translate>
Send PDF
</vn-item>
<vn-item
ng-click="sendCsvConfirmation.show({email: $ctrl.invoiceOut.client.email})"
translate>
Send CSV
</vn-item>
</vn-list>
</vn-menu>
</vn-item>
<vn-item
ng-click="deleteConfirmation.show()"
vn-acl="invoicing"
vn-acl-action="remove"
name="deleteInvoice"
translate>
Delete Invoice
</vn-item>
<vn-item
ng-click="bookConfirmation.show()"
vn-acl="invoicing"
vn-acl-action="remove"
name="bookInvoice"
translate>
Book invoice
</vn-item>
<vn-item
ng-click="createInvoicePdfConfirmation.show()"
ng-show="$ctrl.hasInvoicing || !$ctrl.invoiceOut.hasPdf"
name="regenerateInvoice"
translate>
{{!$ctrl.invoiceOut.hasPdf ? 'Generate PDF invoice': 'Regenerate PDF invoice'}}
</vn-item>
<vn-item
ng-click="$ctrl.showExportationLetter()"
ng-show="$ctrl.invoiceOut.serial == 'E'"
translate>
Show CIES letter
</vn-item>
</slot-menu>
<slot-body> <slot-body>
<div class="attributes"> <div class="attributes">
<vn-label-value <vn-label-value
@ -118,59 +49,4 @@
</div> </div>
</div> </div>
</slot-body> </slot-body>
</vn-descriptor-content> </vn-descriptor-content>
<vn-confirm
vn-id="deleteConfirmation"
on-accept="$ctrl.deleteInvoiceOut()"
question="Are you sure you want to delete this invoice?">
</vn-confirm>
<vn-confirm
vn-id="bookConfirmation"
on-accept="$ctrl.bookInvoiceOut()"
question="Are you sure you want to book this invoice?">
</vn-confirm>
<vn-client-descriptor-popover
vn-id="clientDescriptor">
</vn-client-descriptor-popover>
<!-- Create invoice PDF confirmation dialog -->
<vn-confirm
vn-id="createInvoicePdfConfirmation"
on-accept="$ctrl.createPdfInvoice()"
question="Are you sure you want to generate/regenerate the PDF invoice?"
message="Generate PDF invoice document">
</vn-confirm>
<!-- Send PDF invoice confirmation popup -->
<vn-dialog
vn-id="sendPdfConfirmation"
on-accept="$ctrl.sendPdfInvoice($data)"
message="Send PDF invoice">
<tpl-body>
<span translate>Are you sure you want to send it?</span>
<vn-textfield vn-one
ng-model="sendPdfConfirmation.data.email">
</vn-textfield>
</tpl-body>
<tpl-buttons>
<input type="button" response="cancel" translate-attr="{value: 'Cancel'}"/>
<button response="accept" translate>Confirm</button>
</tpl-buttons>
</vn-dialog>
<!-- Send CSV invoice confirmation popup -->
<vn-dialog
vn-id="sendCsvConfirmation"
on-accept="$ctrl.sendCsvInvoice($data)"
message="Send CSV invoice">
<tpl-body>
<span translate>Are you sure you want to send it?</span>
<vn-textfield vn-one
ng-model="sendCsvConfirmation.data.email">
</vn-textfield>
</tpl-body>
<tpl-buttons>
<input type="button" response="cancel" translate-attr="{value: 'Cancel'}"/>
<button response="accept" translate>Confirm</button>
</tpl-buttons>
</vn-dialog>

View File

@ -41,70 +41,6 @@ class Controller extends Descriptor {
return this.getData(`InvoiceOuts/${this.id}`, {filter}) return this.getData(`InvoiceOuts/${this.id}`, {filter})
.then(res => this.entity = res.data); .then(res => this.entity = res.data);
} }
reload() {
return this.loadData().then(() => {
if (this.cardReload)
this.cardReload();
});
}
cardReload() {
// Prevents error when not defined
}
deleteInvoiceOut() {
return this.$http.post(`InvoiceOuts/${this.id}/delete`)
.then(() => this.$state.go('invoiceOut.index'))
.then(() => this.vnApp.showSuccess(this.$t('InvoiceOut deleted')));
}
bookInvoiceOut() {
return this.$http.post(`InvoiceOuts/${this.invoiceOut.ref}/book`)
.then(() => this.$state.reload())
.then(() => this.vnApp.showSuccess(this.$t('InvoiceOut booked')));
}
createPdfInvoice() {
const invoiceId = this.invoiceOut.id;
return this.$http.post(`InvoiceOuts/${invoiceId}/createPdf`)
.then(() => this.reload())
.then(() => {
const snackbarMessage = this.$t(
`The invoice PDF document has been regenerated`);
this.vnApp.showSuccess(snackbarMessage);
});
}
showCsvInvoice() {
this.vnReport.showCsv('invoice', {
recipientId: this.invoiceOut.client.id,
invoiceId: this.id,
});
}
sendPdfInvoice($data) {
return this.vnEmail.send('invoice', {
recipientId: this.invoiceOut.client.id,
recipient: $data.email,
invoiceId: this.id
});
}
sendCsvInvoice($data) {
return this.vnEmail.sendCsv('invoice', {
recipientId: this.invoiceOut.client.id,
recipient: $data.email,
invoiceId: this.id
});
}
showExportationLetter() {
this.vnReport.show('exportation', {
recipientId: this.invoiceOut.client.id,
invoiceId: this.id,
});
}
} }
ngModule.vnComponent('vnInvoiceOutDescriptor', { ngModule.vnComponent('vnInvoiceOutDescriptor', {
@ -112,6 +48,5 @@ ngModule.vnComponent('vnInvoiceOutDescriptor', {
controller: Controller, controller: Controller,
bindings: { bindings: {
invoiceOut: '<', invoiceOut: '<',
cardReload: '&'
} }
}); });

View File

@ -3,17 +3,11 @@ import './index';
describe('vnInvoiceOutDescriptor', () => { describe('vnInvoiceOutDescriptor', () => {
let controller; let controller;
let $httpBackend; let $httpBackend;
let $httpParamSerializer;
const invoiceOut = {
id: 1,
client: {id: 1101}
};
beforeEach(ngModule('invoiceOut')); beforeEach(ngModule('invoiceOut'));
beforeEach(inject(($componentController, _$httpParamSerializer_, _$httpBackend_) => { beforeEach(inject(($componentController, _$httpBackend_) => {
$httpBackend = _$httpBackend_; $httpBackend = _$httpBackend_;
$httpParamSerializer = _$httpParamSerializer_;
controller = $componentController('vnInvoiceOutDescriptor', {$element: null}); controller = $componentController('vnInvoiceOutDescriptor', {$element: null});
})); }));
@ -29,81 +23,4 @@ describe('vnInvoiceOutDescriptor', () => {
expect(controller.invoiceOut).toEqual(response); expect(controller.invoiceOut).toEqual(response);
}); });
}); });
describe('createPdfInvoice()', () => {
it('should make a query to the createPdf() endpoint and show a success snackbar', () => {
jest.spyOn(controller.vnApp, 'showSuccess');
controller.invoiceOut = invoiceOut;
$httpBackend.whenGET(`InvoiceOuts/${invoiceOut.id}`).respond();
$httpBackend.expectPOST(`InvoiceOuts/${invoiceOut.id}/createPdf`).respond();
controller.createPdfInvoice();
$httpBackend.flush();
expect(controller.vnApp.showSuccess).toHaveBeenCalled();
});
});
describe('showCsvInvoice()', () => {
it('should make a query to the csv invoice download endpoint and show a message snackbar', () => {
jest.spyOn(window, 'open').mockReturnThis();
controller.invoiceOut = invoiceOut;
const expectedParams = {
invoiceId: invoiceOut.id,
recipientId: invoiceOut.client.id
};
const serializedParams = $httpParamSerializer(expectedParams);
const expectedPath = `api/csv/invoice/download?${serializedParams}`;
controller.showCsvInvoice();
expect(window.open).toHaveBeenCalledWith(expectedPath);
});
});
describe('sendPdfInvoice()', () => {
it('should make a query to the email invoice endpoint and show a message snackbar', () => {
jest.spyOn(controller.vnApp, 'showMessage');
controller.invoiceOut = invoiceOut;
const $data = {email: 'brucebanner@gothamcity.com'};
const expectedParams = {
invoiceId: invoiceOut.id,
recipient: $data.email,
recipientId: invoiceOut.client.id
};
const serializedParams = $httpParamSerializer(expectedParams);
$httpBackend.expectGET(`email/invoice?${serializedParams}`).respond();
controller.sendPdfInvoice($data);
$httpBackend.flush();
expect(controller.vnApp.showMessage).toHaveBeenCalled();
});
});
describe('sendCsvInvoice()', () => {
it('should make a query to the csv invoice send endpoint and show a message snackbar', () => {
jest.spyOn(controller.vnApp, 'showMessage');
controller.invoiceOut = invoiceOut;
const $data = {email: 'brucebanner@gothamcity.com'};
const expectedParams = {
invoiceId: invoiceOut.id,
recipient: $data.email,
recipientId: invoiceOut.client.id
};
const serializedParams = $httpParamSerializer(expectedParams);
$httpBackend.expectGET(`csv/invoice/send?${serializedParams}`).respond();
controller.sendCsvInvoice($data);
$httpBackend.flush();
expect(controller.vnApp.showMessage).toHaveBeenCalled();
});
});
}); });

View File

@ -1,20 +1,2 @@
Volume exceded: Volumen excedido
Volume: Volumen
Client card: Ficha del cliente Client card: Ficha del cliente
Invoice ticket list: Listado de tickets de la factura Invoice ticket list: Listado de tickets de la factura
Show invoice...: Ver factura...
Send invoice...: Enviar factura...
Send PDF invoice: Enviar factura en PDF
Send CSV invoice: Enviar factura en CSV
Delete Invoice: Eliminar factura
Clone Invoice: Clonar factura
Book invoice: Asentar factura
Generate PDF invoice: Generar PDF factura
Show CIES letter: Ver carta CIES
InvoiceOut deleted: Factura eliminada
Are you sure you want to delete this invoice?: Estas seguro de eliminar esta factura?
Are you sure you want to clone this invoice?: Estas seguro de clonar esta factura?
InvoiceOut booked: Factura asentada
Are you sure you want to book this invoice?: Estas seguro de querer asentar esta factura?
Regenerate PDF invoice: Regenerar PDF factura
The invoice PDF document has been regenerated: El documento PDF de la factura ha sido regenerado

View File

@ -7,5 +7,6 @@ import './summary';
import './card'; import './card';
import './descriptor'; import './descriptor';
import './descriptor-popover'; import './descriptor-popover';
import './descriptor-menu';
import './index/manual'; import './index/manual';
import './index/global-invoicing'; import './index/global-invoicing';

View File

@ -13,6 +13,10 @@
<vn-icon-button icon="launch"></vn-icon-button> <vn-icon-button icon="launch"></vn-icon-button>
</a> </a>
<span>{{$ctrl.summary.invoiceOut.ref}} - {{$ctrl.summary.invoiceOut.client.socialName}}</span> <span>{{$ctrl.summary.invoiceOut.ref}} - {{$ctrl.summary.invoiceOut.client.socialName}}</span>
<vn-invoice-out-descriptor-menu
invoice-out="$ctrl.summary.invoiceOut"
parent-reload="$ctrl.reload()"
/>
</h5> </h5>
<vn-horizontal> <vn-horizontal>
<vn-one> <vn-one>

View File

@ -6,7 +6,7 @@ class Controller extends Section {
super($element, $); super($element, $);
const from = new Date(); const from = new Date();
from.setDate(from.getDate()); from.setDate(from.getDate() - 75);
from.setHours(0, 0, 0, 0); from.setHours(0, 0, 0, 0);
const to = new Date(); const to = new Date();

View File

@ -20,7 +20,7 @@
url="Workers/activeWithRole" url="Workers/activeWithRole"
search-function="{firstName: $search}" search-function="{firstName: $search}"
value-field="id" value-field="id"
wwhere="{role: {inq: ['logistic', 'buyer']}}" where="{role: {inq: ['logistic', 'buyer']}}"
label="Atender"> label="Atender">
<tpl-item>{{nickname}}</tpl-item> <tpl-item>{{nickname}}</tpl-item>
</vn-autocomplete> </vn-autocomplete>

View File

@ -172,11 +172,11 @@ module.exports = Self => {
LEFT JOIN zoneEstimatedDelivery zed ON zed.zoneFk = t.zoneFk`); LEFT JOIN zoneEstimatedDelivery zed ON zed.zoneFk = t.zoneFk`);
stmt.merge(conn.makeWhere(filter.where)); stmt.merge(conn.makeWhere(filter.where));
stmt.merge(`GROUP BY id`);
stmt.merge(conn.makePagination(filter)); stmt.merge(conn.makePagination(filter));
stmts.push(stmt); stmts.push(stmt);
stmt = new ParameterizedSQL(`SELECT * FROM tmp.filter`); stmt = new ParameterizedSQL(`SELECT * FROM tmp.filter`);
stmt.merge(`GROUP BY id`);
stmt.merge(conn.makeOrderBy(filter.order)); stmt.merge(conn.makeOrderBy(filter.order));
const ordersIndex = stmts.push(stmt) - 1; const ordersIndex = stmts.push(stmt) - 1;

View File

@ -1,12 +1,13 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context');
describe('loopback model Supplier', () => { describe('loopback model Supplier', () => {
let supplierOne; let supplierOne;
let supplierTwo; let supplierTwo;
beforeAll(async() => { beforeAll(async() => {
supplierOne = await app.models.Supplier.findById(1); supplierOne = await models.Supplier.findById(1);
supplierTwo = await app.models.Supplier.findById(442); supplierTwo = await models.Supplier.findById(442);
}); });
afterAll(async() => { afterAll(async() => {
@ -18,9 +19,9 @@ describe('loopback model Supplier', () => {
it('should throw an error when attempting to set an invalid payMethod id in the supplier', async() => { it('should throw an error when attempting to set an invalid payMethod id in the supplier', async() => {
let error; let error;
const expectedError = 'You can not select this payment method without a registered bankery account'; const expectedError = 'You can not select this payment method without a registered bankery account';
const supplier = await app.models.Supplier.findById(1); const supplier = await models.Supplier.findById(1);
await supplier.updateAttribute('payMethodFk', 4) await supplier.updateAttribute('payMethodFk', 8)
.catch(e => { .catch(e => {
error = e; error = e;
@ -31,14 +32,27 @@ describe('loopback model Supplier', () => {
}); });
it('should not throw if the payMethod id is valid', async() => { it('should not throw if the payMethod id is valid', async() => {
const activeCtx = {
accessToken: {userId: 9},
http: {
req: {
headers: {origin: 'http://localhost'}
}
}
};
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: activeCtx
});
let error; let error;
const supplier = await app.models.Supplier.findById(442); const supplier = await models.Supplier.findById(442);
await supplier.updateAttribute('payMethodFk', 4) await supplier.updateAttribute('payMethodFk', 4)
.catch(e => { .catch(e => {
error = e; error = e;
}); });
expect(error).toBeDefined(); expect(error).not.toBeDefined();
}); });
}); });
}); });

View File

@ -9,40 +9,40 @@
"properties": { "properties": {
"id": { "id": {
"id": true, "id": true,
"type": "Number", "type": "number",
"forceId": false "forceId": false
}, },
"originFk": { "originFk": {
"type": "Number", "type": "number",
"required": true "required": true
}, },
"userFk": { "userFk": {
"type": "Number" "type": "number"
}, },
"action": { "action": {
"type": "String", "type": "string",
"required": true "required": true
}, },
"changedModel": { "changedModel": {
"type": "String" "type": "string"
}, },
"oldInstance": { "oldInstance": {
"type": "Object" "type": "object"
}, },
"newInstance": { "newInstance": {
"type": "Object" "type": "object"
}, },
"creationDate": { "creationDate": {
"type": "Date" "type": "date"
}, },
"changedModelId": { "changedModelId": {
"type": "String" "type": "string"
}, },
"changedModelValue": { "changedModelValue": {
"type": "String" "type": "string"
}, },
"description": { "description": {
"type": "String" "type": "string"
} }
}, },
"relations": { "relations": {

View File

@ -80,7 +80,7 @@ module.exports = Self => {
const supplierAccount = await Self.app.models.SupplierAccount.findOne({where: {supplierFk: this.id}}); const supplierAccount = await Self.app.models.SupplierAccount.findOne({where: {supplierFk: this.id}});
const hasIban = supplierAccount && supplierAccount.iban; const hasIban = supplierAccount && supplierAccount.iban;
if (payMethod && payMethod.ibanRequired && !hasIban) if (payMethod && payMethod.ibanRequiredForSuppliers && !hasIban)
err(); err();
done(); done();

View File

@ -101,7 +101,10 @@
"mysql": { "mysql": {
"columnName": "withholdingSageFk" "columnName": "withholdingSageFk"
} }
} },
"isPayMethodChecked": {
"type": "boolean"
}
}, },
"relations": { "relations": {
"payMethod": { "payMethod": {
@ -160,13 +163,5 @@
"model": "SupplierAddress", "model": "SupplierAddress",
"foreignKey": "supplierFk" "foreignKey": "supplierFk"
} }
}, }
"acls": [
{
"accessType": "READ",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW"
}
]
} }

View File

@ -36,6 +36,10 @@
label="Active" label="Active"
ng-model="$ctrl.supplier.isActive"> ng-model="$ctrl.supplier.isActive">
</vn-check> </vn-check>
<vn-check
label="PayMethodChecked"
ng-model="$ctrl.supplier.isPayMethodChecked">
</vn-check>
</vn-horizontal> </vn-horizontal>
<vn-horizontal> <vn-horizontal>
<vn-textarea <vn-textarea

View File

@ -1,4 +1,5 @@
Notes: Notas Notes: Notas
Active: Activo Active: Activo
Verified: Verificado Verified: Verificado
PayMethodChecked: Método de pago validado
Responsible for approving invoices: Responsable de aprobar las facturas Responsible for approving invoices: Responsable de aprobar las facturas

View File

@ -24,7 +24,7 @@
vn-acl="salesAssistant" vn-acl="salesAssistant"
ng-model="$ctrl.supplier.payMethodFk" ng-model="$ctrl.supplier.payMethodFk"
data="paymethods" data="paymethods"
fields="['ibanRequired']" fields="['ibanRequiredForSuppliers']"
initial-data="$ctrl.supplier.payMethod"> initial-data="$ctrl.supplier.payMethod">
</vn-autocomplete> </vn-autocomplete>
<vn-autocomplete <vn-autocomplete

View File

@ -42,27 +42,21 @@ module.exports = Self => {
const stmts = []; const stmts = [];
const startedMinusOne = new Date(started);
startedMinusOne.setDate(started.getDate() - 1);
const endedPlusOne = new Date(ended);
endedPlusOne.setDate(ended.getDate() + 1);
stmts.push(` stmts.push(`
DROP TEMPORARY TABLE IF EXISTS DROP TEMPORARY TABLE IF EXISTS
tmp.timeControlCalculate, tmp.timeControlCalculate,
tmp.timeBusinessCalculate tmp.timeBusinessCalculate
`); `);
stmts.push(new ParameterizedSQL('CALL vn.timeControl_calculateByUser(?, ?, ?)', [userId, startedMinusOne, endedPlusOne])); stmts.push(new ParameterizedSQL('CALL vn.timeControl_calculateByUser(?, ?, ?)', [userId, started, ended]));
stmts.push(new ParameterizedSQL('CALL vn.timeBusiness_calculateByUser(?, ?, ?)', [userId, startedMinusOne, endedPlusOne])); stmts.push(new ParameterizedSQL('CALL vn.timeBusiness_calculateByUser(?, ?, ?)', [userId, started, ended]));
const resultIndex = stmts.push(new ParameterizedSQL(` const resultIndex = stmts.push(new ParameterizedSQL(`
SELECT tbc.dated, tbc.timeWorkSeconds expectedHours, tcc.timeWorkSeconds workedHours SELECT tcc.dated, tbc.timeWorkSeconds expectedHours, tcc.timeWorkSeconds workedHours
FROM tmp.timeBusinessCalculate tbc FROM tmp.timeControlCalculate tcc
LEFT JOIN tmp.timeControlCalculate tcc ON tcc.dated = tbc.dated LEFT JOIN tmp.timeBusinessCalculate tbc ON tcc.dated = tbc.dated
WHERE tbc.dated BETWEEN ? AND ? WHERE tcc.dated BETWEEN DATE(?) AND DATE(?)
`, [started, ended])) - 1; `, [started, ended])) - 1;
stmts.push(` stmts.push(`

View File

@ -1,17 +1,17 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('Worker getWorkedHours()', () => { describe('Worker getWorkedHours()', () => {
it(`should return the expected hours and the worked hours of a given date`, async() => { it(`should return the expected hours and the worked hours of a given date`, async() => {
const workerID = 1106; const workerID = 1106;
let started = new Date(); const started = new Date();
started.setHours(0, 0, 0, 0); started.setHours(0, 0, 0, 0);
let ended = new Date(); const ended = new Date();
ended.setHours(0, 0, 0, 0); ended.setHours(23, 59, 59, 999);
const [result] = await app.models.Worker.getWorkedHours(workerID, started, ended); const [result] = await models.Worker.getWorkedHours(workerID, started, ended);
expect(result.expectedHours).toEqual(28800); // 8:00 hours seconds expect(result.expectedHours).toEqual(28800); // 8:00 hours in seconds
expect(result.workedHours).toEqual(29400); // 8:10 hours in seconds expect(result.workedHours).toEqual(29400); // 8:10 hours in seconds
}); });
}); });

View File

@ -171,7 +171,6 @@ class Controller extends Section {
from: from, from: from,
to: to to: to
}; };
const query = `Workers/${this.$params.id}/getWorkedHours`; const query = `Workers/${this.$params.id}/getWorkedHours`;
return this.$http.get(query, {params}).then(res => { return this.$http.get(query, {params}).then(res => {
const workDays = res.data; const workDays = res.data;
@ -212,7 +211,8 @@ class Controller extends Section {
let todayInWeek = this.weekDays.find(day => day.dated.getTime() === today.getTime()); let todayInWeek = this.weekDays.find(day => day.dated.getTime() === today.getTime());
if (todayInWeek && todayInWeek.hours && todayInWeek.hours.length) { if (todayInWeek && todayInWeek.hours && todayInWeek.hours.length) {
const remainingTime = todayInWeek.workedHours ? ((todayInWeek.expectedHours - todayInWeek.workedHours) * 1000) : null; const remainingTime = todayInWeek.workedHours ?
((todayInWeek.expectedHours - todayInWeek.workedHours) * 1000) : null;
const lastKnownEntry = todayInWeek.hours[todayInWeek.hours.length - 1]; const lastKnownEntry = todayInWeek.hours[todayInWeek.hours.length - 1];
const lastKnownTime = new Date(lastKnownEntry.timed).getTime(); const lastKnownTime = new Date(lastKnownEntry.timed).getTime();
const finishTimeStamp = lastKnownTime && remainingTime ? lastKnownTime + remainingTime : null; const finishTimeStamp = lastKnownTime && remainingTime ? lastKnownTime + remainingTime : null;

View File

@ -0,0 +1,63 @@
module.exports = Self => {
Self.remoteMethod('getEventsFiltered', {
description: 'Get events filtered for zone and date',
accepts: [
{
arg: 'zoneFk',
type: 'number',
description: 'The zone id',
required: true
},
{
arg: 'started',
type: 'date',
description: 'The date calendar start',
},
{
arg: 'ended',
type: 'date',
description: 'The date calendar end',
}
],
returns: {
type: 'object',
root: true
},
http: {
path: `/getEventsFiltered`,
verb: 'GET'
}
});
Self.getEventsFiltered = async(zoneFk, started, ended, options) => {
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
query = `
SELECT *
FROM vn.zoneEvent
WHERE zoneFk = ?
AND ((type = 'indefinitely')
OR (type = 'day' AND dated BETWEEN ? AND ?)
OR (type = 'range'
AND (
(started BETWEEN ? AND ?)
OR (ended BETWEEN ? AND ?)
)
)
)
ORDER BY type='indefinitely' DESC, type='range' DESC, type='day' DESC;`;
const events = await Self.rawSql(query, [zoneFk, started, ended, started, ended, started, ended], myOptions);
query = `
SELECT *
FROM vn.zoneExclusion
WHERE zoneFk = ?
AND dated BETWEEN ? AND ?;`;
const exclusions = await Self.rawSql(query, [zoneFk, started, ended], myOptions);
return {events, exclusions};
};
};

View File

@ -1,12 +1,12 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('agency clone()', () => { describe('agency clone()', () => {
it('should clone a zone', async() => { it('should clone a zone', async() => {
const tx = await app.models.Zone.beginTransaction({}); const tx = await models.Zone.beginTransaction({});
try { try {
const options = {transaction: tx}; const options = {transaction: tx};
const newZone = await app.models.Zone.clone(1, options); const newZone = await models.Zone.clone(1, options);
expect(newZone.name).toEqual('Zone pickup A'); expect(newZone.name).toEqual('Zone pickup A');

View File

@ -1,4 +1,4 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context'); const LoopBackContext = require('loopback-context');
describe('zone deletezone()', () => { describe('zone deletezone()', () => {
@ -16,13 +16,13 @@ describe('zone deletezone()', () => {
active: activeCtx active: activeCtx
}); });
try { try {
const originalTickets = await app.models.Ticket.find({ const originalTickets = await models.Ticket.find({
where: { where: {
zoneFk: zoneId zoneFk: zoneId
} }
}); });
ticketIDs = originalTickets.map(ticket => ticket.id); ticketIDs = originalTickets.map(ticket => ticket.id);
originalTicketStates = await app.models.TicketState.find({where: { originalTicketStates = await models.TicketState.find({where: {
ticketFk: {inq: ticketIDs}, ticketFk: {inq: ticketIDs},
code: 'FIXING'}}); code: 'FIXING'}});
} catch (error) { } catch (error) {
@ -31,16 +31,16 @@ describe('zone deletezone()', () => {
}); });
it('should delete a zone and update their tickets', async() => { it('should delete a zone and update their tickets', async() => {
const tx = await app.models.Zone.beginTransaction({}); const tx = await models.Zone.beginTransaction({});
try { try {
const options = {transaction: tx}; const options = {transaction: tx};
await app.models.Zone.deleteZone(ctx, zoneId, options); await models.Zone.deleteZone(ctx, zoneId, options);
const updatedZone = await app.models.Zone.findById(zoneId, null, options); const updatedZone = await models.Zone.findById(zoneId, null, options);
const anUpdatedTicket = await app.models.Ticket.findById(ticketIDs[0], null, options); const anUpdatedTicket = await models.Ticket.findById(ticketIDs[0], null, options);
const updatedTicketStates = await app.models.TicketState.find({ const updatedTicketStates = await models.TicketState.find({
where: { where: {
ticketFk: {inq: ticketIDs}, ticketFk: {inq: ticketIDs},
code: 'FIXING' code: 'FIXING'

View File

@ -1,13 +1,13 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('zone getEvents()', () => { describe('zone getEvents()', () => {
it('should return all events for the specified geo and agency mode', async() => { it('should return all events for the specified geo and agency mode', async() => {
const tx = await app.models.Zone.beginTransaction({}); const tx = await models.Zone.beginTransaction({});
try { try {
const options = {transaction: tx}; const options = {transaction: tx};
let result = await app.models.Zone.getEvents(20, 1, options); let result = await models.Zone.getEvents(20, 1, options);
expect(result.events.length).toEqual(10); expect(result.events.length).toEqual(10);

View File

@ -0,0 +1,21 @@
const models = require('vn-loopback/server/server').models;
describe('zone getEventsFiltered()', () => {
it('should return events and exclusions for the specified zoneFk in a range of dates', async() => {
const tx = await models.Zone.beginTransaction({});
try {
const options = {transaction: tx};
let result = await models.Zone.getEventsFiltered(10, '2021-10-01', '2021-10-02', options);
expect(result.events.length).toEqual(1);
expect(result.exclusions.length).toEqual(0);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});

View File

@ -1,13 +1,13 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('zone getLeaves()', () => { describe('zone getLeaves()', () => {
it('should return the country and the childs containing the search value', async() => { it('should return the country and the childs containing the search value', async() => {
const tx = await app.models.Zone.beginTransaction({}); const tx = await models.Zone.beginTransaction({});
try { try {
const options = {transaction: tx}; const options = {transaction: tx};
let result = await app.models.Zone.getLeaves(1, null, '46000', options); let result = await models.Zone.getLeaves(1, null, '46000', options);
expect(result.length).toEqual(1); expect(result.length).toEqual(1);

View File

@ -1,4 +1,4 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('zone includingExpired()', () => { describe('zone includingExpired()', () => {
const inhousePickupId = 1; const inhousePickupId = 1;
@ -6,14 +6,14 @@ describe('zone includingExpired()', () => {
const warehouseId = 1; const warehouseId = 1;
it('should return an array containing all zones', async() => { it('should return an array containing all zones', async() => {
const tx = await app.models.Zone.beginTransaction({}); const tx = await models.Zone.beginTransaction({});
const ctx = {req: {accessToken: {userId: 1}}}; const ctx = {req: {accessToken: {userId: 1}}};
const where = {}; const where = {};
try { try {
const options = {transaction: tx}; const options = {transaction: tx};
const result = await app.models.Zone.includingExpired(ctx, {where}, options); const result = await models.Zone.includingExpired(ctx, {where}, options);
expect(result.length).toBeGreaterThan(2); expect(result.length).toBeGreaterThan(2);
@ -28,12 +28,12 @@ describe('zone includingExpired()', () => {
const ctx = {req: {accessToken: {userId: 1}}}; const ctx = {req: {accessToken: {userId: 1}}};
const where = {agencyModeFk: inhousePickupId}; const where = {agencyModeFk: inhousePickupId};
const tx = await app.models.Zone.beginTransaction({}); const tx = await models.Zone.beginTransaction({});
try { try {
const options = {transaction: tx}; const options = {transaction: tx};
const result = await app.models.Zone.includingExpired(ctx, {where}, options); const result = await models.Zone.includingExpired(ctx, {where}, options);
const validAgency = result.every(zone => zone.agencyModeFk = inhousePickupId); const validAgency = result.every(zone => zone.agencyModeFk = inhousePickupId);
@ -56,12 +56,12 @@ describe('zone includingExpired()', () => {
warehouseFk: warehouseId warehouseFk: warehouseId
}; };
const tx = await app.models.Zone.beginTransaction({}); const tx = await models.Zone.beginTransaction({});
try { try {
const options = {transaction: tx}; const options = {transaction: tx};
const result = await app.models.Zone.includingExpired(ctx, {where}, options); const result = await models.Zone.includingExpired(ctx, {where}, options);
const firstZone = result[0]; const firstZone = result[0];
expect(firstZone.name).toEqual('Zone pickup A'); expect(firstZone.name).toEqual('Zone pickup A');

View File

@ -1,13 +1,13 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('zone toggleIsIncluded()', () => { describe('zone toggleIsIncluded()', () => {
it('should return the created location with isIncluded true', async() => { it('should return the created location with isIncluded true', async() => {
const tx = await app.models.Zone.beginTransaction({}); const tx = await models.Zone.beginTransaction({});
try { try {
const options = {transaction: tx}; const options = {transaction: tx};
let result = await app.models.Zone.toggleIsIncluded(1, 20, true, options); let result = await models.Zone.toggleIsIncluded(1, 20, true, options);
expect(result.isIncluded).toBeTrue(); expect(result.isIncluded).toBeTrue();
@ -19,12 +19,12 @@ describe('zone toggleIsIncluded()', () => {
}); });
it('should return the created location with isIncluded false', async() => { it('should return the created location with isIncluded false', async() => {
const tx = await app.models.Zone.beginTransaction({}); const tx = await models.Zone.beginTransaction({});
try { try {
const options = {transaction: tx}; const options = {transaction: tx};
let result = await app.models.Zone.toggleIsIncluded(1, 20, false, options); let result = await models.Zone.toggleIsIncluded(1, 20, false, options);
expect(result.isIncluded).toBeFalse(); expect(result.isIncluded).toBeFalse();
@ -36,14 +36,14 @@ describe('zone toggleIsIncluded()', () => {
}); });
it('should return the amount of deleted locations', async() => { it('should return the amount of deleted locations', async() => {
const tx = await app.models.Zone.beginTransaction({}); const tx = await models.Zone.beginTransaction({});
try { try {
const options = {transaction: tx}; const options = {transaction: tx};
await app.models.Zone.toggleIsIncluded(1, 20, false, options); await models.Zone.toggleIsIncluded(1, 20, false, options);
let result = await app.models.Zone.toggleIsIncluded(1, 20, undefined, options); let result = await models.Zone.toggleIsIncluded(1, 20, undefined, options);
expect(result).toEqual({count: 1}); expect(result).toEqual({count: 1});

View File

@ -2,6 +2,7 @@ module.exports = Self => {
require('../methods/zone/clone')(Self); require('../methods/zone/clone')(Self);
require('../methods/zone/getLeaves')(Self); require('../methods/zone/getLeaves')(Self);
require('../methods/zone/getEvents')(Self); require('../methods/zone/getEvents')(Self);
require('../methods/zone/getEventsFiltered')(Self);
require('../methods/zone/toggleIsIncluded')(Self); require('../methods/zone/toggleIsIncluded')(Self);
require('../methods/zone/getUpcomingDeliveries')(Self); require('../methods/zone/getUpcomingDeliveries')(Self);
require('../methods/zone/deleteZone')(Self); require('../methods/zone/deleteZone')(Self);

View File

@ -1,5 +1,6 @@
<vn-zone-calendar <vn-zone-calendar
id="calendar" id="calendar"
vn-id="calendar"
data="data" data="data"
on-selection="$ctrl.onSelection($days, $type, $weekday, $events, $exclusions)" on-selection="$ctrl.onSelection($days, $type, $weekday, $events, $exclusions)"
class="vn-w-md"> class="vn-w-md">

View File

@ -21,14 +21,18 @@ class Controller extends Section {
} }
refresh() { refresh() {
let data = {}; this.$.data = null;
this.$q.all([ this.$.$applyAsync(() => {
this.$http.get(this.path) const params = {
.then(res => data.events = res.data), zoneFk: this.$params.id,
this.$http.get(this.exclusionsPath) started: this.$.calendar.firstDay,
.then(res => data.exclusions = res.data) ended: this.$.calendar.lastDay
]).finally(() => { };
this.$.data = data;
this.$http.get(`Zones/getEventsFiltered`, {params}).then(res => {
const data = res.data;
this.$.data = data;
});
}); });
} }

View File

@ -17,8 +17,26 @@ describe('component vnZoneEvents', () => {
describe('refresh()', () => { describe('refresh()', () => {
it('should set the zone and then call both getSummary() and getWarehouses()', () => { it('should set the zone and then call both getSummary() and getWarehouses()', () => {
$httpBackend.expectGET(`Zones/1/events`).respond({id: 1}); const date = '2021-10-01';
$httpBackend.expectGET(`Zones/1/exclusions`).respond({id: 1});
controller.$params.id = 999;
controller.$.calendar = {
firstDay: date,
lastDay: date
};
const params = {
zoneFk: controller.$params.id,
started: date,
ended: date
};
const query = `Zones/getEventsFiltered?ended=${date}&started=${date}&zoneFk=${params.zoneFk}`;
const response = {
events: 'myEvents',
exclusions: 'myExclusions'
};
$httpBackend.whenGET(query).respond(response);
controller.refresh(); controller.refresh();
$httpBackend.flush(); $httpBackend.flush();

View File

@ -10,4 +10,5 @@ closed: Cerrado
ticketSubject: Asunto ticketSubject: Asunto
ticketDescription: Descripción ticketDescription: Descripción
resolution: Resolución resolution: Resolución
grafanaLink: "Puedes ver la gráfica desde el siguiente enlace:" grafanaLink: "Puedes ver la gráfica desde el siguiente enlace:"
redmineLink: "Desde el siguiente enlace puedes ver el resumen semanal de tareas de refactor:"

View File

@ -33,6 +33,12 @@
https://grafana.verdnatura.es/d/2kaHDi9Mk/osticket?orgId=1&from={{startedTime}}&to={{endedTime}} https://grafana.verdnatura.es/d/2kaHDi9Mk/osticket?orgId=1&from={{startedTime}}&to={{endedTime}}
</a> </a>
</div> </div>
<p v-html="$t('redmineLink')"></p>
<div class="external-link vn-pa-sm vn-m-md">
<a href="https://redmine.verdnatura.es/projects/refactor/issues?query_id=112" target="_blank">
https://redmine.verdnatura.es/projects/refactor/issues?query_id=112
</a>
</div>
</div> </div>
</div> </div>
<!-- Block --> <!-- Block -->

View File

@ -11,5 +11,5 @@ clientSignature: Firma del cliente
claim: Reclamación {0} claim: Reclamación {0}
sections: sections:
agency: agency:
description: 'Para agilizar su recogida, por favor, póngase en contacto con la oficina description: 'Para agilizar su recogida, por favor, póngase en contacto con la oficina
de integrados. <br/> Tlf: 96 166 77 88 - Ana Gómez (Ext. 2113) <em>(agomezf@integra2.com)</em>' de Logista Parcel. <br/> Tlf: 96 166 77 88 - Ana Gómez (Ext. 2113) <em>(atcsalidas.i2valencia@integra2.es)</em>'

View File

@ -12,8 +12,9 @@ SELECT
FROM claim cl FROM claim cl
JOIN client c ON c.id = cl.clientFk JOIN client c ON c.id = cl.clientFk
JOIN account.user u ON u.id = c.id JOIN account.user u ON u.id = c.id
JOIN country ct ON ct.id = c.countryFk
JOIN ticket t ON t.id = cl.ticketFk JOIN ticket t ON t.id = cl.ticketFk
JOIN address a ON a.id = t.addressFk JOIN address a ON a.id = t.addressFk
LEFT JOIN province p ON p.id = c.provinceFk LEFT JOIN province p ON p.id = a.provinceFk
LEFT JOIN autonomy amy ON amy.id = p.autonomyFk
LEFT JOIN country ct ON ct.id = amy.countryFk
WHERE cl.id = ? WHERE cl.id = ?

View File

@ -96,7 +96,7 @@
</div> </div>
</div> </div>
<div class="pull-left"> <div class="pull-left">
<h2>Shipped</h2> <h2>{{$t('shipped')}}</h2>
</div> </div>
<div class="pull-left"> <div class="pull-left">
<div class="field rectangle"> <div class="field rectangle">

View File

@ -4,4 +4,5 @@ SELECT
t.nickname t.nickname
FROM invoiceOut io FROM invoiceOut io
JOIN ticket t ON t.refFk = io.ref JOIN ticket t ON t.refFk = io.ref
WHERE io.id = ? WHERE io.id = ?
ORDER BY t.shipped