diff --git a/back/methods/chat/sendCheckingPresence.js b/back/methods/chat/sendCheckingPresence.js index c1bc565eb..fcde20130 100644 --- a/back/methods/chat/sendCheckingPresence.js +++ b/back/methods/chat/sendCheckingPresence.js @@ -27,7 +27,7 @@ module.exports = Self => { Self.sendCheckingPresence = async(ctx, recipientId, message, options) => { if (!recipientId) return false; - let myOptions = {}; + const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/back/methods/dms/updateFile.js b/back/methods/dms/updateFile.js index 161f4728c..cfc4c322f 100644 --- a/back/methods/dms/updateFile.js +++ b/back/methods/dms/updateFile.js @@ -60,7 +60,7 @@ module.exports = Self => { const args = ctx.args; let tx; - let myOptions = {}; + const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/back/methods/dms/uploadFile.js b/back/methods/dms/uploadFile.js index 6bda1e6db..fb4b2e5b8 100644 --- a/back/methods/dms/uploadFile.js +++ b/back/methods/dms/uploadFile.js @@ -54,7 +54,7 @@ module.exports = Self => { const args = ctx.args; let tx; - let myOptions = {}; + const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/back/methods/starred-module/getStarredModules.js b/back/methods/starred-module/getStarredModules.js index 7b0f0e945..5d399f16e 100644 --- a/back/methods/starred-module/getStarredModules.js +++ b/back/methods/starred-module/getStarredModules.js @@ -16,7 +16,7 @@ module.exports = function(Self) { const models = Self.app.models; const userId = ctx.req.accessToken.userId; - let myOptions = {}; + const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/back/methods/starred-module/setPosition.js b/back/methods/starred-module/setPosition.js index c72de1083..d993f18e9 100644 --- a/back/methods/starred-module/setPosition.js +++ b/back/methods/starred-module/setPosition.js @@ -31,7 +31,7 @@ module.exports = function(Self) { const userId = ctx.req.accessToken.userId; let tx; - let myOptions = {}; + const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/back/methods/starred-module/toggleStarredModule.js b/back/methods/starred-module/toggleStarredModule.js index 16e14740b..9cc496f44 100644 --- a/back/methods/starred-module/toggleStarredModule.js +++ b/back/methods/starred-module/toggleStarredModule.js @@ -23,7 +23,7 @@ module.exports = function(Self) { const userId = ctx.req.accessToken.userId; let tx; - let myOptions = {}; + const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/back/methods/user-config-view/save.js b/back/methods/user-config-view/save.js index da8a27083..b2144c01e 100644 --- a/back/methods/user-config-view/save.js +++ b/back/methods/user-config-view/save.js @@ -7,8 +7,7 @@ module.exports = function(Self) { required: true, description: `Code of the table you ask its configuration`, http: {source: 'body'} - } - ], + }], returns: { type: 'object', root: true @@ -29,6 +28,6 @@ module.exports = function(Self) { config.userFk = ctx.req.accessToken.userId; - return await Self.app.models.UserConfigView.create(config); + return Self.app.models.UserConfigView.create(config); }; }; diff --git a/back/model-config.json b/back/model-config.json index 18bf4cf98..8ad15a16a 100644 --- a/back/model-config.json +++ b/back/model-config.json @@ -29,6 +29,9 @@ "ChatConfig": { "dataSource": "vn" }, + "DefaultViewConfig": { + "dataSource": "vn" + }, "Delivery": { "dataSource": "vn" }, diff --git a/back/models/default-view-config.json b/back/models/default-view-config.json new file mode 100644 index 000000000..88164692d --- /dev/null +++ b/back/models/default-view-config.json @@ -0,0 +1,25 @@ +{ + "name": "DefaultViewConfig", + "base": "VnModel", + "options": { + "mysql": { + "table": "salix.defaultViewConfig" + } + }, + "properties": { + "tableCode": { + "id": true, + "type": "string", + "required": true + }, + "columns": { + "type": "object" + } + }, + "acls": [{ + "accessType": "READ", + "principalType": "ROLE", + "principalId": "$everyone", + "permission": "ALLOW" + }] +} diff --git a/db/changes/10380-allsaints/00-defaultViewConfig.sql b/db/changes/10380-allsaints/00-defaultViewConfig.sql new file mode 100644 index 000000000..e4b2f6c3d --- /dev/null +++ b/db/changes/10380-allsaints/00-defaultViewConfig.sql @@ -0,0 +1,14 @@ +CREATE TABLE `salix`.`defaultViewConfig` +( + tableCode VARCHAR(25) not null, + columns JSON not null +) +comment 'The default configuration of columns for views'; + +INSERT INTO `salix`.`defaultViewConfig` (tableCode, columns) + VALUES + ('itemsIndex', '{"intrastat":false,"stemMultiplier":false,"landed":false}'), + ('latestBuys', '{"intrastat":false,"description":false,"density":false,"isActive":false,"freightValue":false,"packageValue":false,"isIgnored":false,"price2":false,"minPrice":true,"ektFk":false,"weight":false,"id":true,"packing":true,"grouping":true,"quantity":true,"size":false,"name":true,"code":true,"origin":true,"family":true,"entryFk":true,"buyingValue":true,"comissionValue":false,"price3":true,"packageFk":true,"packingOut":true}'), + ('ticketsMonitor', '{"id":false}'); + + \ No newline at end of file diff --git a/db/changes/10370-pickles/00-item_getBalance.sql b/db/changes/10390-constitution/00-item_getBalance.sql similarity index 97% rename from db/changes/10370-pickles/00-item_getBalance.sql rename to db/changes/10390-constitution/00-item_getBalance.sql index 91e5c3681..90e3ee2bb 100644 --- a/db/changes/10370-pickles/00-item_getBalance.sql +++ b/db/changes/10390-constitution/00-item_getBalance.sql @@ -1,9 +1,9 @@ -DROP PROCEDURE IF EXISTS vn.item_getBalance; +DROP PROCEDURE IF EXISTS `vn`.`item_getBalance`; DELIMITER $$ $$ CREATE - definer = root@`%` procedure vn.item_getBalance(IN vItemId int, IN vWarehouse int) + definer = root@`%` procedure `vn`.`item_getBalance`(IN vItemId int, IN vWarehouse int) BEGIN DECLARE vDateInventory DATETIME; DECLARE vCurdate DATE DEFAULT CURDATE(); diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index 745a2ee07..5b7ac3240 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -739,7 +739,7 @@ INSERT INTO `vn`.`itemType`(`id`, `code`, `name`, `categoryFk`, `warehouseFk`, ` (3, 'WPN', 'Paniculata', 2, 1, 31, 35, 0), (4, 'PRT', 'Delivery ports', 3, 1, NULL, 35, 1), (5, 'CON', 'Container', 3, 1, NULL, 35, 1), - (6, 'ALS', 'Alstroemeria', 1, 1, 31, 35, 0); + (6, 'ALS', 'Alstroemeria', 1, 1, 31, 16, 0); INSERT INTO `vn`.`ink`(`id`, `name`, `picture`, `showOrder`, `hex`) VALUES @@ -796,25 +796,25 @@ INSERT INTO `vn`.`itemFamily`(`code`, `description`) ('SER', 'Services'), ('VT', 'Sales'); -INSERT INTO `vn`.`item`(`id`, `typeFk`, `size`, `inkFk`, `stems`, `originFk`, `description`, `producerFk`, `intrastatFk`, `expenceFk`, `comment`, `relevancy`, `image`, `subName`, `minPrice`, `stars`, `family`) +INSERT INTO `vn`.`item`(`id`, `typeFk`, `size`, `inkFk`, `stems`, `originFk`, `description`, `producerFk`, `intrastatFk`, `expenceFk`, `comment`, `relevancy`, `image`, `subName`, `minPrice`, `stars`, `family`, `isFloramondo`) VALUES - (1, 2, 70, 'YEL', 1, 1, NULL, 1, 06021010, 2000000000, NULL, 0, '1', NULL, 0, 1, 'VT'), - (2, 2, 70, 'BLU', 1, 2, NULL, 1, 06021010, 2000000000, NULL, 0, '2', NULL, 0, 2, 'VT'), - (3, 1, 60, 'YEL', 1, 3, NULL, 1, 05080000, 4751000000, NULL, 0, '3', NULL, 0, 5, 'VT'), - (4, 1, 60, 'YEL', 1, 1, 'Increases block', 1, 05080000, 4751000000, NULL, 0, '4', NULL, 0, 3, 'VT'), - (5, 3, 30, 'RED', 1, 2, NULL, 2, 06021010, 4751000000, NULL, 0, '5', NULL, 0, 3, 'VT'), - (6, 5, 30, 'RED', 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '6', NULL, 0, 4, 'VT'), - (7, 5, 90, 'BLU', 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '7', NULL, 0, 4, 'VT'), - (8, 2, 70, 'YEL', 1, 1, NULL, 1, 06021010, 2000000000, NULL, 0, '8', NULL, 0, 5, 'VT'), - (9, 2, 70, 'BLU', 1, 2, NULL, 1, 06021010, 2000000000, NULL, 0, '9', NULL, 0, 4, 'VT'), - (10, 1, 60, 'YEL', 1, 3, NULL, 1, 05080000, 4751000000, NULL, 0, '10', NULL, 0, 4, 'VT'), - (11, 1, 60, 'YEL', 1, 1, NULL, 1, 05080000, 4751000000, NULL, 0, '11', NULL, 0, 4, 'VT'), - (12, 3, 30, 'RED', 1, 2, NULL, 2, 06021010, 4751000000, NULL, 0, '12', NULL, 0, 3, 'VT'), - (13, 5, 30, 'RED', 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '13', NULL, 0, 2, 'VT'), - (14, 5, 90, 'BLU', 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 4, 'VT'), - (15, 4, NULL, NULL, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 0, 'EMB'), - (16, 4, NULL, NULL, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 0, 'EMB'), - (71, 4, NULL, NULL, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 0, 'VT'); + (1, 2, 70, 'YEL', 1, 1, NULL, 1, 06021010, 2000000000, NULL, 0, '1', NULL, 0, 1, 'VT', 0), + (2, 2, 70, 'BLU', 1, 2, NULL, 1, 06021010, 2000000000, NULL, 0, '2', NULL, 0, 2, 'VT', 0), + (3, 1, 60, 'YEL', 1, 3, NULL, 1, 05080000, 4751000000, NULL, 0, '3', NULL, 0, 5, 'VT', 0), + (4, 1, 60, 'YEL', 1, 1, 'Increases block', 1, 05080000, 4751000000, NULL, 0, '4', NULL, 0, 3, 'VT', 0), + (5, 3, 30, 'RED', 1, 2, NULL, 2, 06021010, 4751000000, NULL, 0, '5', NULL, 0, 3, 'VT', 0), + (6, 5, 30, 'RED', 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '6', NULL, 0, 4, 'VT', 0), + (7, 5, 90, 'BLU', 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '7', NULL, 0, 4, 'VT', 0), + (8, 2, 70, 'YEL', 1, 1, NULL, 1, 06021010, 2000000000, NULL, 0, '8', NULL, 0, 5, 'VT', 0), + (9, 2, 70, 'BLU', 1, 2, NULL, 1, 06021010, 2000000000, NULL, 0, '9', NULL, 0, 4, 'VT', 0), + (10, 1, 60, 'YEL', 1, 3, NULL, 1, 05080000, 4751000000, NULL, 0, '10', NULL, 0, 4, 'VT', 0), + (11, 1, 60, 'YEL', 1, 1, NULL, 1, 05080000, 4751000000, NULL, 0, '11', NULL, 0, 4, 'VT', 0), + (12, 3, 30, 'RED', 1, 2, NULL, 2, 06021010, 4751000000, NULL, 0, '12', NULL, 0, 3, 'VT', 0), + (13, 5, 30, 'RED', 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '13', NULL, 0, 2, 'VT', 1), + (14, 5, 90, 'BLU', 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 4, 'VT', 1), + (15, 4, NULL, NULL, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 0, 'EMB', 0), + (16, 6, NULL, NULL, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 0, 'EMB', 0), + (71, 6, NULL, NULL, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 0, 'VT', 0); -- Update the taxClass after insert of the items UPDATE `vn`.`itemTaxCountry` SET `taxClassFk` = 2 diff --git a/e2e/helpers/extensions.js b/e2e/helpers/extensions.js index 1539aca85..789c800b5 100644 --- a/e2e/helpers/extensions.js +++ b/e2e/helpers/extensions.js @@ -341,48 +341,32 @@ let actions = { }, waitForTextInElement: async function(selector, text) { - const expectedText = text.toLowerCase(); - return new Promise((resolve, reject) => { - let attempts = 0; - const interval = setInterval(async() => { - const currentText = await this.evaluate(selector => { - return document.querySelector(selector).innerText.toLowerCase(); - }, selector); - - if (currentText === expectedText || attempts === 40) { - clearInterval(interval); - resolve(currentText); - } - attempts += 1; - }, 100); - }).then(result => { - return expect(result).toContain(expectedText); - }); + await this.waitForFunction((selector, text) => { + if (document.querySelector(selector)) { + const innerText = document.querySelector(selector).innerText.toLowerCase(); + const expectedText = text.toLowerCase(); + if (innerText.includes(expectedText)) + return innerText; + } + }, {}, selector, text); }, waitForTextInField: async function(selector, text) { - let builtSelector = await this.selectorFormater(selector); - await this.waitForSelector(builtSelector); - const expectedText = text.toLowerCase(); - return new Promise((resolve, reject) => { - let attempts = 0; - const interval = setInterval(async() => { - const currentText = await this.evaluate(selector => { - return document.querySelector(selector).value.toLowerCase(); - }, builtSelector); + const builtSelector = await this.selectorFormater(selector); + const expectedValue = text.toLowerCase(); - if (currentText === expectedText || attempts === 40) { - clearInterval(interval); - resolve(currentText); + try { + await this.waitForFunction((selector, text) => { + const element = document.querySelector(selector); + if (element) { + const value = element.value.toLowerCase(); + if (value.includes(text)) + return true; } - attempts += 1; - }, 100); - }).then(result => { - if (result === '') - return expect(result).toEqual(expectedText); - - return expect(result).toContain(expectedText); - }); + }, {}, builtSelector, expectedValue); + } catch (error) { + throw new Error(`${text} wasn't the value of ${builtSelector}, ${error}`); + } }, selectorFormater: function(selector) { diff --git a/e2e/helpers/selectors.js b/e2e/helpers/selectors.js index d3e4da99a..d8ebaa069 100644 --- a/e2e/helpers/selectors.js +++ b/e2e/helpers/selectors.js @@ -313,27 +313,26 @@ export default { }, itemsIndex: { createItemButton: `vn-float-button`, - firstSearchResult: 'vn-item-index a:nth-child(1)', - searchResult: 'vn-item-index a.vn-tr', - firstResultPreviewButton: 'vn-item-index vn-tbody > :nth-child(1) .buttons > [icon="preview"]', + firstSearchResult: 'vn-item-index tbody tr:nth-child(1)', + searchResult: 'vn-item-index tbody tr:not(.empty-rows)', + firstResultPreviewButton: 'vn-item-index tbody > :nth-child(1) .buttons > [icon="preview"]', searchResultCloneButton: 'vn-item-index .buttons > [icon="icon-clone"]', acceptClonationAlertButton: '.vn-confirm.shown [response="accept"]', closeItemSummaryPreview: '.vn-popup.shown', - fieldsToShowButton: 'vn-item-index vn-table > div > div > vn-icon-button[icon="more_vert"]', - fieldsToShowForm: '.vn-popover.shown .content', - firstItemImage: 'vn-item-index vn-tbody > a:nth-child(1) > vn-td:nth-child(1) > img', - firstItemImageTd: 'vn-item-index vn-table a:nth-child(1) vn-td:nth-child(1)', - firstItemId: 'vn-item-index vn-tbody > a:nth-child(1) > vn-td:nth-child(2)', - idCheckbox: '.vn-popover.shown vn-horizontal:nth-child(1) > vn-check', - stemsCheckbox: '.vn-popover.shown vn-horizontal:nth-child(2) > vn-check', - sizeCheckbox: '.vn-popover.shown vn-horizontal:nth-child(3) > vn-check', - typeCheckbox: '.vn-popover.shown vn-horizontal:nth-child(5) > vn-check', - categoryCheckbox: '.vn-popover.shown vn-horizontal:nth-child(6) > vn-check', - intrastadCheckbox: '.vn-popover.shown vn-horizontal:nth-child(7) > vn-check', - originCheckbox: '.vn-popover.shown vn-horizontal:nth-child(8) > vn-check', - buyerCheckbox: '.vn-popover.shown vn-horizontal:nth-child(9) > vn-check', - destinyCheckbox: '.vn-popover.shown vn-horizontal:nth-child(10) > vn-check', - taxClassCheckbox: '.vn-popover.shown vn-horizontal:nth-child(11) > vn-check', + shownColumns: 'vn-item-index vn-button[id="shownColumns"]', + shownColumnsList: '.vn-popover.shown .content', + firstItemImage: 'vn-item-index tbody > tr:nth-child(1) > td:nth-child(1) > img', + firstItemImageTd: 'vn-item-index smart-table tr:nth-child(1) td:nth-child(1)', + firstItemId: 'vn-item-index tbody > tr:nth-child(1) > td:nth-child(2)', + idCheckbox: '.vn-popover.shown vn-horizontal:nth-child(3) > vn-check[label="Identifier"]', + stemsCheckbox: '.vn-popover.shown vn-horizontal:nth-child(3) > vn-check[label="Stems"]', + sizeCheckbox: '.vn-popover.shown vn-horizontal:nth-child(3) > vn-check[label="Size"]', + typeCheckbox: '.vn-popover.shown vn-horizontal:nth-child(3) > vn-check[label="Type"]', + categoryCheckbox: '.vn-popover.shown vn-horizontal:nth-child(3) > vn-check[label="Category"]', + intrastadCheckbox: '.vn-popover.shown vn-horizontal:nth-child(3) > vn-check[label="Intrastat"]', + originCheckbox: '.vn-popover.shown vn-horizontal:nth-child(3) > vn-check[label="Origin"]', + buyerCheckbox: '.vn-popover.shown vn-horizontal:nth-child(3) > vn-check[label="Buyer"]', + densityCheckbox: '.vn-popover.shown vn-horizontal:nth-child(3) > vn-check[label="Density"]', saveFieldsButton: '.vn-popover.shown vn-button[label="Save"] > button' }, itemFixedPrice: { @@ -1087,7 +1086,7 @@ export default { allBuyCheckbox: 'vn-entry-buy-index thead vn-check', firstBuyCheckbox: 'vn-entry-buy-index tbody:nth-child(2) vn-check', deleteBuysButton: 'vn-entry-buy-index vn-button[icon="delete"]', - addBuyButton: 'vn-entry-buy-index vn-icon[icon="add_circle"]', + addBuyButton: 'vn-entry-buy-index vn-icon[icon="add"]', secondBuyPackingPrice: 'vn-entry-buy-index tbody:nth-child(3) > tr:nth-child(1) vn-input-number[ng-model="buy.price3"]', secondBuyGroupingPrice: 'vn-entry-buy-index tbody:nth-child(3) > tr:nth-child(1) vn-input-number[ng-model="buy.price2"]', secondBuyPrice: 'vn-entry-buy-index tbody:nth-child(3) > tr:nth-child(1) vn-input-number[ng-model="buy.buyingValue"]', @@ -1109,9 +1108,9 @@ export default { importBuysButton: 'vn-entry-buy-import button[type="submit"]' }, entryLatestBuys: { - firstBuy: 'vn-entry-latest-buys vn-tbody > a:nth-child(1)', - allBuysCheckBox: 'vn-entry-latest-buys vn-thead vn-check', - secondBuyCheckBox: 'vn-entry-latest-buys a:nth-child(2) vn-check[ng-model="buy.checked"]', + firstBuy: 'vn-entry-latest-buys tbody > tr:nth-child(1)', + allBuysCheckBox: 'vn-entry-latest-buys thead vn-check', + secondBuyCheckBox: 'vn-entry-latest-buys tbody tr:nth-child(2) vn-check[ng-model="buy.$checked"]', editBuysButton: 'vn-entry-latest-buys vn-button[icon="edit"]', fieldAutocomplete: 'vn-autocomplete[ng-model="$ctrl.editedColumn.field"]', newValueInput: 'vn-textfield[ng-model="$ctrl.editedColumn.newValue"]', diff --git a/e2e/paths/01-salix/01_login.spec.js b/e2e/paths/01-salix/01_login.spec.js index 7414856da..9dba61379 100644 --- a/e2e/paths/01-salix/01_login.spec.js +++ b/e2e/paths/01-salix/01_login.spec.js @@ -19,7 +19,9 @@ describe('Login path', async() => { const message = await page.waitForSnackbar(); const state = await page.getState(); - expect(message.text).toContain('Invalid login, remember that distinction is made between uppercase and lowercase'); + const errorMessage = 'Invalid login, remember that distinction is made between uppercase and lowercase'; + + expect(message.text).toContain(errorMessage); expect(state).toBe('login'); }); @@ -28,7 +30,9 @@ describe('Login path', async() => { const message = await page.waitForSnackbar(); const state = await page.getState(); - expect(message.text).toContain('Invalid login, remember that distinction is made between uppercase and lowercase'); + const errorMessage = 'Invalid login, remember that distinction is made between uppercase and lowercase'; + + expect(message.text).toContain(errorMessage); expect(state).toBe('login'); }); diff --git a/e2e/paths/02-client/01_create_client.spec.js b/e2e/paths/02-client/01_create_client.spec.js index 37b39798d..bde4203b4 100644 --- a/e2e/paths/02-client/01_create_client.spec.js +++ b/e2e/paths/02-client/01_create_client.spec.js @@ -83,6 +83,7 @@ describe('Client create path', () => { expect(message.text).toContain('Some fields are invalid'); }); + /* Tarea #3370 it(`should attempt to create a new user with all it's data but wrong business type`, async() => { await page.clearInput(selectors.createClientView.email); await page.write(selectors.createClientView.email, 'CarolDanvers@verdnatura.es'); @@ -91,9 +92,12 @@ describe('Client create path', () => { const message = await page.waitForSnackbar(); expect(message.text).toContain('Some fields are invalid'); - }); + });*/ it(`should attempt to create a new user with all it's data but wrong postal code`, async() => { + await page.clearInput(selectors.createClientView.email); + await page.write(selectors.createClientView.email, 'CarolDanvers@verdnatura.es'); + await page.autocompleteSearch(selectors.createClientView.businessType, 'florist'); await page.clearInput(selectors.createClientView.postcode); await page.write(selectors.createClientView.postcode, '479999'); diff --git a/e2e/paths/02-client/03_edit_fiscal_data.spec.js b/e2e/paths/02-client/03_edit_fiscal_data.spec.js index ab0a61ddc..4ae1d4eca 100644 --- a/e2e/paths/02-client/03_edit_fiscal_data.spec.js +++ b/e2e/paths/02-client/03_edit_fiscal_data.spec.js @@ -112,7 +112,7 @@ describe('Client Edit fiscalData path', () => { expect(message.text).toContain('Cannot check Equalization Tax in this NIF/CIF'); }); - it('should finally edit the fixcal data correctly as VIES isnt checked and fiscal id is valid for EQtax', async() => { + it('should edit the fiscal data correctly as VIES isnt checked and fiscal id is valid for EQtax', async() => { await page.clearInput(selectors.clientFiscalData.fiscalId); await page.write(selectors.clientFiscalData.fiscalId, '94980061C'); await page.waitToClick(selectors.clientFiscalData.saveButton); diff --git a/e2e/paths/02-client/04_edit_billing_data.spec.js b/e2e/paths/02-client/04_edit_billing_data.spec.js index 6bc48093e..de3270f93 100644 --- a/e2e/paths/02-client/04_edit_billing_data.spec.js +++ b/e2e/paths/02-client/04_edit_billing_data.spec.js @@ -38,10 +38,13 @@ describe('Client Edit billing data path', () => { await page.autocompleteSearch(selectors.clientBillingData.newBankEntityCountry, 'España'); await page.write(selectors.clientBillingData.newBankEntityCode, '9999'); await page.waitToClick(selectors.clientBillingData.acceptBankEntityButton); + const message = await page.waitForSnackbar(); await page.waitForTextInField(selectors.clientBillingData.swiftBic, 'Gotham City Bank'); const newcode = await page.waitToGetProperty(selectors.clientBillingData.swiftBic, 'value'); expect(newcode).toEqual('GTHMCT Gotham City Bank'); + + expect(message.text).toContain('Data saved!'); }); it(`should confirm the IBAN pay method was sucessfully saved`, async() => { diff --git a/e2e/paths/04-item/01_summary.spec.js b/e2e/paths/04-item/01_summary.spec.js index a7526accb..e24fa6a9f 100644 --- a/e2e/paths/04-item/01_summary.spec.js +++ b/e2e/paths/04-item/01_summary.spec.js @@ -16,13 +16,13 @@ describe('Item summary path', () => { it('should search for an item', async() => { await page.doSearch('Ranged weapon'); - const nResults = await page.countElement(selectors.itemsIndex.searchResult); + const resultsCount = await page.countElement(selectors.itemsIndex.searchResult); await page.waitForTextInElement(selectors.itemsIndex.searchResult, 'Ranged weapon'); await page.waitToClick(selectors.itemsIndex.firstResultPreviewButton); const isVisible = await page.isVisible(selectors.itemSummary.basicData); - expect(nResults).toBe(3); + expect(resultsCount).toBe(3); expect(isVisible).toBeTruthy(); }); @@ -61,12 +61,12 @@ describe('Item summary path', () => { it('should search for other item', async() => { await page.doSearch('Melee Reinforced'); - const nResults = await page.countElement(selectors.itemsIndex.searchResult); + const resultsCount = await page.countElement(selectors.itemsIndex.searchResult); await page.waitToClick(selectors.itemsIndex.firstResultPreviewButton); await page.waitForSelector(selectors.itemSummary.basicData, {visible: true}); - expect(nResults).toBe(2); + expect(resultsCount).toBe(2); }); it(`should now check the item summary preview shows fields from basic data`, async() => { diff --git a/e2e/paths/04-item/07_create.spec.js b/e2e/paths/04-item/07_create.spec.js new file mode 100644 index 000000000..0820f2db7 --- /dev/null +++ b/e2e/paths/04-item/07_create.spec.js @@ -0,0 +1,71 @@ +import selectors from '../../helpers/selectors.js'; +import getBrowser from '../../helpers/puppeteer'; + +describe('Item Create', () => { + let browser; + let page; + beforeAll(async() => { + browser = await getBrowser(); + page = browser.page; + await page.loginAndModule('buyer', 'item'); + }); + + afterAll(async() => { + await browser.close(); + }); + + it(`should search for the item Infinity Gauntlet to confirm it isn't created yet`, async() => { + await page.doSearch('Infinity Gauntlet'); + const resultsCount = await page.countElement(selectors.itemsIndex.searchResult); + + expect(resultsCount).toEqual(0); + }); + + it('should access to the create item view by clicking the create floating button', async() => { + await page.waitToClick(selectors.itemsIndex.createItemButton); + await page.waitForState('item.create'); + }); + + it('should return to the item index by clickig the cancel button', async() => { + await page.waitToClick(selectors.itemCreateView.cancelButton); + await page.waitForState('item.index'); + }); + + it('should now access to the create item view by clicking the create floating button', async() => { + await page.waitToClick(selectors.itemsIndex.createItemButton); + await page.waitForState('item.create'); + }); + + it('should create the Infinity Gauntlet item', async() => { + await page.write(selectors.itemCreateView.temporalName, 'Infinity Gauntlet'); + await page.autocompleteSearch(selectors.itemCreateView.type, 'Crisantemo'); + await page.autocompleteSearch(selectors.itemCreateView.intrastat, 'Coral y materiales similares'); + await page.autocompleteSearch(selectors.itemCreateView.origin, 'Holand'); + await page.waitToClick(selectors.itemCreateView.createButton); + const message = await page.waitForSnackbar(); + + expect(message.text).toContain('Data saved!'); + }); + + it('should confirm Infinity Gauntlet item was created', async() => { + let result = await page + .waitToGetProperty(selectors.itemBasicData.name, 'value'); + + expect(result).toEqual('Infinity Gauntlet'); + + result = await page + .waitToGetProperty(selectors.itemBasicData.type, 'value'); + + expect(result).toEqual('Crisantemo'); + + result = await page + .waitToGetProperty(selectors.itemBasicData.intrastat, 'value'); + + expect(result).toEqual('5080000 Coral y materiales similares'); + + result = await page + .waitToGetProperty(selectors.itemBasicData.origin, 'value'); + + expect(result).toEqual('Holand'); + }); +}); diff --git a/e2e/paths/04-item/07_create_and_clone.spec.js b/e2e/paths/04-item/07_create_and_clone.spec.js deleted file mode 100644 index 938f15e3f..000000000 --- a/e2e/paths/04-item/07_create_and_clone.spec.js +++ /dev/null @@ -1,105 +0,0 @@ -import selectors from '../../helpers/selectors.js'; -import getBrowser from '../../helpers/puppeteer'; - -describe('Item Create/Clone path', () => { - let browser; - let page; - beforeAll(async() => { - browser = await getBrowser(); - page = browser.page; - await page.loginAndModule('buyer', 'item'); - }); - - afterAll(async() => { - await browser.close(); - }); - - describe('create', () => { - it(`should search for the item Infinity Gauntlet to confirm it isn't created yet`, async() => { - await page.doSearch('Infinity Gauntlet'); - const nResults = await page.countElement(selectors.itemsIndex.searchResult); - - expect(nResults).toEqual(0); - }); - - it('should access to the create item view by clicking the create floating button', async() => { - await page.waitToClick(selectors.itemsIndex.createItemButton); - await page.waitForState('item.create'); - }); - - it('should return to the item index by clickig the cancel button', async() => { - await page.waitToClick(selectors.itemCreateView.cancelButton); - await page.waitForState('item.index'); - }); - - it('should now access to the create item view by clicking the create floating button', async() => { - await page.waitToClick(selectors.itemsIndex.createItemButton); - await page.waitForState('item.create'); - }); - - it('should create the Infinity Gauntlet item', async() => { - await page.write(selectors.itemCreateView.temporalName, 'Infinity Gauntlet'); - await page.autocompleteSearch(selectors.itemCreateView.type, 'Crisantemo'); - await page.autocompleteSearch(selectors.itemCreateView.intrastat, 'Coral y materiales similares'); - await page.autocompleteSearch(selectors.itemCreateView.origin, 'Holand'); - await page.waitToClick(selectors.itemCreateView.createButton); - const message = await page.waitForSnackbar(); - - expect(message.text).toContain('Data saved!'); - }); - - it('should confirm Infinity Gauntlet item was created', async() => { - let result = await page - .waitToGetProperty(selectors.itemBasicData.name, 'value'); - - expect(result).toEqual('Infinity Gauntlet'); - - result = await page - .waitToGetProperty(selectors.itemBasicData.type, 'value'); - - expect(result).toEqual('Crisantemo'); - - result = await page - .waitToGetProperty(selectors.itemBasicData.intrastat, 'value'); - - expect(result).toEqual('5080000 Coral y materiales similares'); - - result = await page - .waitToGetProperty(selectors.itemBasicData.origin, 'value'); - - expect(result).toEqual('Holand'); - }); - }); - - // Issue #2201 - // When there is just one result you're redirected automatically to it, so - // it's not possible to use the clone option. - xdescribe('clone', () => { - it('should return to the items index by clicking the return to items button', async() => { - await page.waitToClick(selectors.itemBasicData.goToItemIndexButton); - await page.waitForSelector(selectors.itemsIndex.createItemButton); - await page.waitForState('item.index'); - }); - - it(`should search for the item Infinity Gauntlet`, async() => { - await page.doSearch('Infinity Gauntlet'); - const nResults = await page.countElement(selectors.itemsIndex.searchResult); - - expect(nResults).toEqual(1); - }); - - it(`should clone the Infinity Gauntlet`, async() => { - await page.waitForTextInElement(selectors.itemsIndex.searchResult, 'Infinity Gauntlet'); - await page.waitToClick(selectors.itemsIndex.searchResultCloneButton); - await page.waitToClick(selectors.itemsIndex.acceptClonationAlertButton); - await page.waitForState('item.tags'); - }); - - it('should search for the item Infinity Gauntlet and find two', async() => { - await page.doSearch('Infinity Gauntlet'); - const nResults = await page.countElement(selectors.itemsIndex.searchResult); - - expect(nResults).toEqual(2); - }); - }); -}); diff --git a/e2e/paths/04-item/09_index.spec.js b/e2e/paths/04-item/09_index.spec.js index 262627e99..f9262863d 100644 --- a/e2e/paths/04-item/09_index.spec.js +++ b/e2e/paths/04-item/09_index.spec.js @@ -16,8 +16,8 @@ describe('Item index path', () => { }); it('should click on the fields to show button to open the list of columns to show', async() => { - await page.waitToClick(selectors.itemsIndex.fieldsToShowButton); - const visible = await page.isVisible(selectors.itemsIndex.fieldsToShowForm); + await page.waitToClick(selectors.itemsIndex.shownColumns); + const visible = await page.isVisible(selectors.itemsIndex.shownColumnsList); expect(visible).toBeTruthy(); }); @@ -31,7 +31,7 @@ describe('Item index path', () => { await page.waitToClick(selectors.itemsIndex.intrastadCheckbox); await page.waitToClick(selectors.itemsIndex.originCheckbox); await page.waitToClick(selectors.itemsIndex.buyerCheckbox); - await page.waitToClick(selectors.itemsIndex.destinyCheckbox); + await page.waitToClick(selectors.itemsIndex.densityCheckbox); await page.waitToClick(selectors.itemsIndex.saveFieldsButton); const message = await page.waitForSnackbar(); @@ -39,6 +39,7 @@ describe('Item index path', () => { }); it('should navigate forth and back to see the images column is still visible', async() => { + await page.closePopup(); await page.waitToClick(selectors.itemsIndex.firstSearchResult); await page.waitToClick(selectors.itemDescriptor.goBackToModuleIndexButton); await page.waitToClick(selectors.globalItems.searchButton); @@ -54,7 +55,7 @@ describe('Item index path', () => { }); it('should mark all unchecked boxes to leave the index as it was', async() => { - await page.waitToClick(selectors.itemsIndex.fieldsToShowButton); + await page.waitToClick(selectors.itemsIndex.shownColumns); await page.waitToClick(selectors.itemsIndex.idCheckbox); await page.waitToClick(selectors.itemsIndex.stemsCheckbox); await page.waitToClick(selectors.itemsIndex.sizeCheckbox); @@ -63,7 +64,7 @@ describe('Item index path', () => { await page.waitToClick(selectors.itemsIndex.intrastadCheckbox); await page.waitToClick(selectors.itemsIndex.originCheckbox); await page.waitToClick(selectors.itemsIndex.buyerCheckbox); - await page.waitToClick(selectors.itemsIndex.destinyCheckbox); + await page.waitToClick(selectors.itemsIndex.densityCheckbox); await page.waitToClick(selectors.itemsIndex.saveFieldsButton); const message = await page.waitForSnackbar(); @@ -71,6 +72,7 @@ describe('Item index path', () => { }); it('should now navigate forth and back to see the ids column is now visible', async() => { + await page.closePopup(); await page.waitToClick(selectors.itemsIndex.firstSearchResult); await page.waitToClick(selectors.itemDescriptor.goBackToModuleIndexButton); await page.waitToClick(selectors.globalItems.searchButton); diff --git a/e2e/paths/05-ticket/04_packages.spec.js b/e2e/paths/05-ticket/04_packages.spec.js index 06720ed7a..f874307a8 100644 --- a/e2e/paths/05-ticket/04_packages.spec.js +++ b/e2e/paths/05-ticket/04_packages.spec.js @@ -62,7 +62,7 @@ describe('Ticket Create packages path', () => { expect(result).toEqual('7 : Container medical box 1m'); }); - it(`should confirm the first quantity is just a number and the string part was ignored by the imput number`, async() => { + it(`should confirm quantity is just a number and the string part was ignored by the imput number`, async() => { await page.waitForTextInField(selectors.ticketPackages.firstQuantity, '-99'); const result = await page.waitToGetProperty(selectors.ticketPackages.firstQuantity, 'value'); diff --git a/e2e/paths/12-entry/03_latestBuys.spec.js b/e2e/paths/12-entry/03_latestBuys.spec.js index f7dc07ca9..553d41b95 100644 --- a/e2e/paths/12-entry/03_latestBuys.spec.js +++ b/e2e/paths/12-entry/03_latestBuys.spec.js @@ -31,7 +31,7 @@ describe('Entry lastest buys path', () => { await page.waitForSelector(selectors.entryLatestBuys.fieldAutocomplete, {visible: true}); }); - it('should search for the "Description" field and type a new description for the items in each selected buy', async() => { + it('should search for the "Description" and type a new one for the items in each selected buy', async() => { await page.autocompleteSearch(selectors.entryLatestBuys.fieldAutocomplete, 'Description'); await page.write(selectors.entryLatestBuys.newValueInput, 'Crafted item'); await page.waitToClick(selectors.entryLatestBuys.acceptEditBuysDialog); diff --git a/e2e/paths/12-entry/07_buys.spec.js b/e2e/paths/12-entry/07_buys.spec.js index 4042c99b6..a39e88ce6 100644 --- a/e2e/paths/12-entry/07_buys.spec.js +++ b/e2e/paths/12-entry/07_buys.spec.js @@ -28,7 +28,7 @@ describe('Entry import, create and edit buys path', () => { await page.waitForState('entry.card.buy.import'); }); - it('should fill the form, import the designated JSON file and select items for each import and confirm import', async() => { + it('should fill the form, import the a JSON file and select items for each import and confirm import', async() => { let currentDir = process.cwd(); let filePath = `${currentDir}/e2e/assets/07_import_buys.json`; @@ -42,7 +42,8 @@ describe('Entry import, create and edit buys path', () => { await page.waitForTextInField(selectors.entryBuys.observation, '729-6340 2846'); await page.autocompleteSearch(selectors.entryBuys.firstImportedItem, 'Ranged Reinforced weapon pistol 9mm'); - await page.autocompleteSearch(selectors.entryBuys.secondImportedItem, 'Melee Reinforced weapon heavy shield 1x0.5m'); + const itemName = 'Melee Reinforced weapon heavy shield 1x0.5m'; + await page.autocompleteSearch(selectors.entryBuys.secondImportedItem, itemName); await page.autocompleteSearch(selectors.entryBuys.thirdImportedItem, 'Container medical box 1m'); await page.autocompleteSearch(selectors.entryBuys.fourthImportedItem, 'Container ammo box 1m'); @@ -88,37 +89,37 @@ describe('Entry import, create and edit buys path', () => { it('should edit the newest buy', async() => { await page.clearInput(selectors.entryBuys.secondBuyPackingPrice); - await page.waitForTextInField(selectors.entryBuys.secondBuyPackingPrice, ''); + await page.waitForTimeout(250); await page.write(selectors.entryBuys.secondBuyPackingPrice, '100'); await page.waitForSnackbar(); await page.clearInput(selectors.entryBuys.secondBuyGroupingPrice); - await page.waitForTextInField(selectors.entryBuys.secondBuyGroupingPrice, ''); + await page.waitForTimeout(250); await page.write(selectors.entryBuys.secondBuyGroupingPrice, '200'); await page.waitForSnackbar(); await page.clearInput(selectors.entryBuys.secondBuyPrice); - await page.waitForTextInField(selectors.entryBuys.secondBuyPrice, ''); + await page.waitForTimeout(250); await page.write(selectors.entryBuys.secondBuyPrice, '300'); await page.waitForSnackbar(); await page.clearInput(selectors.entryBuys.secondBuyGrouping); - await page.waitForTextInField(selectors.entryBuys.secondBuyGrouping, ''); + await page.waitForTimeout(250); await page.write(selectors.entryBuys.secondBuyGrouping, '400'); await page.waitForSnackbar(); await page.clearInput(selectors.entryBuys.secondBuyPacking); - await page.waitForTextInField(selectors.entryBuys.secondBuyPacking, ''); + await page.waitForTimeout(250); await page.write(selectors.entryBuys.secondBuyPacking, '500'); await page.waitForSnackbar(); await page.clearInput(selectors.entryBuys.secondBuyWeight); - await page.waitForTextInField(selectors.entryBuys.secondBuyWeight, ''); + await page.waitForTimeout(250); await page.write(selectors.entryBuys.secondBuyWeight, '600'); await page.waitForSnackbar(); await page.clearInput(selectors.entryBuys.secondBuyStickers); - await page.waitForTextInField(selectors.entryBuys.secondBuyStickers, ''); + await page.waitForTimeout(250); await page.write(selectors.entryBuys.secondBuyStickers, '700'); await page.waitForSnackbar(); @@ -126,7 +127,7 @@ describe('Entry import, create and edit buys path', () => { await page.waitForSnackbar(); await page.clearInput(selectors.entryBuys.secondBuyQuantity); - await page.waitForTextInField(selectors.entryBuys.secondBuyQuantity, ''); + await page.waitForTimeout(250); await page.write(selectors.entryBuys.secondBuyQuantity, '800'); }); diff --git a/front/core/components/contextmenu/index.js b/front/core/components/contextmenu/index.js index 646df1a0a..fa1db6887 100755 --- a/front/core/components/contextmenu/index.js +++ b/front/core/components/contextmenu/index.js @@ -49,7 +49,7 @@ export default class Contextmenu { get rowIndex() { if (!this.row) return null; - const table = this.row.closest('vn-table, .vn-table'); + const table = this.row.closest('table, vn-table, .vn-table'); const rows = table.querySelectorAll('[ng-repeat]'); return Array.from(rows).findIndex( @@ -67,13 +67,13 @@ export default class Contextmenu { get cell() { if (!this.target) return null; - return this.target.closest('vn-td, .vn-td, vn-td-editable'); + return this.target.closest('td, vn-td, .vn-td, vn-td-editable'); } get cellIndex() { if (!this.row) return null; - const cells = this.row.querySelectorAll('vn-td, .vn-td, vn-td-editable'); + const cells = this.row.querySelectorAll('td, vn-td, .vn-td, vn-td-editable'); return Array.from(cells).findIndex( cellItem => cellItem == this.cell ); @@ -82,8 +82,8 @@ export default class Contextmenu { get rowHeader() { if (!this.row) return null; - const table = this.row.closest('vn-table, .vn-table'); - const headerCells = table && table.querySelectorAll('vn-thead vn-th'); + const table = this.row.closest('table, vn-table, .vn-table'); + const headerCells = table && table.querySelectorAll('thead th, vn-thead vn-th'); const headerCell = headerCells && headerCells[this.cellIndex]; return headerCell; @@ -147,7 +147,7 @@ export default class Contextmenu { */ isActionAllowed() { if (!this.target) return false; - const isTableCell = this.target.closest('vn-td, .vn-td'); + const isTableCell = this.target.closest('td, vn-td, .vn-td'); return isTableCell && this.fieldName; } @@ -172,9 +172,28 @@ export default class Contextmenu { excludeSelection() { let where = {[this.fieldName]: {neq: this.fieldValue}}; if (this.exprBuilder) { - where = buildFilter(where, (param, value) => - this.exprBuilder({param, value}) - ); + where = {[this.fieldName]: this.fieldValue}; + where = buildFilter(where, (param, value) => { + const expr = this.exprBuilder({param, value}); + const props = Object.keys(expr); + let newExpr = {}; + for (let prop of props) { + if (expr[prop].like) { + const operator = expr[prop].like; + newExpr[prop] = {nlike: operator}; + } else if (expr[prop].between) { + const operator = expr[prop].between; + newExpr = { + or: [ + {[prop]: {lt: operator[0]}}, + {[prop]: {gt: operator[1]}}, + ] + }; + } else + newExpr[prop] = {neq: this.fieldValue}; + } + return newExpr; + }); } this.model.addFilter({where}); @@ -208,15 +227,22 @@ export default class Contextmenu { if (prop == findProp) delete instance[prop]; - if (prop === 'and') { - for (let [index, param] of instance[prop].entries()) { + if (prop === 'and' || prop === 'or') { + const instanceCopy = instance[prop].slice(); + for (let param of instanceCopy) { const [key] = Object.keys(param); + const index = instance[prop].findIndex(param => { + return Object.keys(param)[0] == key; + }); if (key == findProp) instance[prop].splice(index, 1); if (param[key] instanceof Array) removeProp(param, filterKey, key); } + + if (instance[prop].length == 0) + delete instance[prop]; } } diff --git a/front/core/components/field/style.scss b/front/core/components/field/style.scss index 5f77e904e..c611773e3 100644 --- a/front/core/components/field/style.scss +++ b/front/core/components/field/style.scss @@ -222,7 +222,7 @@ } } &.focused { - background-color: $color-bg-panel; + background-color: $color-font-dark; & > .container { & > .infix > .control > * { diff --git a/front/core/components/index.js b/front/core/components/index.js index 3ccc64b89..86ab89212 100644 --- a/front/core/components/index.js +++ b/front/core/components/index.js @@ -52,3 +52,4 @@ import './wday-picker'; import './datalist'; import './contextmenu'; import './rating'; +import './smart-table'; diff --git a/front/core/components/multi-check/multi-check.js b/front/core/components/multi-check/multi-check.js index d8fda6404..afa1bc3c4 100644 --- a/front/core/components/multi-check/multi-check.js +++ b/front/core/components/multi-check/multi-check.js @@ -145,9 +145,8 @@ export default class MultiCheck extends FormInput { toggle() { const data = this.model.data; if (!data) return; - data.forEach(el => { + for (let el of data) el[this.checkField] = this.checkAll; - }); } } @@ -156,8 +155,9 @@ ngModule.vnComponent('vnMultiCheck', { controller: MultiCheck, bindings: { model: '<', - checkField: ' + +
+ + +
+
+
+
+ {{model.data.length}} + results +
+ + +
+ + + + + + + + +
+ + +
+
+
+ + + + + + + + + + + +
+ +
Shown columns
+ +
+
+ + +
+ + + + + + + + + +
+
+
\ No newline at end of file diff --git a/front/core/components/smart-table/index.js b/front/core/components/smart-table/index.js new file mode 100644 index 000000000..f32d8aa4f --- /dev/null +++ b/front/core/components/smart-table/index.js @@ -0,0 +1,454 @@ +import ngModule from '../../module'; +import Component from '../../lib/component'; +import {buildFilter} from 'vn-loopback/util/filter'; +import angular from 'angular'; +import {camelToKebab} from '../../lib/string'; +import './style.scss'; +import './table.scss'; + +export default class SmartTable extends Component { + constructor($element, $, $transclude) { + super($element, $); + this.currentUserId = window.localStorage.currentUserWorkerId; + this.$transclude = $transclude; + this.sortCriteria = []; + this.$inputsScope; + this.columns = []; + this.autoSave = false; + this.transclude(); + } + + $onDestroy() { + const styleElement = document.querySelector('style[id="smart-table"]'); + if (this.$.css && styleElement) + styleElement.parentNode.removeChild(styleElement); + } + + get options() { + return this._options; + } + + set options(options) { + this._options = options; + if (!options) return; + + const activeButtons = options.activeButtons; + const missingId = activeButtons && activeButtons.shownColumns && !this.viewConfigId; + if (missingId) + throw new Error('vnSmartTable: View identifier not defined'); + } + + get model() { + return this._model; + } + + set model(value) { + this._model = value; + if (value) + this.$.model = value; + } + + get viewConfigId() { + return this._viewConfigId; + } + + set viewConfigId(value) { + this._viewConfigId = value; + + /* if (value) { + this.defaultViewConfig = {}; + + const url = 'DefaultViewConfigs'; + const filter = {where: {tableCode: value}}; + this.$http.get(url, {filter}) + .then(res => { + if (res && res.data.length) { + const columns = res.data[0].columns; + this.defaultViewConfig = columns; + } + }); + } */ + } + + getDefaultViewConfig() { + const url = 'DefaultViewConfigs'; + const filter = {where: {tableCode: this.viewConfigId}}; + return this.$http.get(url, {filter}) + .then(res => { + if (res && res.data.length) + return res.data[0].columns; + }); + } + + get viewConfig() { + return this._viewConfig; + } + + set viewConfig(value) { + this._viewConfig = value; + + if (!value) return; + + if (!value.length) { + this.getDefaultViewConfig().then(columns => { + const defaultViewConfig = columns ? columns : {}; + + const userViewModel = this.$.userViewModel; + for (const column of this.columns) { + if (defaultViewConfig[column.field] == undefined) + defaultViewConfig[column.field] = true; + } + + userViewModel.insert({ + userFk: this.currentUserId, + tableConfig: this.viewConfigId, + configuration: defaultViewConfig + }); + }).finally(() => this.applyViewConfig()); + } else + this.applyViewConfig(); + } + + get checkedRows() { + const model = this.model; + if (model && model.data) + return model.data.filter(row => row.$checked); + + return null; + } + + get checkAll() { + return this._checkAll; + } + + set checkAll(value) { + this._checkAll = value; + if (value !== undefined) { + const shownColumns = this.viewConfig[0].configuration; + for (let param in shownColumns) + shownColumns[param] = value; + } + } + + transclude() { + const slotTable = this.element.querySelector('#table'); + this.$transclude($clone => { + const table = $clone[0]; + slotTable.appendChild(table); + this.registerColumns(); + this.emptyDataRows(); + }, null, 'table'); + } + + saveViewConfig() { + const userViewModel = this.$.userViewModel; + const [viewConfig] = userViewModel.data; + viewConfig.configuration = Object.assign({}, viewConfig.configuration); + userViewModel.save() + .then(() => this.vnApp.showSuccess(this.$t('Data saved!'))) + .then(() => this.applyViewConfig()) + .then(() => this.$.smartTableColumns.hide()); + } + + applyViewConfig() { + const userViewModel = this.$.userViewModel; + const [viewConfig] = userViewModel.data; + + const selectors = []; + for (const column of this.columns) { + if (viewConfig.configuration[column.field] == false) { + const baseSelector = `smart-table[view-config-id="${this.viewConfigId}"] table`; + selectors.push(`${baseSelector} thead > tr > th:nth-child(${column.index + 1})`); + selectors.push(`${baseSelector} tbody > tr > td:nth-child(${column.index + 1})`); + } + } + + let styleElement = document.querySelector('style[id="smart-table"]'); + + if (styleElement) + styleElement.parentNode.removeChild(styleElement); + + if (selectors.length) { + const rule = selectors.join(', ') + '{display: none}'; + this.$.css = document.createElement('style'); + this.$.css.setAttribute('id', 'smart-table'); + document.head.appendChild(this.$.css); + this.$.css.appendChild(document.createTextNode(rule)); + } + } + + registerColumns() { + const header = this.element.querySelector('thead > tr'); + if (!header) return; + const columns = header.querySelectorAll('th'); + + // Click handler + for (const [index, column] of columns.entries()) { + const field = column.getAttribute('field'); + if (field) { + const columnElement = angular.element(column); + const caption = columnElement.text().trim(); + + this.columns.push({field, caption, index}); + + column.addEventListener('click', () => this.orderHandler(column)); + } + } + } + + emptyDataRows() { + const header = this.element.querySelector('thead > tr'); + const columns = header.querySelectorAll('th'); + const tbody = this.element.querySelector('tbody'); + if (tbody) { + const noSearch = this.$compile(` + + Enter a new search + + `)(this.$); + tbody.appendChild(noSearch[0]); + + const noRows = this.$compile(` + + No data + + `)(this.$); + tbody.appendChild(noRows[0]); + } + } + + orderHandler(element) { + const field = element.getAttribute('field'); + const existingCriteria = this.sortCriteria.find(criteria => { + return criteria.field == field; + }); + + const isASC = existingCriteria && existingCriteria.sortType == 'ASC'; + const isDESC = existingCriteria && existingCriteria.sortType == 'DESC'; + + if (!existingCriteria) { + this.sortCriteria.push({field: field, sortType: 'ASC'}); + element.classList.remove('desc'); + element.classList.add('asc'); + } + + if (isDESC) { + this.sortCriteria.splice(this.sortCriteria.findIndex(criteria => { + return criteria.field == field; + }), 1); + element.classList.remove('desc'); + element.classList.remove('asc'); + } + + if (isASC) { + existingCriteria.sortType = 'DESC'; + element.classList.remove('asc'); + element.classList.add('desc'); + } + + this.applySort(); + } + + displaySearch() { + const header = this.element.querySelector('thead > tr'); + if (!header) return; + + const tbody = this.element.querySelector('tbody'); + const columns = header.querySelectorAll('th'); + + const hasSearchRow = tbody.querySelector('tr#searchRow'); + if (hasSearchRow) { + if (this.$inputsScope) + this.$inputsScope.$destroy(); + + return hasSearchRow.remove(); + } + + const searchRow = document.createElement('tr'); + searchRow.setAttribute('id', 'searchRow'); + + this.$inputsScope = this.$.$new(); + + for (let column of columns) { + const field = column.getAttribute('field'); + const cell = document.createElement('td'); + if (field) { + let input; + let options; + const columnOptions = this.options && this.options.columns; + + if (columnOptions) + options = columnOptions.find(column => column.field == field); + + if (options && options.searchable == false) { + searchRow.appendChild(cell); + continue; + } + + if (options && options.autocomplete) { + let props = ``; + + const autocomplete = options.autocomplete; + for (const prop in autocomplete) + props += `${camelToKebab(prop)}="${autocomplete[prop]}"\n`; + input = this.$compile(` + `)(this.$inputsScope); + } else { + input = this.$compile(` + `)(this.$inputsScope); + } + cell.appendChild(input[0]); + } + searchRow.appendChild(cell); + } + + tbody.prepend(searchRow); + } + + searchWithEvent($event, field) { + if ($event.key != 'Enter') return; + + this.searchByColumn(field); + } + + searchByColumn(field) { + const searchCriteria = this.$inputsScope.searchProps[field]; + const emptySearch = searchCriteria == '' || null; + + const filters = this.filterSanitizer(field); + + if (filters && filters.userFilter) + this.model.userFilter = filters.userFilter; + + if (!emptySearch) + this.addFilter(field, this.$inputsScope.searchProps[field]); + else this.model.refresh(); + } + + addFilter(field, value) { + let where = {[field]: value}; + + if (this.exprBuilder) { + where = buildFilter(where, (param, value) => + this.exprBuilder({param, value}) + ); + } + + this.model.addFilter({where}); + } + + applySort() { + let order = this.sortCriteria.map(criteria => `${criteria.field} ${criteria.sortType}`); + order = order.join(', '); + + if (order) + this.model.order = order; + + this.model.refresh(); + } + + filterSanitizer(field) { + const userFilter = this.model.userFilter; + const userParams = this.model.userParams; + const where = userFilter && userFilter.where; + + if (this.exprBuilder) { + const param = this.exprBuilder({ + param: field, + value: null + }); + if (param) [field] = Object.keys(param); + } + + if (!where) return; + + const whereKeys = Object.keys(where); + for (let key of whereKeys) { + removeProp(where, field, key); + + if (!Object.keys(where)) + delete userFilter.where; + } + + function removeProp(instance, findProp, prop) { + if (prop == findProp) + delete instance[prop]; + + if (prop === 'and') { + for (let [index, param] of instance[prop].entries()) { + const [key] = Object.keys(param); + if (key == findProp) + instance[prop].splice(index, 1); + + if (param[key] instanceof Array) + removeProp(param, field, key); + } + } + } + + return {userFilter, userParams}; + } + + removeFilter() { + this.model.applyFilter(userFilter, userParams); + } + + createRow() { + let data = {}; + + if (this.defaultNewData) + data = this.defaultNewData(); + + this.model.insert(data); + } + + deleteAll() { + for (let row of this.checkedRows) + this.model.removeRow(row); + + if (this.autoSave) + this.saveAll(); + } + + saveAll() { + const model = this.model; + + if (!model.isChanged) + return this.vnApp.showError(this.$t('No changes to save')); + + this.model.save() + .then(() => this.vnApp.showSuccess(this.$t('Data saved!'))); + } +} + +SmartTable.$inject = ['$element', '$scope', '$transclude']; + +ngModule.vnComponent('smartTable', { + template: require('./index.html'), + controller: SmartTable, + transclude: { + table: '?slotTable', + actions: '?slotActions' + }, + bindings: { + model: ' :before { + vertical-align: middle; + font-family: 'Material Icons'; + content: 'arrow_downward'; + color: $color-spacer; + margin-right: 2px; + opacity: 0 + + } + + &.asc > :before, &.desc > :before { + color: $color-font; + opacity: 1; + } + + &.asc > :before { + content: 'arrow_upward'; + } + + &.desc > :before { + content: 'arrow_downward'; + } + + &:hover > :before { + opacity: 1; + } + } + + th[field]:not([number]) { + & > :after { + vertical-align: middle; + font-family: 'Material Icons'; + content: 'arrow_downward'; + color: $color-spacer; + margin-left: 2px; + opacity: 0 + + } + + &.asc > :after, &.desc > :after { + color: $color-font; + opacity: 1; + } + + &.asc > :after { + content: 'arrow_upward'; + } + + &.desc > :after { + content: 'arrow_downward'; + } + + &:hover > :after { + opacity: 1; + } + } + + tr[vn-anchor] { + @extend %clickable; + } + + .totalRows { + color: $color-font-secondary; + } + + .actions-left, + .actions-right { + display: flex; + align-items: center; + + .button-group { + display: flex; + box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .3); + + & > vn-button { + box-shadow: 0 0 0 0 + } + } + } + + .actions-left { + justify-content: flex-start; + + slot-actions > vn-button, + & > vn-button, + .button-group { + margin-right: 10px + } + + slot-actions { + display: flex + } + } + + .actions-right { + justify-content: flex-end; + & > vn-button, + .button-group { + margin-left: 10px + } + } + + #table { + overflow-x: auto; + margin-top: 15px + } + + vn-tbody a[ng-repeat].vn-tr:focus { + background-color: $color-primary-light + } + + .new-row { + background-color: $color-success-light + } + + .changed-row { + background-color: $color-primary-light + } +} + +.smart-table-columns { + h6 { + color: $color-font-secondary + } + + & > vn-horizontal { + align-items: flex-start; + flex-wrap: wrap; + } + + vn-check { + flex: initial; + width: 33% + } +} \ No newline at end of file diff --git a/front/core/components/smart-table/table.scss b/front/core/components/smart-table/table.scss new file mode 100644 index 000000000..855534011 --- /dev/null +++ b/front/core/components/smart-table/table.scss @@ -0,0 +1,111 @@ +@import "effects"; +@import "variables"; + +smart-table table { + width: 100%; + border-collapse: collapse; + + & > thead { + border-bottom: 2px solid $color-spacer; + + & > * > th { + font-weight: normal; + } + } + & > tfoot { + border-top: 2px solid $color-spacer; + } + thead, tbody, tfoot { + & > * { + & > th { + color: $color-font-light; + } + & > th, + & > td { + overflow: hidden; + } + & > th, + & > td { + text-align: left; + padding: 5px; + white-space: nowrap; + text-overflow: ellipsis; + + &[number] { + text-align: right; + } + &[centered] { + text-align: center; + } + &[shrink] { + width: 1px; + text-align: center; + } + &[shrink-date] { + width: 100px; + max-width: 100px; + } + &[shrink-datetime] { + width: 150px; + max-width: 150px; + } + &[expand] { + max-width: 400px; + min-width: 0; + } + &[actions] { + width: 1px; + + & > * { + vertical-align: middle; + } + } + vn-icon.bright, i.bright { + color: #f7931e; + } + } + } + } + tbody > * { + border-bottom: 1px solid $color-spacer-light; + + &:last-child { + border-bottom: none; + } + & > td { + .chip { + padding: 4px; + border-radius: 4px; + + &.notice { + background-color: $color-notice-medium; + color: $color-font-bg; + } + &.success { + background-color: $color-success-medium; + color: $color-font-bg; + } + &.warning { + background-color: $color-main-medium; + color: $color-font-bg; + } + &.alert { + background-color: $color-alert-medium; + color: $color-font-bg; + } + &.message { + background-color: $color-bg-dark; + color: $color-font-dark; + } + } + } + } + .vn-check { + margin: 0; + } + .empty-rows > td { + color: $color-font-secondary; + font-size: 1.375rem; + text-align: center; + } +} \ No newline at end of file diff --git a/front/core/components/table/style.scss b/front/core/components/table/style.scss index 2864ea8a1..edb40d385 100644 --- a/front/core/components/table/style.scss +++ b/front/core/components/table/style.scss @@ -132,23 +132,26 @@ vn-table { .chip { padding: 4px; border-radius: 4px; - color: $color-font-bg; &.notice { - background-color: $color-notice-medium + background-color: $color-notice-medium; + color: $color-font-bg; } &.success { background-color: $color-success-medium; + color: $color-font-bg; } &.warning { background-color: $color-main-medium; + color: $color-font-bg; } &.alert { background-color: $color-alert-medium; + color: $color-font-bg; } &.message { + background-color: $color-bg-dark; color: $color-font-dark; - background-color: $color-bg-dark } } vn-icon-menu { @@ -195,7 +198,7 @@ vn-table.scrollable > .vn-table, thead vn-th, thead th { border-bottom: 2px solid $color-spacer; - background-color: #FFF; + background-color: $color-bg-panel; position: sticky; z-index: 9; top: 0 diff --git a/front/core/directives/index.js b/front/core/directives/index.js index e0f42aef5..e77917285 100644 --- a/front/core/directives/index.js +++ b/front/core/directives/index.js @@ -16,3 +16,4 @@ import './droppable'; import './http-click'; import './http-submit'; import './anchor'; + diff --git a/front/core/styles/icons/salixfont.css b/front/core/styles/icons/salixfont.css index d6466a0eb..48dd91a82 100644 --- a/front/core/styles/icons/salixfont.css +++ b/front/core/styles/icons/salixfont.css @@ -23,30 +23,30 @@ -moz-osx-font-smoothing: grayscale; } -.icon-basketadd:before { - content: "\e901"; +.icon-preserved:before { + content: "\e963"; } -.icon-addperson:before { - content: "\e955"; +.icon-treatments:before { + content: "\e964"; } -.icon-supplierfalse:before { +.icon-funeral:before { + content: "\e965"; +} +.icon-handmadeArtificial:before { + content: "\e966"; +} +.icon-fixedPrice:before { content: "\e962"; } -.icon-invoice-in-create:before { - content: "\e948"; +.icon-accounts:before { + content: "\e95f"; } -.icon-invoiceOut:before { +.icon-clientConsumption:before { content: "\e960"; } -.icon-invoiceIn:before { +.icon-lastBuy:before { content: "\e961"; } -.icon-supplier:before { - content: "\e936"; -} -.icon-latestBuy:before { - content: "\e95f"; -} .icon-zone:before { content: "\e95d"; } @@ -86,6 +86,9 @@ .icon-deliveryprices:before { content: "\e956"; } +.icon-basketadd:before { + content: "\e955"; +} .icon-catalog:before { content: "\e952"; } @@ -128,9 +131,15 @@ .icon-actions:before { content: "\e900"; } +.icon-addperson:before { + content: "\e901"; +} .icon-albaran:before { content: "\e902"; } +.icon-apps:before { + content: "\e948"; +} .icon-artificial:before { content: "\e903"; } @@ -239,6 +248,9 @@ .icon-mandatory:before { content: "\e921"; } +.icon-niche:before { + content: "\e922"; +} .icon-no036:before { content: "\e923"; } @@ -302,6 +314,9 @@ .icon-stowaway:before { content: "\e92c"; } +.icon-supplier:before { + content: "\e936"; +} .icon-tags:before { content: "\e937"; } diff --git a/front/core/styles/icons/salixfont.svg b/front/core/styles/icons/salixfont.svg index 7ff0f037d..42129b284 100644 --- a/front/core/styles/icons/salixfont.svg +++ b/front/core/styles/icons/salixfont.svg @@ -10,16 +10,16 @@ - + - + - + @@ -29,7 +29,7 @@ - + @@ -41,6 +41,7 @@ + @@ -49,7 +50,7 @@ - + @@ -66,7 +67,7 @@ - + @@ -104,6 +105,11 @@ + + + + + diff --git a/front/core/styles/icons/salixfont.ttf b/front/core/styles/icons/salixfont.ttf index 106994f83..f0e5ad047 100644 Binary files a/front/core/styles/icons/salixfont.ttf and b/front/core/styles/icons/salixfont.ttf differ diff --git a/front/core/styles/icons/salixfont.woff b/front/core/styles/icons/salixfont.woff index d2491a538..1cf4179ac 100644 Binary files a/front/core/styles/icons/salixfont.woff and b/front/core/styles/icons/salixfont.woff differ diff --git a/front/core/styles/variables.scss b/front/core/styles/variables.scss index 8883c5480..4a00d716d 100644 --- a/front/core/styles/variables.scss +++ b/front/core/styles/variables.scss @@ -1,6 +1,6 @@ @import "./util"; -$font-size: 12pt; +$font-size: 11pt; $menu-width: 256px; $topbar-height: 56px; $mobile-width: 800px; @@ -24,7 +24,7 @@ $spacing-xl: 70px; // Light theme -$color-primary: #f7931e; +/* $color-primary: #f7931e; $color-secondary: $color-primary; $color-font: #222; @@ -72,28 +72,36 @@ $color-success-light: lighten($color-success, 35%); $color-notice-medium: lighten($color-notice, 20%); $color-notice-light: lighten($color-notice, 35%); $color-alert-medium: lighten($color-alert, 20%); -$color-alert-light: lighten($color-alert, 35%); +$color-alert-light: lighten($color-alert, 35%); */ /**/ // Dark theme -/* -$color-header: #3d3d3d; -$color-bg: #222; -$color-bg-dark: #222; +$color-primary: #f7931e; +$color-secondary: $color-primary; + $color-font: #eee; $color-font-light: #aaa; $color-font-secondary: #777; $color-font-dark: white; +$color-font-link: #66bfff; $color-font-bg: rgba(0, 0, 0, .8); -$color-font-link: #005a9a; +$color-font-bg-marginal: rgba(0, 0, 0, .4); +$color-font-bg-dark: rgba(255, 255, 255, .7); +$color-font-bg-dark-marginal: rgba(255, 255, 255, .4); + +$color-header: #3d3d3d; +$color-menu-header: #3d3d3d; +$color-bg: #222; +$color-bg-dark: #222; $color-active: #666; $color-active-font: white; $color-bg-panel: #3c3b3b; -$color-main: #f7931e; -$color-marginal: #ccc; +$color-main: $color-primary; +$color-marginal: #111; $color-success: #a3d131; $color-notice: #32b1ce; -$color-alert: #f42121; +$color-alert: #fa3939; +$color-button: $color-secondary; $color-spacer: rgba(255, 255, 255, .3); $color-spacer-light: rgba(255, 255, 255, .12); @@ -105,15 +113,18 @@ $color-hover-cd: rgba(255, 255, 255, .1); $color-hover-dc: .7; $color-disabled: .6; -$color-font-link: lighten($color-main, 10%); -$color-main-medium: darken($color-main, 20%); -$color-main-light: darken($color-main, 35%); -$color-success-medium: darken($color-success, 20%); -$color-success-light: darken($color-success, 35%); -$color-notice-medium: darken($color-notice, 20%); -$color-notice-light: darken($color-notice, 35%); -$color-alert-medium: darken($color-alert, 20%); -$color-alert-light: darken($color-alert, 35%); +$color-primary-medium: lighten($color-primary, 20%); +$color-primary-light: lighten($color-primary, 35%); +$color-font-link-medium: lighten($color-font-link, 20%); +$color-font-link-light: lighten($color-font-link, 35%); +$color-main-medium: lighten($color-main, 20%); +$color-main-light: lighten($color-main, 35%); +$color-success-medium: lighten($color-success, 20%); +$color-success-light: lighten($color-success, 35%); +$color-notice-medium: lighten($color-notice, 20%); +$color-notice-light: lighten($color-notice, 35%); +$color-alert-medium: lighten($color-alert, 20%); +$color-alert-light: lighten($color-alert, 35%); /**/ // Border diff --git a/front/salix/components/log/index.html b/front/salix/components/log/index.html index c78e00f44..0a0449038 100644 --- a/front/salix/components/log/index.html +++ b/front/salix/components/log/index.html @@ -1,5 +1,11 @@ - + diff --git a/front/salix/components/summary/style.scss b/front/salix/components/summary/style.scss index 99854fa9d..2db3d961e 100644 --- a/front/salix/components/summary/style.scss +++ b/front/salix/components/summary/style.scss @@ -68,7 +68,6 @@ ui-view > .vn-summary { padding: 7px; padding-bottom: 4px; /* Bottom line-height fix */ font-weight: lighter; - background-color: $color-main-light; border-bottom: 1px solid $color-main; white-space: nowrap; overflow: hidden; @@ -78,7 +77,7 @@ ui-view > .vn-summary { display: block; } a { - color: $color-font; + color: $color-font-link; } } h4 span:after { @@ -87,7 +86,7 @@ ui-view > .vn-summary { position: absolute; right: 5px; text-transform: none; - color: $color-spacer + color: $color-font-link; } & > * { margin: $spacing-sm; diff --git a/gulpfile.js b/gulpfile.js index 59c79c154..102a8a0bf 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -128,7 +128,8 @@ async function launchBackTest(done) { if (err) throw err; } -launchBackTest.description = `Runs the backend tests once using a random container, can receive --ci arg to save reports on a xml file`; +launchBackTest.description = ` + Runs the backend tests once using a random container, can receive --ci arg to save reports on a xml file`; // Backend tests diff --git a/modules/claim/back/methods/claim-beginning/importToNewRefundTicket.js b/modules/claim/back/methods/claim-beginning/importToNewRefundTicket.js index 0e358678e..de812417a 100644 --- a/modules/claim/back/methods/claim-beginning/importToNewRefundTicket.js +++ b/modules/claim/back/methods/claim-beginning/importToNewRefundTicket.js @@ -63,7 +63,7 @@ module.exports = Self => { }; let tx; - let myOptions = {}; + const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/modules/claim/back/methods/claim-dms/removeFile.js b/modules/claim/back/methods/claim-dms/removeFile.js index 310d2b941..edc714235 100644 --- a/modules/claim/back/methods/claim-dms/removeFile.js +++ b/modules/claim/back/methods/claim-dms/removeFile.js @@ -20,7 +20,7 @@ module.exports = Self => { Self.removeFile = async(ctx, id, options) => { let tx; - let myOptions = {}; + const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/modules/claim/back/methods/claim-end/importTicketSales.js b/modules/claim/back/methods/claim-end/importTicketSales.js index 106313f14..6dd64be36 100644 --- a/modules/claim/back/methods/claim-end/importTicketSales.js +++ b/modules/claim/back/methods/claim-end/importTicketSales.js @@ -22,7 +22,7 @@ module.exports = Self => { let userId = ctx.req.accessToken.userId; let tx; - let myOptions = {}; + const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/modules/claim/back/methods/claim/regularizeClaim.js b/modules/claim/back/methods/claim/regularizeClaim.js index 2106ab210..d1fe7c13e 100644 --- a/modules/claim/back/methods/claim/regularizeClaim.js +++ b/modules/claim/back/methods/claim/regularizeClaim.js @@ -24,7 +24,7 @@ module.exports = Self => { const resolvedState = 3; let tx; - let myOptions = {}; + const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/modules/claim/back/methods/claim/updateClaim.js b/modules/claim/back/methods/claim/updateClaim.js index 68df9481c..a646db355 100644 --- a/modules/claim/back/methods/claim/updateClaim.js +++ b/modules/claim/back/methods/claim/updateClaim.js @@ -44,7 +44,7 @@ module.exports = Self => { const userId = ctx.req.accessToken.userId; const args = ctx.args; let tx; - let myOptions = {}; + const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/modules/claim/back/methods/claim/updateClaimAction.js b/modules/claim/back/methods/claim/updateClaimAction.js index 12749fb6b..23d1d417d 100644 --- a/modules/claim/back/methods/claim/updateClaimAction.js +++ b/modules/claim/back/methods/claim/updateClaimAction.js @@ -30,7 +30,7 @@ module.exports = Self => { Self.updateClaimAction = async(ctx, id, options) => { let tx; - let myOptions = {}; + const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/modules/claim/back/methods/claim/uploadFile.js b/modules/claim/back/methods/claim/uploadFile.js index daab9341a..81ad40219 100644 --- a/modules/claim/back/methods/claim/uploadFile.js +++ b/modules/claim/back/methods/claim/uploadFile.js @@ -54,7 +54,7 @@ module.exports = Self => { Self.uploadFile = async(ctx, id, options) => { let tx; - let myOptions = {}; + const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/modules/client/back/methods/client/canBeInvoiced.js b/modules/client/back/methods/client/canBeInvoiced.js index d8a126ed2..567d491f1 100644 --- a/modules/client/back/methods/client/canBeInvoiced.js +++ b/modules/client/back/methods/client/canBeInvoiced.js @@ -25,7 +25,7 @@ module.exports = function(Self) { Self.canBeInvoiced = async(id, options) => { const models = Self.app.models; - let myOptions = {}; + const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/modules/client/back/models/client.json b/modules/client/back/models/client.json index 76e1bffdb..d6a98d83c 100644 --- a/modules/client/back/models/client.json +++ b/modules/client/back/models/client.json @@ -135,8 +135,7 @@ "type": "string", "mysql": { "columnName": "businessTypeFk" - }, - "required": true + } } }, "relations": { diff --git a/modules/entry/back/methods/entry/addBuy.js b/modules/entry/back/methods/entry/addBuy.js index f21c1650c..f612c1651 100644 --- a/modules/entry/back/methods/entry/addBuy.js +++ b/modules/entry/back/methods/entry/addBuy.js @@ -68,7 +68,7 @@ module.exports = Self => { Self.addBuy = async(ctx, options) => { const conn = Self.dataSource.connector; let tx; - let myOptions = {}; + const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/modules/entry/back/methods/entry/deleteBuys.js b/modules/entry/back/methods/entry/deleteBuys.js index ce5ff6a7d..ac6d30ce6 100644 --- a/modules/entry/back/methods/entry/deleteBuys.js +++ b/modules/entry/back/methods/entry/deleteBuys.js @@ -21,7 +21,7 @@ module.exports = Self => { Self.deleteBuys = async(ctx, options) => { const models = Self.app.models; let tx; - let myOptions = {}; + const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/modules/entry/back/methods/entry/editLatestBuys.js b/modules/entry/back/methods/entry/editLatestBuys.js index 53b92d966..fb0397d2b 100644 --- a/modules/entry/back/methods/entry/editLatestBuys.js +++ b/modules/entry/back/methods/entry/editLatestBuys.js @@ -32,7 +32,7 @@ module.exports = Self => { Self.editLatestBuys = async(field, newValue, lines, options) => { let tx; - let myOptions = {}; + const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/modules/entry/back/methods/entry/filter.js b/modules/entry/back/methods/entry/filter.js index 24c518de8..13690d3ac 100644 --- a/modules/entry/back/methods/entry/filter.js +++ b/modules/entry/back/methods/entry/filter.js @@ -108,7 +108,7 @@ module.exports = Self => { }); Self.filter = async(ctx, filter, options) => { - let myOptions = {}; + const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/modules/entry/back/methods/entry/getBuys.js b/modules/entry/back/methods/entry/getBuys.js index 8adcc950d..6da9ec53e 100644 --- a/modules/entry/back/methods/entry/getBuys.js +++ b/modules/entry/back/methods/entry/getBuys.js @@ -29,7 +29,7 @@ module.exports = Self => { Self.getBuys = async(id, filter, options) => { const models = Self.app.models; - let myOptions = {}; + const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/modules/entry/back/methods/entry/getEntry.js b/modules/entry/back/methods/entry/getEntry.js index 74ccc88c5..66238d0dc 100644 --- a/modules/entry/back/methods/entry/getEntry.js +++ b/modules/entry/back/methods/entry/getEntry.js @@ -21,7 +21,7 @@ module.exports = Self => { Self.getEntry = async(id, options) => { const models = Self.app.models; - let myOptions = {}; + const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/modules/entry/back/methods/entry/importBuysPreview.js b/modules/entry/back/methods/entry/importBuysPreview.js index 790d33364..5b88b587c 100644 --- a/modules/entry/back/methods/entry/importBuysPreview.js +++ b/modules/entry/back/methods/entry/importBuysPreview.js @@ -26,7 +26,7 @@ module.exports = Self => { Self.importBuysPreview = async(id, buys, options) => { const models = Self.app.models; - let myOptions = {}; + const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/modules/entry/back/methods/entry/latestBuysFilter.js b/modules/entry/back/methods/entry/latestBuysFilter.js index cbf9e3b6a..7711bc0f1 100644 --- a/modules/entry/back/methods/entry/latestBuysFilter.js +++ b/modules/entry/back/methods/entry/latestBuysFilter.js @@ -76,7 +76,7 @@ module.exports = Self => { }); Self.latestBuysFilter = async(ctx, filter, options) => { - let myOptions = {}; + const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/modules/entry/front/buy/import/index.spec.js b/modules/entry/front/buy/import/index.spec.js index c948304c7..bf100dc83 100644 --- a/modules/entry/front/buy/import/index.spec.js +++ b/modules/entry/front/buy/import/index.spec.js @@ -63,8 +63,21 @@ describe('Entry', () => { } ]}`; const expectedBuys = [ - {'buyingValue': 5.77, 'description': 'Bow', 'grouping': 1, 'packing': 1, 'size': 1, 'volume': 1200}, - {'buyingValue': 2.16, 'description': 'Arrow', 'grouping': 1, 'packing': 1, 'size': 25, 'volume': 1125} + { + 'buyingValue': 5.77, + 'description': 'Bow', + 'grouping': 1, + 'packing': 1, + 'size': 1, + 'volume': 1200}, + + { + 'buyingValue': 2.16, + 'description': 'Arrow', + 'grouping': 1, + 'packing': 1, + 'size': 25, + 'volume': 1125} ]; controller.fillData(rawData); controller.$.$apply(); @@ -81,8 +94,21 @@ describe('Entry', () => { describe('fetchBuys()', () => { it(`should perform a query to fetch the buys data`, () => { const buys = [ - {'buyingValue': 5.77, 'description': 'Bow', 'grouping': 1, 'packing': 1, 'size': 1, 'volume': 1200}, - {'buyingValue': 2.16, 'description': 'Arrow', 'grouping': 1, 'packing': 1, 'size': 25, 'volume': 1125} + { + 'buyingValue': 5.77, + 'description': 'Bow', + 'grouping': 1, + 'packing': 1, + 'size': 1, + 'volume': 1200}, + + { + 'buyingValue': 2.16, + 'description': 'Arrow', + 'grouping': 1, + 'packing': 1, + 'size': 25, + 'volume': 1125} ]; const serializedParams = $httpParamSerializer({buys}); @@ -105,17 +131,31 @@ describe('Entry', () => { observation: '123456', ref: '1, 2', buys: [ - {'buyingValue': 5.77, 'description': 'Bow', 'grouping': 1, 'packing': 1, 'size': 1, 'volume': 1200}, - {'buyingValue': 2.16, 'description': 'Arrow', 'grouping': 1, 'packing': 1, 'size': 25, 'volume': 1125} + { + 'buyingValue': 5.77, + 'description': 'Bow', + 'grouping': 1, + 'packing': 1, + 'size': 1, + 'volume': 1200}, + { + 'buyingValue': 2.16, + 'description': 'Arrow', + 'grouping': 1, + 'packing': 1, + 'size': 25, + 'volume': 1125} ] }; controller.onSubmit(); - expect(controller.vnApp.showError).toHaveBeenCalledWith(`Some of the imported buys doesn't have an item`); + const message = `Some of the imported buys doesn't have an item`; + + expect(controller.vnApp.showError).toHaveBeenCalledWith(message); }); - it(`should perform a query to update columns`, () => { + it(`should now perform a query to update columns`, () => { jest.spyOn(controller.vnApp, 'showSuccess'); controller.$state.go = jest.fn(); @@ -123,8 +163,22 @@ describe('Entry', () => { observation: '123456', ref: '1, 2', buys: [ - {'itemFk': 10, 'buyingValue': 5.77, 'description': 'Bow', 'grouping': 1, 'packing': 1, 'size': 1, 'volume': 1200}, - {'itemFk': 11, 'buyingValue': 2.16, 'description': 'Arrow', 'grouping': 1, 'packing': 1, 'size': 25, 'volume': 1125} + { + 'itemFk': 10, + 'buyingValue': 5.77, + 'description': 'Bow', + 'grouping': 1, + 'packing': 1, + 'size': 1, + 'volume': 1200}, + { + 'itemFk': 11, + 'buyingValue': 2.16, + 'description': 'Arrow', + 'grouping': 1, + 'packing': 1, + 'size': 25, + 'volume': 1125} ] }; const params = controller.import; diff --git a/modules/entry/front/buy/index/index.html b/modules/entry/front/buy/index/index.html index dbe43c467..bb33b98b3 100644 --- a/modules/entry/front/buy/index/index.html +++ b/modules/entry/front/buy/index/index.html @@ -188,22 +188,19 @@ -
- - -
- + + - - - + - - - - - - - Picture - Id - Packing - Grouping - Quantity - Description - Size - Tags - Type - Intrastat - Origin - Density - Active - Family - Entry - Buying value - Freight value - Commission value - Package value - Is ignored - Grouping price - Packing price - Min price - Ekt - Weight - PackageName - PackingOut - - - - - - - - - - - - - - {{::buy.itemFk | zeroFill:6}} - - - - - {{::buy.packing | dashIfEmpty}} - - - - - {{::buy.grouping | dashIfEmpty}} - - - {{::buy.quantity}} - - {{::buy.description | dashIfEmpty}} - - {{::buy.size}} - -
- {{::buy.name}} - -

{{::buy.subName}}

-
-
- - -
- - {{::buy.code}} - - - {{::buy.intrastat}} - - {{::buy.origin}} - {{::buy.density}} - - - - - {{::buy.family}} - - - {{::buy.entryFk}} - - - {{::buy.buyingValue | currency: 'EUR':2}} - {{::buy.freightValue | currency: 'EUR':2}} - {{::buy.comissionValue | currency: 'EUR':2}} - {{::buy.packageValue | currency: 'EUR':2}} - - - - - {{::buy.price2 | currency: 'EUR':2}} - {{::buy.price3 | currency: 'EUR':2}} - {{::buy.minPrice | currency: 'EUR':2}} - {{::buy.ektFk | dashIfEmpty}} - {{::buy.weight}} - {{::buy.packageFk}} - {{::buy.packingOut}} -
- - - - + view-config-id="latestBuys" + options="$ctrl.smartTableOptions" + expr-builder="$ctrl.exprBuilder(param, value)"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + Picture + Identifier + + Packing + + Grouping + + Quantity + + Description + + Size + + Tags + + Type + + Intrastat + + Origin + + Density + + Active + + Family + + Entry + + Buying value + + Freight value + + Commission value + + Package value + + Is ignored + + Grouping + + Packing + + Min + + Ekt + + Weight + + Package + + Package out +
+ + + + + + + {{::buy.itemFk}} + + + + {{::buy.packing | dashIfEmpty}} + + + + {{::buy.grouping | dashIfEmpty}} + + {{::buy.quantity}} + {{::buy.description | dashIfEmpty}} + {{::buy.size}} +
+ {{::buy.name}} + +

{{::buy.subName}}

+
+
+ + +
+ {{::buy.code}} + + {{::buy.intrastat}} + {{::buy.origin}}{{::buy.density}} + + + {{::buy.family}} + + {{::buy.entryFk}} + + {{::buy.buyingValue | currency: 'EUR':2}}{{::buy.freightValue | currency: 'EUR':2}}{{::buy.comissionValue | currency: 'EUR':2}}{{::buy.packageValue | currency: 'EUR':2}} + + + {{::buy.price2 | currency: 'EUR':2}}{{::buy.price3 | currency: 'EUR':2}}{{::buy.minPrice | currency: 'EUR':2}}{{::buy.ektFk | dashIfEmpty}}{{::buy.weight}}{{::buy.packageFk}}{{::buy.packingOut}}
+
+ +
{ beforeEach(ngModule('entry')); - beforeEach(angular.mock.inject(($componentController, $compile, $rootScope, _$httpBackend_) => { + beforeEach(angular.mock.inject(($componentController, $rootScope, _$httpBackend_) => { $httpBackend = _$httpBackend_; - let $element = $compile(' {}}, @@ -31,10 +31,10 @@ describe('Entry', () => { describe('get checked', () => { it(`should return a set of checked lines`, () => { controller.$.model.data = [ - {checked: true, id: 1}, - {checked: true, id: 2}, - {checked: true, id: 3}, - {checked: false, id: 4}, + {$checked: true, id: 1}, + {$checked: true, id: 2}, + {$checked: true, id: 3}, + {$checked: false, id: 4}, ]; let result = controller.checked; @@ -43,38 +43,10 @@ describe('Entry', () => { }); }); - describe('uncheck()', () => { - it(`should clear the selection of lines on the controller`, () => { - controller.$.model.data = [ - {checked: true, id: 1}, - {checked: true, id: 2}, - {checked: true, id: 3}, - {checked: false, id: 4}, - ]; - - let result = controller.checked; - - expect(result.length).toEqual(3); - - controller.uncheck(); - - result = controller.checked; - - expect(result.length).toEqual(0); - }); - }); - describe('onEditAccept()', () => { it(`should perform a query to update columns`, () => { - $httpBackend.whenGET('UserConfigViews/getConfig?tableCode=latestBuys').respond([]); - $httpBackend.whenGET('Buys/latestBuysFilter?filter=%7B%22limit%22:20%7D').respond([ - {entryFk: 1}, - {entryFk: 2}, - {entryFk: 3}, - {entryFk: 4} - ]); controller.editedColumn = {field: 'my field', newValue: 'the new value'}; - let query = 'Buys/editLatestBuys'; + const query = 'Buys/editLatestBuys'; $httpBackend.expectPOST(query).respond(); controller.onEditAccept(); diff --git a/modules/entry/front/latest-buys/locale/es.yml b/modules/entry/front/latest-buys/locale/es.yml index cb45724f8..21eae0307 100644 --- a/modules/entry/front/latest-buys/locale/es.yml +++ b/modules/entry/front/latest-buys/locale/es.yml @@ -14,4 +14,4 @@ Field to edit: Campo a editar PackageName: Cubo Edit: Editar buy(s): compra(s) -PackingOut: Packing envíos \ No newline at end of file +Package out: Embalaje envíos \ No newline at end of file diff --git a/modules/entry/front/main/index.html b/modules/entry/front/main/index.html index 6c08cd0c4..f6a4c61fc 100644 --- a/modules/entry/front/main/index.html +++ b/modules/entry/front/main/index.html @@ -2,7 +2,8 @@ vn-id="model" url="Entries/filter" limit="20" - auto-load="true"> + auto-load="true" + order="landed DESC, id DESC"> { { arg: 'isBooked', type: 'boolean', - description: 'Whether the the invoice is booked or not', + description: 'Whether the invoice is booked or not', }, ], returns: { @@ -95,7 +95,7 @@ module.exports = Self => { const conn = Self.dataSource.connector; const args = ctx.args; - let myOptions = {}; + const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/modules/invoiceIn/back/methods/invoice-in/summary.js b/modules/invoiceIn/back/methods/invoice-in/summary.js index f09be4add..3693245cc 100644 --- a/modules/invoiceIn/back/methods/invoice-in/summary.js +++ b/modules/invoiceIn/back/methods/invoice-in/summary.js @@ -20,7 +20,7 @@ module.exports = Self => { }); Self.summary = async(id, options) => { - let myOptions = {}; + const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/modules/invoiceOut/back/methods/invoiceOut/book.js b/modules/invoiceOut/back/methods/invoiceOut/book.js index 0371d4f74..7aa0eac1f 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/book.js +++ b/modules/invoiceOut/back/methods/invoiceOut/book.js @@ -23,7 +23,7 @@ module.exports = Self => { Self.book = async(ref, options) => { const models = Self.app.models; let tx; - let myOptions = {}; + const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/modules/invoiceOut/back/methods/invoiceOut/createPdf.js b/modules/invoiceOut/back/methods/invoiceOut/createPdf.js index ac79f0d5d..3f577c9b0 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/createPdf.js +++ b/modules/invoiceOut/back/methods/invoiceOut/createPdf.js @@ -35,7 +35,7 @@ module.exports = Self => { throw new UserError(`Action not allowed on the test environment`); let tx; - let myOptions = {}; + const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/modules/invoiceOut/back/methods/invoiceOut/filter.js b/modules/invoiceOut/back/methods/invoiceOut/filter.js index 3496c9296..99a80c169 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/filter.js +++ b/modules/invoiceOut/back/methods/invoiceOut/filter.js @@ -35,7 +35,7 @@ module.exports = Self => { { arg: 'hasPdf', type: 'boolean', - description: 'Whether the the invoiceOut has PDF or not', + description: 'Whether the invoiceOut has PDF or not', http: {source: 'query'} }, { @@ -87,7 +87,7 @@ module.exports = Self => { Self.filter = async(ctx, filter, options) => { const conn = Self.dataSource.connector; - let myOptions = {}; + const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/modules/invoiceOut/back/methods/invoiceOut/getTickets.js b/modules/invoiceOut/back/methods/invoiceOut/getTickets.js index dc3296aba..dc94f0f0f 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/getTickets.js +++ b/modules/invoiceOut/back/methods/invoiceOut/getTickets.js @@ -29,7 +29,7 @@ module.exports = Self => { Self.getTickets = async(id, filter, options) => { const models = Self.app.models; - let myOptions = {}; + const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/modules/invoiceOut/back/methods/invoiceOut/summary.js b/modules/invoiceOut/back/methods/invoiceOut/summary.js index a95016ff2..db01a4189 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/summary.js +++ b/modules/invoiceOut/back/methods/invoiceOut/summary.js @@ -21,7 +21,7 @@ module.exports = Self => { Self.summary = async(id, options) => { let summary = {}; - let myOptions = {}; + const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/modules/item/back/methods/item/activeBuyers.js b/modules/item/back/methods/item/activeBuyers.js new file mode 100644 index 000000000..e16ff877b --- /dev/null +++ b/modules/item/back/methods/item/activeBuyers.js @@ -0,0 +1,44 @@ +const ParameterizedSQL = require('loopback-connector').ParameterizedSQL; +const mergeFilters = require('vn-loopback/util/filter').mergeFilters; + +module.exports = Self => { + Self.remoteMethod('activeBuyers', { + description: 'Returns a list of buyers for the given item type', + accepts: [{ + arg: 'filter', + type: 'object', + description: `Filter defining where, order, offset, and limit - must be a JSON-encoded string` + }], + returns: { + type: ['object'], + root: true + }, + http: { + path: `/activeBuyers`, + verb: 'GET' + } + }); + + Self.activeBuyers = async(filter, options) => { + const conn = Self.dataSource.connector; + const where = {isActive: true}; + const myOptions = {}; + + if (typeof options == 'object') + Object.assign(myOptions, options); + + filter = mergeFilters(filter, {where}); + + let stmt = new ParameterizedSQL( + `SELECT DISTINCT w.id workerFk, w.firstName, w.lastName, u.name, u.nickname + FROM worker w + JOIN itemType it ON it.workerFk = w.id + JOIN account.user u ON u.id = w.id + JOIN item i ON i.typeFk = it.id`, + null, myOptions); + + stmt.merge(conn.makeSuffix(filter)); + + return conn.executeStmt(stmt); + }; +}; diff --git a/modules/item/back/methods/item/filter.js b/modules/item/back/methods/item/filter.js index cff36a223..29099c7ec 100644 --- a/modules/item/back/methods/item/filter.js +++ b/modules/item/back/methods/item/filter.js @@ -41,10 +41,10 @@ module.exports = Self => { { arg: 'isActive', type: 'boolean', - description: 'Whether the the item is or not active', + description: 'Whether the item is or not active', }, { - arg: 'salesPersonFk', + arg: 'buyerFk', type: 'integer', description: 'The buyer of the item', }, @@ -62,6 +62,11 @@ module.exports = Self => { arg: 'landed', type: 'date', description: 'The item last buy landed date', + }, + { + arg: 'isFloramondo', + type: 'boolean', + description: 'Whether the the item is or not floramondo', } ], returns: { @@ -104,16 +109,16 @@ module.exports = Self => { ? {or: [{'i.id': value}, codeWhere]} : {or: [{'i.name': {like: `%${value}%`}}, codeWhere]}; case 'id': - return {'i.id': value}; case 'isActive': - return {'i.isActive': value}; + case 'typeFk': + case 'isFloramondo': + param = `i.${param}`; + return {[param]: value}; case 'multiplier': return {'i.stemMultiplier': value}; - case 'typeFk': - return {'i.typeFk': value}; case 'categoryFk': return {'ic.id': value}; - case 'salesPersonFk': + case 'buyerFk': return {'it.workerFk': value}; case 'origin': return {'ori.code': value}; @@ -146,6 +151,7 @@ module.exports = Self => { i.density, i.stemMultiplier, i.typeFk, + i.isFloramondo, it.name AS typeName, it.workerFk AS buyerFk, u.name AS userName, diff --git a/modules/item/back/methods/item/specs/activeBuyers.spec.js b/modules/item/back/methods/item/specs/activeBuyers.spec.js new file mode 100644 index 000000000..5bf36756f --- /dev/null +++ b/modules/item/back/methods/item/specs/activeBuyers.spec.js @@ -0,0 +1,24 @@ +const models = require('vn-loopback/server/server').models; + +describe('Worker activeBuyers', () => { + it('should return the buyers in itemType as result', async() => { + const tx = await models.Item.beginTransaction({}); + + try { + const options = {transaction: tx}; + const filter = {}; + const result = await models.Item.activeBuyers(filter, options); + const firstWorker = result[0]; + const secondWorker = result[1]; + + expect(result.length).toEqual(2); + expect(firstWorker.nickname).toEqual('logisticBossNick'); + expect(secondWorker.nickname).toEqual('buyerNick'); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); +}); diff --git a/modules/item/back/methods/item/specs/filter.spec.js b/modules/item/back/methods/item/specs/filter.spec.js index 572aa0167..7b1fac9ac 100644 --- a/modules/item/back/methods/item/specs/filter.spec.js +++ b/modules/item/back/methods/item/specs/filter.spec.js @@ -60,4 +60,23 @@ describe('item filter()', () => { throw e; } }); + + it('should return 2 result filtering by isFloramondo checkbox', async() => { + const tx = await models.Item.beginTransaction({}); + const options = {transaction: tx}; + + try { + const filter = {}; + const ctx = {args: {filter: filter, isFloramondo: true}}; + const result = await models.Item.filter(ctx, filter, options); + + expect(result.length).toEqual(2); + expect(result[0].id).toEqual(13); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); }); diff --git a/modules/item/back/model-config.json b/modules/item/back/model-config.json index 6e171e9b0..d134d9283 100644 --- a/modules/item/back/model-config.json +++ b/modules/item/back/model-config.json @@ -23,6 +23,9 @@ "ItemCategory": { "dataSource": "vn" }, + "ItemFamily": { + "dataSource": "vn" + }, "ItemLog": { "dataSource": "vn" }, diff --git a/modules/item/back/models/intrastat.json b/modules/item/back/models/intrastat.json index e536e2581..18a964e7b 100644 --- a/modules/item/back/models/intrastat.json +++ b/modules/item/back/models/intrastat.json @@ -8,12 +8,12 @@ }, "properties": { "id": { - "type": "Number", + "type": "number", "id": true, "description": "Identifier" }, "description": { - "type": "String" + "type": "string" } }, "relations": { diff --git a/modules/item/back/models/item-category.json b/modules/item/back/models/item-category.json index fe6d804d8..89fb6d6c9 100644 --- a/modules/item/back/models/item-category.json +++ b/modules/item/back/models/item-category.json @@ -8,18 +8,18 @@ }, "properties": { "id": { - "type": "Number", + "type": "number", "id": true, "description": "Identifier" }, "name": { - "type": "String" + "type": "string" }, "display": { - "type": "Boolean" + "type": "boolean" }, "icon": { - "type": "String" + "type": "string" } }, "relations": { diff --git a/modules/item/back/models/item-family.json b/modules/item/back/models/item-family.json new file mode 100644 index 000000000..270c86061 --- /dev/null +++ b/modules/item/back/models/item-family.json @@ -0,0 +1,27 @@ +{ + "name": "ItemFamily", + "base": "VnModel", + "options": { + "mysql": { + "table": "itemFamily" + } + }, + "properties": { + "code": { + "type": "string", + "id": true, + "description": "Identifier" + }, + "description": { + "type": "string" + } + }, + "acls": [ + { + "accessType": "READ", + "principalType": "ROLE", + "principalId": "$everyone", + "permission": "ALLOW" + } + ] +} \ No newline at end of file diff --git a/modules/item/back/models/item-type.json b/modules/item/back/models/item-type.json index b9f038f84..cb9d5ace8 100644 --- a/modules/item/back/models/item-type.json +++ b/modules/item/back/models/item-type.json @@ -8,21 +8,21 @@ }, "properties": { "id": { - "type": "Number", + "type": "number", "id": true, "description": "Identifier" }, "code": { - "type": "String" + "type": "string" }, "name": { - "type": "String" + "type": "string" }, "life": { - "type": "Number" + "type": "number" }, "isPackaging": { - "type": "Boolean" + "type": "boolean" } }, "relations": { diff --git a/modules/item/back/models/item.js b/modules/item/back/models/item.js index 6cf5ba625..457cce4f2 100644 --- a/modules/item/back/models/item.js +++ b/modules/item/back/models/item.js @@ -14,6 +14,7 @@ module.exports = Self => { require('../methods/item/getWasteByWorker')(Self); require('../methods/item/getWasteByItem')(Self); require('../methods/item/createIntrastat')(Self); + require('../methods/item/activeBuyers')(Self); Self.validatesPresenceOf('originFk', {message: 'Cannot be blank'}); diff --git a/modules/item/back/models/item.json b/modules/item/back/models/item.json index d39b39178..fd4b6b079 100644 --- a/modules/item/back/models/item.json +++ b/modules/item/back/models/item.json @@ -140,6 +140,9 @@ }, "isFragile": { "type": "boolean" + }, + "isFloramondo": { + "type": "boolean" } }, "relations": { diff --git a/modules/item/back/models/origin.json b/modules/item/back/models/origin.json index c381600bf..d2fe3fdf0 100644 --- a/modules/item/back/models/origin.json +++ b/modules/item/back/models/origin.json @@ -8,15 +8,15 @@ }, "properties": { "id": { - "type": "Number", + "type": "number", "id": true, "description": "Identifier" }, "code": { - "type": "String" + "type": "string" }, "name": { - "type": "String" + "type": "string" } }, "acls": [ diff --git a/modules/item/front/fixed-price-search-panel/index.html b/modules/item/front/fixed-price-search-panel/index.html index e34c55ccf..5c8a58674 100644 --- a/modules/item/front/fixed-price-search-panel/index.html +++ b/modules/item/front/fixed-price-search-panel/index.html @@ -44,7 +44,7 @@ + on-change="$ctrl.upsertPrice(price)" + step="0.01"> @@ -140,7 +141,7 @@ + ng-click="deleteFixedPrice.show({$index})"> @@ -154,9 +155,19 @@ ng-click="model.insert()">
+ +
- \ No newline at end of file + + + \ No newline at end of file diff --git a/modules/item/front/fixed-price/locale/es.yml b/modules/item/front/fixed-price/locale/es.yml index c19b7703c..f52aef02c 100644 --- a/modules/item/front/fixed-price/locale/es.yml +++ b/modules/item/front/fixed-price/locale/es.yml @@ -1,4 +1,5 @@ Fixed prices: Precios fijados Search prices by item ID or code: Buscar por ID de artículo o código Search fixed prices: Buscar precios fijados -Add fixed price: Añadir precio fijado \ No newline at end of file +Add fixed price: Añadir precio fijado +This row will be removed: Esta linea se eliminará \ No newline at end of file diff --git a/modules/item/front/index/index.html b/modules/item/front/index/index.html index 023295042..816777a74 100644 --- a/modules/item/front/index/index.html +++ b/modules/item/front/index/index.html @@ -1,115 +1,148 @@ - - - - - - - Id - Grouping - Packing - Description - Stems - Size - Type - Category - Intrastat - Origin - Buyer - Density - Multiplier - Active - Landed - - - - - - - - - - - {{::item.id}} - - - {{::item.grouping | dashIfEmpty}} - {{::item.packing | dashIfEmpty}} - -
- {{::item.name}} - -

{{::item.subName}}

-
-
- - -
- {{::item.stems}} - {{::item.size}} - - {{::item.typeName}} - - - {{::item.category}} - - - {{::item.intrastat}} - - {{::item.origin}} - - - {{::item.userName}} - - - {{::item.density}} - {{::item.stemMultiplier}} - - - - - {{::item.landed | date:'dd/MM/yyyy'}} - - - - - - - - -
-
-
-
-
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Identifier + + Grouping + + Packing + + Description + + Stems + + Size + + Type + + Category + + Intrastat + + Origin + + Buyer + + Density + + Multiplier + + Active + + Landed +
+ + + + {{::item.id}} + + {{::item.grouping | dashIfEmpty}}{{::item.packing | dashIfEmpty}} +
+ {{::item.name}} + +

{{::item.subName}}

+
+
+ + +
{{::item.stems}}{{::item.size}} + {{::item.typeName}} + + {{::item.category}} + + {{::item.intrastat}} + {{::item.origin}} + + {{::item.userName}} + + {{::item.density}}{{::item.stemMultiplier}} + + + {{::item.landed | date:'dd/MM/yyyy'}} + + + + + + +
+
+
+
@@ -133,7 +166,7 @@ diff --git a/modules/item/front/index/index.js b/modules/item/front/index/index.js index 3235d684e..915027c3c 100644 --- a/modules/item/front/index/index.js +++ b/modules/item/front/index/index.js @@ -5,9 +5,61 @@ import './style.scss'; class Controller extends Section { constructor($element, $) { super($element, $); - this.showFields = { - id: false, - actions: false + + this.smartTableOptions = { + activeButtons: { + search: true, + shownColumns: true, + }, + columns: [ + { + field: 'category', + autocomplete: { + url: 'ItemCategories', + valueField: 'name', + } + }, + { + field: 'origin', + autocomplete: { + url: 'Origins', + showField: 'code', + valueField: 'code' + } + }, + { + field: 'typeFk', + autocomplete: { + url: 'ItemTypes', + } + }, + { + field: 'intrastat', + autocomplete: { + url: 'Intrastats', + showField: 'description', + valueField: 'description' + } + }, + { + field: 'buyerFk', + autocomplete: { + url: 'Workers/activeWithRole', + where: `{role: {inq: ['logistic', 'buyer']}}`, + searchFunction: '{firstName: $search}', + showField: 'nickname', + valueField: 'id', + } + }, + { + field: 'active', + searchable: false + }, + { + field: 'landed', + searchable: false + }, + ] }; } @@ -15,7 +67,7 @@ class Controller extends Section { switch (param) { case 'category': return {'ic.name': value}; - case 'salesPersonFk': + case 'buyerFk': return {'it.workerFk': value}; case 'grouping': return {'b.grouping': value}; @@ -27,9 +79,10 @@ class Controller extends Section { return {'i.typeFk': value}; case 'intrastat': return {'intr.description': value}; + case 'name': + return {'i.name': {like: `%${value}%`}}; case 'id': case 'size': - case 'name': case 'subname': case 'isActive': case 'density': diff --git a/modules/item/front/index/style.scss b/modules/item/front/index/style.scss index b0b94c19d..eaa1a16ed 100644 --- a/modules/item/front/index/style.scss +++ b/modules/item/front/index/style.scss @@ -23,7 +23,7 @@ vn-item-product { } } -vn-table { +table { img { border-radius: 50%; width: 50px; diff --git a/modules/item/front/last-entries/index.html b/modules/item/front/last-entries/index.html index af7bbd751..29047c613 100644 --- a/modules/item/front/last-entries/index.html +++ b/modules/item/front/last-entries/index.html @@ -23,7 +23,6 @@ - diff --git a/modules/item/front/main/index.html b/modules/item/front/main/index.html index a57d4fb2d..44d125758 100644 --- a/modules/item/front/main/index.html +++ b/modules/item/front/main/index.html @@ -1,16 +1,19 @@ + data="items" + auto-load="true"> diff --git a/modules/item/front/main/index.js b/modules/item/front/main/index.js index f34369982..1d99c91a1 100644 --- a/modules/item/front/main/index.js +++ b/modules/item/front/main/index.js @@ -1,7 +1,15 @@ import ngModule from '../module'; import ModuleMain from 'salix/components/module-main'; +export default class Items extends ModuleMain { + constructor($element, $) { + super($element, $); -export default class Items extends ModuleMain {} + this.filterParams = { + isActive: true, + isFloramondo: false + }; + } +} ngModule.vnComponent('vnItems', { controller: Items, diff --git a/modules/item/front/routes.json b/modules/item/front/routes.json index 8f3e03746..6d39083b4 100644 --- a/modules/item/front/routes.json +++ b/modules/item/front/routes.json @@ -9,7 +9,7 @@ {"state": "item.index", "icon": "icon-item"}, {"state": "item.request", "icon": "pan_tool"}, {"state": "item.waste.index", "icon": "icon-claims"}, - {"state": "item.fixedPrice", "icon": "contact_support"} + {"state": "item.fixedPrice", "icon": "icon-fixedPrice"} ], "card": [ {"state": "item.card.basicData", "icon": "settings"}, diff --git a/modules/item/front/search-panel/index.html b/modules/item/front/search-panel/index.html index 518062eba..57f05bb54 100644 --- a/modules/item/front/search-panel/index.html +++ b/modules/item/front/search-panel/index.html @@ -40,13 +40,11 @@ @@ -155,6 +153,14 @@ tabindex="-1"> + + + + diff --git a/modules/monitor/front/index/locale/es.yml b/modules/monitor/front/index/locale/es.yml index b17861e9f..3a115797d 100644 --- a/modules/monitor/front/index/locale/es.yml +++ b/modules/monitor/front/index/locale/es.yml @@ -9,5 +9,6 @@ Minimize/Maximize: Minimizar/Maximizar Problems: Problemas Theoretical: Teórica Practical: Práctica +Preparation: Preparación Auto-refresh: Auto-refresco Toggle auto-refresh every 2 minutes: Conmuta el refresco automático cada 2 minutos \ No newline at end of file diff --git a/modules/monitor/front/index/orders/style.scss b/modules/monitor/front/index/orders/style.scss index 102712eaf..d9d50360e 100644 --- a/modules/monitor/front/index/orders/style.scss +++ b/modules/monitor/front/index/orders/style.scss @@ -11,7 +11,7 @@ vn-monitor-sales-orders { color: gray; & > vn-td { - border-bottom: 2px solid $color-marginal; + border-bottom: 2px solid $color-spacer; font-size: 13px; } } diff --git a/modules/monitor/front/index/tickets/index.html b/modules/monitor/front/index/tickets/index.html index 04f7f339f..34f2841fd 100644 --- a/modules/monitor/front/index/tickets/index.html +++ b/modules/monitor/front/index/tickets/index.html @@ -20,155 +20,187 @@ Tickets monitor - - + + + - - - - - - - - - - Problems - Client - Salesperson - Date - Prep. - Theoretical - Practical - Province - State - Zone - Total - - - - - - - - - - - - - - - - - - - - - - {{::ticket.nickname}} - - - - - {{::ticket.userName | dashIfEmpty}} - - - - - {{::ticket.shipped | date: 'dd/MM/yyyy'}} - - - {{::ticket.shipped | date: 'HH:mm'}} - {{::ticket.zoneLanding | date: 'HH:mm'}} - {{::ticket.practicalHour | date: 'HH:mm'}} - {{::ticket.province}} - - - {{::ticket.refFk}} - - - {{::ticket.state}} - - - - - {{::ticket.zoneName | dashIfEmpty}} - - - - - {{::(ticket.totalWithVat ? ticket.totalWithVat : 0) | currency: 'EUR': 2}} - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - + }"> + + + + + + + + + + + + + + + +
+ Problems + + Identifier + + Client + + Salesperson + + Date + + Theoretical + + Practical + + Preparation + + Province + + State + + Zone + + Total +
+ + + + + + + + + + + + + + + {{::ticket.id}} + + + + {{::ticket.nickname}} + + + + {{::ticket.userName | dashIfEmpty}} + + + + {{::ticket.shipped | date: 'dd/MM/yyyy'}} + + {{::ticket.zoneLanding | date: 'HH:mm'}}{{::ticket.practicalHour | date: 'HH:mm'}}{{::ticket.shipped | date: 'HH:mm'}}{{::ticket.province}} + + {{::ticket.refFk}} + + + {{::ticket.state}} + + + + {{::ticket.zoneName | dashIfEmpty}} + + + + {{::(ticket.totalWithVat ? ticket.totalWithVat : 0) | currency: 'EUR': 2}} + + + + + + +
+
+
@@ -185,7 +217,7 @@ model="model"> - { - return $params && $params[param]; + return $params && $params[param] != undefined; }); const hasParams = Object.entries($params).length; if (!hasParams || !hasExcludedParams) @@ -93,8 +151,10 @@ export default class Controller extends Section { return {'t.shipped': { between: this.dateRange(value)} }; - case 'zoneFk': case 'nickname': + return {[`t.nickname`]: {like: `%${value}%`}}; + case 'zoneFk': + case 'totalWithVat': return {[`t.${param}`]: value}; } } diff --git a/modules/route/back/methods/route/getSuggestedTickets.js b/modules/route/back/methods/route/getSuggestedTickets.js index fe268f8cc..49d7c1977 100644 --- a/modules/route/back/methods/route/getSuggestedTickets.js +++ b/modules/route/back/methods/route/getSuggestedTickets.js @@ -20,7 +20,7 @@ module.exports = Self => { }); Self.getSuggestedTickets = async(id, options) => { - let myOptions = {}; + const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/modules/route/back/methods/route/getTickets.js b/modules/route/back/methods/route/getTickets.js index 5705d8905..9a2f5289a 100644 --- a/modules/route/back/methods/route/getTickets.js +++ b/modules/route/back/methods/route/getTickets.js @@ -26,7 +26,8 @@ module.exports = Self => { Self.getTickets = async(filter, options) => { const conn = Self.dataSource.connector; - let myOptions = {}; + const myOptions = {}; + if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/modules/route/back/methods/route/insertTicket.js b/modules/route/back/methods/route/insertTicket.js index d716bd8ba..f78e1cb83 100644 --- a/modules/route/back/methods/route/insertTicket.js +++ b/modules/route/back/methods/route/insertTicket.js @@ -30,7 +30,7 @@ module.exports = Self => { const models = Self.app.models; let tx; - let myOptions = {}; + const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/modules/route/back/methods/route/updateVolume.js b/modules/route/back/methods/route/updateVolume.js index ce6e16b5c..f3b8da130 100644 --- a/modules/route/back/methods/route/updateVolume.js +++ b/modules/route/back/methods/route/updateVolume.js @@ -24,7 +24,7 @@ module.exports = Self => { const models = Self.app.models; let tx; - let myOptions = {}; + const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/modules/supplier/front/contact/style.scss b/modules/supplier/front/contact/style.scss index 84e98050d..becc66dcf 100644 --- a/modules/supplier/front/contact/style.scss +++ b/modules/supplier/front/contact/style.scss @@ -6,5 +6,5 @@ margin-bottom: 10px; padding-right: 10px; padding-left: 10px; - border: 1px solid $color-marginal; + border: 1px solid $color-spacer; } diff --git a/modules/supplier/front/descriptor/index.html b/modules/supplier/front/descriptor/index.html index 9781c95b8..dcc065eff 100644 --- a/modules/supplier/front/descriptor/index.html +++ b/modules/supplier/front/descriptor/index.html @@ -28,11 +28,6 @@ icon="icon-disabled" ng-if="$ctrl.supplier.isActive == false"> - - { - return $params && $params[param]; + return $params && $params[param] != undefined; }); const hasParams = Object.entries($params).length; if (!hasParams || !hasExcludedParams) diff --git a/modules/worker/back/methods/calendar/absences.js b/modules/worker/back/methods/calendar/absences.js index 96293c931..32d311cdb 100644 --- a/modules/worker/back/methods/calendar/absences.js +++ b/modules/worker/back/methods/calendar/absences.js @@ -40,7 +40,7 @@ module.exports = Self => { ended.setMonth(12); ended.setDate(0); - let myOptions = {}; + const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/modules/worker/back/methods/worker-time-control/addTimeEntry.js b/modules/worker/back/methods/worker-time-control/addTimeEntry.js index 2079a62a3..80786b723 100644 --- a/modules/worker/back/methods/worker-time-control/addTimeEntry.js +++ b/modules/worker/back/methods/worker-time-control/addTimeEntry.js @@ -34,8 +34,8 @@ module.exports = Self => { const models = Self.app.models; const args = ctx.args; const currentUserId = ctx.req.accessToken.userId; + const myOptions = {}; - let myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/modules/worker/back/methods/worker-time-control/deleteTimeEntry.js b/modules/worker/back/methods/worker-time-control/deleteTimeEntry.js index 23e4c5fff..c80dcab81 100644 --- a/modules/worker/back/methods/worker-time-control/deleteTimeEntry.js +++ b/modules/worker/back/methods/worker-time-control/deleteTimeEntry.js @@ -25,7 +25,7 @@ module.exports = Self => { const currentUserId = ctx.req.accessToken.userId; const models = Self.app.models; - let myOptions = {}; + const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/modules/worker/back/methods/worker-time-control/updateTimeEntry.js b/modules/worker/back/methods/worker-time-control/updateTimeEntry.js index abeda7f8e..a99a61770 100644 --- a/modules/worker/back/methods/worker-time-control/updateTimeEntry.js +++ b/modules/worker/back/methods/worker-time-control/updateTimeEntry.js @@ -31,7 +31,7 @@ module.exports = Self => { const models = Self.app.models; const args = ctx.args; - let myOptions = {}; + const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/modules/worker/back/methods/worker/createAbsence.js b/modules/worker/back/methods/worker/createAbsence.js index ba13a8a10..89830197d 100644 --- a/modules/worker/back/methods/worker/createAbsence.js +++ b/modules/worker/back/methods/worker/createAbsence.js @@ -41,7 +41,7 @@ module.exports = Self => { const userId = ctx.req.accessToken.userId; let tx; - let myOptions = {}; + const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/modules/worker/back/methods/worker/deleteAbsence.js b/modules/worker/back/methods/worker/deleteAbsence.js index 18427424d..72e9243d9 100644 --- a/modules/worker/back/methods/worker/deleteAbsence.js +++ b/modules/worker/back/methods/worker/deleteAbsence.js @@ -28,7 +28,7 @@ module.exports = Self => { const userId = ctx.req.accessToken.userId; let tx; - let myOptions = {}; + const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/modules/worker/back/methods/worker/holidays.js b/modules/worker/back/methods/worker/holidays.js index f3ce0c661..e11d13002 100644 --- a/modules/worker/back/methods/worker/holidays.js +++ b/modules/worker/back/methods/worker/holidays.js @@ -34,7 +34,7 @@ module.exports = Self => { const models = Self.app.models; const args = ctx.args; - let myOptions = {}; + const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/modules/worker/back/methods/worker/isSubordinate.js b/modules/worker/back/methods/worker/isSubordinate.js index 13cc365c6..f051cf768 100644 --- a/modules/worker/back/methods/worker/isSubordinate.js +++ b/modules/worker/back/methods/worker/isSubordinate.js @@ -27,7 +27,7 @@ module.exports = Self => { const models = Self.app.models; const myUserId = ctx.req.accessToken.userId; - let myOptions = {}; + const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/modules/worker/back/methods/worker/mySubordinates.js b/modules/worker/back/methods/worker/mySubordinates.js index 07a22291d..b6711e382 100644 --- a/modules/worker/back/methods/worker/mySubordinates.js +++ b/modules/worker/back/methods/worker/mySubordinates.js @@ -25,7 +25,7 @@ module.exports = Self => { const userId = ctx.req.accessToken.userId; const stmts = []; - let myOptions = {}; + const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/modules/zone/back/methods/agency-mode/byWarehouse.js b/modules/zone/back/methods/agency-mode/byWarehouse.js index 30716d145..945e79320 100644 --- a/modules/zone/back/methods/agency-mode/byWarehouse.js +++ b/modules/zone/back/methods/agency-mode/byWarehouse.js @@ -22,7 +22,7 @@ module.exports = Self => { Self.byWarehouse = async(filter, options) => { const conn = Self.dataSource.connector; const where = {isActive: true}; - let myOptions = {}; + const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/modules/zone/back/methods/agency/getAgenciesWithWarehouse.js b/modules/zone/back/methods/agency/getAgenciesWithWarehouse.js index 296b9ee8d..846ad6a3d 100644 --- a/modules/zone/back/methods/agency/getAgenciesWithWarehouse.js +++ b/modules/zone/back/methods/agency/getAgenciesWithWarehouse.js @@ -29,7 +29,7 @@ module.exports = Self => { }); Self.getAgenciesWithWarehouse = async(addressFk, landed, warehouseFk, options) => { - let myOptions = {}; + const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/modules/zone/back/methods/agency/landsThatDay.js b/modules/zone/back/methods/agency/landsThatDay.js index 5a9efefe8..b7f13ddda 100644 --- a/modules/zone/back/methods/agency/landsThatDay.js +++ b/modules/zone/back/methods/agency/landsThatDay.js @@ -23,7 +23,7 @@ module.exports = Self => { }); Self.landsThatDay = async(addressFk, landed, options) => { - let myOptions = {}; + const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/modules/zone/back/methods/zone/clone.js b/modules/zone/back/methods/zone/clone.js index 64dc5aa55..391b3762a 100644 --- a/modules/zone/back/methods/zone/clone.js +++ b/modules/zone/back/methods/zone/clone.js @@ -22,7 +22,7 @@ module.exports = Self => { Self.clone = async(id, options) => { const models = Self.app.models; let tx; - let myOptions = {}; + const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/modules/zone/back/methods/zone/getEvents.js b/modules/zone/back/methods/zone/getEvents.js index c76a38ea5..a8ee8bb7b 100644 --- a/modules/zone/back/methods/zone/getEvents.js +++ b/modules/zone/back/methods/zone/getEvents.js @@ -26,7 +26,7 @@ module.exports = Self => { }); Self.getEvents = async(geoFk, agencyModeFk, options) => { - let myOptions = {}; + const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/modules/zone/back/methods/zone/getLeaves.js b/modules/zone/back/methods/zone/getLeaves.js index cda5d7ff9..db17beb1b 100644 --- a/modules/zone/back/methods/zone/getLeaves.js +++ b/modules/zone/back/methods/zone/getLeaves.js @@ -32,7 +32,7 @@ module.exports = Self => { }); Self.getLeaves = async(id, parentId = null, search, options) => { - let myOptions = {}; + const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/modules/zone/back/methods/zone/getUpcomingDeliveries.js b/modules/zone/back/methods/zone/getUpcomingDeliveries.js index 6aceb694b..2a1c39ed6 100644 --- a/modules/zone/back/methods/zone/getUpcomingDeliveries.js +++ b/modules/zone/back/methods/zone/getUpcomingDeliveries.js @@ -14,7 +14,7 @@ module.exports = Self => { }); Self.getUpcomingDeliveries = async options => { - let myOptions = {}; + const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/modules/zone/back/methods/zone/includingExpired.js b/modules/zone/back/methods/zone/includingExpired.js index 75aa41e1c..e93b86471 100644 --- a/modules/zone/back/methods/zone/includingExpired.js +++ b/modules/zone/back/methods/zone/includingExpired.js @@ -2,7 +2,7 @@ const ParameterizedSQL = require('loopback-connector').ParameterizedSQL; module.exports = Self => { Self.remoteMethodCtx('includingExpired', { - description: 'Returns a list of agencies from a warehouse', + description: 'Returns a list of zones for the given warehouse and user', accepts: [{ arg: 'filter', type: 'Object', @@ -19,7 +19,7 @@ module.exports = Self => { }); Self.includingExpired = async(ctx, filter, options) => { - let myOptions = {}; + const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/modules/zone/back/methods/zone/toggleIsIncluded.js b/modules/zone/back/methods/zone/toggleIsIncluded.js index 32144ab97..bf8c86f46 100644 --- a/modules/zone/back/methods/zone/toggleIsIncluded.js +++ b/modules/zone/back/methods/zone/toggleIsIncluded.js @@ -29,7 +29,7 @@ module.exports = Self => { Self.toggleIsIncluded = async(id, geoId, isIncluded, options) => { const models = Self.app.models; - let myOptions = {}; + const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); diff --git a/modules/zone/front/calendar/index.js b/modules/zone/front/calendar/index.js index 00b6176c7..a24d10aef 100644 --- a/modules/zone/front/calendar/index.js +++ b/modules/zone/front/calendar/index.js @@ -45,6 +45,8 @@ class Controller extends Component { let date = new Date(this.date.getTime()); date.setMonth(date.getMonth() + (this.nMonths * direction)); this.date = date; + + this.emit('step'); } get data() { diff --git a/modules/zone/front/events/index.html b/modules/zone/front/events/index.html index 25ec2827f..e71a1ae26 100644 --- a/modules/zone/front/events/index.html +++ b/modules/zone/front/events/index.html @@ -3,6 +3,7 @@ vn-id="calendar" data="data" on-selection="$ctrl.onSelection($days, $type, $weekday, $events, $exclusions)" + on-step="$ctrl.refresh()" class="vn-w-md"> diff --git a/print/core/smtp.js b/print/core/smtp.js index 5fb5c4a2c..36a76dbaf 100644 --- a/print/core/smtp.js +++ b/print/core/smtp.js @@ -24,13 +24,24 @@ module.exports = { throw err; }).finally(async() => { + const attachments = []; + for (let attachment of options.attachments) { + const fileName = attachment.filename; + const filePath = attachment.path; + if (fileName.includes('.png')) return; + + if (fileName || filePath) + attachments.push(filePath ? filePath : fileName); + } + const fileNames = attachments.join(',\n'); await db.rawSql(` - INSERT INTO vn.mail (receiver, replyTo, sent, subject, body, status) - VALUES (?, ?, 1, ?, ?, ?)`, [ + INSERT INTO vn.mail (receiver, replyTo, sent, subject, body, attachment, status) + VALUES (?, ?, 1, ?, ?, ?, ?)`, [ options.to, options.replyTo, options.subject, options.text || options.html, + fileNames, error && error.message || 'Sent' ]); });