diff --git a/Jenkinsfile b/Jenkinsfile index 8f87ffe61..85914ad62 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -49,7 +49,7 @@ pipeline { NODE_ENV = "" } steps { - nodejs('node-lts') { + nodejs('node-v12') { sh 'npm install --no-audit --prefer-offline' sh 'gulp install --ci' } @@ -66,14 +66,14 @@ pipeline { parallel { stage('Frontend') { steps { - nodejs('node-lts') { + nodejs('node-v12') { sh 'jest --ci --reporters=default --reporters=jest-junit --maxWorkers=2' } } } // stage('Backend') { // steps { - // nodejs('node-lts') { + // nodejs('node-v12') { // sh 'gulp launchBackTest --ci' // } // } @@ -89,7 +89,7 @@ pipeline { CREDS = credentials('docker-registry') } steps { - nodejs('node-lts') { + nodejs('node-v12') { sh 'gulp build' } diff --git a/back/methods/dms/updateFile.js b/back/methods/dms/updateFile.js index 4182148f7..314761932 100644 --- a/back/methods/dms/updateFile.js +++ b/back/methods/dms/updateFile.js @@ -38,8 +38,7 @@ module.exports = Self => { { arg: 'hasFile', type: 'Boolean', - description: 'True if has an attached file', - required: true + description: 'True if has an attached file' }, { arg: 'hasFileAttached', diff --git a/db/changes/10281-valentineDay/00-item_getBalance.sql b/db/changes/10281-valentineDay/00-item_getBalance.sql new file mode 100644 index 000000000..96c82cc01 --- /dev/null +++ b/db/changes/10281-valentineDay/00-item_getBalance.sql @@ -0,0 +1,137 @@ +DROP PROCEDURE `vn`.`item_getBalance`; + +DELIMITER $$ +$$ +CREATE DEFINER=`root`@`%` PROCEDURE `vn`.`item_getBalance`(IN vItemId INT, IN vWarehouse INT) +BEGIN + DECLARE vDateInventory DATETIME; + DECLARE vCurdate DATE DEFAULT CURDATE(); + DECLARE vDayEnd DATETIME DEFAULT util.dayEnd(vCurdate); + + SELECT inventoried INTO vDateInventory FROM config; + SET @a = 0; + SET @currentLineFk = 0; + SET @shipped = ''; + + SELECT DATE(@shipped:= shipped) shipped, + alertLevel, + stateName, + origin, + reference, + clientFk, + name, + `in`, + `out`, + @a := @a + IFNULL(`in`,0) - IFNULL(`out`,0) as balance, + @currentLineFk := IF (@shipped < CURDATE() + OR (@shipped = CURDATE() AND (isPicked OR alertLevel >= 2)), + lineFk,@currentLineFk) lastPreparedLineFk, + isTicket, + lineFk, + isPicked, + clientType + FROM + ( SELECT tr.landed AS shipped, + b.quantity AS `in`, + NULL AS `out`, + al.alertLevel AS alertLevel, + st.name AS stateName, + s.name AS name, + e.ref AS reference, + e.id AS origin, + s.id AS clientFk, + IF(al.alertLevel = 3, TRUE, FALSE) isPicked, + FALSE AS isTicket, + b.id lineFk, + NULL `order`, + NULL AS clientType + FROM buy b + JOIN entry e ON e.id = b.entryFk + JOIN travel tr ON tr.id = e.travelFk + JOIN supplier s ON s.id = e.supplierFk + JOIN alertLevel al ON al.alertLevel = + CASE + WHEN tr.shipped < CURDATE() THEN 3 + WHEN tr.shipped = CURDATE() AND tr.isReceived = TRUE THEN 3 + ELSE 0 + END + JOIN state st ON st.code = al.code + WHERE tr.landed >= vDateInventory + AND vWarehouse = tr.warehouseInFk + AND b.itemFk = vItemId + AND e.isInventory = FALSE + AND e.isRaid = FALSE + UNION ALL + + SELECT tr.shipped, + NULL as `in`, + b.quantity AS `out`, + al.alertLevel AS alertLevel, + st.name AS stateName, + s.name AS name, + e.ref AS reference, + e.id AS origin, + s.id AS clientFk, + IF(al.alertLevel = 3, TRUE, FALSE) isPicked, + FALSE AS isTicket, + b.id, + NULL `order`, + NULL AS clientType + FROM buy b + JOIN entry e ON e.id = b.entryFk + JOIN travel tr ON tr.id = e.travelFk + JOIN warehouse w ON w.id = tr.warehouseOutFk + JOIN supplier s ON s.id = e.supplierFk + JOIN alertLevel al ON al.alertLevel = + CASE + WHEN tr.shipped < CURDATE() THEN 3 + WHEN tr.shipped = CURDATE() AND tr.isReceived = TRUE THEN 3 + ELSE 0 + END + JOIN state st ON st.code = al.code + WHERE tr.shipped >= vDateInventory + AND vWarehouse =tr.warehouseOutFk + AND s.id <> 4 + AND b.itemFk = vItemId + AND e.isInventory = FALSE + AND w.isFeedStock = FALSE + AND e.isRaid = FALSE + UNION ALL + + SELECT DATE(t.shipped), + NULL as `in`, + s.quantity AS `out`, + al.alertLevel AS alertLevel, + st.name AS stateName, + t.nickname AS name, + t.refFk AS reference, + t.id AS origin, + t.clientFk, + stk.id AS isPicked, + TRUE AS isTicket, + s.id, + st.`order`, + ct.code AS clientType + FROM sale s + JOIN ticket t ON t.id = s.ticketFk + LEFT JOIN ticketState ts ON ts.ticket = t.id + LEFT JOIN state st ON st.code = ts.code + JOIN client c ON c.id = t.clientFk + JOIN clientType ct ON ct.id = c.clientTypeFk + JOIN alertLevel al ON al.alertLevel = + CASE + WHEN t.shipped < curdate() THEN 3 + WHEN t.shipped > util.dayEnd(curdate()) THEN 0 + ELSE IFNULL(ts.alertLevel, 0) + END + LEFT JOIN state stPrep ON stPrep.`code` = 'PREPARED' + LEFT JOIN saleTracking stk ON stk.saleFk = s.id AND stk.stateFk = stPrep.id + WHERE t.shipped >= vDateInventory + AND s.itemFk = vItemId + AND vWarehouse =t.warehouseFk + ORDER BY shipped, alertLevel DESC, isTicket, `order` DESC, isPicked DESC, `in` DESC, `out` DESC + ) AS itemDiary; + +END$$ +DELIMITER ; + diff --git a/db/changes/10281-valentineDay/00-supplier.sql b/db/changes/10281-valentineDay/00-supplier.sql new file mode 100644 index 000000000..c35a86a23 --- /dev/null +++ b/db/changes/10281-valentineDay/00-supplier.sql @@ -0,0 +1,2 @@ +ALTER TABLE `vn`.`supplier` ADD COLUMN `workerFk` INT(11) NULL DEFAULT NULL COMMENT 'Responsible for approving invoices' AFTER `isTrucker`; +ALTER TABLE `vn`.`supplier` ADD CONSTRAINT `supplier_workerFk` FOREIGN KEY (`workerFk`) REFERENCES `vn`.`worker` (`id`) ON UPDATE CASCADE; \ No newline at end of file diff --git a/db/changes/10281-valentineDay/delete.keep b/db/changes/10281-valentineDay/delete.keep deleted file mode 100644 index e69de29bb..000000000 diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index 3200cf4ab..d821c7bfc 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -1233,11 +1233,11 @@ INSERT INTO `vn`.`annualAverageInvoiced`(`clientFk`, `invoiced`) (104, 500), (105, 5000); -INSERT INTO `vn`.`supplier`(`id`, `name`, `nickname`,`account`,`countryFk`,`nif`,`isFarmer`,`commission`, `created`, `isActive`, `street`, `city`, `provinceFk`, `postCode`, `payMethodFk`, `payDemFk`, `payDay`, `taxTypeSageFk`, `withholdingSageFk`, `transactionTypeSageFk`) +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`) 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), - (2, 'Farmer King', 'The farmer', 4000020002, 1, '87945234L', 1, 0, CURDATE(), 1, 'supplier address 2', 'SILLA', 2, 43022, 1, 2, 10, 93, 2, 8), - (442, 'Verdnatura Levante SL', 'Verdnatura', 5115000442, 1, '06815934E', 0, 0, CURDATE(), 1, 'supplier address 3', 'SILLA', 1, 43022, 1, 2, 15, 6, 9, 3); + (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), + (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), + (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); INSERT INTO `vn`.`supplierContact`(`id`, `supplierFk`, `phone`, `mobile`, `email`, `observation`, `name`) VALUES diff --git a/e2e/helpers/selectors.js b/e2e/helpers/selectors.js index fe35dcfe3..ca521f445 100644 --- a/e2e/helpers/selectors.js +++ b/e2e/helpers/selectors.js @@ -316,7 +316,7 @@ export default { fourthRelevancy: 'vn-item-tags vn-horizontal:nth-child(4) [ng-model="itemTag.priority"]', fourthRemoveTagButton: 'vn-item-tags vn-horizontal:nth-child(4) vn-icon-button[icon="delete"]', fifthTag: 'vn-item-tags vn-horizontal:nth-child(5) > vn-autocomplete[ng-model="itemTag.tagFk"]', - fifthValue: 'vn-item-tags vn-horizontal:nth-child(5) vn-textfield[ng-model="itemTag.value"]', + fifthValue: 'vn-item-tags vn-horizontal:nth-child(5) vn-autocomplete[ng-model="itemTag.value"]', fifthRelevancy: 'vn-item-tags vn-horizontal:nth-child(5) vn-input-number[ng-model="itemTag.priority"]', sixthTag: 'vn-item-tags vn-horizontal:nth-child(6) > vn-autocomplete[ng-model="itemTag.tagFk"]', sixthValue: 'vn-item-tags vn-horizontal:nth-child(6) vn-textfield[ng-model="itemTag.value"]', diff --git a/e2e/paths/04-item/04_tags.spec.js b/e2e/paths/04-item/04_tags.spec.js index 9f2a8e295..574ff7562 100644 --- a/e2e/paths/04-item/04_tags.spec.js +++ b/e2e/paths/04-item/04_tags.spec.js @@ -16,7 +16,7 @@ describe('Item create tags path', () => { await browser.close(); }); - it(`should create a new tag and delete a former one`, async() => { + it('should create a new tag and delete a former one', async() => { await page.waitToClick(selectors.itemTags.fourthRemoveTagButton); await page.waitToClick(selectors.itemTags.addItemTagButton); await page.autocompleteSearch(selectors.itemTags.seventhTag, 'Ancho de la base'); @@ -29,7 +29,7 @@ describe('Item create tags path', () => { expect(message.text).toContain('Data saved!'); }); - it(`should confirm the fourth row data is the expected one`, async() => { + it('should confirm the fourth row data is the expected one', async() => { await page.reloadSection('item.card.tags'); await page.waitForSelector('vn-item-tags'); let result = await page.waitToGetProperty(selectors.itemTags.fourthTag, 'value'); @@ -47,7 +47,7 @@ describe('Item create tags path', () => { expect(result).toEqual('4'); }); - it(`should confirm the fifth row data is the expected one`, async() => { + it('should confirm the fifth row data is the expected one', async() => { let tag = await page .waitToGetProperty(selectors.itemTags.fifthTag, 'value'); @@ -62,7 +62,7 @@ describe('Item create tags path', () => { expect(relevancy).toEqual('5'); }); - it(`should confirm the sixth row data is the expected one`, async() => { + it('should confirm the sixth row data is the expected one', async() => { let tag = await page .waitToGetProperty(selectors.itemTags.sixthTag, 'value'); diff --git a/modules/item/back/methods/item/getBalance.js b/modules/item/back/methods/item/getBalance.js index 26fc2a7dc..916757c46 100644 --- a/modules/item/back/methods/item/getBalance.js +++ b/modules/item/back/methods/item/getBalance.js @@ -20,8 +20,12 @@ module.exports = Self => { }); Self.getBalance = async filter => { - let where = filter.where; + const where = filter.where; let [diary] = await Self.rawSql(`CALL vn.item_getBalance(?, ?)`, [where.itemFk, where.warehouseFk]); + + for (const entry of diary) + if (entry.clientType === 'loses') entry.highlighted = true; + return diary; }; }; diff --git a/modules/item/back/methods/item/specs/getBalance.spec.js b/modules/item/back/methods/item/specs/getBalance.spec.js new file mode 100644 index 000000000..671b8c103 --- /dev/null +++ b/modules/item/back/methods/item/specs/getBalance.spec.js @@ -0,0 +1,33 @@ +const app = require('vn-loopback/server/server'); +const LoopBackContext = require('loopback-context'); + +describe('item getBalance()', () => { + it('should return the balance lines of a client type loses in which one has highlighted true', async() => { + const activeCtx = { + accessToken: {userId: 9}, + }; + spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ + active: activeCtx + }); + + const losesClientId = 111; + const ticket = await app.models.Ticket.findById(7); + const originalClientId = ticket.clientFk; + await ticket.updateAttribute('clientFk', losesClientId); + + const filter = { + where: { + itemFk: 1, + warehouseFk: 1 + } + }; + const results = await app.models.Item.getBalance(filter); + + const result = results.find(element => element.clientType == 'loses'); + + expect(result.highlighted).toBe(true); + + // restores + await ticket.updateAttribute('clientFk', originalClientId); + }); +}); diff --git a/modules/item/front/diary/index.html b/modules/item/front/diary/index.html index 3fdc9a9e4..7c210a26a 100644 --- a/modules/item/front/diary/index.html +++ b/modules/item/front/diary/index.html @@ -64,14 +64,16 @@ {{::sale.stateName | dashIfEmpty}} {{::sale.reference | dashIfEmpty}} - - {{::sale.name | dashIfEmpty}} - - - {{::sale.name | dashIfEmpty}} + + + {{::sale.name | dashIfEmpty}} + + + {{::sale.name | dashIfEmpty}} + {{::sale.in | dashIfEmpty}} diff --git a/modules/item/front/tags/index.html b/modules/item/front/tags/index.html index 3775526be..c040b9984 100644 --- a/modules/item/front/tags/index.html +++ b/modules/item/front/tags/index.html @@ -32,14 +32,14 @@ rule> { 'sageTaxTypeFk', 'sageTransactionTypeFk', 'sageWithholdingFk', + 'workerFk' ], include: [ { @@ -85,7 +86,19 @@ module.exports = Self => { scope: { fields: ['id', 'withholding'] } - } + }, + { + relation: 'worker', + scope: { + fields: ['userFk'], + include: { + relation: 'user', + scope: { + fields: ['nickname'] + } + } + } + }, ] }; let supplier = await Self.app.models.Supplier.findOne(filter); diff --git a/modules/supplier/back/models/supplier.json b/modules/supplier/back/models/supplier.json index eb3c5989e..4ec568c8b 100644 --- a/modules/supplier/back/models/supplier.json +++ b/modules/supplier/back/models/supplier.json @@ -11,75 +11,78 @@ }, "properties": { "id": { - "type": "Number", + "type": "number", "id": true, "description": "Identifier" }, "name": { - "type": "String" + "type": "string" }, "account": { - "type": "String" + "type": "string" }, "countryFk": { - "type": "Number" + "type": "number" }, "nif": { - "type": "String" + "type": "string" }, "isFarmer": { - "type": "Boolean" + "type": "boolean" }, "phone": { - "type": "Number" + "type": "number" }, "retAccount": { - "type": "Number" + "type": "number" }, "commission": { - "type": "Boolean" + "type": "boolean" }, "created": { - "type": "Date" + "type": "date" }, "postcodeFk": { - "type": "Number" + "type": "number" }, "isActive": { - "type": "Boolean" + "type": "boolean" }, "isOfficial": { - "type": "Boolean" + "type": "boolean" }, "isSerious": { - "type": "Boolean" + "type": "boolean" }, "note": { - "type": "String" + "type": "string" }, "street": { - "type": "String" + "type": "string" }, "city": { - "type": "String" + "type": "string" }, "provinceFk": { - "type": "Number" + "type": "number" }, "postCode": { - "type": "String" + "type": "string" }, "payMethodFk": { - "type": "Number" + "type": "number" }, "payDemFk": { - "type": "Number" + "type": "number" }, "payDay": { - "type": "Number" + "type": "number" }, "nickname": { - "type": "String" + "type": "string" + }, + "workerFk": { + "type": "number" }, "sageTaxTypeFk": { "type": "number", @@ -126,6 +129,11 @@ "model": "Client", "foreignKey": "nif", "primaryKey": "fi" + }, + "worker": { + "type": "belongsTo", + "model": "Worker", + "foreignKey": "workerFk" }, "sageTaxType": { "type": "belongsTo", diff --git a/modules/supplier/front/basic-data/index.html b/modules/supplier/front/basic-data/index.html index 72accfb5f..7d2f801a4 100644 --- a/modules/supplier/front/basic-data/index.html +++ b/modules/supplier/front/basic-data/index.html @@ -15,6 +15,17 @@ rule vn-focus> + + + + + {{$ctrl.summary.worker.user.nickname}} + + diff --git a/modules/supplier/front/summary/locale/es.yml b/modules/supplier/front/summary/locale/es.yml index 6afaf857d..512b75f9d 100644 --- a/modules/supplier/front/summary/locale/es.yml +++ b/modules/supplier/front/summary/locale/es.yml @@ -6,4 +6,5 @@ Is Farmer: Es agrícola Sage tax type: Tipo de impuesto Sage Sage transaction type: Tipo de transacción Sage Sage withholding: Retencion Sage -Go to the supplier: Ir al proveedor \ No newline at end of file +Go to the supplier: Ir al proveedor +Responsible: Responsable \ No newline at end of file