diff --git a/back/Dockerfile b/back/Dockerfile index 363192a0b..0f75f6949 100644 --- a/back/Dockerfile +++ b/back/Dockerfile @@ -32,8 +32,7 @@ RUN apt-get update \ RUN apt-get update \ && apt-get install -y --no-install-recommends \ samba-common-bin samba-dsdb-modules\ - && rm -rf /var/lib/apt/lists/* \ - && npm -g install pm2 + && rm -rf /var/lib/apt/lists/* # Salix @@ -55,7 +54,4 @@ COPY \ README.md \ ./ -CMD ["pm2-runtime", "./back/process.yml"] - -HEALTHCHECK --interval=15s --timeout=10s \ - CMD curl -f http://localhost:3000/api/Applications/status || exit 1 +CMD ["node", "--tls-min-v1.0", "--openssl-legacy-provider", "./loopback/server/server.js"] \ No newline at end of file diff --git a/back/methods/collection/assignCollection.js b/back/methods/collection/assignCollection.js index 2ff37ab59..2a7ec9ad5 100644 --- a/back/methods/collection/assignCollection.js +++ b/back/methods/collection/assignCollection.js @@ -19,8 +19,15 @@ module.exports = Self => { if (typeof options == 'object') Object.assign(myOptions, options); - const [info, info2, [{'@vCollectionFk': collectionFk}]] = await Self.rawSql( - 'CALL vn.collection_getAssigned(?, @vCollectionFk);SELECT @vCollectionFk', [userId], myOptions); + + const randStr = Math.random().toString(36).substring(3); + const result = await Self.rawSql(` + CALL vn.collection_getAssigned(?, @vCollectionFk); + SELECT @vCollectionFk ? + `, [userId, randStr], myOptions); + + const collectionFk = result.find(item => item[0]?.[randStr] !== undefined)?.[0]?.[randStr]; + if (!collectionFk) throw new UserError('There are not picking tickets'); await Self.rawSql('CALL vn.collection_printSticker(?, NULL)', [collectionFk], myOptions); diff --git a/back/methods/collection/getTickets.js b/back/methods/collection/getTickets.js index 2a2b67524..48301a366 100644 --- a/back/methods/collection/getTickets.js +++ b/back/methods/collection/getTickets.js @@ -62,7 +62,8 @@ module.exports = Self => { p.code parkingCodePrevia, p.pickingOrder pickingOrderPrevia, iss.id itemShelvingSaleFk, - iss.isPicked + iss.isPicked, + iss.itemShelvingFk FROM ticketCollection tc LEFT JOIN collection c ON c.id = tc.collectionFk JOIN sale s ON s.ticketFk = tc.ticketFk @@ -102,7 +103,8 @@ module.exports = Self => { p.code, p.pickingOrder, iss.id itemShelvingSaleFk, - iss.isPicked + iss.isPicked, + iss.itemShelvingFk FROM sectorCollection sc JOIN sectorCollectionSaleGroup ss ON ss.sectorCollectionFk = sc.id JOIN saleGroup sg ON sg.id = ss.saleGroupFk diff --git a/back/methods/docuware/core.js b/back/methods/docuware/core.js index 74d922236..3de33b786 100644 --- a/back/methods/docuware/core.js +++ b/back/methods/docuware/core.js @@ -4,21 +4,45 @@ module.exports = Self => { /** * Returns basic headers * - * @param {string} cookie - The docuware cookie * @return {object} - The headers */ Self.getOptions = async() => { const docuwareConfig = await Self.app.models.DocuwareConfig.findOne(); + const now = Date.vnNow(); + let {url, username, password, token, expired} = docuwareConfig; + + if (process.env.NODE_ENV && (!expired || expired < now + 60)) { + const {data: {IdentityServiceUrl}} = await axios.get(`${url}/Home/IdentityServiceInfo`); + const {data: {token_endpoint}} = await axios.get(`${IdentityServiceUrl}/.well-known/openid-configuration`); + const {data} = await axios.post(token_endpoint, { + grant_type: 'password', + scope: 'docuware.platform', + client_id: 'docuware.platform.net.client', + username, + password + }, {headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/x-www-form-urlencoded' + }}); + + const newToken = data.access_token; + token = data.token_type + ' ' + newToken; + await docuwareConfig.updateAttributes({ + token, + expired: now + data.expires_in + }); + } + const headers = { headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', - 'Cookie': docuwareConfig.cookie + 'Authorization': token } }; return { - url: docuwareConfig.url, + url, headers }; }; diff --git a/back/methods/docuware/specs/core.spec.js b/back/methods/docuware/specs/core.spec.js index cdf8a3b62..47580483d 100644 --- a/back/methods/docuware/specs/core.spec.js +++ b/back/methods/docuware/specs/core.spec.js @@ -2,87 +2,54 @@ const axios = require('axios'); const models = require('vn-loopback/server/server').models; describe('Docuware core', () => { - beforeAll(() => { + const fileCabinetCode = 'deliveryNote'; + beforeAll(async() => { process.env.NODE_ENV = 'testing'; - }); - afterAll(() => { - delete process.env.NODE_ENV; - }); - - describe('getOptions()', () => { - it('should return url and headers', async() => { - const result = await models.Docuware.getOptions(); - - expect(result.url).toBeDefined(); - expect(result.headers).toBeDefined(); + const docuwareInfo = await models.Docuware.findOne({ + where: { + code: fileCabinetCode + } }); - }); - describe('getDialog()', () => { - it('should return dialogId', async() => { - const dialogs = { - data: { - Dialog: [ - { - DisplayName: 'find', - Id: 'getDialogTest' - } - ] - } - }; - spyOn(axios, 'get').and.returnValue(new Promise(resolve => resolve(dialogs))); - const result = await models.Docuware.getDialog('deliveryNote', 'find', 'randomFileCabinetId'); + spyOn(axios, 'get').and.callFake(url => { + if (url.includes('IdentityServiceInfo')) return {data: {IdentityServiceUrl: 'IdentityServiceUrl'}}; + if (url.includes('IdentityServiceUrl')) return {data: {token_endpoint: 'token_endpoint'}}; + if (url.includes('dialogs')) { + return { + data: { + Dialog: [ + { + DisplayName: 'find', + Id: 'getDialogTest' + } + ] + } + }; + } - expect(result).toEqual('getDialogTest'); - }); - }); - - describe('getFileCabinet()', () => { - it('should return fileCabinetId', async() => { - const code = 'deliveryNote'; - const docuwareInfo = await models.Docuware.findOne({ - where: { - code - } - }); - const dialogs = { - data: { + if (url.includes('FileCabinets')) { + return {data: { FileCabinet: [ { Name: docuwareInfo.fileCabinetName, Id: 'getFileCabinetTest' } ] - } - }; - spyOn(axios, 'get').and.returnValue(new Promise(resolve => resolve(dialogs))); - const result = await models.Docuware.getFileCabinet(code); - - expect(result).toEqual('getFileCabinetTest'); - }); - }); - - describe('get()', () => { - it('should return data without parse', async() => { - spyOn(models.Docuware, 'getFileCabinet').and.returnValue((new Promise(resolve => resolve(Math.random())))); - spyOn(models.Docuware, 'getDialog').and.returnValue((new Promise(resolve => resolve(Math.random())))); - const data = { - data: { - id: 1 - } - }; - spyOn(axios, 'post').and.returnValue(new Promise(resolve => resolve(data))); - const result = await models.Docuware.get('deliveryNote'); - - expect(result.id).toEqual(1); + }}; + } }); - it('should return data with parse', async() => { - spyOn(models.Docuware, 'getFileCabinet').and.returnValue((new Promise(resolve => resolve(Math.random())))); - spyOn(models.Docuware, 'getDialog').and.returnValue((new Promise(resolve => resolve(Math.random())))); - const data = { - data: { + spyOn(axios, 'post').and.callFake(url => { + if (url.includes('token_endpoint')) { + return {data: { + access_token: 'access_token', + token_type: 'bearer', + expires_in: 10000 + }}; + } + if (url.includes('DialogExpression')) { + return {data: { Items: [{ Fields: [ { @@ -103,12 +70,52 @@ describe('Docuware core', () => { ] }] } - }; + }; + } + }); + }); + + afterAll(() => { + delete process.env.NODE_ENV; + }); + + describe('getOptions()', () => { + it('should return url and headers', async() => { + const result = await models.Docuware.getOptions(); + + expect(result.url).toBeDefined(); + expect(result.headers).toBeDefined(); + }); + }); + + describe('Dialog()', () => { + it('should return dialogId', async() => { + const result = await models.Docuware.getDialog('deliveryNote', 'find', 'randomFileCabinetId'); + + expect(result).toEqual('getDialogTest'); + }); + }); + + describe('getFileCabinet()', () => { + it('should return fileCabinetId', async() => { + const result = await models.Docuware.getFileCabinet(fileCabinetCode); + + expect(result).toEqual('getFileCabinetTest'); + }); + }); + + describe('get()', () => { + it('should return data without parse', async() => { + const [result] = await models.Docuware.get('deliveryNote'); + + expect(result.firstRequiredField).toEqual(1); + }); + + it('should return data with parse', async() => { const parse = { 'firstRequiredField': 'id', 'secondRequiredField': 'name', }; - spyOn(axios, 'post').and.returnValue(new Promise(resolve => resolve(data))); const [result] = await models.Docuware.get('deliveryNote', null, parse); expect(result.id).toEqual(1); @@ -119,17 +126,14 @@ describe('Docuware core', () => { describe('getById()', () => { it('should return data', async() => { - spyOn(models.Docuware, 'getFileCabinet').and.returnValue((new Promise(resolve => resolve(Math.random())))); - spyOn(models.Docuware, 'getDialog').and.returnValue((new Promise(resolve => resolve(Math.random())))); - const data = { - data: { - id: 1 - } - }; - spyOn(axios, 'post').and.returnValue(new Promise(resolve => resolve(data))); - const result = await models.Docuware.getById('deliveryNote', 1); + spyOn(models.Docuware, 'get'); + await models.Docuware.getById('deliveryNote', 1); - expect(result.id).toEqual(1); + expect(models.Docuware.get).toHaveBeenCalledWith( + 'deliveryNote', + {condition: [Object({DBName: 'N__ALBAR_N', Value: [1]})]}, + undefined + ); }); }); }); diff --git a/back/methods/docuware/upload.js b/back/methods/docuware/upload.js index 0102911e0..5b35b7598 100644 --- a/back/methods/docuware/upload.js +++ b/back/methods/docuware/upload.js @@ -143,7 +143,7 @@ module.exports = Self => { headers: { 'Content-Type': 'multipart/form-data', 'X-File-ModifiedDate': Date.vnNew(), - 'Cookie': docuwareOptions.headers.headers.Cookie, + 'Authorization': docuwareOptions.headers.headers.Authorization, ...data.getHeaders() }, }; diff --git a/back/methods/vn-user/specs/renew-token.spec.js b/back/methods/vn-user/specs/renew-token.spec.js index 8f1bb54c1..8941916ec 100644 --- a/back/methods/vn-user/specs/renew-token.spec.js +++ b/back/methods/vn-user/specs/renew-token.spec.js @@ -72,9 +72,9 @@ describe('Renew Token', () => { } expect(error).toBeDefined(); - const query = 'SELECT * FROM util.debug'; - const debugLog = await models.Application.rawSql(query, null); + const query = 'SELECT * FROM util.debug WHERE variable = "renewToken"'; + const debugLog = await models.Application.rawSql(query); expect(debugLog.length).toEqual(1); }); diff --git a/back/model-config.json b/back/model-config.json index 20bfb06bd..b6d304675 100644 --- a/back/model-config.json +++ b/back/model-config.json @@ -175,6 +175,9 @@ "PrintConfig": { "dataSource": "vn" }, + "QueueMember": { + "dataSource": "vn" + }, "ViaexpressConfig": { "dataSource": "vn" }, diff --git a/back/models/docuware-config.json b/back/models/docuware-config.json index 9d06c4874..b15cb4c03 100644 --- a/back/models/docuware-config.json +++ b/back/models/docuware-config.json @@ -16,17 +16,17 @@ "url": { "type": "string" }, - "cookie": { + "token": { "type": "string" + }, + "username": { + "type": "string" + }, + "password": { + "type": "string" + }, + "expired":{ + "type": "number" } - }, - "acls": [ - { - "property": "*", - "accessType": "*", - "principalType": "ROLE", - "principalId": "$everyone", - "permission": "ALLOW" - } - ] + } } diff --git a/back/models/queue-member.json b/back/models/queue-member.json new file mode 100644 index 000000000..93ca2ebd7 --- /dev/null +++ b/back/models/queue-member.json @@ -0,0 +1,38 @@ +{ + "name": "QueueMember", + "base": "VnModel", + "options": { + "mysql": { + "table": "pbx.queueMember" + } + }, + "properties": { + "id": { + "type": "number", + "id": true + }, + "queue": { + "type": "string" + }, + "extension": { + "type": "string" + } + }, + "relations": { + "queueRelation": { + "type": "belongsTo", + "model": "Queue", + "foreignKey": "queue", + "primaryKey": "name" + } + }, + "acls": [ + { + "property": "*", + "accessType": "READ", + "principalType": "ROLE", + "principalId": "employee", + "permission": "ALLOW" + } + ] +} \ No newline at end of file diff --git a/back/process.yml b/back/process.yml deleted file mode 100644 index 94072b57d..000000000 --- a/back/process.yml +++ /dev/null @@ -1,7 +0,0 @@ -apps: - - script: ./loopback/server/server.js - name: salix-back - instances: 1 - max_restarts: 0 - autorestart: false - node_args: --tls-min-v1.0 --openssl-legacy-provider diff --git a/db/dump/fixtures.before.sql b/db/dump/fixtures.before.sql index 58a4dc9f1..a6852be7e 100644 --- a/db/dump/fixtures.before.sql +++ b/db/dump/fixtures.before.sql @@ -185,6 +185,7 @@ INSERT INTO `vn`.`warehouse`(`id`, `name`, `code`, `isComparative`, `isInventory (3, 'Warehouse Three', NULL, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0), (4, 'Warehouse Four', NULL, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1), (5, 'Warehouse Five', NULL, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0), + (6, 'Warehouse six', 'vnh', 1, 1, 1, 1, 0, 0, 1, 1, 0, 0), (13, 'Inventory', 'inv', 1, 1, 1, 0, 0, 0, 1, 0, 0, 0), (60, 'Algemesi', NULL, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0); @@ -387,23 +388,23 @@ INSERT INTO `vn`.`contactChannel`(`id`, `name`) (4, 'GCN Channel'), (5, 'The Newspaper'); -INSERT INTO `vn`.`client`(`id`,`name`,`fi`,`socialName`,`contact`,`street`,`city`,`postcode`,`phone`,`mobile`,`isRelevant`,`email`,`iban`,`dueDay`,`accountingAccount`,`isEqualizated`,`provinceFk`,`hasToInvoice`,`credit`,`countryFk`,`isActive`,`gestdocFk`,`quality`,`payMethodFk`,`created`,`isToBeMailed`,`contactChannelFk`,`hasSepaVnl`,`hasCoreVnl`,`hasCoreVnh`,`riskCalculated`, `hasToInvoiceByAddress`,`isTaxDataChecked`,`isFreezed`,`creditInsurance`,`isCreatedAsServed`,`hasInvoiceSimplified`,`salesPersonFk`,`isVies`,`businessTypeFk`,`typeFk`) +INSERT INTO `vn`.`client`(`id`,`name`,`fi`,`socialName`,`contact`,`street`,`city`,`postcode`,`phone`,`mobile`,`isRelevant`,`email`,`iban`,`dueDay`,`accountingAccount`,`isEqualizated`,`provinceFk`,`hasToInvoice`,`credit`,`countryFk`,`isActive`,`quality`,`payMethodFk`,`created`,`isToBeMailed`,`contactChannelFk`,`hasSepaVnl`,`hasCoreVnl`,`hasCoreVnh`,`riskCalculated`, `hasToInvoiceByAddress`,`isTaxDataChecked`,`isFreezed`,`creditInsurance`,`isCreatedAsServed`,`hasInvoiceSimplified`,`salesPersonFk`,`isVies`,`businessTypeFk`,`typeFk`) VALUES - (1101, 'Bruce Wayne', '84612325V', 'BATMAN', 'Alfred', '1007 MOUNTAIN DRIVE, GOTHAM', 'Gotham', 46460, 1111111111, 222222222, 1, 'BruceWayne@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 0, NULL, 0, 0, 18, 0, 'florist','normal'), - (1102, 'Petter Parker', '87945234L', 'SPIDER MAN', 'Aunt May', '20 INGRAM STREET, QUEENS, USA', 'Gotham', 46460, 1111111111, 222222222, 1, 'PetterParker@mydomain.com', NULL, 0, 1234567890, 0, 2, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 0, NULL, 0, 0, 18, 0, 'florist','normal'), - (1103, 'Clark Kent', '06815934E', 'SUPER MAN', 'lois lane', '344 CLINTON STREET, APARTAMENT 3-D', 'Gotham', 46460, 1111111111, 222222222, 1, 'ClarkKent@mydomain.com', NULL, 0, 1234567890, 0, 3, 1, 0, 19, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 0, NULL, 0, 0, 18, 0, 'florist','normal'), - (1104, 'Tony Stark', '06089160W', 'IRON MAN', 'Pepper Potts', '10880 MALIBU POINT, 90265', 'Gotham', 46460, 1111111111, 222222222, 1, 'TonyStark@mydomain.com', NULL, 0, 1234567890, 0, 2, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 0, NULL, 0, 0, 18, 0, 'florist','normal'), - (1105, 'Max Eisenhardt', '251628698', 'MAGNETO', 'Rogue', 'UNKNOWN WHEREABOUTS', 'Gotham', 46460, 1111111111, 222222222, 1, 'MaxEisenhardt@mydomain.com', NULL, 0, 1234567890, 0, 3, 1, 300, 8, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, NULL, 0, 0, 18, 0, 'florist','normal'), - (1106, 'DavidCharlesHaller', '53136686Q', 'LEGION', 'Charles Xavier', 'CITY OF NEW YORK, NEW YORK, USA', 'Gotham', 46460, 1111111111, 222222222, 1, 'DavidCharlesHaller@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 0, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 0, NULL, 0, 0, 19, 0, 'florist','normal'), - (1107, 'Hank Pym', '09854837G', 'ANT MAN', 'Hawk', 'ANTHILL, SAN FRANCISCO, CALIFORNIA', 'Gotham', 46460, 1111111111, 222222222, 1, 'HankPym@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 0, 0, NULL, 0, 0, 19, 0, 'florist','normal'), - (1108, 'Charles Xavier', '22641921P', 'PROFESSOR X', 'Beast', '3800 VICTORY PKWY, CINCINNATI, OH 45207, USA', 'Gotham', 46460, 1111111111, 222222222, 1, 'CharlesXavier@mydomain.com', NULL, 0, 1234567890, 0, 5, 1, 300, 13, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, NULL, 0, 0, 19, 0, 'florist','normal'), - (1109, 'Bruce Banner', '16104829E', 'HULK', 'Black widow', 'SOMEWHERE IN NEW YORK', 'Gotham', 46460, 1111111111, 222222222, 1, 'BruceBanner@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 0, 0, NULL, 0, 0, 9, 0, 'florist','normal'), - (1110, 'Jessica Jones', '58282869H', 'JESSICA JONES', 'Luke Cage', 'NYCC 2015 POSTER', 'Gotham', 46460, 1111111111, 222222222, 1, 'JessicaJones@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 0, NULL, 0, 0, NULL, 1, 'florist','normal'), - (1111, 'Missing', NULL, 'MISSING MAN', 'Anton', 'THE SPACE, UNIVERSE FAR AWAY', 'Gotham', 46460, 1111111111, 222222222, 1, NULL, NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 0, 1, 0, NULL, 1, 0, NULL, 0, 'others','loses'), - (1112, 'Trash', NULL, 'GARBAGE MAN', 'Unknown name', 'NEW YORK CITY, UNDERGROUND', 'Gotham', 46460, 1111111111, 222222222, 1, NULL, NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 0, 1, 0, NULL, 1, 0, NULL, 0, 'others','loses'); + (1101, 'Bruce Wayne', '84612325V', 'BATMAN', 'Alfred', '1007 MOUNTAIN DRIVE, GOTHAM', 'Gotham', 46460, 1111111111, 222222222, 1, 'BruceWayne@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 0, NULL, 0, 0, 18, 0, 'florist','normal'), + (1102, 'Petter Parker', '87945234L', 'SPIDER MAN', 'Aunt May', '20 INGRAM STREET, QUEENS, USA', 'Gotham', 46460, 1111111111, 222222222, 1, 'PetterParker@mydomain.com', NULL, 0, 1234567890, 0, 2, 1, 300, 1, 1, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 0, NULL, 0, 0, 18, 0, 'florist','normal'), + (1103, 'Clark Kent', '06815934E', 'SUPER MAN', 'lois lane', '344 CLINTON STREET, APARTAMENT 3-D', 'Gotham', 46460, 1111111111, 222222222, 1, 'ClarkKent@mydomain.com', NULL, 0, 1234567890, 0, 3, 1, 0, 19, 1, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 0, NULL, 0, 0, 18, 0, 'florist','normal'), + (1104, 'Tony Stark', '06089160W', 'IRON MAN', 'Pepper Potts', '10880 MALIBU POINT, 90265', 'Gotham', 46460, 1111111111, 222222222, 1, 'TonyStark@mydomain.com', NULL, 0, 1234567890, 0, 2, 1, 300, 1, 1, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 0, NULL, 0, 0, 18, 0, 'florist','normal'), + (1105, 'Max Eisenhardt', '251628698', 'MAGNETO', 'Rogue', 'UNKNOWN WHEREABOUTS', 'Gotham', 46460, 1111111111, 222222222, 1, 'MaxEisenhardt@mydomain.com', NULL, 0, 1234567890, 0, 3, 1, 300, 8, 1, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, NULL, 0, 0, 18, 0, 'florist','normal'), + (1106, 'DavidCharlesHaller', '53136686Q', 'LEGION', 'Charles Xavier', 'CITY OF NEW YORK, NEW YORK, USA', 'Gotham', 46460, 1111111111, 222222222, 1, 'DavidCharlesHaller@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 0, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 0, NULL, 0, 0, 19, 0, 'florist','normal'), + (1107, 'Hank Pym', '09854837G', 'ANT MAN', 'Hawk', 'ANTHILL, SAN FRANCISCO, CALIFORNIA', 'Gotham', 46460, 1111111111, 222222222, 1, 'HankPym@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 0, 0, NULL, 0, 0, 19, 0, 'florist','normal'), + (1108, 'Charles Xavier', '22641921P', 'PROFESSOR X', 'Beast', '3800 VICTORY PKWY, CINCINNATI, OH 45207, USA', 'Gotham', 46460, 1111111111, 222222222, 1, 'CharlesXavier@mydomain.com', NULL, 0, 1234567890, 0, 5, 1, 300, 13, 1, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, NULL, 0, 0, 19, 0, 'florist','normal'), + (1109, 'Bruce Banner', '16104829E', 'HULK', 'Black widow', 'SOMEWHERE IN NEW YORK', 'Gotham', 46460, 1111111111, 222222222, 1, 'BruceBanner@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 0, 0, NULL, 0, 0, 9, 0, 'florist','normal'), + (1110, 'Jessica Jones', '58282869H', 'JESSICA JONES', 'Luke Cage', 'NYCC 2015 POSTER', 'Gotham', 46460, 1111111111, 222222222, 1, 'JessicaJones@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 0, NULL, 0, 0, NULL, 1, 'florist','normal'), + (1111, 'Missing', NULL, 'MISSING MAN', 'Anton', 'THE SPACE, UNIVERSE FAR AWAY', 'Gotham', 46460, 1111111111, 222222222, 1, NULL, NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 0, 1, 0, NULL, 1, 0, NULL, 0, 'others','loses'), + (1112, 'Trash', NULL, 'GARBAGE MAN', 'Unknown name', 'NEW YORK CITY, UNDERGROUND', 'Gotham', 46460, 1111111111, 222222222, 1, NULL, NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 0, 1, 0, NULL, 1, 0, NULL, 0, 'others','loses'); -INSERT INTO `vn`.`client`(`id`, `name`, `fi`, `socialName`, `contact`, `street`, `city`, `postcode`, `isRelevant`, `email`, `iban`,`dueDay`,`accountingAccount`, `isEqualizated`, `provinceFk`, `hasToInvoice`, `credit`, `countryFk`, `isActive`, `gestdocFk`, `quality`, `payMethodFk`,`created`, `isTaxDataChecked`) - SELECT id, name, CONCAT(RPAD(CONCAT(id,9),8,id),'A'), UPPER(CONCAT(name, 'Social')), CONCAT(name, 'Contact'), CONCAT(name, 'Street'), 'GOTHAM', 46460, 1, CONCAT(name,'@mydomain.com'), NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1,NULL, 10, 5, util.VN_CURDATE(), 1 +INSERT INTO `vn`.`client`(`id`, `name`, `fi`, `socialName`, `contact`, `street`, `city`, `postcode`, `isRelevant`, `email`, `iban`,`dueDay`,`accountingAccount`, `isEqualizated`, `provinceFk`, `hasToInvoice`, `credit`, `countryFk`, `isActive`, `quality`, `payMethodFk`,`created`, `isTaxDataChecked`) + SELECT id, name, CONCAT(RPAD(CONCAT(id,9),8,id),'A'), UPPER(CONCAT(name, 'Social')), CONCAT(name, 'Contact'), CONCAT(name, 'Street'), 'GOTHAM', 46460, 1, CONCAT(name,'@mydomain.com'), NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, 10, 5, util.VN_CURDATE(), 1 FROM `account`.`role` `r` WHERE `r`.`hasLogin` = 1; @@ -545,7 +546,8 @@ INSERT INTO `vn`.`observationType`(`id`,`description`, `code`) (6, 'Weight', 'weight'), (7, 'InvoiceOut', 'invoiceOut'), (8, 'DropOff', 'dropOff'), - (9, 'Sustitución', 'substitution'); + (9, 'Sustitución', 'substitution'), + (10, 'Finance', 'finance'); INSERT INTO `vn`.`addressObservation`(`id`,`addressFk`,`observationTypeFk`,`description`) VALUES @@ -3941,6 +3943,11 @@ INSERT INTO vn.medicalReview (id, workerFk, centerFk, `date`, `time`, isFit, amount, invoice, remark) VALUES(3, 9, 2, '2000-01-01', '8:00', 1, 150.0, NULL, NULL); +INSERT INTO vn.stockBought (workerFk, bought, reserve, dated) + VALUES(35, 1.00, 1.00, '2001-01-01'); +INSERT INTO vn.auctionConfig (id,conversionCoefficient,warehouseFk) + VALUES (1,0.6,6); + INSERT INTO vn.payrollComponent (id, name, isSalaryAgreed, isVariable, isException) VALUES @@ -3982,3 +3989,25 @@ VALUES INSERT IGNORE INTO ormConfig SET id =1, selectLimit = 1000; + +INSERT INTO pbx.queueMultiConfig + SET id = 'ring', + strategy = 20, + timeout = 2, + retry = 0, + weight = 0, + maxLen = 0, + ringInUse = 0; + +INSERT INTO pbx.queue (description, name, config) + VALUES ('X-men', '1000', 1), + ('Avengers', '2000', 1); + +INSERT IGNORE INTO pbx.queueMember + SET queue = '1000', + extension = '1010'; + +UPDATE vn.department SET pbxQueue = '1000' WHERE name = "CAMARA"; +UPDATE vn.department SET pbxQueue = '2000' WHERE name = "VENTAS"; + + diff --git a/db/routines/hedera/procedures/orderRow_updateOverstocking.sql b/db/routines/hedera/procedures/orderRow_updateOverstocking.sql index ff8362c65..bbfa9432a 100644 --- a/db/routines/hedera/procedures/orderRow_updateOverstocking.sql +++ b/db/routines/hedera/procedures/orderRow_updateOverstocking.sql @@ -1,52 +1,52 @@ -DELIMITER $$ -CREATE OR REPLACE DEFINER=`vn`@`localhost` -PROCEDURE `hedera`.`orderRow_updateOverstocking`(vOrderFk INT) -BEGIN -/** -* Set amount = 0 to avoid overbooking sales -* -* @param vOrderFk hedera.order.id -*/ - DECLARE vCalcFk INT; - DECLARE vDone BOOL; - DECLARE vWarehouseFk INT; - - DECLARE cWarehouses CURSOR FOR - SELECT DISTINCT warehouseFk - FROM orderRow - WHERE orderFk = vOrderFk - AND shipped = util.VN_CURDATE(); - - DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = TRUE; - - DECLARE EXIT HANDLER FOR SQLEXCEPTION - BEGIN - ROLLBACK; - RESIGNAL; - END; - - OPEN cWarehouses; - checking: LOOP - SET vDone = FALSE; - - FETCH cWarehouses INTO vWarehouseFk; - - IF vDone THEN - LEAVE checking; - END IF; - - CALL cache.available_refresh(vCalcFk, FALSE, vWarehouseFk, util.VN_CURDATE()); - - UPDATE orderRow r - JOIN `order` o ON o.id = r.orderFk - JOIN orderConfig oc - JOIN cache.available a ON a.calc_id = vCalcFk AND a.item_id = r.itemFk - SET r.amount = 0 - WHERE ADDTIME(o.rowUpdated, oc.reserveTime) < util.VN_NOW() - AND a.available <= 0 - AND r.warehouseFk = vWarehouseFk - AND r.orderFk = vOrderFk; - END LOOP; - CLOSE cWarehouses; -END$$ -DELIMITER ; \ No newline at end of file +DELIMITER $$ +CREATE OR REPLACE DEFINER=`vn`@`localhost` +PROCEDURE `hedera`.`orderRow_updateOverstocking`(vOrderFk INT) +BEGIN +/** +* Set amount = 0 to avoid overbooking sales +* +* @param vOrderFk hedera.order.id +*/ + DECLARE vCalcFk INT; + DECLARE vDone BOOL; + DECLARE vWarehouseFk INT; + + DECLARE cWarehouses CURSOR FOR + SELECT DISTINCT warehouseFk + FROM orderRow + WHERE orderFk = vOrderFk + AND shipment = util.VN_CURDATE(); + + DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = TRUE; + + DECLARE EXIT HANDLER FOR SQLEXCEPTION + BEGIN + ROLLBACK; + RESIGNAL; + END; + + OPEN cWarehouses; + checking: LOOP + SET vDone = FALSE; + + FETCH cWarehouses INTO vWarehouseFk; + + IF vDone THEN + LEAVE checking; + END IF; + + CALL cache.available_refresh(vCalcFk, FALSE, vWarehouseFk, util.VN_CURDATE()); + + UPDATE orderRow r + JOIN `order` o ON o.id = r.orderFk + JOIN orderConfig oc + JOIN cache.available a ON a.calc_id = vCalcFk AND a.item_id = r.itemFk + SET r.amount = 0 + WHERE ADDTIME(o.rowUpdated, oc.reserveTime) < util.VN_NOW() + AND a.available <= 0 + AND r.warehouseFk = vWarehouseFk + AND r.orderFk = vOrderFk; + END LOOP; + CLOSE cWarehouses; +END$$ +DELIMITER ; diff --git a/db/routines/hedera/procedures/order_confirmWithUser.sql b/db/routines/hedera/procedures/order_confirmWithUser.sql index b3aab522e..644d68a87 100644 --- a/db/routines/hedera/procedures/order_confirmWithUser.sql +++ b/db/routines/hedera/procedures/order_confirmWithUser.sql @@ -22,7 +22,6 @@ BEGIN DECLARE vItemFk INT; DECLARE vConcept VARCHAR(30); DECLARE vAmount INT; - DECLARE vAvailable INT; DECLARE vPrice DECIMAL(10,2); DECLARE vSaleFk INT; DECLARE vRowFk INT; @@ -32,7 +31,6 @@ BEGIN DECLARE vClientFk INT; DECLARE vCompanyFk INT; DECLARE vAgencyModeFk INT; - DECLARE vCalcFk INT; DECLARE vIsTaxDataChecked BOOL; DECLARE vDates CURSOR FOR @@ -98,22 +96,8 @@ BEGIN SELECT employeeFk INTO vUserFk FROM orderConfig; END IF; - START TRANSACTION; - - CALL order_checkEditable(vSelf); - CALL orderRow_updateOverstocking(vSelf); - -- Check order is not empty - SELECT COUNT(*) > 0 INTO vHasRows - FROM orderRow - WHERE orderFk = vSelf - AND amount > 0; - - IF NOT vHasRows THEN - CALL util.throw('ORDER_EMPTY'); - END IF; - -- Check if any product has a quantity of 0 SELECT EXISTS ( SELECT id @@ -123,7 +107,21 @@ BEGIN ) INTO vHas0Amount; IF vHas0Amount THEN - CALL util.throw('Remove lines with quantity = 0 before confirming'); + CALL util.throw('Hay líneas vacías. Por favor, elimínelas'); + END IF; + + START TRANSACTION; + + CALL order_checkEditable(vSelf); + + -- Check order is not empty + SELECT COUNT(*) > 0 INTO vHasRows + FROM orderRow + WHERE orderFk = vSelf + AND amount > 0; + + IF NOT vHasRows THEN + CALL util.throw('ORDER_EMPTY'); END IF; -- Crea los tickets del pedido diff --git a/db/routines/hedera/triggers/orderRow_afterInsert.sql b/db/routines/hedera/triggers/orderRow_afterInsert.sql index af1a1479f..7196dce10 100644 --- a/db/routines/hedera/triggers/orderRow_afterInsert.sql +++ b/db/routines/hedera/triggers/orderRow_afterInsert.sql @@ -1,10 +1,10 @@ -DELIMITER $$ -CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER `hedera`.`orderRow_afterInsert` - AFTER INSERT ON `orderRow` - FOR EACH ROW -BEGIN - UPDATE `order` - SET rowUpdated = NOW() - WHERE id = NEW.orderFk; -END$$ -DELIMITER ; \ No newline at end of file +DELIMITER $$ +CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER `hedera`.`orderRow_afterInsert` + AFTER INSERT ON `orderRow` + FOR EACH ROW +BEGIN + UPDATE `order` + SET rowUpdated = util.VN_NOW() + WHERE id = NEW.orderFk; +END$$ +DELIMITER ; diff --git a/db/routines/vn/procedures/clean.sql b/db/routines/vn/procedures/clean.sql index ad6d66e12..d3fed0242 100644 --- a/db/routines/vn/procedures/clean.sql +++ b/db/routines/vn/procedures/clean.sql @@ -23,6 +23,13 @@ BEGIN DELETE FROM messageInbox WHERE sendDate < v2Months; DELETE FROM messageInbox WHERE sendDate < v2Months; DELETE FROM workerTimeControl WHERE timed < v4Years; + DELETE FROM itemShelvingSale + WHERE itemShelvingFk IN ( + SELECT id + FROM itemShelving + WHERE created < util.VN_CURDATE() + AND visible = 0 + ); DELETE FROM itemShelving WHERE created < util.VN_CURDATE() AND visible = 0; DELETE FROM ticketDown WHERE created < util.yesterday(); DELETE IGNORE FROM expedition WHERE created < v26Months; diff --git a/db/routines/vn/procedures/collection_assign.sql b/db/routines/vn/procedures/collection_assign.sql index ba83f1fbb..a4c861c96 100644 --- a/db/routines/vn/procedures/collection_assign.sql +++ b/db/routines/vn/procedures/collection_assign.sql @@ -3,7 +3,7 @@ CREATE OR REPLACE DEFINER=`vn`@`localhost` PROCEDURE `vn`.`collection_assign`( vUserFk INT, OUT vCollectionFk INT ) -BEGIN +BEGIN /** * Comprueba si existen colecciones libres que se ajustan * al perfil del usuario y le asigna la más antigua. @@ -45,6 +45,12 @@ BEGIN DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = TRUE; -- Si hay colecciones sin terminar, sale del proceso + DECLARE EXIT HANDLER FOR SQLEXCEPTION + BEGIN + ROLLBACK; + RESIGNAL; + END; + CALL collection_get(vUserFk); SELECT (pc.maxNotReadyCollections - COUNT(*)) <= 0, pc.maxNotAssignedCollectionLifeTime @@ -118,9 +124,19 @@ BEGIN IF vCollectionFk IS NULL THEN CALL collection_new(vUserFk, vCollectionFk); - UPDATE `collection` - SET workerFk = vUserFk - WHERE id = vCollectionFk; + START TRANSACTION; + + SELECT workerFk INTO vCollectionWorker + FROM `collection` + WHERE id = vCollectionFk FOR UPDATE; + + IF vCollectionWorker IS NULL THEN + UPDATE `collection` + SET workerFk = vUserFk + WHERE id = vCollectionFk; + END IF; + + COMMIT; END IF; END$$ DELIMITER ; \ No newline at end of file diff --git a/db/routines/vn/procedures/collection_getAssigned.sql b/db/routines/vn/procedures/collection_getAssigned.sql index 518e2dd7b..7151129bf 100644 --- a/db/routines/vn/procedures/collection_getAssigned.sql +++ b/db/routines/vn/procedures/collection_getAssigned.sql @@ -5,100 +5,139 @@ CREATE OR REPLACE DEFINER=`vn`@`localhost` PROCEDURE `vn`.`collection_getAssigne ) BEGIN /** - * Comprueba si existen colecciones libres que se ajustan al perfil del usuario - * y le asigna la más antigua. - * Añade un registro al semillero de colecciones y hace la reserva para la colección - * + * Comprueba si existen colecciones libres que se ajustan + * al perfil del usuario y le asigna la más antigua. + * Añade un registro al semillero de colecciones. + * * @param vUserFk Id de usuario * @param vCollectionFk Id de colección */ DECLARE vHasTooMuchCollections BOOL; - DECLARE vItemPackingTypeFk VARCHAR(1); - DECLARE vWarehouseFk INT; - DECLARE vLockName VARCHAR(215); - DECLARE vLockTime INT DEFAULT 30; + DECLARE vDone BOOL DEFAULT FALSE; + DECLARE vCollectionWorker INT; + DECLARE vMaxNotAssignedCollectionLifeTime TIME; + + DECLARE vCollections CURSOR FOR + WITH collections AS ( + SELECT tc.collectionFk, + SUM(sv.volume) volume, + c.saleTotalCount, + c.itemPackingTypeFk, + c.trainFk, + c.warehouseFk, + c.wagons + FROM vn.ticketCollection tc + JOIN vn.collection c ON c.id = tc.collectionFk + JOIN vn.saleVolume sv ON sv.ticketFk = tc.ticketFk + WHERE c.workerFk IS NULL + AND sv.shipped >= util.VN_CURDATE() + GROUP BY tc.collectionFk + ) SELECT c.collectionFk + FROM collections c + JOIN vn.operator o + WHERE o.workerFk = vUserFk + AND (c.saleTotalCount <= o.linesLimit OR o.linesLimit IS NULL) + AND (c.itemPackingTypeFk = o.itemPackingTypeFk OR o.itemPackingTypeFk IS NULL) + AND o.numberOfWagons = c.wagons + AND o.trainFk = c.trainFk + AND o.warehouseFk = c.warehouseFk; + + DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = TRUE; + -- Si hay colecciones sin terminar, sale del proceso DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN - IF vLockName IS NOT NULL THEN - DO RELEASE_LOCK(vLockName); - END IF; - + ROLLBACK; RESIGNAL; END; - -- Si hay colecciones sin terminar, sale del proceso CALL collection_get(vUserFk); - SELECT (pc.maxNotReadyCollections - COUNT(*)) <= 0, - pc.collection_assign_lockname - INTO vHasTooMuchCollections, - vLockName - FROM tmp.collection c - JOIN productionConfig pc; + SELECT (pc.maxNotReadyCollections - COUNT(*)) <= 0, pc.maxNotAssignedCollectionLifeTime + INTO vHasTooMuchCollections, vMaxNotAssignedCollectionLifeTime + FROM productionConfig pc + LEFT JOIN tmp.collection ON TRUE; DROP TEMPORARY TABLE tmp.collection; IF vHasTooMuchCollections THEN - CALL util.throw('There are pending collections'); - END IF; - - SELECT warehouseFk, itemPackingTypeFk - INTO vWarehouseFk, vItemPackingTypeFk - FROM operator - WHERE workerFk = vUserFk; - - SET vLockName = CONCAT_WS('/', - vLockName, - vWarehouseFk, - vItemPackingTypeFk - ); - - IF NOT GET_LOCK(vLockName, vLockTime) THEN - CALL util.throw(CONCAT('Cannot get lock: ', vLockName)); + CALL util.throw('Hay colecciones pendientes'); END IF; -- Se eliminan las colecciones sin asignar que estan obsoletas - INSERT INTO ticketTracking(stateFk, ticketFk) - SELECT s.id, tc.ticketFk - FROM collection c - JOIN ticketCollection tc ON tc.collectionFk = c.id - JOIN state s ON s.code = 'PRINTED_AUTO' - JOIN productionConfig pc - WHERE c.workerFk IS NULL - AND TIMEDIFF(util.VN_NOW(), c.created) > pc.maxNotAssignedCollectionLifeTime; - DELETE c - FROM collection c - JOIN productionConfig pc - WHERE c.workerFk IS NULL - AND TIMEDIFF(util.VN_NOW(), c.created) > pc.maxNotAssignedCollectionLifeTime; + INSERT INTO ticketTracking(stateFk, ticketFk) + SELECT s.id, tc.ticketFk + FROM `collection` c + JOIN ticketCollection tc ON tc.collectionFk = c.id + JOIN `state` s ON s.code = 'PRINTED_AUTO' + WHERE c.workerFk IS NULL + AND TIMEDIFF(util.VN_NOW(), c.created) > vMaxNotAssignedCollectionLifeTime; + + DELETE FROM `collection` + WHERE workerFk IS NULL + AND TIMEDIFF(util.VN_NOW(), created) > vMaxNotAssignedCollectionLifeTime; -- Se añade registro al semillero - INSERT INTO collectionHotbed - SET userFk = vUserFk; + + INSERT INTO collectionHotbed(userFk) VALUES(vUserFk); -- Comprueba si hay colecciones disponibles que se ajustan a su configuracion - SELECT MIN(c.id) INTO vCollectionFk - FROM collection c - JOIN operator o ON (o.itemPackingTypeFk = c.itemPackingTypeFk - OR c.itemPackingTypeFk IS NULL) - AND o.numberOfWagons = c.wagons - AND o.trainFk = c.trainFk - AND o.warehouseFk = c.warehouseFk - AND c.workerFk IS NULL - WHERE o.workerFk = vUserFk; + + OPEN vCollections; + l: LOOP + SET vDone = FALSE; + FETCH vCollections INTO vCollectionFk; + + IF vDone THEN + LEAVE l; + END IF; + + BEGIN + DECLARE EXIT HANDLER FOR SQLEXCEPTION + BEGIN + ROLLBACK; + SET vCollectionFk = NULL; + RESIGNAL; + END; + + START TRANSACTION; + + SELECT workerFk INTO vCollectionWorker + FROM `collection` + WHERE id = vCollectionFk FOR UPDATE; + + IF vCollectionWorker IS NULL THEN + UPDATE `collection` + SET workerFk = vUserFk + WHERE id = vCollectionFk; + + COMMIT; + LEAVE l; + END IF; + + ROLLBACK; + END; + END LOOP; + CLOSE vCollections; IF vCollectionFk IS NULL THEN CALL collection_new(vUserFk, vCollectionFk); + + START TRANSACTION; + + SELECT workerFk INTO vCollectionWorker + FROM `collection` + WHERE id = vCollectionFk FOR UPDATE; + + IF vCollectionWorker IS NULL THEN + UPDATE `collection` + SET workerFk = vUserFk + WHERE id = vCollectionFk; + END IF; + + COMMIT; END IF; - - UPDATE collection - SET workerFk = vUserFk - WHERE id = vCollectionFk; - CALL itemShelvingSale_addByCollection(vCollectionFk); - - DO RELEASE_LOCK(vLockName); END$$ DELIMITER ; \ No newline at end of file diff --git a/db/routines/vn/procedures/collection_getTickets.sql b/db/routines/vn/procedures/collection_getTickets.sql index 6b7a794a9..fed7a3eb6 100644 --- a/db/routines/vn/procedures/collection_getTickets.sql +++ b/db/routines/vn/procedures/collection_getTickets.sql @@ -45,7 +45,7 @@ BEGIN LEFT JOIN observation ob ON ob.ticketFk = t.id WHERE t.id = vParamFk AND t.shipped >= vYesterday - UNION ALL + UNION SELECT t.id ticketFk, IF(NOT(vItemPackingTypeFk <=> 'V'), cc.code, CONCAT(SUBSTRING('ABCDEFGH', tc.wagon, 1), '-', tc.`level`)) `level`, am.name agencyName, @@ -66,7 +66,7 @@ BEGIN LEFT JOIN vn.worker w ON w.id = c.salesPersonFk LEFT JOIN observation ob ON ob.ticketFk = t.id WHERE tc.collectionFk = vParamFk - UNION ALL + UNION SELECT sg.ticketFk, NULL `level`, am.name agencyName, @@ -83,6 +83,7 @@ BEGIN LEFT JOIN observation ob ON ob.ticketFk = t.id LEFT JOIN vn.client c ON c.id = t.clientFk WHERE sc.id = vParamFk - AND t.shipped >= vYesterday; + AND t.shipped >= vYesterday + GROUP BY ticketFk; END$$ DELIMITER ; diff --git a/db/routines/vn/procedures/expeditionPallet_build.sql b/db/routines/vn/procedures/expeditionPallet_build.sql index 2df73bb85..a33439061 100644 --- a/db/routines/vn/procedures/expeditionPallet_build.sql +++ b/db/routines/vn/procedures/expeditionPallet_build.sql @@ -5,22 +5,26 @@ CREATE OR REPLACE DEFINER=`vn`@`localhost` PROCEDURE `vn`.`expeditionPallet_buil vWorkerFk INT, OUT vPalletFk INT ) -BEGIN -/** Construye un pallet de expediciones. +proc: BEGIN +/** + * Builds an expedition pallet. * - * Primero comprueba si esas expediciones ya pertenecen a otro pallet, - * en cuyo caso actualiza ese pallet. + * First, it checks if these expeditions already belong to another pallet, + * in which case it returns an error. * - * @param vExpeditions JSON_ARRAY con esta estructura [exp1, exp2, exp3, ...] - * @param vArcId INT Identificador de arcRead - * @param vWorkerFk INT Identificador de worker - * @param out vPalletFk Identificador de expeditionPallet + * @param vExpeditions JSON_ARRAY with this structure [exp1, exp2, exp3, ...] + * @param vArcId INT Identifier of arcRead + * @param vWorkerFk INT Identifier of worker + * @param out vPalletFk Identifier of expeditionPallet */ + DECLARE vCounter INT; DECLARE vExpeditionFk INT; DECLARE vTruckFk INT; DECLARE vPrinterFk INT; DECLARE vExpeditionStateTypeFk INT; + DECLARE vFreeExpeditionCount INT; + DECLARE vExpeditionWithPallet INT; CREATE OR REPLACE TEMPORARY TABLE tExpedition ( expeditionFk INT, @@ -44,48 +48,63 @@ BEGIN WHERE e.id = vExpeditionFk; END WHILE; - SELECT palletFk INTO vPalletFk - FROM ( - SELECT palletFk, count(*) n - FROM tExpedition - WHERE palletFk > 0 - GROUP BY palletFk - ORDER BY n DESC - LIMIT 100 - ) sub - LIMIT 1; + SELECT COUNT(expeditionFk) INTO vFreeExpeditionCount + FROM tExpedition + WHERE palletFk IS NULL; - IF vPalletFk IS NULL THEN - SELECT roadmapStopFk INTO vTruckFk - FROM ( - SELECT rm.roadmapStopFk, count(*) n - FROM routesMonitor rm - JOIN tExpedition e ON e.routeFk = rm.routeFk - GROUP BY roadmapStopFk - ORDER BY n DESC - LIMIT 1 - ) sub; + SELECT COUNT(expeditionFk) INTO vExpeditionWithPallet + FROM tExpedition + WHERE palletFk; - IF vTruckFk IS NULL THEN - CALL util.throw ('TRUCK_NOT_AVAILABLE'); - END IF; - - INSERT INTO expeditionPallet SET truckFk = vTruckFk; - - SET vPalletFk = LAST_INSERT_ID(); + IF vExpeditionWithPallet THEN + UPDATE arcRead + SET error = ( + SELECT GROUP_CONCAT(expeditionFk SEPARATOR ', ') + FROM tExpedition + WHERE palletFk + ) + WHERE id = vArcId; + LEAVE proc; END IF; + IF NOT vFreeExpeditionCount THEN + CALL util.throw ('NO_FREE_EXPEDITIONS'); + END IF; + + SELECT roadmapStopFk INTO vTruckFk + FROM ( + SELECT rm.roadmapStopFk, count(*) n + FROM routesMonitor rm + JOIN tExpedition e ON e.routeFk = rm.routeFk + WHERE e.palletFk IS NULL + GROUP BY roadmapStopFk + ORDER BY n DESC + LIMIT 1 + ) sub; + + IF vTruckFk IS NULL THEN + CALL util.throw ('TRUCK_NOT_AVAILABLE'); + END IF; + + INSERT INTO expeditionPallet SET truckFk = vTruckFk; + + SET vPalletFk = LAST_INSERT_ID(); + INSERT INTO expeditionScan(expeditionFk, palletFk, workerFk) SELECT expeditionFk, vPalletFk, vWorkerFk FROM tExpedition - ON DUPLICATE KEY UPDATE palletFk = vPalletFk, workerFk = vWorkerFk; + WHERE palletFk IS NULL; SELECT id INTO vExpeditionStateTypeFk FROM expeditionStateType WHERE code = 'PALLETIZED'; - + INSERT INTO expeditionState(expeditionFk, typeFk) - SELECT expeditionFk, vExpeditionStateTypeFk FROM tExpedition; + SELECT expeditionFk, vExpeditionStateTypeFk + FROM tExpedition + WHERE palletFk IS NULL; + + UPDATE arcRead SET error = NULL WHERE id = vArcId; SELECT printerFk INTO vPrinterFk FROM arcRead WHERE id = vArcId; diff --git a/db/routines/vn/procedures/itemShelvingSale_deleteAdded.sql b/db/routines/vn/procedures/itemShelvingSale_deleteAdded.sql new file mode 100644 index 000000000..9b15e82d1 --- /dev/null +++ b/db/routines/vn/procedures/itemShelvingSale_deleteAdded.sql @@ -0,0 +1,49 @@ +DELIMITER $$ +CREATE OR REPLACE DEFINER=`vn`@`localhost` PROCEDURE `vn`.`itemShelvingSale_deleteAdded`( + vSelf INT(11) +) +proc: BEGIN +/** + * Borra una reservea devolviendo la cantidad al itemShelving + * + * @param vSelf Identificador del itemShelvingSale + */ + DECLARE vSaleFk INT; + DECLARE vHasSalesPicked BOOL; + + DECLARE EXIT HANDLER FOR SQLEXCEPTION + BEGIN + ROLLBACK; + RESIGNAL; + END; + + START TRANSACTION; + + SELECT iss.saleFk INTO vSaleFk + FROM itemShelvingSale iss + JOIN sale s ON s.id = iss.saleFk + WHERE iss.id = vSelf AND s.isAdded + FOR UPDATE; + + IF vSaleFk IS NULL THEN + CALL util.throw('The sale can not be deleted'); + END IF; + + SELECT COUNT(*) INTO vHasSalesPicked + FROM itemShelvingSale + WHERE saleFk = vSaleFk AND isPicked; + + IF vHasSalesPicked THEN + CALL util.throw('A sale with picked sales cannot be deleted'); + END IF; + + UPDATE itemShelvingSale iss + JOIN itemShelving ish ON ish.id = iss.itemShelvingFk + SET ish.available = ish.available + iss.quantity + WHERE iss.saleFk = vSaleFk; + + DELETE FROM sale WHERE id = vSaleFk; + + COMMIT; +END$$ +DELIMITER ; \ No newline at end of file diff --git a/db/routines/vn/procedures/item_getSimilar.sql b/db/routines/vn/procedures/item_getSimilar.sql index 243aacc2f..537f53848 100644 --- a/db/routines/vn/procedures/item_getSimilar.sql +++ b/db/routines/vn/procedures/item_getSimilar.sql @@ -8,17 +8,18 @@ CREATE OR REPLACE DEFINER=`vn`@`localhost` PROCEDURE `vn`.`item_getSimilar`( ) BEGIN /** -* Propone articulos ordenados, con la cantidad -* de veces usado y segun sus caracteristicas. -* -* @param vSelf Id de artículo -* @param vWarehouseFk Id de almacen -* @param vDated Fecha -* @param vShowType Mostrar tipos -* @param vDaysInForward Días de alcance para las ventas -*/ + * Propone articulos ordenados, con la cantidad + * de veces usado y segun sus caracteristicas. + * + * @param vSelf Id de artículo + * @param vWarehouseFk Id de almacen + * @param vDated Fecha + * @param vShowType Mostrar tipos + * @param vDaysInForward Días de alcance para las ventas (https://redmine.verdnatura.es/issues/7956#note-4) + */ DECLARE vAvailableCalcFk INT; DECLARE vVisibleCalcFk INT; + DECLARE vTypeFk INT; DECLARE vPriority INT DEFAULT 1; CALL cache.available_refresh(vAvailableCalcFk, FALSE, vWarehouseFk, vDated); @@ -42,19 +43,9 @@ BEGIN AND it.priority = vPriority LEFT JOIN vn.tag t ON t.id = it.tagFk WHERE i.id = vSelf - ), - sold AS ( - SELECT SUM(s.quantity) quantity, s.itemFk - FROM vn.sale s - JOIN vn.ticket t ON t.id = s.ticketFk - LEFT JOIN vn.itemShelvingSale iss ON iss.saleFk = s.id - WHERE t.shipped >= CURDATE() + INTERVAL vDaysInForward DAY - AND iss.saleFk IS NULL - AND t.warehouseFk = vWarehouseFk - GROUP BY s.itemFk ) SELECT i.id itemFk, - LEAST(CAST(sd.quantity AS INT), v.visible) advanceable, + NULL advanceable, -- https://redmine.verdnatura.es/issues/7956#note-4 i.longName, i.subName, i.tag5, @@ -79,7 +70,6 @@ BEGIN v.visible located, b.price2 FROM vn.item i - LEFT JOIN sold sd ON sd.itemFk = i.id JOIN cache.available a ON a.item_id = i.id AND a.calc_id = vAvailableCalcFk LEFT JOIN cache.visible v ON v.item_id = i.id @@ -93,21 +83,20 @@ BEGIN LEFT JOIN vn.tag t ON t.id = it.tagFk LEFT JOIN vn.buy b ON b.id = lb.buy_id JOIN itemTags its - WHERE (a.available > 0 OR sd.quantity < v.visible) + WHERE a.available > 0 AND (i.typeFk = its.typeFk OR NOT vShowType) AND i.id <> vSelf - ORDER BY (a.available > 0) DESC, - `counter` DESC, - (t.name = its.name) DESC, - (it.value = its.value) DESC, - (i.tag5 = its.tag5) DESC, - match5 DESC, - (i.tag6 = its.tag6) DESC, - match6 DESC, - (i.tag7 = its.tag7) DESC, - match7 DESC, - (i.tag8 = its.tag8) DESC, - match8 DESC + ORDER BY `counter` DESC, + (t.name = its.name) DESC, + (it.value = its.value) DESC, + (i.tag5 = its.tag5) DESC, + match5 DESC, + (i.tag6 = its.tag6) DESC, + match6 DESC, + (i.tag7 = its.tag7) DESC, + match7 DESC, + (i.tag8 = its.tag8) DESC, + match8 DESC LIMIT 100; END$$ DELIMITER ; diff --git a/db/routines/vn/procedures/queueMember_updateQueue.sql b/db/routines/vn/procedures/queueMember_updateQueue.sql new file mode 100644 index 000000000..5af44da4f --- /dev/null +++ b/db/routines/vn/procedures/queueMember_updateQueue.sql @@ -0,0 +1,29 @@ +DELIMITER $$ + +CREATE OR REPLACE DEFINER=`vn`@`localhost` PROCEDURE `vn`.`queueMember_updateQueue`( + vBusinessFk INT +) +BEGIN + /** + * Elimina la entrada de la cola anterior y luego inserta la nueva para un trabajador. + * + * @param vBusinessFk ID del negocio + */ + DECLARE vNewQueue VARCHAR(10); + DECLARE vExtension VARCHAR(10); + DECLARE exit handler FOR SQLEXCEPTION + + SELECT d.pbxQueue, s.extension + INTO vNewQueue, vExtension + FROM business b + JOIN department d ON d.id = b.departmentFk + JOIN pbx.sip s ON s.user_id = b.workerFk + WHERE b.id = vBusinessFk; + + DELETE FROM pbx.queueMember + WHERE extension = vExtension COLLATE utf8_general_ci; + + INSERT IGNORE INTO pbx.queueMember (queue, extension) + VALUES (vNewQueue, vExtension); +END$$ +DELIMITER ; \ No newline at end of file diff --git a/db/routines/vn/procedures/saleTracking_sectorCollectionAddPrevOK.sql b/db/routines/vn/procedures/saleTracking_sectorCollectionAddPrevOK.sql new file mode 100644 index 000000000..003168ec8 --- /dev/null +++ b/db/routines/vn/procedures/saleTracking_sectorCollectionAddPrevOK.sql @@ -0,0 +1,20 @@ +DELIMITER $$ +CREATE OR REPLACE DEFINER=`vn`@`localhost` PROCEDURE `vn`.`saleTracking_sectorCollectionAddPrevOK`( + vSectorCollectionFk INT +) +BEGIN +/** + * Inserta los registros de sectorCollection con el estado PREVIA OK si la reserva está picked + * + * @param vSectorCollectionFk Identificador de vn.sectorCollection + */ + REPLACE saleTracking(saleFk, isChecked, workerFk, stateFk) + SELECT sgd.saleFk, TRUE, sc.userFk, s.id + FROM sectorCollection sc + JOIN sectorCollectionSaleGroup scsg ON scsg.sectorCollectionFk = sc.id + JOIN saleGroupDetail sgd ON sgd.saleGroupFk = scsg.saleGroupFk + JOIN state s ON s.code = 'OK PREVIOUS' + JOIN itemShelvingSale iss ON iss.saleFk = sgd.saleFk + WHERE sc.id = vSectorCollectionFk AND iss.isPicked; +END$$ +DELIMITER ; diff --git a/db/routines/vn/procedures/sale_getProblems.sql b/db/routines/vn/procedures/sale_getProblems.sql index 2bba8fbc3..b50b4784d 100644 --- a/db/routines/vn/procedures/sale_getProblems.sql +++ b/db/routines/vn/procedures/sale_getProblems.sql @@ -40,7 +40,7 @@ BEGIN isTooLittle BOOL DEFAULT FALSE, isVip BOOL DEFAULT FALSE, PRIMARY KEY (ticketFk, saleFk) - ) ENGINE = MEMORY; + ); -- No memory INSERT INTO tmp.sale_problems(ticketFk, saleFk, diff --git a/db/routines/vn/procedures/ticket_getTax.sql b/db/routines/vn/procedures/ticket_getTax.sql index 947c45806..cb9dc09d9 100644 --- a/db/routines/vn/procedures/ticket_getTax.sql +++ b/db/routines/vn/procedures/ticket_getTax.sql @@ -1,5 +1,7 @@ DELIMITER $$ -CREATE OR REPLACE DEFINER=`vn`@`localhost` PROCEDURE `vn`.`ticket_getTax`(IN vTaxArea VARCHAR(25)) +CREATE OR REPLACE DEFINER=`vn`@`localhost` PROCEDURE `vn`.`ticket_getTax`( + vTaxArea VARCHAR(25) +) BEGIN /** * Calcula la base imponible, el IVA y el recargo de equivalencia para @@ -33,30 +35,39 @@ BEGIN CREATE OR REPLACE TEMPORARY TABLE tmp.ticketTax (PRIMARY KEY (ticketFk, code, rate)) ENGINE = MEMORY - SELECT * FROM ( - SELECT tmpTicket.ticketFk, - bp.pgcFk, - SUM(s.quantity * s.price * (100 - s.discount) / 100 ) taxableBase, - pgc.rate, - tc.code, - bp.priority - FROM tmp.ticket tmpTicket - JOIN sale s ON s.ticketFk = tmpTicket.ticketFk - JOIN item i ON i.id = s.itemFk - JOIN ticket t ON t.id = tmpTicket.ticketFk - JOIN supplier su ON su.id = t.companyFk + WITH sales AS ( + SELECT s.ticketFk, + s.itemFk, + s.quantity * s.price * (100 - s.discount) / 100 total, + t.companyFk, + t.addressFk, + su.countryFk, + ata.areaFk, + itc.taxClassFk + FROM vn.sale s + JOIN tmp.ticket tmp ON tmp.ticketFk = s.ticketFk + JOIN vn.ticket t ON t.id = s.ticketFk + JOIN vn.supplier su ON su.id = t.companyFk JOIN tmp.addressTaxArea ata ON ata.addressFk = t.addressFk AND ata.companyFk = t.companyFk - JOIN itemTaxCountry itc ON itc.itemFk = i.id + JOIN vn.itemTaxCountry itc ON itc.itemFk = s.itemFk AND itc.countryFk = su.countryFk - JOIN bookingPlanner bp ON bp.countryFk = su.countryFk - AND bp.taxAreaFk = ata.areaFk - AND bp.taxClassFk = itc.taxClassFk - JOIN pgc ON pgc.code = bp.pgcFk - JOIN taxClass tc ON tc.id = bp.taxClassFk - GROUP BY tmpTicket.ticketFk, pgc.code, pgc.rate - HAVING taxableBase - ) t3 + HAVING total + ) + SELECT s.ticketFk, + bp.pgcFk, + SUM(s.total) taxableBase, + pgc.rate, + tc.code, + bp.priority + FROM sales s + JOIN vn.bookingPlanner bp ON bp.countryFk = s.countryFk + AND bp.taxAreaFk = s.areaFk + AND bp.taxClassFk = s.taxClassFk + JOIN vn.pgc ON pgc.code = bp.pgcFk + JOIN vn.taxClass tc ON tc.id = bp.taxClassFk + GROUP BY s.ticketFk, pgc.code, pgc.rate + HAVING taxableBase ORDER BY priority; CREATE OR REPLACE TEMPORARY TABLE tmp.ticketServiceTax diff --git a/db/routines/vn/procedures/worker_updateBusiness.sql b/db/routines/vn/procedures/worker_updateBusiness.sql index a160c417a..43edb0416 100644 --- a/db/routines/vn/procedures/worker_updateBusiness.sql +++ b/db/routines/vn/procedures/worker_updateBusiness.sql @@ -21,6 +21,8 @@ BEGIN SET businessFk = vNewBusinessFk WHERE id = vSelf; + CALL queueMember_updateQueue(vNewBusinessFk); + IF vOldBusinessFk IS NULL THEN CALL account.account_enable(vSelf); diff --git a/db/routines/vn/triggers/business_afterUpdate.sql b/db/routines/vn/triggers/business_afterUpdate.sql index 888308b9a..11aeb88b6 100644 --- a/db/routines/vn/triggers/business_afterUpdate.sql +++ b/db/routines/vn/triggers/business_afterUpdate.sql @@ -3,10 +3,20 @@ CREATE OR REPLACE DEFINER=`vn`@`localhost` TRIGGER `vn`.`business_afterUpdate` AFTER UPDATE ON `business` FOR EACH ROW BEGIN + DECLARE vIsActive BOOL; + DECLARE vExtension VARCHAR(10); + CALL worker_updateBusiness(NEW.workerFk); IF NOT (OLD.workerFk <=> NEW.workerFk) THEN CALL worker_updateBusiness(OLD.workerFk); END IF; + + IF NOT (OLD.departmentFk <=> NEW.departmentFk) THEN + SELECT COUNT(*) INTO vIsActive FROM worker WHERE businessFk = NEW.id; + IF vIsActive THEN + CALL queueMember_updateQueue(NEW.id); + END IF; + END IF; END$$ DELIMITER ; diff --git a/db/routines/vn/triggers/itemShelvingSale_afterInsert.sql b/db/routines/vn/triggers/itemShelvingSale_afterInsert.sql index 3531b094c..ad4a6f670 100644 --- a/db/routines/vn/triggers/itemShelvingSale_afterInsert.sql +++ b/db/routines/vn/triggers/itemShelvingSale_afterInsert.sql @@ -3,10 +3,10 @@ CREATE OR REPLACE DEFINER=`vn`@`localhost` TRIGGER `vn`.`itemShelvingSale_afterI AFTER INSERT ON `itemShelvingSale` FOR EACH ROW BEGIN - UPDATE sale s JOIN operator o ON o.workerFk = account.myUser_getId() - SET s.isPicked = IF(o.isOnReservationMode, s.isPicked, TRUE) - WHERE id = NEW.saleFk; + JOIN sector se ON se.id = o.sectorFk + SET s.isPicked = IF(IFNULL(se.isOnReservationMode, o.isOnReservationMode), s.isPicked, TRUE) + WHERE s.id = NEW.saleFk; END$$ DELIMITER ; \ No newline at end of file diff --git a/db/routines/vn/triggers/itemShelving_beforeUpdate.sql b/db/routines/vn/triggers/itemShelving_beforeUpdate.sql index fabdf8efb..53f85de01 100644 --- a/db/routines/vn/triggers/itemShelving_beforeUpdate.sql +++ b/db/routines/vn/triggers/itemShelving_beforeUpdate.sql @@ -9,5 +9,8 @@ BEGIN SET NEW.userFk = account.myUser_getId(); END IF; + IF NEW.shelvingFk <> OLD.shelvingFk THEN + SET NEW.movingState = NULL; + END IF; END$$ DELIMITER ; diff --git a/db/routines/vn2008/views/Clientes.sql b/db/routines/vn2008/views/Clientes.sql index 153d875bc..9f8ef712e 100644 --- a/db/routines/vn2008/views/Clientes.sql +++ b/db/routines/vn2008/views/Clientes.sql @@ -22,7 +22,6 @@ AS SELECT `c`.`id` AS `id_cliente`, `c`.`credit` AS `credito`, `c`.`countryFk` AS `Id_Pais`, `c`.`isActive` AS `activo`, - `c`.`gestdocFk` AS `gestdoc_id`, `c`.`quality` AS `calidad`, `c`.`payMethodFk` AS `pay_met_id`, `c`.`created` AS `created`, diff --git a/db/versions/11230-brownEucalyptus/00-addClientObservationType.sql b/db/versions/11230-brownEucalyptus/00-addClientObservationType.sql new file mode 100644 index 000000000..f69e20611 --- /dev/null +++ b/db/versions/11230-brownEucalyptus/00-addClientObservationType.sql @@ -0,0 +1,3 @@ +ALTER TABLE vn.clientObservation DROP COLUMN IF EXISTS observationTypeFk; +ALTER TABLE vn.clientObservation ADD COLUMN IF NOT EXISTS observationTypeFk TINYINT(3) UNSIGNED NULL; +ALTER TABLE vn.clientObservation ADD CONSTRAINT clientObservationTypeFk FOREIGN KEY IF NOT EXISTS (observationTypeFk) REFERENCES vn.observationType(id); diff --git a/db/versions/11230-brownEucalyptus/01-addNewObservation.vn.sql b/db/versions/11230-brownEucalyptus/01-addNewObservation.vn.sql new file mode 100644 index 000000000..983419111 --- /dev/null +++ b/db/versions/11230-brownEucalyptus/01-addNewObservation.vn.sql @@ -0,0 +1,3 @@ +INSERT IGNORE INTO vn.observationType + SET description = 'Finance', + code = 'finance'; \ No newline at end of file diff --git a/db/versions/11242-whiteAnthurium/00-firstScript.sql b/db/versions/11242-whiteAnthurium/00-firstScript.sql new file mode 100644 index 000000000..43dccf374 --- /dev/null +++ b/db/versions/11242-whiteAnthurium/00-firstScript.sql @@ -0,0 +1,3 @@ +DELETE FROM salix.ACL + WHERE model = 'WorkerLog' + AND property = '*'; \ No newline at end of file diff --git a/db/versions/11251-navyChrysanthemum/00-firstScript.sql b/db/versions/11251-navyChrysanthemum/00-firstScript.sql new file mode 100644 index 000000000..801405e59 --- /dev/null +++ b/db/versions/11251-navyChrysanthemum/00-firstScript.sql @@ -0,0 +1,3 @@ +UPDATE vn.sale + SET originalQuantity = quantity + WHERE originalQuantity IS NULL diff --git a/db/versions/11251-navyChrysanthemum/01-firstScript.sql b/db/versions/11251-navyChrysanthemum/01-firstScript.sql new file mode 100644 index 000000000..e3e08e0aa --- /dev/null +++ b/db/versions/11251-navyChrysanthemum/01-firstScript.sql @@ -0,0 +1 @@ +ALTER TABLE vn.sale MODIFY COLUMN originalQuantity decimal(10,2) DEFAULT 0.00 NOT NULL COMMENT 'Se utiliza para notificar a través de rocket los cambios de quantity'; \ No newline at end of file diff --git a/db/versions/11283-redAspidistra/00-firstScript.sql b/db/versions/11283-redAspidistra/00-firstScript.sql new file mode 100644 index 000000000..a88091297 --- /dev/null +++ b/db/versions/11283-redAspidistra/00-firstScript.sql @@ -0,0 +1,3 @@ +ALTER TABLE vn.itemShelving DROP FOREIGN KEY itemShelving_fk2; +ALTER TABLE vn.itemShelving ADD CONSTRAINT itemShelving_fk2 + FOREIGN KEY (shelvingFk) REFERENCES vn.shelving(code) ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/db/versions/11284-turquoiseLaurel/00-firstScript.sql b/db/versions/11284-turquoiseLaurel/00-firstScript.sql new file mode 100644 index 000000000..34762faf6 --- /dev/null +++ b/db/versions/11284-turquoiseLaurel/00-firstScript.sql @@ -0,0 +1,2 @@ +-- Place your SQL code here +ALTER TABLE vn.itemShelving ADD IF NOT EXISTS isMoving BOOL DEFAULT FALSE NOT NULL COMMENT 'Indica que se ha marcado este registro para transferirlo a otro sector'; diff --git a/db/versions/11285-orangeErica/00-firstScript.sql b/db/versions/11285-orangeErica/00-firstScript.sql new file mode 100644 index 000000000..c13571f3a --- /dev/null +++ b/db/versions/11285-orangeErica/00-firstScript.sql @@ -0,0 +1,3 @@ +-- Place your SQL code here +ALTER TABLE vn.itemShelving DROP COLUMN IF EXISTS isMoving; +ALTER TABLE vn.itemShelving ADD IF NOT EXISTS movingState ENUM('selected','printed') NULL; diff --git a/db/versions/11287-azureRaphis/00-firstScript.sql b/db/versions/11287-azureRaphis/00-firstScript.sql new file mode 100644 index 000000000..77d60eb40 --- /dev/null +++ b/db/versions/11287-azureRaphis/00-firstScript.sql @@ -0,0 +1,3 @@ +-- Place your SQL code here +ALTER TABLE hedera.`order` ADD IF NOT EXISTS rowUpdated DATETIME NULL + COMMENT 'Timestamp for last updated record in orderRow table'; \ No newline at end of file diff --git a/db/versions/11288-purpleFern/00-firstScript.sql b/db/versions/11288-purpleFern/00-firstScript.sql new file mode 100644 index 000000000..77d60eb40 --- /dev/null +++ b/db/versions/11288-purpleFern/00-firstScript.sql @@ -0,0 +1,3 @@ +-- Place your SQL code here +ALTER TABLE hedera.`order` ADD IF NOT EXISTS rowUpdated DATETIME NULL + COMMENT 'Timestamp for last updated record in orderRow table'; \ No newline at end of file diff --git a/db/versions/11289-azureAralia/00-firstScript.sql b/db/versions/11289-azureAralia/00-firstScript.sql new file mode 100644 index 000000000..ab091f53f --- /dev/null +++ b/db/versions/11289-azureAralia/00-firstScript.sql @@ -0,0 +1,2 @@ + +ALTER TABLE vn.sector ADD isOnReservationMode tinyint(1) DEFAULT FALSE NULL; diff --git a/db/versions/11290-blackOrchid/00-firstScript.sql b/db/versions/11290-blackOrchid/00-firstScript.sql new file mode 100644 index 000000000..fe568ed6e --- /dev/null +++ b/db/versions/11290-blackOrchid/00-firstScript.sql @@ -0,0 +1,6 @@ +ALTER TABLE `vn`.`operator` +ADD COLUMN `machineFk` int(11) DEFAULT NULL, +ADD CONSTRAINT `operator_machine_FK` FOREIGN KEY (`machineFk`) REFERENCES `vn`.`machine` (`id`) ON DELETE SET NULL ON UPDATE CASCADE; + +INSERT INTO salix.ACL (model,property,accessType,permission,principalType,principalId) + VALUES ('Machine','*','*','ALLOW','ROLE','productionBoss'); diff --git a/db/versions/11291-purpleChico/00-firstScript.sql b/db/versions/11291-purpleChico/00-firstScript.sql new file mode 100644 index 000000000..e60b90376 --- /dev/null +++ b/db/versions/11291-purpleChico/00-firstScript.sql @@ -0,0 +1,4 @@ +ALTER TABLE vn.docuwareConfig ADD IF NOT EXISTS username varchar(100) NULL; +ALTER TABLE vn.docuwareConfig ADD IF NOT EXISTS password varchar(100) NULL; +ALTER TABLE vn.docuwareConfig ADD IF NOT EXISTS token text NULL; +ALTER TABLE vn.docuwareConfig ADD IF NOT EXISTS expired int(11) NULL; diff --git a/db/versions/11294-azureFern/00-firstScript.sql b/db/versions/11294-azureFern/00-firstScript.sql new file mode 100644 index 000000000..2d6ed3a5b --- /dev/null +++ b/db/versions/11294-azureFern/00-firstScript.sql @@ -0,0 +1,3 @@ +-- Place your SQL code here +ALTER TABLE vn.itemShelving DROP COLUMN IF EXISTS isMoving; +ALTER TABLE vn.itemShelving ADD IF NOT EXISTS movingState ENUM('selected','printed') NULL; \ No newline at end of file diff --git a/db/versions/11295-brownLaurel/00-firstScript.sql b/db/versions/11295-brownLaurel/00-firstScript.sql new file mode 100644 index 000000000..2d6ed3a5b --- /dev/null +++ b/db/versions/11295-brownLaurel/00-firstScript.sql @@ -0,0 +1,3 @@ +-- Place your SQL code here +ALTER TABLE vn.itemShelving DROP COLUMN IF EXISTS isMoving; +ALTER TABLE vn.itemShelving ADD IF NOT EXISTS movingState ENUM('selected','printed') NULL; \ No newline at end of file diff --git a/db/versions/11298-wheatIvy/00-closure.sql b/db/versions/11298-wheatIvy/00-closure.sql new file mode 100644 index 000000000..7b33939cf --- /dev/null +++ b/db/versions/11298-wheatIvy/00-closure.sql @@ -0,0 +1,3 @@ +ALTER TABLE `vn`.`ticketConfig` +ADD COLUMN `closureDaysAgo` int(11) NOT NULL DEFAULT 2 COMMENT 'Number of days to look back for ticket closure', +ADD CONSTRAINT `closureDaysAgo_check` CHECK (`closureDaysAgo` > 0); diff --git a/db/versions/11311-tealFern/00-firstScript.sql b/db/versions/11311-tealFern/00-firstScript.sql new file mode 100644 index 000000000..909747f3c --- /dev/null +++ b/db/versions/11311-tealFern/00-firstScript.sql @@ -0,0 +1 @@ +ALTER TABLE vn.client CHANGE gestdocFk gestdocFk__ int(11) DEFAULT NULL NULL COMMENT '@deprecated 2024-10-17'; \ No newline at end of file diff --git a/e2e/paths/02-client/08_add_notes.spec.js b/e2e/paths/02-client/08_add_notes.spec.js deleted file mode 100644 index d0c483a11..000000000 --- a/e2e/paths/02-client/08_add_notes.spec.js +++ /dev/null @@ -1,42 +0,0 @@ -import selectors from '../../helpers/selectors'; -import getBrowser from '../../helpers/puppeteer'; - -describe('Client Add notes path', () => { - let browser; - let page; - beforeAll(async() => { - browser = await getBrowser(); - page = browser.page; - await page.loginAndModule('employee', 'client'); - await page.accessToSearchResult('Bruce Banner'); - await page.accessToSection('client.card.note.index'); - }); - - afterAll(async() => { - await browser.close(); - }); - - it(`should reach the notes index`, async() => { - await page.waitForState('client.card.note.index'); - }); - - it(`should click on the add note button`, async() => { - await page.waitToClick(selectors.clientNotes.addNoteFloatButton); - await page.waitForState('client.card.note.create'); - }); - - it(`should create a note`, async() => { - await page.waitForSelector(selectors.clientNotes.note); - await page.type(`${selectors.clientNotes.note} textarea`, 'Meeting with Black Widow 21st 9am'); - await page.waitToClick(selectors.clientNotes.saveButton); - const message = await page.waitForSnackbar(); - - expect(message.text).toContain('Data saved!'); - }); - - it('should confirm the note was created', async() => { - const result = await page.waitToGetProperty(selectors.clientNotes.firstNoteText, 'innerText'); - - expect(result).toEqual('Meeting with Black Widow 21st 9am'); - }); -}); diff --git a/e2e/paths/02-client/21_defaulter.spec.js b/e2e/paths/02-client/21_defaulter.spec.js index 2bb3d6254..01f394bc8 100644 --- a/e2e/paths/02-client/21_defaulter.spec.js +++ b/e2e/paths/02-client/21_defaulter.spec.js @@ -28,12 +28,12 @@ describe('Client defaulter path', () => { const salesPersonName = await page.waitToGetProperty(selectors.clientDefaulter.firstSalesPersonName, 'innerText'); - expect(clientName).toEqual('Bruce Banner'); - expect(salesPersonName).toEqual('developer'); + expect(clientName).toEqual('Ororo Munroe'); + expect(salesPersonName).toEqual('salesperson'); }); it('should first observation not changed', async() => { - const expectedObservation = 'Meeting with Black Widow 21st 9am'; + const expectedObservation = 'Madness, as you know, is like gravity, all it takes is a little push'; const result = await page.waitToGetProperty(selectors.clientDefaulter.firstObservation, 'value'); expect(result).toContain(expectedObservation); @@ -62,13 +62,4 @@ describe('Client defaulter path', () => { await page.write(selectors.clientDefaulter.observation, 'My new observation'); await page.waitToClick(selectors.clientDefaulter.saveButton); }); - - it('should first observation changed', async() => { - const message = await page.waitForSnackbar(); - await page.waitForSelector(selectors.clientDefaulter.firstObservation); - const result = await page.waitToGetProperty(selectors.clientDefaulter.firstObservation, 'value'); - - expect(message.text).toContain('Observation saved!'); - expect(result).toContain('My new observation'); - }); }); diff --git a/e2e/paths/07-order/01_summary.spec.js b/e2e/paths/07-order/01_summary.spec.js deleted file mode 100644 index 9df481ef6..000000000 --- a/e2e/paths/07-order/01_summary.spec.js +++ /dev/null @@ -1,46 +0,0 @@ -import getBrowser from '../../helpers/puppeteer'; - -const $ = { - id: 'vn-order-summary vn-one:nth-child(1) > vn-label-value:nth-child(1) span', - alias: 'vn-order-summary vn-one:nth-child(1) > vn-label-value:nth-child(2) span', - consignee: 'vn-order-summary vn-one:nth-child(2) > vn-label-value:nth-child(6) span', - subtotal: 'vn-order-summary vn-one.taxes > p:nth-child(1)', - vat: 'vn-order-summary vn-one.taxes > p:nth-child(2)', - total: 'vn-order-summary vn-one.taxes > p:nth-child(3)', - sale: 'vn-order-summary vn-tbody > vn-tr', -}; - -describe('Order summary path', () => { - let browser; - let page; - beforeAll(async() => { - browser = await getBrowser(); - page = browser.page; - await page.loginAndModule('employee', 'order'); - await page.accessToSearchResult('16'); - }); - - afterAll(async() => { - await browser.close(); - }); - - it('should reach the order summary section and check data', async() => { - await page.waitForState('order.card.summary'); - - const id = await page.innerText($.id); - const alias = await page.innerText($.alias); - const consignee = await page.innerText($.consignee); - const subtotal = await page.innerText($.subtotal); - const vat = await page.innerText($.vat); - const total = await page.innerText($.total); - const sale = await page.countElement($.sale); - - expect(id).toEqual('16'); - expect(alias).toEqual('Many places'); - expect(consignee).toEqual('address 26 - Gotham (Province one)'); - expect(subtotal.length).toBeGreaterThan(1); - expect(vat.length).toBeGreaterThan(1); - expect(total.length).toBeGreaterThan(1); - expect(sale).toBeGreaterThan(0); - }); -}); diff --git a/e2e/paths/07-order/02_basic_data.spec.js b/e2e/paths/07-order/02_basic_data.spec.js deleted file mode 100644 index b2c21b071..000000000 --- a/e2e/paths/07-order/02_basic_data.spec.js +++ /dev/null @@ -1,69 +0,0 @@ -import selectors from '../../helpers/selectors.js'; -import getBrowser from '../../helpers/puppeteer'; - -const $ = { - form: 'vn-order-basic-data form', - observation: 'vn-order-basic-data form [vn-name="note"]', - saveButton: `vn-order-basic-data form button[type=submit]`, - acceptButton: '.vn-confirm.shown button[response="accept"]' -}; - -describe('Order edit basic data path', () => { - let browser; - let page; - - beforeAll(async() => { - browser = await getBrowser(); - page = browser.page; - - await page.loginAndModule('employee', 'order'); - await page.accessToSearchResult('1'); - await page.accessToSection('order.card.basicData'); - }); - - afterAll(async() => { - await browser.close(); - }); - - describe('when confirmed order', () => { - it('should not be able to change the client', async() => { - const message = await page.sendForm($.form, { - client: 'Tony Stark', - address: 'Tony Stark', - }); - - expect(message.text).toContain(`You can't make changes on the basic data`); - }); - }); - - describe('when new order', () => { - it('should create an order and edit its basic data', async() => { - await page.waitToClick(selectors.globalItems.returnToModuleIndexButton); - await page.waitToClick($.acceptButton); - await page.waitForContentLoaded(); - await page.waitToClick(selectors.ordersIndex.createOrderButton); - await page.waitForState('order.create'); - - await page.autocompleteSearch(selectors.createOrderView.client, 'Jessica Jones'); - await page.pickDate(selectors.createOrderView.landedDatePicker); - await page.autocompleteSearch(selectors.createOrderView.agency, 'Other agency'); - await page.waitToClick(selectors.createOrderView.createButton); - await page.waitForState('order.card.catalog'); - - await page.accessToSection('order.card.basicData'); - - const values = { - client: 'Tony Stark', - address: 'Tony Stark', - agencyMode: 'Other agency' - }; - - const message = await page.sendForm($.form, values); - await page.reloadSection('order.card.basicData'); - const formValues = await page.fetchForm($.form, Object.keys(values)); - - expect(message.isSuccess).toBeTrue(); - expect(formValues).toEqual(values); - }); - }); -}); diff --git a/e2e/paths/07-order/03_lines.spec.js b/e2e/paths/07-order/03_lines.spec.js deleted file mode 100644 index 718ea5ce5..000000000 --- a/e2e/paths/07-order/03_lines.spec.js +++ /dev/null @@ -1,48 +0,0 @@ -import selectors from '../../helpers/selectors.js'; -import getBrowser from '../../helpers/puppeteer'; - -describe('Order lines', () => { - let browser; - let page; - beforeAll(async() => { - browser = await getBrowser(); - page = browser.page; - await page.loginAndModule('employee', 'order'); - await page.accessToSearchResult('8'); - await page.accessToSection('order.card.line'); - }); - - afterAll(async() => { - await browser.close(); - }); - - it('should check the order subtotal', async() => { - const result = await page - .waitToGetProperty(selectors.orderLine.orderSubtotal, 'innerText'); - - expect(result).toContain('112.30'); - }); - - it('should delete the first line in the order', async() => { - await page.waitToClick(selectors.orderLine.firstLineDeleteButton); - await page.waitToClick(selectors.orderLine.confirmButton); - const message = await page.waitForSnackbar(); - - expect(message.text).toContain('Data saved!'); - }); - - it('should confirm the order subtotal has changed', async() => { - await page.waitForTextInElement(selectors.orderLine.orderSubtotal, '92.80'); - const result = await page - .waitToGetProperty(selectors.orderLine.orderSubtotal, 'innerText'); - - expect(result).toContain('92.80'); - }); - - it('should confirm the whole order and redirect to ticket index filtered by clientFk', async() => { - await page.waitToClick(selectors.orderLine.confirmOrder); - - await page.expectURL('ticket/index'); - await page.expectURL('clientFk'); - }); -}); diff --git a/e2e/paths/07-order/04_catalog.spec.js b/e2e/paths/07-order/04_catalog.spec.js deleted file mode 100644 index b8a20e938..000000000 --- a/e2e/paths/07-order/04_catalog.spec.js +++ /dev/null @@ -1,97 +0,0 @@ -import selectors from '../../helpers/selectors.js'; -import getBrowser from '../../helpers/puppeteer'; - -describe('Order catalog', () => { - let browser; - let page; - - beforeAll(async() => { - browser = await getBrowser(); - page = browser.page; - await page.loginAndModule('employee', 'order'); - }); - - afterAll(async() => { - await browser.close(); - }); - - it('should open the create new order form', async() => { - await page.waitToClick(selectors.ordersIndex.createOrderButton); - await page.waitForState('order.create'); - }); - - it('should create a new order', async() => { - await page.autocompleteSearch(selectors.createOrderView.client, 'Tony Stark'); - await page.pickDate(selectors.createOrderView.landedDatePicker); - await page.autocompleteSearch(selectors.createOrderView.agency, 'Other agency'); - await page.waitToClick(selectors.createOrderView.createButton); - await page.waitForState('order.card.catalog'); - }); - - it('should add the realm and type filters and obtain results', async() => { - await page.waitToClick(selectors.orderCatalog.plantRealmButton); - await page.autocompleteSearch(selectors.orderCatalog.type, 'Anthurium'); - await page.waitForNumberOfElements('section.product', 4); - const result = await page.countElement('section.product'); - - expect(result).toEqual(4); - }); - - it('should perfom an "OR" search for the item tag colors silver and brown', async() => { - await page.waitToClick(selectors.orderCatalog.openTagSearch); - await page.autocompleteSearch(selectors.orderCatalog.tag, 'Color'); - await page.autocompleteSearch(selectors.orderCatalog.firstTagAutocomplete, 'silver'); - await page.waitToClick(selectors.orderCatalog.addTagButton); - await page.autocompleteSearch(selectors.orderCatalog.secondTagAutocomplete, 'brown'); - await page.waitToClick(selectors.orderCatalog.searchTagButton); - await page.waitForNumberOfElements('section.product', 4); - }); - - it('should perfom an "OR" search for the item tag tallos 2 and 9', async() => { - await page.waitToClick(selectors.orderCatalog.openTagSearch); - await page.autocompleteSearch(selectors.orderCatalog.tag, 'Tallos'); - await page.write(selectors.orderCatalog.firstTagValue, '2'); - await page.waitToClick(selectors.orderCatalog.addTagButton); - await page.write(selectors.orderCatalog.secondTagValue, '9'); - await page.waitToClick(selectors.orderCatalog.searchTagButton); - await page.waitForNumberOfElements('section.product', 2); - }); - - it('should perform a general search for category', async() => { - await page.write(selectors.orderCatalog.itemTagValue, 'concussion'); - await page.keyboard.press('Enter'); - await page.waitForNumberOfElements('section.product', 2); - }); - - it('should perfom an "AND" search for the item tag tallos 2', async() => { - await page.waitToClick(selectors.orderCatalog.openTagSearch); - await page.autocompleteSearch(selectors.orderCatalog.tag, 'Tallos'); - await page.write(selectors.orderCatalog.firstTagValue, '2'); - await page.waitToClick(selectors.orderCatalog.searchTagButton); - await page.waitForNumberOfElements('section.product', 1); - }); - - it('should remove the tag filters and have 4 results', async() => { - await page.waitForContentLoaded(); - await page.waitToClick(selectors.orderCatalog.sixthFilterRemoveButton); - await page.waitForContentLoaded(); - await page.waitToClick(selectors.orderCatalog.fifthFilterRemoveButton); - await page.waitForContentLoaded(); - await page.waitToClick(selectors.orderCatalog.fourthFilterRemoveButton); - await page.waitForContentLoaded(); - await page.waitToClick(selectors.orderCatalog.thirdFilterRemoveButton); - - await page.waitForNumberOfElements('.product', 4); - const result = await page.countElement('section.product'); - - expect(result).toEqual(4); - }); - - it('should search for an item by id', async() => { - await page.accessToSearchResult('2'); - await page.waitForNumberOfElements('section.product', 1); - const result = await page.countElement('section.product'); - - expect(result).toEqual(1); - }); -}); diff --git a/e2e/paths/07-order/05_index.spec.js b/e2e/paths/07-order/05_index.spec.js deleted file mode 100644 index 23769766c..000000000 --- a/e2e/paths/07-order/05_index.spec.js +++ /dev/null @@ -1,34 +0,0 @@ -import selectors from '../../helpers/selectors.js'; -import getBrowser from '../../helpers/puppeteer'; - -describe('Order Index', () => { - let browser; - let page; - - beforeAll(async() => { - browser = await getBrowser(); - page = browser.page; - await page.loginAndModule('employee', 'order'); - }); - - afterAll(async() => { - await browser.close(); - }); - - it(`should check the second search result doesn't contain a total of 0€`, async() => { - await page.waitToClick(selectors.globalItems.searchButton); - const result = await page.waitToGetProperty(selectors.ordersIndex.secondSearchResultTotal, 'innerText'); - - expect(result).not.toContain('0.00'); - }); - - it('should search including empty orders', async() => { - await page.waitToClick(selectors.ordersIndex.openAdvancedSearch); - await page.waitToClick(selectors.ordersIndex.advancedSearchShowEmptyCheckbox); - await page.waitToClick(selectors.ordersIndex.advancedSearchButton); - await page.waitForTextInElement(selectors.ordersIndex.secondSearchResultTotal, '0.00'); - const result = await page.waitToGetProperty(selectors.ordersIndex.secondSearchResultTotal, 'innerText'); - - expect(result).toContain('0.00'); - }); -}); diff --git a/front/core/services/app.js b/front/core/services/app.js index b8fcc43e1..dba6e70bf 100644 --- a/front/core/services/app.js +++ b/front/core/services/app.js @@ -66,10 +66,16 @@ export default class App { ]} }; - - if (this.logger.$params.q) - newRoute = newRoute.concat(`?table=${this.logger.$params.q}`); + const hasId = !isNaN(parseInt(route.split('/')[1])); + if (this.logger.$params.q) { + let tableValue = this.logger.$params.q; + const q = JSON.parse(tableValue); + if (typeof q === 'number') + tableValue = JSON.stringify({id: tableValue}); + newRoute = newRoute.concat(`?table=${tableValue}`); + } else if (!hasId && this.logger.$params.id && newRoute.indexOf(this.logger.$params.id) < 0) + newRoute = newRoute.concat(`${this.logger.$params.id}`); return this.logger.$http.get('Urls/findOne', {filter}) .then(res => { diff --git a/loopback/locale/en.json b/loopback/locale/en.json index ea84cb6eb..a7e21960b 100644 --- a/loopback/locale/en.json +++ b/loopback/locale/en.json @@ -240,5 +240,6 @@ "There is already a tray with the same height": "There is already a tray with the same height", "The height must be greater than 50cm": "The height must be greater than 50cm", "The maximum height of the wagon is 200cm": "The maximum height of the wagon is 200cm", - "The quantity claimed cannot be greater than the quantity of the line": "The quantity claimed cannot be greater than the quantity of the line" + "The quantity claimed cannot be greater than the quantity of the line": "The quantity claimed cannot be greater than the quantity of the line", + "There are tickets for this area, delete them first": "There are tickets for this area, delete them first" } diff --git a/loopback/locale/es.json b/loopback/locale/es.json index 796c945e8..6d50f634e 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -381,5 +381,7 @@ "The entry does not have stickers": "La entrada no tiene etiquetas", "This buyer has already made a reservation for this date": "Este comprador ya ha hecho una reserva para esta fecha", "No valid travel thermograph found": "No se encontró un termógrafo válido", - "The quantity claimed cannot be greater than the quantity of the line": "La cantidad reclamada no puede ser mayor que la cantidad de la línea" + "The quantity claimed cannot be greater than the quantity of the line": "La cantidad reclamada no puede ser mayor que la cantidad de la línea", + "type cannot be blank": "Se debe rellenar el tipo", + "There are tickets for this area, delete them first": "Hay tickets para esta sección, borralos primero" } diff --git a/modules/account/back/models/sip.json b/modules/account/back/models/sip.json index f2e2221b5..dbcef3b9e 100644 --- a/modules/account/back/models/sip.json +++ b/modules/account/back/models/sip.json @@ -25,7 +25,12 @@ "type": "belongsTo", "model": "VnUser", "foreignKey": "user_id" + }, + "queueMember": { + "type": "belongsTo", + "model": "QueueMember", + "foreignKey": "extension", + "primaryKey": "extension" } } -} - \ No newline at end of file +} \ No newline at end of file diff --git a/modules/client/back/models/client-observation.js b/modules/client/back/models/client-observation.js index e34eedca9..d022a440a 100644 --- a/modules/client/back/models/client-observation.js +++ b/modules/client/back/models/client-observation.js @@ -1,8 +1,11 @@ module.exports = function(Self) { - Self.validate('text', isEnabled, {message: 'Description cannot be blank'}); - function isEnabled(err) { + Self.validate('text', function(err) { if (!this.text) err(); - } + }, {message: 'Description cannot be blank'}); + + Self.validate('observationTypeFk', function(err) { + if (!this.observationTypeFk) err(); + }, {message: 'type cannot be blank'}); Self.observe('before save', function(ctx, next) { ctx.instance.created = Date(); diff --git a/modules/client/back/models/client-observation.json b/modules/client/back/models/client-observation.json index b204ebeb4..86351862d 100644 --- a/modules/client/back/models/client-observation.json +++ b/modules/client/back/models/client-observation.json @@ -1,10 +1,10 @@ { - "name": "ClientObservation", + "name": "ClientObservation", "description": "Client notes", "base": "VnModel", - "mixins": { - "Loggable": true - }, + "mixins": { + "Loggable": true + }, "options": { "mysql": { "table": "clientObservation" @@ -26,6 +26,10 @@ "created": { "type": "date", "description": "Creation date and time" + }, + "observationTypeFk": { + "type": "number", + "description": "Type of observation" } }, "relations": { @@ -44,14 +48,18 @@ "include": { "relation": "worker", "scope": { - "fields": ["id"], + "fields": [ + "id" + ], "include": { "relation": "user", "scope": { - "fields": ["nickname"] + "fields": [ + "nickname" + ] } } } } } -} +} \ No newline at end of file diff --git a/modules/client/front/defaulter/index.html b/modules/client/front/defaulter/index.html index 33bb751f1..440f34d3d 100644 --- a/modules/client/front/defaulter/index.html +++ b/modules/client/front/defaulter/index.html @@ -54,7 +54,7 @@ Client - + Es trabajador diff --git a/modules/client/front/defaulter/index.js b/modules/client/front/defaulter/index.js index bc8686c10..2ec53d380 100644 --- a/modules/client/front/defaulter/index.js +++ b/modules/client/front/defaulter/index.js @@ -57,6 +57,11 @@ export default class Controller extends Section { field: 'observation', searchable: false }, + { + field: 'isWorker', + checkbox: true, + + }, { field: 'created', datepicker: true @@ -73,9 +78,6 @@ export default class Controller extends Section { set defaulters(value) { if (!value || !value.length) return; - for (let defaulter of value) - defaulter.isWorker = defaulter.businessTypeFk === 'worker'; - this._defaulters = value; } @@ -164,6 +166,8 @@ export default class Controller extends Section { exprBuilder(param, value) { switch (param) { + case 'isWorker': + return {isWorker: value}; case 'creditInsurance': case 'amount': case 'clientFk': diff --git a/modules/client/front/note/index/index.html b/modules/client/front/note/index/index.html index 634a9c3ce..e69de29bb 100644 --- a/modules/client/front/note/index/index.html +++ b/modules/client/front/note/index/index.html @@ -1,31 +0,0 @@ - - - - -
- - {{::note.worker.user.nickname}} - {{::note.created | date:'dd/MM/yyyy HH:mm'}} - - - {{::note.text}} - -
-
-
- - - diff --git a/modules/client/front/note/index/index.js b/modules/client/front/note/index/index.js index ed15db671..1610bdaab 100644 --- a/modules/client/front/note/index/index.js +++ b/modules/client/front/note/index/index.js @@ -5,9 +5,10 @@ import './style.scss'; export default class Controller extends Section { constructor($element, $) { super($element, $); - this.filter = { - order: 'created DESC', - }; + } + async $onInit() { + this.$state.go('home'); + window.location.href = await this.vnApp.getUrl(`customer/${this.$params.id}/notes`); } } diff --git a/modules/entry/back/methods/entry/specs/filter.spec.js b/modules/entry/back/methods/entry/specs/filter.spec.js index 105838858..4bf5127b0 100644 --- a/modules/entry/back/methods/entry/specs/filter.spec.js +++ b/modules/entry/back/methods/entry/specs/filter.spec.js @@ -39,7 +39,7 @@ describe('Entry filter()', () => { const result = await models.Entry.filter(ctx, options); - expect(result.length).toEqual(11); + expect(result.length).toEqual(12); await tx.rollback(); } catch (e) { @@ -152,7 +152,7 @@ describe('Entry filter()', () => { const result = await models.Entry.filter(ctx, options); - expect(result.length).toEqual(10); + expect(result.length).toEqual(11); await tx.rollback(); } catch (e) { diff --git a/modules/entry/back/methods/stock-bought/getStockBoughtDetail.js b/modules/entry/back/methods/stock-bought/getStockBoughtDetail.js index 3e040d0d3..d5f712edf 100644 --- a/modules/entry/back/methods/stock-bought/getStockBoughtDetail.js +++ b/modules/entry/back/methods/stock-bought/getStockBoughtDetail.js @@ -45,8 +45,8 @@ module.exports = Self => { i.id itemFk, i.name itemName, ti.quantity, - (ac.conversionCoefficient * (ti.quantity / b.packing) * buy_getVolume(b.id)) - / (vc.trolleyM3 * 1000000) volume, + ROUND((ac.conversionCoefficient * (ti.quantity / b.packing) * buy_getVolume(b.id)) + / (vc.trolleyM3 * 1000000),1) volume, b.packagingFk packagingFk, b.packing FROM tmp.item ti diff --git a/modules/entry/front/descriptor-popover/index.html b/modules/entry/front/descriptor-popover/index.html new file mode 100644 index 000000000..23f641632 --- /dev/null +++ b/modules/entry/front/descriptor-popover/index.html @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/modules/entry/front/descriptor-popover/index.js b/modules/entry/front/descriptor-popover/index.js new file mode 100644 index 000000000..d79aed03e --- /dev/null +++ b/modules/entry/front/descriptor-popover/index.js @@ -0,0 +1,9 @@ +import ngModule from '../module'; +import DescriptorPopover from 'salix/components/descriptor-popover'; + +class Controller extends DescriptorPopover {} + +ngModule.vnComponent('vnEntryDescriptorPopover', { + slotTemplate: require('./index.html'), + controller: Controller +}); diff --git a/modules/entry/front/descriptor/index.html b/modules/entry/front/descriptor/index.html new file mode 100644 index 000000000..3354d4155 --- /dev/null +++ b/modules/entry/front/descriptor/index.html @@ -0,0 +1,65 @@ + + + + Show entry report + + + +
+ + + + + + +
+
+ + + + +
+ +
+
+ + + \ No newline at end of file diff --git a/modules/entry/front/descriptor/index.js b/modules/entry/front/descriptor/index.js new file mode 100644 index 000000000..3452a6d34 --- /dev/null +++ b/modules/entry/front/descriptor/index.js @@ -0,0 +1,99 @@ +import ngModule from '../module'; +import Descriptor from 'salix/components/descriptor'; + +class Controller extends Descriptor { + get entry() { + return this.entity; + } + + set entry(value) { + this.entity = value; + } + + get travelFilter() { + let travelFilter; + const entryTravel = this.entry && this.entry.travel; + + if (entryTravel && entryTravel.agencyModeFk) { + travelFilter = this.entry && JSON.stringify({ + agencyModeFk: entryTravel.agencyModeFk + }); + } + return travelFilter; + } + + get entryFilter() { + let entryTravel = this.entry && this.entry.travel; + + if (!entryTravel || !entryTravel.landed) return null; + + const date = new Date(entryTravel.landed); + date.setHours(0, 0, 0, 0); + + const from = new Date(date.getTime()); + from.setDate(from.getDate() - 10); + + const to = new Date(date.getTime()); + to.setDate(to.getDate() + 10); + + return JSON.stringify({ + supplierFk: this.entry.supplierFk, + from, + to + }); + } + + loadData() { + const filter = { + include: [ + { + relation: 'travel', + scope: { + fields: ['id', 'landed', 'agencyModeFk', 'warehouseOutFk'], + include: [ + { + relation: 'agency', + scope: { + fields: ['name'] + } + }, + { + relation: 'warehouseOut', + scope: { + fields: ['name'] + } + }, + { + relation: 'warehouseIn', + scope: { + fields: ['name'] + } + } + ] + } + }, + { + relation: 'supplier', + scope: { + fields: ['id', 'nickname'] + } + } + ] + }; + + return this.getData(`Entries/${this.id}`, {filter}) + .then(res => this.entity = res.data); + } + + showEntryReport() { + this.vnReport.show(`Entries/${this.id}/entry-order-pdf`); + } +} + +ngModule.vnComponent('vnEntryDescriptor', { + template: require('./index.html'), + controller: Controller, + bindings: { + entry: '<' + } +}); diff --git a/modules/entry/front/index.js b/modules/entry/front/index.js index a7209a0bd..0f2208862 100644 --- a/modules/entry/front/index.js +++ b/modules/entry/front/index.js @@ -1,3 +1,6 @@ export * from './module'; import './main'; +import './descriptor'; +import './descriptor-popover'; +import './summary'; diff --git a/modules/entry/front/routes.json b/modules/entry/front/routes.json index 53c599cf1..a2e70e37d 100644 --- a/modules/entry/front/routes.json +++ b/modules/entry/front/routes.json @@ -8,6 +8,12 @@ "main": [ {"state": "entry.index", "icon": "icon-entry"}, {"state": "entry.latestBuys", "icon": "contact_support"} + ], + "card": [ + {"state": "entry.card.basicData", "icon": "settings"}, + {"state": "entry.card.buy.index", "icon": "icon-lines"}, + {"state": "entry.card.observation", "icon": "insert_drive_file"}, + {"state": "entry.card.log", "icon": "history"} ] }, "keybindings": [ @@ -27,6 +33,90 @@ "component": "vn-entry-index", "description": "Entries", "acl": ["buyer", "administrative"] + }, + { + "url": "/latest-buys?q", + "state": "entry.latestBuys", + "component": "vn-entry-latest-buys", + "description": "Latest buys", + "acl": ["buyer", "administrative"] + }, + { + "url": "/create?supplierFk&travelFk&companyFk", + "state": "entry.create", + "component": "vn-entry-create", + "description": "New entry", + "acl": ["buyer", "administrative"] + }, + { + "url": "/:id", + "state": "entry.card", + "abstract": true, + "component": "vn-entry-card" + }, + { + "url": "/summary", + "state": "entry.card.summary", + "component": "vn-entry-summary", + "description": "Summary", + "params": { + "entry": "$ctrl.entry" + }, + "acl": ["buyer", "administrative"] + }, + { + "url": "/basic-data", + "state": "entry.card.basicData", + "component": "vn-entry-basic-data", + "description": "Basic data", + "params": { + "entry": "$ctrl.entry" + }, + "acl": ["buyer", "administrative"] + }, + { + "url": "/observation", + "state": "entry.card.observation", + "component": "vn-entry-observation", + "description": "Notes", + "params": { + "entry": "$ctrl.entry" + }, + "acl": ["buyer", "administrative"] + }, + { + "url" : "/log", + "state": "entry.card.log", + "component": "vn-entry-log", + "description": "Log", + "acl": ["buyer", "administrative"] + }, + { + "url": "/buy", + "state": "entry.card.buy", + "abstract": true, + "component": "ui-view", + "acl": ["buyer"] + }, + { + "url" : "/index", + "state": "entry.card.buy.index", + "component": "vn-entry-buy-index", + "description": "Buys", + "params": { + "entry": "$ctrl.entry" + }, + "acl": ["buyer", "administrative"] + }, + { + "url" : "/import", + "state": "entry.card.buy.import", + "component": "vn-entry-buy-import", + "description": "Import buys", + "params": { + "entry": "$ctrl.entry" + }, + "acl": ["buyer"] } ] } diff --git a/modules/entry/front/summary/index.html b/modules/entry/front/summary/index.html new file mode 100644 index 000000000..22ea87bdf --- /dev/null +++ b/modules/entry/front/summary/index.html @@ -0,0 +1,195 @@ + + + +
+ + + + #{{$ctrl.entryData.id}} - {{$ctrl.entryData.supplier.nickname}} +
+ + + + + + + + + + + + + + + + + {{$ctrl.entryData.travel.ref}} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Buys

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
QuantityStickersPackageWeightPackingGroupingBuying valueImportPVP
{{::line.quantity}}{{::line.stickers | dashIfEmpty}}{{::line.packagingFk | dashIfEmpty}}{{::line.weight}} + + {{::line.packing | dashIfEmpty}} + + + + {{::line.grouping | dashIfEmpty}} + + + {{::line.buyingValue | currency: 'EUR':2}}{{::line.quantity * line.buyingValue | currency: 'EUR':2}}{{::line.price2 | currency: 'EUR':2 | dashIfEmpty}} / {{::line.price3 | currency: 'EUR':2 | dashIfEmpty}}
+ + {{::line.item.itemType.code}} + + + + {{::line.item.id}} + + + + {{::line.item.size}} + + + + {{::line.item.minPrice | currency: 'EUR':2}} + + +
+ {{::line.item.name}} + +

{{::line.item.subName}}

+
+
+ + +
+ + +
+
+
+ + + + diff --git a/modules/entry/front/summary/index.js b/modules/entry/front/summary/index.js new file mode 100644 index 000000000..6e18bc959 --- /dev/null +++ b/modules/entry/front/summary/index.js @@ -0,0 +1,33 @@ +import ngModule from '../module'; +import './style.scss'; +import Summary from 'salix/components/summary'; + +class Controller extends Summary { + get entry() { + if (!this._entry) + return this.$params; + + return this._entry; + } + + set entry(value) { + this._entry = value; + + if (value && value.id) + this.getEntryData(); + } + + getEntryData() { + return this.$http.get(`Entries/${this.entry.id}/getEntry`).then(response => { + this.entryData = response.data; + }); + } +} + +ngModule.vnComponent('vnEntrySummary', { + template: require('./index.html'), + controller: Controller, + bindings: { + entry: '<' + } +}); diff --git a/modules/entry/front/summary/style.scss b/modules/entry/front/summary/style.scss new file mode 100644 index 000000000..1d5b22e30 --- /dev/null +++ b/modules/entry/front/summary/style.scss @@ -0,0 +1,30 @@ +@import "variables"; + + +vn-entry-summary .summary { + max-width: $width-lg; + + .dark-row { + background-color: lighten($color-marginal, 10%); + } + + tbody tr:nth-child(1) { + border-top: $border-thin; + } + + tbody tr:nth-child(1), + tbody tr:nth-child(2) { + border-left: $border-thin; + border-right: $border-thin + } + + tbody tr:nth-child(3) { + height: inherit + } + + tr { + margin-bottom: 10px; + } +} + +$color-font-link-medium: lighten($color-font-link, 20%) \ No newline at end of file diff --git a/modules/invoiceOut/back/methods/invoiceOut/negativeBases.js b/modules/invoiceOut/back/methods/invoiceOut/negativeBases.js index 76ef29604..9e491b35c 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/negativeBases.js +++ b/modules/invoiceOut/back/methods/invoiceOut/negativeBases.js @@ -48,13 +48,13 @@ module.exports = Self => { let stmt; stmts.push(new ParameterizedSQL( `CREATE OR REPLACE TEMPORARY TABLE tmp.ticket - (KEY (ticketFk)) + (INDEX (ticketFk)) ENGINE = MEMORY SELECT id ticketFk - FROM ticket t + FROM ticket WHERE shipped BETWEEN ? AND util.dayEnd(?) AND refFk IS NULL`, [args.from, args.to])); - stmts.push(`CALL vn.ticket_getTax(NULL)`); + stmts.push(`CALL ticket_getTax(NULL)`); stmts.push(new ParameterizedSQL( `CREATE OR REPLACE TEMPORARY TABLE tmp.filter ENGINE = MEMORY @@ -71,12 +71,12 @@ module.exports = Self => { c.isTaxDataChecked, w.id comercialId, u.name workerName - FROM vn.ticket t - JOIN vn.company co ON co.id = t.companyFk - JOIN vn.sale s ON s.ticketFk = t.id - JOIN vn.client c ON c.id = t.clientFk - JOIN vn.country cou ON cou.id = c.countryFk - LEFT JOIN vn.worker w ON w.id = c.salesPersonFk + FROM ticket t + JOIN company co ON co.id = t.companyFk + JOIN sale s ON s.ticketFk = t.id + JOIN client c ON c.id = t.clientFk + JOIN country cou ON cou.id = c.countryFk + LEFT JOIN worker w ON w.id = c.salesPersonFk JOIN account.user u ON u.id = w.id LEFT JOIN ( SELECT ticketFk, taxableBase diff --git a/modules/item/back/methods/item-shelving/deleteItemShelvings.js b/modules/item/back/methods/item-shelving/deleteItemShelvings.js index f534b4e9a..fbc354cce 100644 --- a/modules/item/back/methods/item-shelving/deleteItemShelvings.js +++ b/modules/item/back/methods/item-shelving/deleteItemShelvings.js @@ -34,6 +34,11 @@ module.exports = Self => { try { const promises = []; for (let itemShelvingId of itemShelvingIds) { + const itemShelvingSaleToDelete = models.ItemShelvingSale.destroyAll({ + itemShelvingFk: itemShelvingId + }, myOptions); + promises.push(itemShelvingSaleToDelete); + const itemShelvingToDelete = models.ItemShelving.destroyById(itemShelvingId, myOptions); promises.push(itemShelvingToDelete); } diff --git a/modules/item/back/methods/item-shelving/specs/deleteItemShelvings.spec.js b/modules/item/back/methods/item-shelving/specs/deleteItemShelvings.spec.js index b4113d7cf..541a529cb 100644 --- a/modules/item/back/methods/item-shelving/specs/deleteItemShelvings.spec.js +++ b/modules/item/back/methods/item-shelving/specs/deleteItemShelvings.spec.js @@ -10,7 +10,7 @@ describe('ItemShelving deleteItemShelvings()', () => { const itemShelvingIds = [1, 2]; const result = await models.ItemShelving.deleteItemShelvings(itemShelvingIds, options); - expect(result.length).toEqual(2); + expect(result.length).toEqual(4); await tx.rollback(); } catch (e) { diff --git a/modules/item/back/methods/item/specs/lastEntriesFilter.spec.js b/modules/item/back/methods/item/specs/lastEntriesFilter.spec.js index 00488e534..2fd30c2ca 100644 --- a/modules/item/back/methods/item/specs/lastEntriesFilter.spec.js +++ b/modules/item/back/methods/item/specs/lastEntriesFilter.spec.js @@ -1,6 +1,6 @@ const {models} = require('vn-loopback/server/server'); describe('item lastEntriesFilter()', () => { - it('should return one entry for the given item', async() => { + it('should return two entry for the given item', async() => { const minDate = Date.vnNew(); minDate.setHours(0, 0, 0, 0); const maxDate = Date.vnNew(); @@ -13,7 +13,7 @@ describe('item lastEntriesFilter()', () => { const filter = {where: {itemFk: 1, landed: {between: [minDate, maxDate]}}}; const result = await models.Item.lastEntriesFilter(filter, options); - expect(result.length).toEqual(1); + expect(result.length).toEqual(2); await tx.rollback(); } catch (e) { @@ -22,7 +22,7 @@ describe('item lastEntriesFilter()', () => { } }); - it('should return five entries for the given item', async() => { + it('should return six entries for the given item', async() => { const minDate = Date.vnNew(); minDate.setHours(0, 0, 0, 0); minDate.setMonth(minDate.getMonth() - 2, 1); @@ -37,7 +37,7 @@ describe('item lastEntriesFilter()', () => { const filter = {where: {itemFk: 1, landed: {between: [minDate, maxDate]}}}; const result = await models.Item.lastEntriesFilter(filter, options); - expect(result.length).toEqual(5); + expect(result.length).toEqual(6); await tx.rollback(); } catch (e) { diff --git a/modules/item/front/routes.json b/modules/item/front/routes.json index 4b7cd1490..05b887a96 100644 --- a/modules/item/front/routes.json +++ b/modules/item/front/routes.json @@ -3,7 +3,7 @@ "name": "Items", "icon": "icon-item", "validations" : true, - "dependencies": ["worker", "client", "ticket"], + "dependencies": ["worker", "client", "ticket", "entry"], "menus": { "main": [ {"state": "item.index", "icon": "icon-item"}, diff --git a/modules/monitor/front/index.js b/modules/monitor/front/index.js index 19ea06b5a..a7209a0bd 100644 --- a/modules/monitor/front/index.js +++ b/modules/monitor/front/index.js @@ -1,8 +1,3 @@ export * from './module'; import './main'; -import './index/'; -import './index/tickets'; -import './index/clients'; -import './index/orders'; -import './index/search-panel'; diff --git a/modules/monitor/front/index/clients/index.html b/modules/monitor/front/index/clients/index.html deleted file mode 100644 index c0e3d1b14..000000000 --- a/modules/monitor/front/index/clients/index.html +++ /dev/null @@ -1,110 +0,0 @@ - - - - - Clients on website - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Date - - Hour - - Salesperson - - Client -
- - {{::visit.dated | date:'dd/MM/yy'}} - - - - {{::visit.hour | date: 'HH:mm'}} - - - - {{::visit.salesPerson | dashIfEmpty}} - - - - {{::visit.clientName}} - -
-
- - - - -
-
- - - - diff --git a/modules/monitor/front/index/clients/index.js b/modules/monitor/front/index/clients/index.js deleted file mode 100644 index ac3ce9140..000000000 --- a/modules/monitor/front/index/clients/index.js +++ /dev/null @@ -1,96 +0,0 @@ -import ngModule from '../../module'; -import Section from 'salix/components/section'; - -export default class Controller extends Section { - constructor($element, $) { - super($element, $); - - const date = Date.vnNew(); - this.dateFrom = date; - this.dateTo = date; - this.filter = { - where: { - 'v.stamp': { - between: this.dateRange() - } - } - }; - - this.smartTableOptions = { - activeButtons: { - search: true - }, - columns: [ - { - field: 'clientFk', - autocomplete: { - url: 'Clients', - showField: 'name', - valueField: 'id' - } - }, - { - field: 'salesPersonFk', - autocomplete: { - url: 'Workers/activeWithInheritedRole', - where: `{role: 'salesPerson'}`, - searchFunction: '{firstName: $search}', - showField: 'nickname', - valueField: 'id', - } - }, - { - field: 'dated', - searchable: false - }, - { - field: 'hour', - searchable: false - } - ] - }; - } - - exprBuilder(param, value) { - switch (param) { - case 'clientFk': - return {[`c.id`]: value}; - case 'salesPersonFk': - return {[`c.${param}`]: value}; - } - } - - dateRange() { - let from = this.dateFrom; - let to = this.dateTo; - if (!from) - from = Date.vnNew(); - if (!to) - to = Date.vnNew(); - const minHour = new Date(from); - minHour.setHours(0, 0, 0, 0); - const maxHour = new Date(to); - maxHour.setHours(23, 59, 59, 59); - - return [minHour, maxHour]; - } - - addFilterDate() { - this.$.model.filter = { - where: { - 'v.stamp': { - between: this.dateRange() - } - } - }; - this.$.model.refresh(); - } -} - -ngModule.vnComponent('vnMonitorSalesClients', { - template: require('./index.html'), - controller: Controller, - require: { - main: '^vnMonitorIndex' - } -}); diff --git a/modules/monitor/front/index/index.html b/modules/monitor/front/index/index.html deleted file mode 100644 index 85987ac20..000000000 --- a/modules/monitor/front/index/index.html +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/modules/monitor/front/index/index.js b/modules/monitor/front/index/index.js deleted file mode 100644 index 72ca9dae9..000000000 --- a/modules/monitor/front/index/index.js +++ /dev/null @@ -1,34 +0,0 @@ -import ngModule from '../module'; -import Section from 'salix/components/section'; -import './style.scss'; - -export default class Controller extends Section { - constructor($element, $) { - super($element, $); - - const isTopPanelHidden = localStorage.getItem('ticketTopPanelHidden'); - if (isTopPanelHidden === 'true') - this.isTopPanelHidden = true; - } - - toggle() { - const monitor = this.element.querySelector('vn-horizontal'); - const isHidden = monitor.classList.contains('hidden'); - - if (!isHidden) { - monitor.classList.add('hidden'); - localStorage.setItem('ticketTopPanelHidden', true); - } else { - monitor.classList.remove('hidden'); - localStorage.setItem('ticketTopPanelHidden', false); - } - } -} - -ngModule.vnComponent('vnMonitorIndex', { - template: require('./index.html'), - controller: Controller, - require: { - main: '^vnMonitorIndex' - } -}); diff --git a/modules/monitor/front/index/index.spec.js b/modules/monitor/front/index/index.spec.js deleted file mode 100644 index 506e75720..000000000 --- a/modules/monitor/front/index/index.spec.js +++ /dev/null @@ -1,38 +0,0 @@ -import './index.js'; -describe('Component vnMonitorIndex', () => { - let controller; - let $element; - - beforeEach(ngModule('monitor')); - - beforeEach(inject(($compile, $rootScope) => { - $element = $compile('')($rootScope); - controller = $element.controller('vnMonitorIndex'); - })); - - describe('toggle()', () => { - it('should add the hidden class to the horizontal contaning the panel to hide', () => { - controller.toggle(); - - const targetElement = $element[0].querySelector('vn-horizontal'); - const firstClass = targetElement.classList[0]; - - const isTopPanelHidden = localStorage.getItem('ticketTopPanelHidden'); - - expect(firstClass).toEqual('hidden'); - expect(isTopPanelHidden).toEqual('true'); - }); - - it('should remove the hidden class to the horizontal contaning the panel to hide', () => { - const targetElement = $element[0].querySelector('vn-horizontal'); - targetElement.classList.add('hidden'); - controller.toggle(); - const firstClass = targetElement.classList[0]; - - const isTopPanelHidden = localStorage.getItem('ticketTopPanelHidden'); - - expect(firstClass).toBeUndefined(); - expect(isTopPanelHidden).toEqual('false'); - }); - }); -}); diff --git a/modules/monitor/front/index/locale/es.yml b/modules/monitor/front/index/locale/es.yml deleted file mode 100644 index f114a2259..000000000 --- a/modules/monitor/front/index/locale/es.yml +++ /dev/null @@ -1,16 +0,0 @@ -Tickets monitor: Monitor de tickets -Clients on website: Clientes activos en la web -Recent order actions: Acciones recientes en pedidos -Search tickets: Buscar tickets -Delete selected elements: Eliminar los elementos seleccionados -All the selected elements will be deleted. Are you sure you want to continue?: Todos los elementos seleccionados serán eliminados. ¿Seguro que quieres continuar? -Component lack: Faltan componentes -Ticket too little: Ticket demasiado pequeño -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 -Is fragile: Es frágil diff --git a/modules/monitor/front/index/orders/index.html b/modules/monitor/front/index/orders/index.html deleted file mode 100644 index 4d1171185..000000000 --- a/modules/monitor/front/index/orders/index.html +++ /dev/null @@ -1,141 +0,0 @@ - - - - - Recent order actions - - - - - - - - - - - - - - - - - - - Date - Client - SalesPerson - - - - - - - - - - - {{::order.date_send | date: 'dd/MM/yyyy'}} - - - - - {{::order.clientName}} - - - - - {{::order.salesPerson | dashIfEmpty}} - - - - - - - - {{::order.date_make | date: 'dd/MM/yyyy HH:mm'}} - - - - - {{::order.agencyName | dashIfEmpty}} - - - - {{::order.import | currency: 'EUR':2}} - - - - - - - - - - - - - - - Filter by selection - - - Exclude selection - - - Remove filter - - - Remove all filters - - - Copy value - - - - - diff --git a/modules/monitor/front/index/orders/index.js b/modules/monitor/front/index/orders/index.js deleted file mode 100644 index 40100b79f..000000000 --- a/modules/monitor/front/index/orders/index.js +++ /dev/null @@ -1,74 +0,0 @@ -import ngModule from '../../module'; -import Section from 'salix/components/section'; -import './style.scss'; - -export default class Controller extends Section { - get checked() { - const rows = this.$.model.data || []; - const checkedRows = []; - for (let row of rows) { - if (row.checked) - checkedRows.push(row.id); - } - - return checkedRows; - } - - get totalChecked() { - return this.checked.length; - } - - onDelete() { - const params = {deletes: this.checked}; - const query = `SalesMonitors/deleteOrders`; - this.$http.post(query, params).then( - () => this.$.model.refresh()); - } - - chipColor(date) { - const today = Date.vnNew(); - today.setHours(0, 0, 0, 0); - - const orderLanded = new Date(date); - orderLanded.setHours(0, 0, 0, 0); - - const difference = today - orderLanded; - - if (difference == 0) - return 'warning'; - if (difference < 0) - return 'success'; - if (difference > 0) - return 'alert'; - } - - exprBuilder(param, value) { - switch (param) { - case 'date_send': - return {[`o.date_send`]: { - between: this.dateRange(value)} - }; - case 'clientFk': - return {[`c.id`]: value}; - case 'salesPersonFk': - return {[`c.${param}`]: value}; - } - } - - dateRange(value) { - const minHour = new Date(value); - minHour.setHours(0, 0, 0, 0); - const maxHour = new Date(value); - maxHour.setHours(23, 59, 59, 59); - - return [minHour, maxHour]; - } -} - -ngModule.vnComponent('vnMonitorSalesOrders', { - template: require('./index.html'), - controller: Controller, - require: { - main: '^vnMonitorIndex' - } -}); diff --git a/modules/monitor/front/index/orders/index.spec.js b/modules/monitor/front/index/orders/index.spec.js deleted file mode 100644 index 109925358..000000000 --- a/modules/monitor/front/index/orders/index.spec.js +++ /dev/null @@ -1,50 +0,0 @@ -import './index.js'; -import crudModel from 'core/mocks/crud-model'; - -describe('Component vnMonitorSalesOrders', () => { - let controller; - let $httpBackend; - - beforeEach(ngModule('monitor')); - - beforeEach(inject(($componentController, _$httpBackend_) => { - $httpBackend = _$httpBackend_; - const $element = angular.element(''); - controller = $componentController('vnMonitorSalesOrders', {$element}); - controller.$.model = crudModel; - controller.$.model.data = [ - {id: 1, name: 'My item 1'}, - {id: 2, name: 'My item 2'}, - {id: 3, name: 'My item 3'} - ]; - })); - - describe('checked() getter', () => { - it('should return a the selected rows', () => { - const modelData = controller.$.model.data; - modelData[0].checked = true; - modelData[1].checked = true; - - const result = controller.checked; - - expect(result).toEqual(expect.arrayContaining([1, 2])); - }); - }); - - describe('onDelete()', () => { - it('should make a query and then call to the model refresh() method', () => { - jest.spyOn(controller.$.model, 'refresh'); - - const modelData = controller.$.model.data; - modelData[0].checked = true; - modelData[1].checked = true; - - const expectedParams = {deletes: [1, 2]}; - $httpBackend.expect('POST', 'SalesMonitors/deleteOrders', expectedParams).respond(200); - controller.onDelete(); - $httpBackend.flush(); - - expect(controller.$.model.refresh).toHaveBeenCalledWith(); - }); - }); -}); diff --git a/modules/monitor/front/index/orders/style.scss b/modules/monitor/front/index/orders/style.scss deleted file mode 100644 index 64d6497c9..000000000 --- a/modules/monitor/front/index/orders/style.scss +++ /dev/null @@ -1,19 +0,0 @@ -@import "variables"; - -vn-monitor-sales-orders { - vn-table.scrollable { - max-height: 350px; - overflow-x: hidden - } - - vn-table a.vn-tbody { - & > vn-tr:nth-child(2) { - color: gray; - - & > vn-td { - border-bottom: $border; - font-size: 13px; - } - } - } -} \ No newline at end of file diff --git a/modules/monitor/front/index/search-panel/index.html b/modules/monitor/front/index/search-panel/index.html deleted file mode 100644 index 25a3510ab..000000000 --- a/modules/monitor/front/index/search-panel/index.html +++ /dev/null @@ -1,120 +0,0 @@ -
- - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {{name}} - - - - - - - - - - - - - - - - - - - - -
-
diff --git a/modules/monitor/front/index/search-panel/index.js b/modules/monitor/front/index/search-panel/index.js deleted file mode 100644 index ef6625e8a..000000000 --- a/modules/monitor/front/index/search-panel/index.js +++ /dev/null @@ -1,59 +0,0 @@ -import ngModule from '../../module'; -import SearchPanel from 'core/components/searchbar/search-panel'; - -class Controller extends SearchPanel { - constructor($, $element) { - super($, $element); - this.filter = this.$.filter; - - this.getGroupedStates(); - } - - getGroupedStates() { - let groupedStates = []; - this.$http.get('AlertLevels').then(res => { - for (let state of res.data) { - groupedStates.push({ - id: state.id, - code: state.code, - name: this.$t(state.code) - }); - } - this.groupedStates = groupedStates; - }); - } - - get from() { - return this._from; - } - - set from(value) { - this._from = value; - this.filter.scopeDays = null; - } - - get to() { - return this._to; - } - - set to(value) { - this._to = value; - this.filter.scopeDays = null; - } - - get scopeDays() { - return this._scopeDays; - } - - set scopeDays(value) { - this._scopeDays = value; - - this.filter.from = null; - this.filter.to = null; - } -} - -ngModule.vnComponent('vnMonitorSalesSearchPanel', { - template: require('./index.html'), - controller: Controller -}); diff --git a/modules/monitor/front/index/search-panel/index.spec.js b/modules/monitor/front/index/search-panel/index.spec.js deleted file mode 100644 index 18cf1abfc..000000000 --- a/modules/monitor/front/index/search-panel/index.spec.js +++ /dev/null @@ -1,71 +0,0 @@ -import './index'; - -describe('Monitor Component vnMonitorSalesSearchPanel', () => { - let $httpBackend; - let controller; - - beforeEach(ngModule('monitor')); - - beforeEach(inject(($componentController, _$httpBackend_) => { - $httpBackend = _$httpBackend_; - controller = $componentController('vnMonitorSalesSearchPanel', {$element: null}); - controller.$t = () => {}; - controller.filter = {}; - })); - - describe('getGroupedStates()', () => { - it('should set an array of groupedStates with the adition of a name translation', () => { - jest.spyOn(controller, '$t').mockReturnValue('miCodigo'); - const data = [ - { - id: 9999, - code: 'myCode' - } - ]; - $httpBackend.whenGET('AlertLevels').respond(data); - controller.getGroupedStates(); - $httpBackend.flush(); - - expect(controller.groupedStates).toEqual([{ - id: 9999, - code: 'myCode', - name: 'miCodigo' - }]); - }); - }); - - describe('from() setter', () => { - it('should clear the scope days when setting the from property', () => { - controller.filter.scopeDays = 1; - - controller.from = Date.vnNew(); - - expect(controller.filter.scopeDays).toBeNull(); - expect(controller.from).toBeDefined(); - }); - }); - - describe('to() setter', () => { - it('should clear the scope days when setting the to property', () => { - controller.filter.scopeDays = 1; - - controller.to = Date.vnNew(); - - expect(controller.filter.scopeDays).toBeNull(); - expect(controller.to).toBeDefined(); - }); - }); - - describe('scopeDays() setter', () => { - it('should clear the date range when setting the scopeDays property', () => { - controller.filter.from = Date.vnNew(); - controller.filter.to = Date.vnNew(); - - controller.scopeDays = 1; - - expect(controller.filter.from).toBeNull(); - expect(controller.filter.to).toBeNull(); - expect(controller.scopeDays).toBeDefined(); - }); - }); -}); diff --git a/modules/monitor/front/index/style.scss b/modules/monitor/front/index/style.scss deleted file mode 100644 index 2b193ac88..000000000 --- a/modules/monitor/front/index/style.scss +++ /dev/null @@ -1,85 +0,0 @@ -@import "variables"; -@import "effects"; - -vn-monitor-index { - .header { - padding: 12px 0 5px 0; - color: gray; - font-size: 1.2rem; - border-bottom: $border; - margin-bottom: 10px; - - & > vn-none > vn-icon { - @extend %clickable-light; - color: $color-button; - font-size: 1.4rem; - } - - vn-none > .arrow { - transition: transform 200ms; - } - } - - vn-monitor-sales-clients { - vn-card { - margin-right: 15px; - } - - .header { - padding-right: 15px; - - & > vn-none > .arrow { - display: none - } - } - } - - vn-table.scrollable { - height: 300px - } - - vn-horizontal { - flex-wrap: wrap - } - - .hidden { - vn-card { - display: none - } - - .header > vn-none > .arrow { - transform: rotate(180deg); - } - } -} - -@media (max-width:1150px) { - vn-monitor-index { - & > vn-horizontal { - flex-direction: column; - - vn-monitor-sales-clients, - vn-monitor-sales-orders { - width: 100% - } - - vn-monitor-sales-clients { - margin-bottom: 15px - } - } - - vn-monitor-sales-clients { - vn-card { - margin-right: 0 - } - - .header { - padding-right: 0; - - & > vn-none > .arrow { - display: inline-block - } - } - } - } -} \ No newline at end of file diff --git a/modules/monitor/front/index/tickets/index.html b/modules/monitor/front/index/tickets/index.html deleted file mode 100644 index 94a950baf..000000000 --- a/modules/monitor/front/index/tickets/index.html +++ /dev/null @@ -1,270 +0,0 @@ - - - - - - - - - Tickets monitor - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Problems - - Identifier - - Client - - Salesperson - - Date - - Theoretical - - Practical - - Preparation - - Province - - State - - Fragile - - Zone - - Total -
- - - - - - - - - - - - - - - - - {{ticket.id}} - - - - {{ticket.nickname}} - - - - {{ticket.userName | dashIfEmpty}} - - - - {{ticket.shippedDate | 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}} - - - - - - -
-
-
-
- - - - - - - - - - - - - - - - Filter by selection - - - Exclude selection - - - Remove filter - - - Remove all filters - - - Copy value - - - diff --git a/modules/monitor/front/index/tickets/index.js b/modules/monitor/front/index/tickets/index.js deleted file mode 100644 index 2f2dead05..000000000 --- a/modules/monitor/front/index/tickets/index.js +++ /dev/null @@ -1,178 +0,0 @@ -import ngModule from '../../module'; -import Section from 'salix/components/section'; -import './style.scss'; - -export default class Controller extends Section { - constructor($element, $) { - super($element, $); - - this.filterParams = this.fetchParams(); - this.smartTableOptions = { - activeButtons: { - search: true, - shownColumns: true, - }, - columns: [ - { - field: 'totalProblems', - searchable: false - }, - { - field: 'salesPersonFk', - autocomplete: { - url: 'Workers/activeWithInheritedRole', - where: `{role: 'salesPerson'}`, - searchFunction: '{firstName: $search}', - showField: 'nickname', - valueField: 'id', - } - }, - { - field: 'provinceFk', - autocomplete: { - url: 'Provinces', - } - }, - { - field: 'stateFk', - autocomplete: { - url: 'States', - } - }, - { - field: 'zoneFk', - autocomplete: { - url: 'Zones', - } - }, - { - field: 'warehouseFk', - autocomplete: { - url: 'Warehouses', - } - }, - { - field: 'shippedDate', - datepicker: true - }, - { - field: 'theoreticalHour', - searchable: false - }, - { - field: 'preparationHour', - searchable: false - } - ] - }; - } - - $onInit() { - if (!this.$params.q) { - this.$.$applyAsync( - () => this.$.model.applyFilter(null, this.filterParams)); - } - } - - fetchParams($params = {}) { - const excludedParams = [ - 'search', - 'clientFk', - 'orderFk', - 'refFk', - 'scopeDays' - ]; - - const hasExcludedParams = excludedParams.some(param => { - return $params && $params[param] != undefined; - }); - const hasParams = Object.entries($params).length; - if (!hasParams || !hasExcludedParams) - $params.scopeDays = 1; - - if (typeof $params.scopeDays === 'number') { - const from = Date.vnNew(); - from.setHours(0, 0, 0, 0); - - const to = new Date(from.getTime()); - to.setDate(to.getDate() + $params.scopeDays); - to.setHours(23, 59, 59, 999); - - Object.assign($params, {from, to}); - } - - return $params; - } - - compareDate(date) { - let today = Date.vnNew(); - today.setHours(0, 0, 0, 0); - let timeTicket = new Date(date); - timeTicket.setHours(0, 0, 0, 0); - - let comparation = today - timeTicket; - - if (comparation == 0) - return 'warning'; - if (comparation < 0) - return 'success'; - } - - totalPriceColor(ticket) { - const total = parseInt(ticket.totalWithVat); - if (total > 0 && total < 50) - return 'warning'; - } - - exprBuilder(param, value) { - switch (param) { - case 'stateFk': - return {'ts.stateFk': value}; - case 'salesPersonFk': - return {'c.salesPersonFk': value}; - case 'provinceFk': - return {'a.provinceFk': value}; - case 'theoreticalHour': - return {'z.hour': value}; - case 'practicalHour': - return {'zed.etc': value}; - case 'shippedDate': - return {'t.shipped': { - between: this.dateRange(value)} - }; - case 'nickname': - return {[`t.nickname`]: {like: `%${value}%`}}; - case 'zoneFk': - case 'totalWithVat': - return {[`t.${param}`]: value}; - } - } - - dateRange(value) { - const minHour = new Date(value); - minHour.setHours(0, 0, 0, 0); - const maxHour = new Date(value); - maxHour.setHours(23, 59, 59, 59); - - return [minHour, maxHour]; - } - - preview(ticket) { - this.selectedTicket = ticket; - this.$.summary.show(); - } - - autoRefresh(value) { - if (value) - this.refreshTimer = setInterval(() => this.$.model.refresh(), 120000); - else { - clearInterval(this.refreshTimer); - this.refreshTimer = null; - } - } -} - -ngModule.vnComponent('vnMonitorSalesTickets', { - template: require('./index.html'), - controller: Controller -}); diff --git a/modules/monitor/front/index/tickets/index.spec.js b/modules/monitor/front/index/tickets/index.spec.js deleted file mode 100644 index c12ea6844..000000000 --- a/modules/monitor/front/index/tickets/index.spec.js +++ /dev/null @@ -1,133 +0,0 @@ -import './index.js'; -describe('Component vnMonitorSalesTickets', () => { - let controller; - let $window; - let tickets = [{ - id: 1, - clientFk: 1, - checked: false, - totalWithVat: 10.5 - }, { - id: 2, - clientFk: 1, - checked: true, - totalWithVat: 20.5 - }, { - id: 3, - clientFk: 1, - checked: true, - totalWithVat: 30 - }]; - - beforeEach(ngModule('monitor')); - - beforeEach(inject(($componentController, _$window_) => { - $window = _$window_; - const $element = angular.element(''); - controller = $componentController('vnMonitorSalesTickets', {$element}); - })); - - describe('fetchParams()', () => { - it('should return a range of dates with passed scope days', () => { - let params = controller.fetchParams({ - scopeDays: 2 - }); - const from = Date.vnNew(); - from.setHours(0, 0, 0, 0); - const to = new Date(from.getTime()); - to.setDate(to.getDate() + params.scopeDays); - to.setHours(23, 59, 59, 999); - - const expectedParams = { - from, - scopeDays: params.scopeDays, - to - }; - - expect(params).toEqual(expectedParams); - }); - - it('should return default value for scope days', () => { - let params = controller.fetchParams({ - scopeDays: 1 - }); - - expect(params.scopeDays).toEqual(1); - }); - - it('should return the given scope days', () => { - let params = controller.fetchParams({ - scopeDays: 2 - }); - - expect(params.scopeDays).toEqual(2); - }); - }); - - describe('compareDate()', () => { - it('should return warning when the date is the present', () => { - let today = Date.vnNew(); - let result = controller.compareDate(today); - - expect(result).toEqual('warning'); - }); - - it('should return sucess when the date is in the future', () => { - let futureDate = Date.vnNew(); - futureDate = futureDate.setDate(futureDate.getDate() + 10); - let result = controller.compareDate(futureDate); - - expect(result).toEqual('success'); - }); - - it('should return undefined when the date is in the past', () => { - let pastDate = Date.vnNew(); - pastDate = pastDate.setDate(pastDate.getDate() - 10); - let result = controller.compareDate(pastDate); - - expect(result).toEqual(undefined); - }); - }); - - describe('totalPriceColor()', () => { - it('should return "warning" when the ticket amount is less than 50€', () => { - const result = controller.totalPriceColor({totalWithVat: '8.50'}); - - expect(result).toEqual('warning'); - }); - }); - - describe('dateRange()', () => { - it('should return two dates with the hours at the start and end of the given date', () => { - const now = Date.vnNew(); - - const today = now.getDate(); - - const dateRange = controller.dateRange(now); - const start = dateRange[0].toString(); - const end = dateRange[1].toString(); - - expect(start).toContain(today); - expect(start).toContain('00:00:00'); - - expect(end).toContain(today); - expect(end).toContain('23:59:59'); - }); - }); - - describe('preview()', () => { - it('should show the dialog summary', () => { - controller.$.summary = {show: () => {}}; - jest.spyOn(controller.$.summary, 'show'); - - let event = new MouseEvent('click', { - view: $window, - bubbles: true, - cancelable: true - }); - controller.preview(event, tickets[0]); - - expect(controller.$.summary.show).toHaveBeenCalledWith(); - }); - }); -}); diff --git a/modules/monitor/front/index/tickets/style.scss b/modules/monitor/front/index/tickets/style.scss deleted file mode 100644 index 102c92a8a..000000000 --- a/modules/monitor/front/index/tickets/style.scss +++ /dev/null @@ -1,47 +0,0 @@ -@import "variables"; - -vn-monitor-sales-tickets { - @media screen and (max-width: 1440px) { - .expendable { - display: none; - } - } - - vn-th.icon-field, - vn-th.icon-field *, - vn-td.icon-field, - vn-td.icon-field * { - padding: 0; - max-width: 50px - } - - vn-th[field="nickname"], - vn-td[name="nickname"] { - min-width: 250px - } - - vn-td.icon-field > vn-icon { - margin-left: 3px; - margin-right: 3px; - } - - vn-table.scrollable.lg { - height: 736px - } - - tbody tr[ng-repeat]:focus { - background-color: $color-primary-light - } - - .highRisk i { - color: $color-alert - } - - td[name="nickname"] { - max-width: 200px - } - - td[name="zone"] { - max-width: 150px - } -} \ No newline at end of file diff --git a/modules/monitor/front/locale/es.yml b/modules/monitor/front/locale/es.yml index 7d7e72f6b..01b26b70c 100644 --- a/modules/monitor/front/locale/es.yml +++ b/modules/monitor/front/locale/es.yml @@ -1 +1,16 @@ -Sales monitor: Monitor de ventas \ No newline at end of file +Tickets monitor: Monitor de tickets +Clients on website: Clientes activos en la web +Recent order actions: Acciones recientes en pedidos +Search tickets: Buscar tickets +Delete selected elements: Eliminar los elementos seleccionados +All the selected elements will be deleted. Are you sure you want to continue?: Todos los elementos seleccionados serán eliminados. ¿Seguro que quieres continuar? +Component lack: Faltan componentes +Ticket too little: Ticket demasiado pequeño +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 +Is fragile: Es frágil \ No newline at end of file diff --git a/modules/monitor/front/main/index.html b/modules/monitor/front/main/index.html index 6e04f06d0..e69de29bb 100644 --- a/modules/monitor/front/main/index.html +++ b/modules/monitor/front/main/index.html @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/modules/monitor/front/main/index.js b/modules/monitor/front/main/index.js index 42fc159d5..3af5292cb 100644 --- a/modules/monitor/front/main/index.js +++ b/modules/monitor/front/main/index.js @@ -1,7 +1,16 @@ import ngModule from '../module'; import ModuleMain from 'salix/components/module-main'; -export default class Monitor extends ModuleMain {} +export default class Monitor extends ModuleMain { + constructor($element, $) { + super($element, $); + } + + async $onInit() { + this.$state.go('home'); + window.location.href = await this.vnApp.getUrl(`monitor/`); + } +} ngModule.vnComponent('vnMonitor', { controller: Monitor, diff --git a/modules/monitor/front/routes.json b/modules/monitor/front/routes.json index acad3ecbc..30da8bcac 100644 --- a/modules/monitor/front/routes.json +++ b/modules/monitor/front/routes.json @@ -1,13 +1,9 @@ { "module": "monitor", "name": "Monitors", - "icon" : "grid_view", - "dependencies": ["ticket", "worker", "client"], - "validations" : true, + "icon": "grid_view", "menus": { - "main": [ - {"state": "monitor.index", "icon": "grid_view"} - ], + "main": [], "card": [] }, "keybindings": [ @@ -23,7 +19,7 @@ "abstract": true, "component": "vn-monitor", "description": "Monitors" - }, + }, { "url": "/index?q", "state": "monitor.index", diff --git a/modules/order/front/basic-data/index.html b/modules/order/front/basic-data/index.html deleted file mode 100644 index 019153b0d..000000000 --- a/modules/order/front/basic-data/index.html +++ /dev/null @@ -1,88 +0,0 @@ - - - - - -
- - - - -
{{::name}}
-
#{{::id}}
-
-
- - {{::nickname}} - -
- - - - - - - - - - -
- - - - - - -
diff --git a/modules/order/front/basic-data/index.js b/modules/order/front/basic-data/index.js deleted file mode 100644 index 16a3cea5e..000000000 --- a/modules/order/front/basic-data/index.js +++ /dev/null @@ -1,57 +0,0 @@ -import ngModule from '../module'; -import Section from 'salix/components/section'; -import './style.scss'; - -class Controller extends Section { - constructor($element, $) { - super($element, $); - let isDirty = false; - this.$.$watch('$ctrl.selection', newValue => { - if (newValue) { - this.$.addressModel.where = {clientFk: newValue.id}; - this.$.addressModel.refresh(); - if (isDirty) - this.order.addressFk = newValue.defaultAddressFk; - isDirty = true; - } else { - this.$.addressModel.clear(); - if (isDirty) - this.order.addressFk = null; - } - }); - } - - set order(value = {}) { - this._order = value; - - const agencyModeFk = value.agencyModeFk; - this.getAvailableAgencies(); - this._order.agencyModeFk = agencyModeFk; - } - - get order() { - return this._order; - } - - getAvailableAgencies() { - const order = this.order; - order.agencyModeFk = null; - - const params = { - addressFk: order.addressFk, - landed: order.landed - }; - if (params.landed && params.addressFk) { - this.$http.get(`Agencies/landsThatDay`, {params}) - .then(res => this._availableAgencies = res.data); - } - } -} - -ngModule.vnComponent('vnOrderBasicData', { - controller: Controller, - template: require('./index.html'), - bindings: { - order: '<' - } -}); diff --git a/modules/order/front/basic-data/index.spec.js b/modules/order/front/basic-data/index.spec.js deleted file mode 100644 index 21dee0765..000000000 --- a/modules/order/front/basic-data/index.spec.js +++ /dev/null @@ -1,67 +0,0 @@ -import './index.js'; - -describe('Order', () => { - describe('Component vnOrderBasicData', () => { - let $httpBackend; - let $httpParamSerializer; - let controller; - let $scope; - - beforeEach(ngModule('order')); - - beforeEach(inject(($compile, _$httpBackend_, $rootScope, _$httpParamSerializer_) => { - $httpBackend = _$httpBackend_; - $httpParamSerializer = _$httpParamSerializer_; - $scope = $rootScope.$new(); - - $httpBackend.whenRoute('GET', 'Addresses') - .respond([{id: 2, nickname: 'address 2'}]); - $httpBackend.whenRoute('GET', 'Clients') - .respond([{id: 1, defaultAddressFk: 1}]); - $scope.order = {clientFk: 1, addressFk: 1}; - - let $element = $compile('')($scope); - $httpBackend.flush(); - controller = $element.controller('vnOrderBasicData'); - })); - - afterAll(() => { - $scope.$destroy(); - $element.remove(); - }); - - describe('constructor()', () => { - it('should update the address after the client changes', async() => { - const addressId = 999; - const id = 444; - - controller.selection = {id: id, defaultAddressFk: addressId}; - $scope.$digest(); - - expect(controller.order.addressFk).toEqual(addressId); - }); - }); - - describe('getAvailableAgencies()', () => { - it('should set agencyModeFk to null and get the available agencies if the order has landed and client', async() => { - controller.order.agencyModeFk = 999; - controller.order.addressFk = 999; - controller.order.landed = Date.vnNew(); - - const expectedAgencies = [{id: 1}, {id: 2}]; - - const paramsObj = { - addressFk: controller.order.addressFk, - landed: controller.order.landed - }; - const serializedParams = $httpParamSerializer(paramsObj); - $httpBackend.expect('GET', `Agencies/landsThatDay?${serializedParams}`).respond(expectedAgencies); - controller.getAvailableAgencies(); - $httpBackend.flush(); - - expect(controller.order.agencyModeFk).toBeDefined(); - expect(controller._availableAgencies).toEqual(expectedAgencies); - }); - }); - }); -}); diff --git a/modules/order/front/basic-data/locale/es.yml b/modules/order/front/basic-data/locale/es.yml deleted file mode 100644 index 5c6014c9c..000000000 --- a/modules/order/front/basic-data/locale/es.yml +++ /dev/null @@ -1 +0,0 @@ -This form has been disabled because there are lines in this order or it's confirmed: Este formulario ha sido deshabilitado por que esta orden contiene líneas o está confirmada \ No newline at end of file diff --git a/modules/order/front/basic-data/style.scss b/modules/order/front/basic-data/style.scss deleted file mode 100644 index 34d6c2931..000000000 --- a/modules/order/front/basic-data/style.scss +++ /dev/null @@ -1,9 +0,0 @@ -vn-order-basic-data { - .disabledForm { - text-align: center; - color: red; - span { - margin: 0 auto; - } - } -} \ No newline at end of file diff --git a/modules/order/front/card/index.html b/modules/order/front/card/index.html deleted file mode 100644 index 4f10c1728..000000000 --- a/modules/order/front/card/index.html +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/modules/order/front/card/index.js b/modules/order/front/card/index.js deleted file mode 100644 index a7e5eeb5d..000000000 --- a/modules/order/front/card/index.js +++ /dev/null @@ -1,58 +0,0 @@ -import ngModule from '../module'; -import ModuleCard from 'salix/components/module-card'; - -class Controller extends ModuleCard { - reload() { - let filter = { - include: [ - { - relation: 'agencyMode', - scope: { - fields: ['name'] - } - }, { - relation: 'address', - scope: { - fields: ['nickname'] - } - }, { - relation: 'rows', - scope: { - fields: ['id'] - } - }, { - relation: 'client', - scope: { - fields: [ - 'salesPersonFk', - 'name', - 'isActive', - 'isFreezed', - 'isTaxDataChecked' - ], - include: { - relation: 'salesPersonUser', - scope: { - fields: ['id', 'name'] - } - } - } - } - ] - }; - - return this.$q.all([ - this.$http.get(`Orders/${this.$params.id}`, {filter}) - .then(res => this.order = res.data), - this.$http.get(`Orders/${this.$params.id}/getTotal`) - .then(res => ({total: res.data})) - ]).then(res => { - this.order = Object.assign.apply(null, res); - }); - } -} - -ngModule.vnComponent('vnOrderCard', { - template: require('./index.html'), - controller: Controller -}); diff --git a/modules/order/front/card/index.spec.js b/modules/order/front/card/index.spec.js deleted file mode 100644 index f0de26b72..000000000 --- a/modules/order/front/card/index.spec.js +++ /dev/null @@ -1,31 +0,0 @@ -import './index.js'; - -describe('Order', () => { - describe('Component vnOrderCard', () => { - let controller; - let $httpBackend; - let data = {id: 1, name: 'fooName'}; - let total = 10.5; - - beforeEach(ngModule('order')); - - beforeEach(inject(($componentController, _$httpBackend_, $stateParams) => { - $httpBackend = _$httpBackend_; - - let $element = angular.element('
'); - controller = $componentController('vnOrderCard', {$element}); - - $stateParams.id = data.id; - $httpBackend.whenRoute('GET', 'Orders/:id').respond(data); - $httpBackend.whenRoute('GET', 'Orders/:id/getTotal').respond(200, total); - })); - - it('should request data and total, merge them, and set it on the controller', () => { - controller.reload(); - $httpBackend.flush(); - - expect(controller.order).toEqual(Object.assign({}, data, {total})); - }); - }); -}); - diff --git a/modules/order/front/catalog-search-panel/index.html b/modules/order/front/catalog-search-panel/index.html deleted file mode 100644 index 42f2e0f50..000000000 --- a/modules/order/front/catalog-search-panel/index.html +++ /dev/null @@ -1,54 +0,0 @@ -
-
- - - - - - - - - - - - - - - - - - - -
-
diff --git a/modules/order/front/catalog-search-panel/index.js b/modules/order/front/catalog-search-panel/index.js deleted file mode 100644 index b84243ca7..000000000 --- a/modules/order/front/catalog-search-panel/index.js +++ /dev/null @@ -1,38 +0,0 @@ -import ngModule from '../module'; -import SearchPanel from 'core/components/searchbar/search-panel'; - -class Controller extends SearchPanel { - constructor($element, $) { - super($element, $); - - this.filter = {}; - } - - get filter() { - return this.$.filter; - } - - set filter(value) { - if (!value) - value = {}; - if (!value.values) - value.values = [{}]; - - this.$.filter = value; - } - - addValue() { - this.filter.values.push({}); - setTimeout(() => this.parentPopover.relocate()); - } -} - -ngModule.vnComponent('vnOrderCatalogSearchPanel', { - template: require('./index.html'), - controller: Controller, - bindings: { - onSubmit: '&?', - parentPopover: ' - -
- -
-
-
-
- -
-
- -

- {{::item.subName}} -

-
- - - - - - -
- - - - - - {{::item.minQuantity}} - - -
-
-
-
- - - - - diff --git a/modules/order/front/catalog-view/index.js b/modules/order/front/catalog-view/index.js deleted file mode 100644 index 6f2cead8f..000000000 --- a/modules/order/front/catalog-view/index.js +++ /dev/null @@ -1,12 +0,0 @@ -import ngModule from '../module'; -import Component from 'core/lib/component'; -import './style.scss'; - -ngModule.vnComponent('vnOrderCatalogView', { - template: require('./index.html'), - controller: Component, - bindings: { - order: '<', - model: '<' - } -}); diff --git a/modules/order/front/catalog-view/locale/es.yml b/modules/order/front/catalog-view/locale/es.yml deleted file mode 100644 index 187dbbc83..000000000 --- a/modules/order/front/catalog-view/locale/es.yml +++ /dev/null @@ -1 +0,0 @@ -Order created: Orden creada \ No newline at end of file diff --git a/modules/order/front/catalog-view/style.scss b/modules/order/front/catalog-view/style.scss deleted file mode 100644 index 1e48745ca..000000000 --- a/modules/order/front/catalog-view/style.scss +++ /dev/null @@ -1,50 +0,0 @@ -@import "variables"; - -vn-order-catalog { - .catalog-header { - border-bottom: $border-thin; - padding: $spacing-md; - align-items: center; - - & > vn-one { - display: flex; - flex: 1; - - span { - color: $color-font-secondary - } - } - & > vn-auto { - width: 448px; - display: flex; - overflow: hidden; - - & > * { - padding-left: $spacing-md; - } - } - } - .catalog-list { - padding-top: $spacing-sm; - } - .item-color-background { - background: linear-gradient($color-bg-panel, $color-main); - border-radius: 50%; - margin-left: 140px; - margin-top: 140px; - width: 40px; - height: 40px; - position: absolute; - } - .item-color { - margin: auto; - margin-top: 5px; - border-radius: 50%; - width: 30px; - height: 30px; - position: relative; - } - .alert { - color: $color-alert; - } -} diff --git a/modules/order/front/catalog/index.html b/modules/order/front/catalog/index.html deleted file mode 100644 index 0f7928c8b..000000000 --- a/modules/order/front/catalog/index.html +++ /dev/null @@ -1,166 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - -
{{name}}
-
- {{categoryName}} -
-
-
-
- - - - - -
- More than {{model.limit}} results -
-
- - - - - - - - - - - - - - - -
- - Id: {{$ctrl.itemId}} - - -
- - Name: - - {{$ctrl.itemName}} -
-
- - {{category.selection.name}} - - - {{type.selection.name}} - - -
- - {{::tagGroup.tagSelection.name}}: - - - , - "{{::tagValue.value}}" - -
-
-
-
diff --git a/modules/order/front/catalog/index.js b/modules/order/front/catalog/index.js deleted file mode 100644 index c0777ebc9..000000000 --- a/modules/order/front/catalog/index.js +++ /dev/null @@ -1,377 +0,0 @@ -import ngModule from '../module'; -import Section from 'salix/components/section'; -import './style.scss'; - -class Controller extends Section { - constructor($element, $) { - super($element, $); - this.itemTypes = []; - this._tagGroups = []; - - // Static autocomplete data - this.orderWays = [ - {way: 'ASC', name: 'Ascendant'}, - {way: 'DESC', name: 'Descendant'}, - ]; - this.defaultOrderFields = [ - {field: 'relevancy DESC, name', name: 'Relevancy', priority: 999}, - {field: 'showOrder, price', name: 'Color and price', priority: 999}, - {field: 'name', name: 'Name', priority: 999}, - {field: 'price', name: 'Price', priority: 999} - ]; - this.orderFields = [].concat(this.defaultOrderFields); - this._orderWay = this.orderWays[0].way; - this.orderField = this.orderFields[0].field; - } - - $onChanges() { - this.getData().then(() => { - if (this.order && this.order.isConfirmed) - this.$state.go('order.card.line'); - }); - } - - getData() { - return this.$http.get(`Orders/${this.$params.id}`) - .then(res => this.order = res.data); - } - - /** - * Fills order autocomplete with tags - * obtained from last filtered - */ - get order() { - return this._order; - } - - /** - * Sets filter values from state params - * - * @param {Object} value - Order data - */ - set order(value) { - this._order = value; - - if (!value) return; - - this.$.$applyAsync(() => { - if (this.$params.categoryId) - this.categoryId = parseInt(this.$params.categoryId); - - if (this.$params.typeId) - this.typeId = parseInt(this.$params.typeId); - - if (this.$params.tagGroups) - this.tagGroups = JSON.parse(this.$params.tagGroups); - }); - } - - get items() { - return this._items; - } - - set items(value) { - this._items = value; - - if (!value) return; - - this.fetchResultTags(value); - this.buildOrderFilter(); - } - - get categoryId() { - return this._categoryId; - } - - set categoryId(value = null) { - this._categoryId = value; - this.itemTypes = []; - this.typeId = null; - - this.updateStateParams(); - - if (this.tagGroups.length > 0) - this.applyFilters(); - - if (value) - this.updateItemTypes(); - } - - changeCategory(id) { - if (this._categoryId == id) id = null; - this.categoryId = id; - } - - get typeId() { - return this._typeId; - } - - set typeId(value) { - this._typeId = value; - - this.updateStateParams(); - - if (value || this.tagGroups.length > 0) - this.applyFilters(); - } - - get tagGroups() { - return this._tagGroups; - } - - set tagGroups(value) { - this._tagGroups = value; - - this.updateStateParams(); - - if (value.length) - this.applyFilters(); - } - - /** - * Get order way ASC/DESC - */ - get orderWay() { - return this._orderWay; - } - - set orderWay(value) { - this._orderWay = value; - if (value) this.applyOrder(); - } - - /** - * Returns the order way selection - */ - get orderSelection() { - return this._orderSelection; - } - - set orderSelection(value) { - this._orderSelection = value; - - if (value) this.applyOrder(); - } - - /** - * Apply order to model - */ - applyOrder() { - if (this.typeId || this.tagGroups.length > 0 || this.itemName) - this.$.model.addFilter(null, {orderBy: this.getOrderBy()}); - } - - /** - * Returns order param - * - * @return {Object} - Order param - */ - getOrderBy() { - const isTag = !!(this.orderSelection && this.orderSelection.isTag); - return { - field: this.orderField, - way: this.orderWay, - isTag: isTag - }; - } - - /** - * Refreshes item type dropdown data - */ - updateItemTypes() { - let params = { - itemCategoryId: this.categoryId - }; - - const query = `Orders/${this.order.id}/getItemTypeAvailable`; - this.$http.get(query, {params}).then(res => - this.itemTypes = res.data); - } - - /** - * Search by tag value - * @param {object} event - */ - onSearchByTag(event) { - const value = this.$.search.value; - if (event.key !== 'Enter' || !value) return; - this.tagGroups.push({values: [{value: value}]}); - this.$.search.value = null; - this.updateStateParams(); - this.applyFilters(); - } - - remove(index) { - this.tagGroups.splice(index, 1); - this.updateStateParams(); - - if (this.tagGroups.length >= 0 || this.itemId || this.typeId) - this.applyFilters(); - } - - removeItemId() { - this.itemId = null; - this.$.searchbar.doSearch({}, 'bar'); - } - - removeItemName() { - this.itemName = null; - this.$.searchbar.doSearch({}, 'bar'); - } - - applyFilters(filter = {}) { - let newParams = {}; - let newFilter = Object.assign({}, filter); - const model = this.$.model; - - if (this.categoryId) - newFilter.categoryFk = this.categoryId; - - if (this.typeId) - newFilter.typeFk = this.typeId; - - newParams = { - orderFk: this.$params.id, - orderBy: this.getOrderBy(), - tagGroups: this.tagGroups, - }; - - return model.applyFilter({where: newFilter}, newParams); - } - - openPanel(event) { - if (event.defaultPrevented) return; - event.preventDefault(); - - this.panelFilter = {}; - this.$.popover.show(this.$.search.element); - } - - onPanelSubmit(filter) { - this.$.popover.hide(); - const values = filter.values; - const nonEmptyValues = values.filter(tagValue => { - return tagValue.value; - }); - - filter.values = nonEmptyValues; - - if (filter.tagFk && nonEmptyValues.length) { - this.tagGroups.push(filter); - this.updateStateParams(); - this.applyFilters(); - } - } - - /** - * Updates url state params from filter values - */ - updateStateParams() { - const params = {}; - - params.categoryId = undefined; - if (this.categoryId) - params.categoryId = this.categoryId; - - params.typeId = undefined; - if (this.typeId) - params.typeId = this.typeId; - - params.tagGroups = undefined; - if (this.tagGroups && this.tagGroups.length) - params.tagGroups = JSON.stringify(this.sanitizedTagGroupParam()); - - this.$state.go(this.$state.current.name, params); - } - - sanitizedTagGroupParam() { - const tagGroups = []; - for (let tagGroup of this.tagGroups) { - const tagParam = {values: []}; - - for (let tagValue of tagGroup.values) - tagParam.values.push({value: tagValue.value}); - - if (tagGroup.tagFk) - tagParam.tagFk = tagGroup.tagFk; - - if (tagGroup.tagSelection) { - tagParam.tagSelection = { - name: tagGroup.tagSelection.name - }; - } - - tagGroups.push(tagParam); - } - - return tagGroups; - } - - fetchResultTags(items) { - const resultTags = []; - for (let item of items) { - for (let itemTag of item.tags) { - const alreadyAdded = resultTags.findIndex(tag => { - return tag.tagFk == itemTag.tagFk; - }); - - if (alreadyAdded == -1) - resultTags.push({...itemTag, priority: 1}); - else - resultTags[alreadyAdded].priority += 1; - } - } - this.resultTags = resultTags; - } - - buildOrderFilter() { - const filter = [].concat(this.defaultOrderFields); - for (let tag of this.resultTags) - filter.push({...tag, field: tag.id, isTag: true}); - - this.orderFields = filter; - } - - onSearch(params) { - if (!params) return; - - this.itemId = null; - this.itemName = null; - - if (params.search) { - if (/^\d+$/.test(params.search)) { - this.itemId = params.search; - return this.applyFilters({ - 'i.id': params.search - }); - } else { - this.itemName = params.search; - return this.applyFilters({ - 'i.name': {like: `%${params.search}%`} - }); - } - } else return this.applyFilters(); - } - - formatTooltip(tagGroup) { - const tagValues = tagGroup.values; - - let title = ''; - if (tagGroup.tagFk) { - const tagName = tagGroup.tagSelection.name; - title += `${tagName}: `; - } - - for (let [i, tagValue] of tagValues.entries()) { - if (i > 0) title += ', '; - title += `"${tagValue.value}"`; - } - - return `${title}`; - } -} - -ngModule.vnComponent('vnOrderCatalog', { - template: require('./index.html'), - controller: Controller -}); diff --git a/modules/order/front/catalog/index.spec.js b/modules/order/front/catalog/index.spec.js deleted file mode 100644 index 03d7c41ba..000000000 --- a/modules/order/front/catalog/index.spec.js +++ /dev/null @@ -1,386 +0,0 @@ -import './index.js'; -import crudModel from 'core/mocks/crud-model'; - -describe('Order', () => { - describe('Component vnOrderCatalog', () => { - let $scope; - let $state; - let controller; - let $httpBackend; - - beforeEach(ngModule('order')); - - beforeEach(inject(($componentController, _$state_, _$httpBackend_, $rootScope) => { - $httpBackend = _$httpBackend_; - $scope = $rootScope.$new(); - $scope.model = crudModel; - $scope.search = {}; - $scope.itemId = {}; - $state = _$state_; - $state.current.name = 'my.current.state'; - const $element = angular.element(''); - controller = $componentController('vnOrderCatalog', {$element, $scope}); - controller._order = {id: 4}; - controller.$params = { - categoryId: 1, - typeId: 2, - id: 4 - }; - })); - - describe('getData()', () => { - it(`should make a query an fetch the order data`, () => { - controller._order = null; - - $httpBackend.expect('GET', `Orders/4`).respond(200, {id: 4, isConfirmed: true}); - $httpBackend.expect('GET', `Orders/4/getItemTypeAvailable?itemCategoryId=1`).respond(); - controller.getData(); - $httpBackend.flush(); - - const order = controller.order; - - expect(order.id).toEqual(4); - expect(order.isConfirmed).toBeTruthy(); - }); - }); - - describe('order() setter', () => { - it(`should call scope $applyAsync() method and apply filters from state params`, () => { - $httpBackend.expect('GET', `Orders/4/getItemTypeAvailable?itemCategoryId=1`).respond(); - controller.order = {id: 4}; - - $scope.$apply(); - - expect(controller.categoryId).toEqual(1); - expect(controller.typeId).toEqual(2); - }); - }); - - describe('items() setter', () => { - it(`should return an object with order params`, () => { - jest.spyOn(controller, 'fetchResultTags'); - jest.spyOn(controller, 'buildOrderFilter'); - - const expectedResult = [{field: 'showOrder, price', name: 'Color and price', priority: 999}]; - const items = [{id: 1, name: 'My Item', tags: [ - {tagFk: 4, name: 'Length'}, - {tagFk: 5, name: 'Color'} - ]}]; - controller.items = items; - - expect(controller.orderFields.length).toEqual(6); - expect(controller.orderFields).toEqual(jasmine.arrayContaining(expectedResult)); - expect(controller.fetchResultTags).toHaveBeenCalledWith(items); - expect(controller.buildOrderFilter).toHaveBeenCalledWith(); - }); - }); - - describe('categoryId() setter', () => { - it(`should set category property to null, call updateStateParams() method and not call applyFilters()`, () => { - jest.spyOn(controller, 'updateStateParams'); - - controller.categoryId = null; - - expect(controller.updateStateParams).toHaveBeenCalledWith(); - }); - - it(`should set category property and then call updateStateParams() and applyFilters() methods`, () => { - jest.spyOn(controller, 'updateStateParams'); - - controller.categoryId = 2; - - expect(controller.updateStateParams).toHaveBeenCalledWith(); - }); - }); - - describe('changeCategory()', () => { - it(`should set categoryId property to null if the new value equals to the old one`, () => { - controller.categoryId = 2; - controller.changeCategory(2); - - expect(controller.categoryId).toBeNull(); - }); - - it(`should set categoryId property`, () => { - controller.categoryId = 2; - controller.changeCategory(1); - - expect(controller.categoryId).toEqual(1); - }); - }); - - describe('typeId() setter', () => { - it(`should set type property to null, call updateStateParams() method and not call applyFilters()`, () => { - jest.spyOn(controller, 'updateStateParams'); - jest.spyOn(controller, 'applyFilters'); - - controller.typeId = null; - - expect(controller.updateStateParams).toHaveBeenCalledWith(); - expect(controller.applyFilters).not.toHaveBeenCalledWith(); - }); - - it(`should set category property and then call updateStateParams() and applyFilters() methods`, () => { - jest.spyOn(controller, 'updateStateParams'); - jest.spyOn(controller, 'applyFilters'); - - controller.typeId = 2; - - expect(controller.updateStateParams).toHaveBeenCalledWith(); - expect(controller.applyFilters).toHaveBeenCalledWith(); - }); - }); - - describe('tagGroups() setter', () => { - it(`should set tagGroups property and then call updateStateParams() and applyFilters() methods`, () => { - jest.spyOn(controller, 'updateStateParams'); - jest.spyOn(controller, 'applyFilters'); - - controller.tagGroups = [{tagFk: 11, values: [{value: 'Brown'}]}]; - - expect(controller.updateStateParams).toHaveBeenCalledWith(); - expect(controller.applyFilters).toHaveBeenCalledWith(); - }); - }); - - describe('onSearchByTag()', () => { - it(`should not add a new tag if the event key code doesn't equals to 'Enter'`, () => { - jest.spyOn(controller, 'applyFilters'); - - controller.order = {id: 4}; - controller.$.search.value = 'Brown'; - controller.onSearchByTag({key: 'Tab'}); - - expect(controller.applyFilters).not.toHaveBeenCalledWith(); - }); - - it(`should add a new tag if the event key code equals to 'Enter' an then call applyFilters()`, () => { - jest.spyOn(controller, 'applyFilters'); - - controller.order = {id: 4}; - controller.$.search.value = 'Brown'; - controller.onSearchByTag({key: 'Enter'}); - - expect(controller.applyFilters).toHaveBeenCalledWith(); - }); - }); - - describe('onSearch()', () => { - it(`should apply a filter by item id an then call the applyFilters method`, () => { - jest.spyOn(controller, 'applyFilters'); - - const itemId = 1; - controller.onSearch({search: itemId}); - - expect(controller.applyFilters).toHaveBeenCalledWith({ - 'i.id': itemId - }); - }); - - it(`should apply a filter by item name an then call the applyFilters method`, () => { - jest.spyOn(controller, 'applyFilters'); - - const itemName = 'Bow'; - controller.onSearch({search: itemName}); - - expect(controller.applyFilters).toHaveBeenCalledWith({ - 'i.name': {like: `%${itemName}%`} - }); - }); - }); - - describe('applyFilters()', () => { - it(`should call model applyFilter() method with a new filter`, () => { - jest.spyOn(controller.$.model, 'applyFilter'); - - controller._categoryId = 2; - controller._typeId = 4; - - controller.applyFilters(); - - expect(controller.$.model.applyFilter).toHaveBeenCalledWith( - {where: {categoryFk: 2, typeFk: 4}}, - {orderFk: 4, orderBy: controller.getOrderBy(), tagGroups: []}); - }); - }); - - describe('remove()', () => { - it(`should remove a tag from tags property`, () => { - jest.spyOn(controller, 'applyFilters'); - - controller.tagGroups = [ - {tagFk: 1, values: [{value: 'Brown'}]}, - {tagFk: 67, values: [{value: 'Concussion'}]} - ]; - controller.remove(0); - - const firstTag = controller.tagGroups[0]; - - expect(controller.tagGroups.length).toEqual(1); - expect(firstTag.tagFk).toEqual(67); - expect(controller.applyFilters).toHaveBeenCalledWith(); - }); - - it(`should remove a tag from tags property and call applyFilters() if there's no more tags`, () => { - jest.spyOn(controller, 'applyFilters'); - - controller._categoryId = 1; - controller._typeId = 1; - controller.tagGroups = [{tagFk: 1, values: [{value: 'Blue'}]}]; - controller.remove(0); - - expect(controller.tagGroups.length).toEqual(0); - expect(controller.applyFilters).toHaveBeenCalledWith(); - }); - }); - - describe('updateStateParams()', () => { - it(`should call state go() method passing category and type state params`, () => { - jest.spyOn(controller.$state, 'go'); - - controller._categoryId = 2; - controller._typeId = 4; - controller._tagGroups = [ - {tagFk: 67, values: [{value: 'Concussion'}], tagSelection: {name: 'Category'}} - ]; - const tagGroups = JSON.stringify([ - {values: [{value: 'Concussion'}], tagFk: 67, tagSelection: {name: 'Category'}} - ]); - const expectedResult = {categoryId: 2, typeId: 4, tagGroups: tagGroups}; - controller.updateStateParams(); - - expect(controller.$state.go).toHaveBeenCalledWith('my.current.state', expectedResult); - }); - }); - - describe('getOrderBy()', () => { - it(`should return an object with order params`, () => { - controller.orderField = 'relevancy DESC, name'; - controller.orderWay = 'DESC'; - let expectedResult = { - field: 'relevancy DESC, name', - way: 'DESC', - isTag: false - }; - let result = controller.getOrderBy(); - - expect(result).toEqual(expectedResult); - }); - }); - - describe('applyOrder()', () => { - it(`should apply order param to model calling getOrderBy()`, () => { - jest.spyOn(controller, 'getOrderBy'); - jest.spyOn(controller.$.model, 'addFilter'); - - controller.field = 'relevancy DESC, name'; - controller.way = 'ASC'; - controller._categoryId = 1; - controller._typeId = 1; - let expectedOrder = {orderBy: controller.getOrderBy()}; - - controller.applyOrder(); - - expect(controller.getOrderBy).toHaveBeenCalledWith(); - expect(controller.$.model.addFilter).toHaveBeenCalledWith(null, expectedOrder); - }); - }); - - describe('fetchResultTags()', () => { - it(`should create an array of non repeated tags then set the resultTags property`, () => { - const items = [ - { - id: 1, name: 'My Item 1', tags: [ - {tagFk: 4, name: 'Length', value: 1}, - {tagFk: 5, name: 'Color', value: 'red'} - ] - }, - { - id: 2, name: 'My Item 2', tags: [ - {tagFk: 4, name: 'Length', value: 1}, - {tagFk: 5, name: 'Color', value: 'blue'} - ] - }]; - controller.fetchResultTags(items); - - expect(controller.resultTags.length).toEqual(2); - }); - }); - - describe('buildOrderFilter()', () => { - it(`should create an array of non repeated tags plus default filters and then set the orderFields property`, () => { - const items = [ - { - id: 1, name: 'My Item 1', tags: [ - {tagFk: 4, name: 'Length'}, - {tagFk: 5, name: 'Color'} - ] - }, - { - id: 2, name: 'My Item 2', tags: [ - {tagFk: 5, name: 'Color'}, - {tagFk: 6, name: 'Relevancy'} - ] - }]; - - controller.fetchResultTags(items); - controller.buildOrderFilter(); - - expect(controller.orderFields.length).toEqual(7); - }); - }); - - describe('formatTooltip()', () => { - it(`should return a formatted text with the tag name and values`, () => { - const tagGroup = { - values: [{value: 'Silver'}, {value: 'Brown'}], - tagFk: 1, - tagSelection: { - name: 'Color' - } - }; - - const result = controller.formatTooltip(tagGroup); - - expect(result).toEqual(`Color: "Silver", "Brown"`); - }); - - it(`should return a formatted text with the tag value`, () => { - const tagGroup = { - values: [{value: 'Silver'}] - }; - - const result = controller.formatTooltip(tagGroup); - - expect(result).toEqual(`"Silver"`); - }); - }); - - describe('sanitizedTagGroupParam()', () => { - it(`should return an array of tags`, () => { - const dirtyTagGroups = [{ - values: [{value: 'Silver'}, {value: 'Brown'}], - tagFk: 1, - tagSelection: { - name: 'Color', - $orgRow: {name: 'Color'} - }, - $orgIndex: 1 - }]; - controller.tagGroups = dirtyTagGroups; - - const expectedResult = [{ - values: [{value: 'Silver'}, {value: 'Brown'}], - tagFk: 1, - tagSelection: { - name: 'Color' - } - }]; - const result = controller.sanitizedTagGroupParam(); - - expect(result).toEqual(expect.objectContaining(expectedResult)); - }); - }); - }); -}); - diff --git a/modules/order/front/catalog/locale/es.yml b/modules/order/front/catalog/locale/es.yml deleted file mode 100644 index fc78755ae..000000000 --- a/modules/order/front/catalog/locale/es.yml +++ /dev/null @@ -1,3 +0,0 @@ -Name: Nombre -Search by item id or name: Buscar por id de artículo o nombre -OR: O \ No newline at end of file diff --git a/modules/order/front/catalog/style.scss b/modules/order/front/catalog/style.scss deleted file mode 100644 index 9ffe81dfb..000000000 --- a/modules/order/front/catalog/style.scss +++ /dev/null @@ -1,54 +0,0 @@ -@import "variables"; - -vn-order-catalog vn-side-menu div { - & > .input { - padding-left: $spacing-md; - padding-right: $spacing-md; - border-color: $color-spacer; - border-bottom: $border-thin; - } - .item-category { - padding: $spacing-sm; - justify-content: flex-start; - align-items: flex-start; - flex-wrap: wrap; - - vn-autocomplete[vn-id="category"] { - display: none - } - - & > vn-one { - padding: $spacing-sm; - min-width: 33.33%; - text-align: center; - box-sizing: border-box; - - & > vn-icon { - padding: $spacing-sm; - background-color: $color-font-secondary; - border-radius: 50%; - cursor: pointer; - - &.active { - background-color: $color-main; - color: #FFF - } - & > i:before { - font-size: 2.6rem; - width: 16px; - height: 16px; - } - } - } - } - .chips { - display: flex; - flex-wrap: wrap; - padding: $spacing-md; - overflow: hidden; - max-width: 100%; - } - vn-autocomplete[vn-id="type"] .list { - max-height: 320px - } -} \ No newline at end of file diff --git a/modules/order/front/create/card.html b/modules/order/front/create/card.html deleted file mode 100644 index ed6f752d3..000000000 --- a/modules/order/front/create/card.html +++ /dev/null @@ -1,38 +0,0 @@ - - {{id}}: {{name}} - - - {{nickname}}: {{street}}, {{city}} - - - - - diff --git a/modules/order/front/create/card.js b/modules/order/front/create/card.js deleted file mode 100644 index 315cc8255..000000000 --- a/modules/order/front/create/card.js +++ /dev/null @@ -1,114 +0,0 @@ -import ngModule from '../module'; -import Component from 'core/lib/component'; - -class Controller extends Component { - constructor($element, $) { - super($element, $); - this.order = {}; - this.clientFk = this.$params.clientFk; - } - - $onInit() { - if (this.$params && this.$params.clientFk) - this.clientFk = this.$params.clientFk; - } - - set order(value) { - if (value) - this._order = value; - } - - get order() { - return this._order; - } - - set clientFk(value) { - this.order.clientFk = value; - - if (value) { - let filter = { - include: { - relation: 'defaultAddress', - scope: { - fields: 'id' - } - }, - where: {id: value} - }; - filter = encodeURIComponent(JSON.stringify(filter)); - let query = `Clients?filter=${filter}`; - this.$http.get(query).then(res => { - if (res.data) { - let client = res.data[0]; - let defaultAddress = client.defaultAddress; - this.addressFk = defaultAddress.id; - } - }); - } else - this.addressFk = null; - } - - get clientFk() { - return this.order.clientFk; - } - - set addressFk(value) { - this.order.addressFk = value; - this.getAvailableAgencies(); - } - - get addressFk() { - return this.order.addressFk; - } - - set landed(value) { - this.order.landed = value; - this.getAvailableAgencies(); - } - - get landed() { - return this.order.landed; - } - - get warehouseFk() { - return this.order.warehouseFk; - } - - getAvailableAgencies() { - let order = this.order; - order.agencyModeFk = null; - - let params = { - addressFk: order.addressFk, - landed: order.landed - }; - if (params.landed && params.addressFk) { - this.$http.get(`Agencies/landsThatDay`, {params}) - .then(res => this._availableAgencies = res.data); - } - } - - onSubmit() { - this.createOrder(); - } - - createOrder() { - let params = { - landed: this.order.landed, - addressId: this.order.addressFk, - agencyModeId: this.order.agencyModeFk - }; - this.$http.post(`Orders/new`, params).then(res => { - this.vnApp.showSuccess(this.$t('Data saved!')); - this.$state.go('order.card.catalog', {id: res.data}); - }); - } -} - -ngModule.vnComponent('vnOrderCreateCard', { - template: require('./card.html'), - controller: Controller, - bindings: { - order: ' { - describe('Component vnOrderCreateCard', () => { - let controller; - let $httpBackend; - let $scope; - - beforeEach(ngModule('order')); - - beforeEach(inject(($componentController, _$httpBackend_, _vnApp_, $rootScope) => { - $httpBackend = _$httpBackend_; - $scope = $rootScope.$new(); - const $element = angular.element(''); - controller = $componentController('vnOrderCreateCard', {$element, $scope}); - controller.item = {id: 3}; - })); - - describe('set order', () => { - it(`should set order if the value given is not null`, () => { - controller.order = 1; - - expect(controller.order).toEqual(1); - }); - }); - - describe('set clientFk', () => { - it(`should set addressFk to null and clientFk to a value and set addressFk to a value given`, () => { - let filter = { - include: { - relation: 'defaultAddress', - scope: { - fields: 'id' - } - }, - where: {id: 2} - }; - filter = encodeURIComponent(JSON.stringify(filter)); - let response = [ - { - defaultAddress: {id: 1} - } - ]; - $httpBackend.whenGET(`Clients?filter=${filter}`).respond(response); - $httpBackend.expectGET(`Clients?filter=${filter}`); - - controller.clientFk = 2; - $httpBackend.flush(); - - expect(controller.clientFk).toEqual(2); - expect(controller.order.addressFk).toBe(1); - }); - }); - - describe('set addressFk', () => { - it(`should set agencyModeFk property to null and addressFk to a value`, () => { - controller.addressFk = 1101; - - expect(controller.addressFk).toEqual(1101); - expect(controller.order.agencyModeFk).toBe(null); - }); - }); - - describe('getAvailableAgencies()', () => { - it(`should make a query if landed and addressFk exists`, () => { - controller.order.addressFk = 1101; - controller.order.landed = 1101; - - $httpBackend.whenRoute('GET', 'Agencies/landsThatDay') - .respond({data: 1}); - - controller.getAvailableAgencies(); - $httpBackend.flush(); - }); - }); - - describe('onSubmit()', () => { - it(`should call createOrder()`, () => { - jest.spyOn(controller, 'createOrder'); - controller.onSubmit(); - - expect(controller.createOrder).toHaveBeenCalledWith(); - }); - }); - - describe('createOrder()', () => { - it(`should make a query, call vnApp.showSuccess and $state.go if the response is defined`, () => { - controller.order.landed = 1101; - controller.order.addressFk = 1101; - controller.order.agencyModeFk = 1101; - - jest.spyOn(controller.vnApp, 'showSuccess'); - jest.spyOn(controller.$state, 'go'); - $httpBackend.expect('POST', 'Orders/new', {landed: 1101, addressId: 1101, agencyModeId: 1101}).respond(200, 1); - controller.createOrder(); - $httpBackend.flush(); - - expect(controller.vnApp.showSuccess).toHaveBeenCalled(); - expect(controller.$state.go).toHaveBeenCalledWith('order.card.catalog', {id: 1}); - }); - }); - }); -}); - diff --git a/modules/order/front/create/index.html b/modules/order/front/create/index.html deleted file mode 100644 index 86df579a6..000000000 --- a/modules/order/front/create/index.html +++ /dev/null @@ -1,16 +0,0 @@ -
- - - - - - - - - -
\ No newline at end of file diff --git a/modules/order/front/create/index.js b/modules/order/front/create/index.js deleted file mode 100644 index 317c4e27e..000000000 --- a/modules/order/front/create/index.js +++ /dev/null @@ -1,14 +0,0 @@ -import ngModule from '../module'; -import Section from 'salix/components/section'; - -class Controller extends Section { - async onSubmit() { - let newOrderID = await this.$.card.createOrder(); - this.$state.go('order.card.summary', {id: newOrderID}); - } -} - -ngModule.vnComponent('vnOrderCreate', { - template: require('./index.html'), - controller: Controller -}); diff --git a/modules/order/front/create/index.spec.js b/modules/order/front/create/index.spec.js deleted file mode 100644 index af8c8f974..000000000 --- a/modules/order/front/create/index.spec.js +++ /dev/null @@ -1,34 +0,0 @@ -import './index.js'; - -describe('Order', () => { - describe('Component vnOrderCreate', () => { - let $scope; - let controller; - - beforeEach(ngModule('order')); - - beforeEach(inject(($componentController, $rootScope) => { - $scope = $rootScope.$new(); - $scope.card = {createOrder: () => {}}; - const $element = angular.element(''); - controller = $componentController('vnOrderCreate', {$element, $scope}); - })); - - describe('onSubmit()', () => { - it(`should call createOrder()`, () => { - jest.spyOn(controller.$.card, 'createOrder'); - controller.onSubmit(); - - expect(controller.$.card.createOrder).toHaveBeenCalledWith(); - }); - - it(`should call go()`, async() => { - jest.spyOn(controller.$state, 'go'); - await controller.onSubmit(); - - expect(controller.$state.go).toHaveBeenCalledWith('order.card.summary', {id: undefined}); - }); - }); - }); -}); - diff --git a/modules/order/front/create/locale/es.yml b/modules/order/front/create/locale/es.yml deleted file mode 100644 index 49cd64c4a..000000000 --- a/modules/order/front/create/locale/es.yml +++ /dev/null @@ -1,6 +0,0 @@ -You can't create an order for a frozen client: No puedes crear una orden a un cliente congelado -You can't create an order for an inactive client: No puedes crear una orden a un cliente inactivo -You can't create an order for a client that doesn't has tax data verified: - No puedes crear una orden a un cliente cuyos datos fiscales no han sido verificados -You can't create an order for a client that has a debt: No puedes crear una orden a un cliente que tiene deuda -New order: Nueva orden \ No newline at end of file diff --git a/modules/order/front/descriptor/index.html b/modules/order/front/descriptor/index.html deleted file mode 100644 index 538789027..000000000 --- a/modules/order/front/descriptor/index.html +++ /dev/null @@ -1,78 +0,0 @@ - - - - Delete order - - - -
- - - - - {{$ctrl.order.client.salesPersonUser.name}} - - - - - - - - - - - - -
- -
-
- - - - - - - \ No newline at end of file diff --git a/modules/order/front/descriptor/index.js b/modules/order/front/descriptor/index.js deleted file mode 100644 index 5d22dd721..000000000 --- a/modules/order/front/descriptor/index.js +++ /dev/null @@ -1,32 +0,0 @@ -import ngModule from '../module'; -import Descriptor from 'salix/components/descriptor'; - -class Controller extends Descriptor { - get order() { - return this.entity; - } - - set order(value) { - this.entity = value; - } - - get ticketFilter() { - return JSON.stringify({orderFk: this.id}); - } - - deleteOrder() { - return this.$http.delete(`Orders/${this.id}`) - .then(() => { - this.$state.go('order.index'); - this.vnApp.showSuccess(this.$t('Order deleted')); - }); - } -} - -ngModule.vnComponent('vnOrderDescriptor', { - template: require('./index.html'), - controller: Controller, - bindings: { - order: '<' - } -}); diff --git a/modules/order/front/descriptor/index.spec.js b/modules/order/front/descriptor/index.spec.js deleted file mode 100644 index e6147faee..000000000 --- a/modules/order/front/descriptor/index.spec.js +++ /dev/null @@ -1,29 +0,0 @@ -import './index.js'; - -describe('Order Component vnOrderDescriptor', () => { - let $httpBackend; - let controller; - const order = {id: 1}; - - beforeEach(ngModule('order')); - - beforeEach(inject(($componentController, _$httpBackend_) => { - $httpBackend = _$httpBackend_; - controller = $componentController('vnOrderDescriptor', {$element: null}, {order}); - })); - - describe('deleteOrder()', () => { - it(`should perform a DELETE query`, () => { - jest.spyOn(controller.vnApp, 'showSuccess'); - jest.spyOn(controller.$state, 'go'); - - $httpBackend.expectDELETE(`Orders/${order.id}`).respond(); - controller.deleteOrder(); - $httpBackend.flush(); - - expect(controller.vnApp.showSuccess).toHaveBeenCalled(); - expect(controller.$state.go).toHaveBeenCalledWith('order.index'); - }); - }); -}); - diff --git a/modules/order/front/descriptor/locale/es.yml b/modules/order/front/descriptor/locale/es.yml deleted file mode 100644 index 0734d7638..000000000 --- a/modules/order/front/descriptor/locale/es.yml +++ /dev/null @@ -1,12 +0,0 @@ -Client: Cliente -Confirmed: Confirmado -Not confirmed: Sin confirmar -State: Estado -Landed: F. entrega -Items: Articulos -Agency: Agencia -Sales person: Comercial -Order ticket list: Ticket del pedido -Delete order: Eliminar pedido -You are going to delete this order: El pedido se eliminará -continue anyway?: ¿Continuar de todos modos? \ No newline at end of file diff --git a/modules/order/front/index.js b/modules/order/front/index.js index 4d5b5615e..a7209a0bd 100644 --- a/modules/order/front/index.js +++ b/modules/order/front/index.js @@ -1,17 +1,3 @@ export * from './module'; import './main'; -import './index/'; -import './card'; -import './descriptor'; -import './search-panel'; -import './catalog-search-panel'; -import './catalog-view'; -import './catalog'; -import './summary'; -import './line'; -import './prices-popover'; -import './volume'; -import './create'; -import './create/card'; -import './basic-data'; diff --git a/modules/order/front/index/index.html b/modules/order/front/index/index.html deleted file mode 100644 index c4bed7307..000000000 --- a/modules/order/front/index/index.html +++ /dev/null @@ -1,90 +0,0 @@ - - - - - - - - - Id - Sales person - Client - Confirmed - Created - Landed - Hour - Agency - Total - - - - - {{::order.id}} - - - {{::order.name | dashIfEmpty}} - - - - - {{::order.clientName}} - - - - - - - {{::order.created | date: 'dd/MM/yyyy HH:mm'}} - - - {{::order.landed | date:'dd/MM/yyyy'}} - - - {{::(order.hourTheoretical - ? order.hourTheoretical - : order.hourEffective) | dashIfEmpty - }} - {{::order.agencyName}} - {{::order.total | currency: 'EUR': 2 | dashIfEmpty}} - - - - - - - - - - - - - - - - - - - - diff --git a/modules/order/front/index/index.js b/modules/order/front/index/index.js deleted file mode 100644 index 750f2e226..000000000 --- a/modules/order/front/index/index.js +++ /dev/null @@ -1,26 +0,0 @@ -import ngModule from '../module'; -import Section from 'salix/components/section'; - -export default class Controller extends Section { - preview(order) { - this.selectedOrder = order; - this.$.summary.show(); - } - - compareDate(date) { - let today = Date.vnNew(); - today.setHours(0, 0, 0, 0); - - date = new Date(date); - date.setHours(0, 0, 0, 0); - - const timeDifference = today - date; - if (timeDifference == 0) return 'warning'; - if (timeDifference < 0) return 'success'; - } -} - -ngModule.vnComponent('vnOrderIndex', { - template: require('./index.html'), - controller: Controller -}); diff --git a/modules/order/front/index/index.spec.js b/modules/order/front/index/index.spec.js deleted file mode 100644 index abe336478..000000000 --- a/modules/order/front/index/index.spec.js +++ /dev/null @@ -1,67 +0,0 @@ -import './index.js'; -describe('Component vnOrderIndex', () => { - let controller; - let $window; - let orders = [{ - id: 1, - clientFk: 1, - isConfirmed: false - }, { - id: 2, - clientFk: 1, - isConfirmed: false - }, { - id: 3, - clientFk: 1, - isConfirmed: true - }]; - - beforeEach(ngModule('order')); - - beforeEach(inject(($componentController, _$window_) => { - $window = _$window_; - const $element = angular.element(''); - controller = $componentController('vnOrderIndex', {$element}); - })); - - describe('compareDate()', () => { - it('should return warning when the date is the present', () => { - let curDate = Date.vnNew(); - let result = controller.compareDate(curDate); - - expect(result).toEqual('warning'); - }); - - it('should return sucess when the date is in the future', () => { - let futureDate = Date.vnNew(); - futureDate = futureDate.setDate(futureDate.getDate() + 10); - let result = controller.compareDate(futureDate); - - expect(result).toEqual('success'); - }); - - it('should return undefined when the date is in the past', () => { - let pastDate = Date.vnNew(); - pastDate = pastDate.setDate(pastDate.getDate() - 10); - let result = controller.compareDate(pastDate); - - expect(result).toEqual(undefined); - }); - }); - - describe('preview()', () => { - it('should show the dialog summary', () => { - controller.$.summary = {show: () => {}}; - jest.spyOn(controller.$.summary, 'show'); - - let event = new MouseEvent('click', { - view: $window, - bubbles: true, - cancelable: true - }); - controller.preview(event, orders[0]); - - expect(controller.$.summary.show).toHaveBeenCalledWith(); - }); - }); -}); diff --git a/modules/order/front/line/index.html b/modules/order/front/line/index.html deleted file mode 100644 index 7be5a00af..000000000 --- a/modules/order/front/line/index.html +++ /dev/null @@ -1,96 +0,0 @@ - - -
- Subtotal - {{$ctrl.subtotal | currency: 'EUR':2}} -
-
- VAT - {{$ctrl.VAT | currency: 'EUR':2}} -
-
- Total - {{$ctrl.order.total | currency: 'EUR':2}} -
-
- - - - - - Id - Description - Warehouse - Shipped - Quantity - Price - Amount - - - - - - - - - - - {{::row.itemFk}} - - - -
- {{::row.item.name}} - -

{{::row.item.subName}}

-
-
- - -
- {{::row.warehouse.name}} - {{::row.shipped | date: 'dd/MM/yyyy'}} - {{::row.quantity}} - - {{::row.price | currency: 'EUR':2}} - - - {{::row.price * row.quantity | currency: 'EUR':2}} - - - - - -
-
-
-
-
- - - - - - \ No newline at end of file diff --git a/modules/order/front/line/index.js b/modules/order/front/line/index.js deleted file mode 100644 index 94d1fbfbf..000000000 --- a/modules/order/front/line/index.js +++ /dev/null @@ -1,70 +0,0 @@ -import ngModule from '../module'; -import Section from 'salix/components/section'; -import './style.scss'; - -class Controller extends Section { - $onInit() { - this.getRows(); - } - - set order(value) { - this._order = value; - this.getVAT(); - } - - get order() { - return this._order; - } - - get subtotal() { - return this.order ? this.order.total - this.VAT : 0; - } - - getRows() { - let filter = { - where: {orderFk: this.$params.id}, - include: [ - {relation: 'item'}, - {relation: 'warehouse'} - ] - }; - this.$http.get(`OrderRows`, {filter}) - .then(res => this.rows = res.data); - } - - getVAT() { - this.$http.get(`Orders/${this.$params.id}/getVAT`) - .then(res => this.VAT = res.data); - } - - deleteRow(index) { - let [row] = this.rows.splice(index, 1); - let params = { - rows: [row.id], - actualOrderId: this.$params.id - }; - return this.$http.post(`OrderRows/removes`, params) - .then(() => this.card.reload()) - .then(() => this.vnApp.showSuccess(this.$t('Data saved!'))); - } - - save() { - this.$http.post(`Orders/${this.$params.id}/confirm`).then(() => { - this.vnApp.showSuccess(this.$t('Order confirmed')); - this.$state.go(`ticket.index`, { - q: JSON.stringify({clientFk: this.order.clientFk}) - }); - }); - } -} - -ngModule.vnComponent('vnOrderLine', { - template: require('./index.html'), - controller: Controller, - bindings: { - order: '<' - }, - require: { - card: '^vnOrderCard' - } -}); diff --git a/modules/order/front/line/index.spec.js b/modules/order/front/line/index.spec.js deleted file mode 100644 index ad0e1edbc..000000000 --- a/modules/order/front/line/index.spec.js +++ /dev/null @@ -1,66 +0,0 @@ -import './index.js'; - -describe('Order', () => { - describe('Component vnOrderLine', () => { - let $state; - let controller; - let $httpBackend; - - const vat = 10.5; - const rows = [ - { - quantity: 4, - price: 10.5 - }, { - quantity: 3, - price: 2.4 - } - ]; - - beforeEach(ngModule('order')); - - beforeEach(inject(($componentController, _$state_, _$httpBackend_) => { - $state = _$state_; - $httpBackend = _$httpBackend_; - - $state.params.id = 1; - $httpBackend.whenGET(`OrderRows`).respond(rows); - $httpBackend.whenRoute('GET', `Orders/:id/getVAT`).respond(200, vat); - - controller = $componentController('vnOrderLine', {$element: null}); - })); - - describe('getRows()', () => { - it('should make a query to get the rows of a given order', () => { - controller.getRows(); - $httpBackend.flush(); - - expect(controller.rows).toEqual(rows); - }); - }); - - describe('getVAT()', () => { - it('should make a query to get the VAT of a given order', () => { - controller.getVAT(); - $httpBackend.flush(); - - expect(controller.VAT).toBe(vat); - }); - }); - - describe('deleteRow()', () => { - it('should remove a row from rows and add save the data if the response is accept', () => { - controller.getRows(); - $httpBackend.flush(); - - controller.card = {reload: jasmine.createSpy('reload')}; - $httpBackend.expectPOST(`OrderRows/removes`).respond(); - controller.deleteRow(0); - $httpBackend.flush(); - - expect(controller.rows.length).toBe(1); - expect(controller.card.reload).toHaveBeenCalled(); - }); - }); - }); -}); diff --git a/modules/order/front/line/locale/es.yml b/modules/order/front/line/locale/es.yml deleted file mode 100644 index d1368d369..000000000 --- a/modules/order/front/line/locale/es.yml +++ /dev/null @@ -1,3 +0,0 @@ -Delete row: Eliminar linea -Order confirmed: Pedido confirmado -Are you sure you want to delete this row?: ¿Estas seguro de que quieres eliminar esta línea? \ No newline at end of file diff --git a/modules/order/front/line/style.scss b/modules/order/front/line/style.scss deleted file mode 100644 index 4da941a2c..000000000 --- a/modules/order/front/line/style.scss +++ /dev/null @@ -1,18 +0,0 @@ -@import "./variables"; - -vn-order-line { - vn-table { - img { - border-radius: 50%; - width: 50px; - height: 50px; - } - } - .header { - text-align: right; - - & > div { - margin-bottom: $spacing-xs; - } - } -} \ No newline at end of file diff --git a/modules/order/front/main/index.js b/modules/order/front/main/index.js index caf819c9d..61b0201fd 100644 --- a/modules/order/front/main/index.js +++ b/modules/order/front/main/index.js @@ -2,8 +2,12 @@ import ngModule from '../module'; import ModuleMain from 'salix/components/module-main'; export default class Order extends ModuleMain { - $postLink() { - this.filter = {showEmpty: false}; + constructor($element, $) { + super($element, $); + } + async $onInit() { + this.$state.go('home'); + window.location.href = await this.vnApp.getUrl(`order/`); } } diff --git a/modules/order/front/prices-popover/index.html b/modules/order/front/prices-popover/index.html deleted file mode 100644 index 2551853e6..000000000 --- a/modules/order/front/prices-popover/index.html +++ /dev/null @@ -1,52 +0,0 @@ - -
- - - - - - {{::price.warehouse}} - - - -
- {{::price.grouping}} - x {{::price.price | currency: 'EUR': 2}} -
-
- {{::price.priceKg | currency: 'EUR'}}/Kg -
-
- - - - - - - -
-
-
- -
-
diff --git a/modules/order/front/prices-popover/index.js b/modules/order/front/prices-popover/index.js deleted file mode 100644 index aa5570f59..000000000 --- a/modules/order/front/prices-popover/index.js +++ /dev/null @@ -1,115 +0,0 @@ -import ngModule from '../module'; -import Popover from 'core/components/popover'; -import './style.scss'; - -class Controller extends Popover { - constructor(...args) { - super(...args); - this.totalBasquet = 0; - } - - set prices(value) { - this._prices = value; - if (value && value[0].grouping) - this.getTotalQuantity(); - } - - get prices() { - return this._prices; - } - - show(parent, item) { - this.id = item.id; - this.item = JSON.parse(JSON.stringify(item)); - this.maxQuantity = this.item.available; - this.prices = this.item.prices; - - super.show(parent); - } - - onClose() { - this.id = null; - this.item = {}; - this.tags = {}; - this._prices = {}; - this.totalQuantity = 0; - super.onClose(); - } - - getTotalQuantity() { - let total = 0; - for (let price of this.prices) { - if (!price.quantity) price.quantity = 0; - total += price.quantity; - } - - this.totalQuantity = total; - } - - addQuantity(price) { - this.getTotalQuantity(); - const quantity = this.totalQuantity + price.grouping; - if (quantity <= this.maxQuantity) - price.quantity += price.grouping; - } - - getGroupings() { - const filledRows = []; - for (let priceOption of this.prices) { - if (priceOption.quantity && priceOption.quantity > 0) { - const priceMatch = filledRows.find(row => { - return row.warehouseFk == priceOption.warehouseFk - && row.price == priceOption.price; - }); - - if (!priceMatch) - filledRows.push(Object.assign({}, priceOption)); - else priceMatch.quantity += priceOption.quantity; - } - } - - return filledRows; - } - - submit() { - const filledRows = this.getGroupings(); - - try { - const hasInvalidGropings = filledRows.some(row => - row.quantity % row.grouping != 0 - ); - - if (filledRows.length <= 0) - throw new Error('First you must add some quantity'); - - if (hasInvalidGropings) - throw new Error(`The amounts doesn't match with the grouping`); - - const params = { - orderFk: this.order.id, - items: filledRows - }; - this.$http.post(`OrderRows/addToOrder`, params) - .then(() => { - this.vnApp.showSuccess(this.$t('Data saved!')); - this.hide(); - if (this.card) this.card.reload(); - }); - } catch (e) { - this.vnApp.showError(this.$t(e.message)); - return false; - } - return true; - } -} - -ngModule.vnComponent('vnOrderPricesPopover', { - slotTemplate: require('./index.html'), - controller: Controller, - bindings: { - order: '<' - }, - require: { - card: '?^vnOrderCard' - } -}); diff --git a/modules/order/front/prices-popover/index.spec.js b/modules/order/front/prices-popover/index.spec.js deleted file mode 100644 index 734a9e254..000000000 --- a/modules/order/front/prices-popover/index.spec.js +++ /dev/null @@ -1,171 +0,0 @@ -import './index.js'; - -describe('Order', () => { - describe('Component vnOrderPricesPopover', () => { - let controller; - let $httpBackend; - let orderId = 16; - - beforeEach(ngModule('order')); - - beforeEach(inject(($componentController, $rootScope, _$httpBackend_) => { - $httpBackend = _$httpBackend_; - const $scope = $rootScope.$new(); - const $element = angular.element(''); - const $transclude = { - $$boundTransclude: { - $$slots: [] - } - }; - controller = $componentController('vnOrderPricesPopover', {$element, $scope, $transclude}); - controller._prices = [ - {warehouseFk: 1, grouping: 10, quantity: 0}, - {warehouseFk: 1, grouping: 100, quantity: 100} - ]; - controller.item = {available: 1000}; - controller.maxQuantity = 1000; - controller.order = {id: orderId}; - })); - - describe('prices() setter', () => { - it('should call to the getTotalQuantity() method', () => { - controller.getTotalQuantity = jest.fn(); - - controller.prices = [ - {grouping: 10, quantity: 0}, - {grouping: 100, quantity: 0}, - {grouping: 1000, quantity: 0}, - ]; - - expect(controller.getTotalQuantity).toHaveBeenCalledWith(); - }); - }); - - describe('getTotalQuantity()', () => { - it('should set the totalQuantity property', () => { - controller.getTotalQuantity(); - - expect(controller.totalQuantity).toEqual(100); - }); - }); - - describe('addQuantity()', () => { - it('should call to the getTotalQuantity() method and NOT set the quantity property', () => { - jest.spyOn(controller, 'getTotalQuantity'); - - controller.prices = [ - {grouping: 10, quantity: 0}, - {grouping: 100, quantity: 0}, - {grouping: 1000, quantity: 1000}, - ]; - - const oneThousandGrouping = controller.prices[2]; - - expect(oneThousandGrouping.quantity).toEqual(1000); - - controller.addQuantity(oneThousandGrouping); - - expect(controller.getTotalQuantity).toHaveBeenCalledWith(); - expect(oneThousandGrouping.quantity).toEqual(1000); - }); - - it('should call to the getTotalQuantity() method and then set the quantity property', () => { - jest.spyOn(controller, 'getTotalQuantity'); - - const oneHandredGrouping = controller.prices[1]; - controller.addQuantity(oneHandredGrouping); - - expect(controller.getTotalQuantity).toHaveBeenCalledWith(); - expect(oneHandredGrouping.quantity).toEqual(200); - }); - }); - - describe('getGroupings()', () => { - it('should return a row with the total filled quantity', () => { - jest.spyOn(controller, 'getTotalQuantity'); - - controller.prices = [ - {warehouseFk: 1, grouping: 10, quantity: 10}, - {warehouseFk: 1, grouping: 100, quantity: 100}, - {warehouseFk: 1, grouping: 1000, quantity: 1000}, - ]; - - const rows = controller.getGroupings(); - const firstRow = rows[0]; - - expect(rows.length).toEqual(1); - expect(firstRow.quantity).toEqual(1110); - }); - - it('should return two filled rows with a quantity', () => { - jest.spyOn(controller, 'getTotalQuantity'); - - controller.prices = [ - {warehouseFk: 1, grouping: 10, quantity: 10}, - {warehouseFk: 2, grouping: 10, quantity: 10}, - {warehouseFk: 1, grouping: 100, quantity: 0}, - {warehouseFk: 1, grouping: 1000, quantity: 1000}, - ]; - - const rows = controller.getGroupings(); - const firstRow = rows[0]; - const secondRow = rows[1]; - - expect(rows.length).toEqual(2); - expect(firstRow.quantity).toEqual(1010); - expect(secondRow.quantity).toEqual(10); - }); - }); - - describe('submit()', () => { - it('should throw an error if none of the rows contains a quantity', () => { - jest.spyOn(controller, 'getTotalQuantity'); - jest.spyOn(controller.vnApp, 'showError'); - - controller.prices = [ - {warehouseFk: 1, grouping: 10, quantity: 0}, - {warehouseFk: 1, grouping: 100, quantity: 0} - ]; - - controller.submit(); - - expect(controller.vnApp.showError).toHaveBeenCalledWith(`First you must add some quantity`); - }); - - it(`should throw an error if the quantity doesn't match the grouping value`, () => { - jest.spyOn(controller, 'getTotalQuantity'); - jest.spyOn(controller.vnApp, 'showError'); - - controller.prices = [ - {warehouseFk: 1, grouping: 10, quantity: 0}, - {warehouseFk: 1, grouping: 100, quantity: 1101} - ]; - - controller.submit(); - - expect(controller.vnApp.showError).toHaveBeenCalledWith(`The amounts doesn't match with the grouping`); - }); - - it('should should make an http query and then show a success message', () => { - jest.spyOn(controller, 'getTotalQuantity'); - jest.spyOn(controller.vnApp, 'showSuccess'); - - controller.prices = [ - {warehouseFk: 1, grouping: 10, quantity: 0}, - {warehouseFk: 1, grouping: 100, quantity: 100} - ]; - - const params = { - orderFk: orderId, - items: [{warehouseFk: 1, grouping: 100, quantity: 100}] - }; - - $httpBackend.expectPOST('OrderRows/addToOrder', params).respond(200); - controller.submit(); - $httpBackend.flush(); - - expect(controller.vnApp.showSuccess).toHaveBeenCalledWith(`Data saved!`); - }); - }); - }); -}); diff --git a/modules/order/front/prices-popover/locale/es.yml b/modules/order/front/prices-popover/locale/es.yml deleted file mode 100644 index 27eac802d..000000000 --- a/modules/order/front/prices-popover/locale/es.yml +++ /dev/null @@ -1,3 +0,0 @@ -Qty.: Cant. -First you must add some quantity: Primero debes agregar alguna cantidad -The amounts doesn't match with the grouping: Las cantidades no coinciden con el grouping \ No newline at end of file diff --git a/modules/order/front/prices-popover/style.scss b/modules/order/front/prices-popover/style.scss deleted file mode 100644 index deaeab044..000000000 --- a/modules/order/front/prices-popover/style.scss +++ /dev/null @@ -1,18 +0,0 @@ -@import "variables"; - -.vn-order-prices-popover .content { - .prices { - vn-table { - .price-kg { - color: $color-font-secondary; - font-size: .75rem - } - .vn-input-number { - width: 80px; - } - } - .footer { - text-align: center; - } - } -} \ No newline at end of file diff --git a/modules/order/front/routes.json b/modules/order/front/routes.json index 2eeb60553..25c68300f 100644 --- a/modules/order/front/routes.json +++ b/modules/order/front/routes.json @@ -28,19 +28,19 @@ "abstract": true, "component": "vn-order", "description": "Orders" - }, + }, { "url": "/index?q", "state": "order.index", "component": "vn-order-index", "description": "Orders" - }, + }, { "url": "/:id", "state": "order.card", "abstract": true, "component": "vn-order-card" - }, + }, { "url": "/summary", "state": "order.card.summary", @@ -49,48 +49,6 @@ "params": { "order": "$ctrl.order" } - }, - { - "url": "/catalog?q&categoryId&typeId&tagGroups", - "state": "order.card.catalog", - "component": "vn-order-catalog", - "description": "Catalog", - "params": { - "order": "$ctrl.order" - } - }, - { - "url": "/volume", - "state": "order.card.volume", - "component": "vn-order-volume", - "description": "Volume", - "params": { - "order": "$ctrl.order" - } - }, - { - "url": "/line", - "state": "order.card.line", - "component": "vn-order-line", - "description": "Lines", - "params": { - "order": "$ctrl.order" - } - }, - { - "url": "/create?clientFk", - "state": "order.create", - "component": "vn-order-create", - "description": "New order" - }, - { - "url": "/basic-data", - "state": "order.card.basicData", - "component": "vn-order-basic-data", - "description": "Basic data", - "params": { - "order": "$ctrl.order" - } } ] -} \ No newline at end of file +} diff --git a/modules/order/front/search-panel/index.html b/modules/order/front/search-panel/index.html deleted file mode 100644 index 001fc0bcb..000000000 --- a/modules/order/front/search-panel/index.html +++ /dev/null @@ -1,86 +0,0 @@ -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
diff --git a/modules/order/front/search-panel/index.js b/modules/order/front/search-panel/index.js deleted file mode 100644 index 07be9ca24..000000000 --- a/modules/order/front/search-panel/index.js +++ /dev/null @@ -1,7 +0,0 @@ -import ngModule from '../module'; -import SearchPanel from 'core/components/searchbar/search-panel'; - -ngModule.vnComponent('vnOrderSearchPanel', { - template: require('./index.html'), - controller: SearchPanel -}); diff --git a/modules/order/front/search-panel/locale/es.yml b/modules/order/front/search-panel/locale/es.yml deleted file mode 100644 index 9801e151f..000000000 --- a/modules/order/front/search-panel/locale/es.yml +++ /dev/null @@ -1,11 +0,0 @@ -Order id: Id cesta -Client id: Id cliente -From landed: Desde f. entrega -To landed: Hasta f. entrega -To: Hasta -Agency: Agencia -Application: Aplicación -SalesPerson: Comercial -Order confirmed: Pedido confirmado -Show empty: Mostrar vacías -Search orders by ticket id: Buscar pedido por id ticket \ No newline at end of file diff --git a/modules/order/front/summary/index.html b/modules/order/front/summary/index.html deleted file mode 100644 index 218359992..000000000 --- a/modules/order/front/summary/index.html +++ /dev/null @@ -1,131 +0,0 @@ - -
- - - - - Basket #{{$ctrl.summary.id}} - {{$ctrl.summary.client.name}} - ({{$ctrl.summary.client.id}}) - - - -
- - - - - - - {{$ctrl.summary.address.nickname}} - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Subtotal {{$ctrl.summary.subTotal | currency: 'EUR':2}}

-

VAT {{$ctrl.summary.VAT | currency: 'EUR':2}}

-

Total {{$ctrl.summary.total | currency: 'EUR':2}}

-
- - - - - - Item - Description - Quantity - Price - Amount - - - - - - - - - - - - {{::row.itemFk}} - - - -
- {{::row.item.name}} - -

{{::row.item.subName}}

-
-
- - -
- {{::row.quantity}} - {{::row.price | currency: 'EUR':2}} - {{::row.quantity * row.price | currency: 'EUR':2}} -
-
- -
-
-
- - - - diff --git a/modules/order/front/summary/index.js b/modules/order/front/summary/index.js deleted file mode 100644 index cc1df8f5d..000000000 --- a/modules/order/front/summary/index.js +++ /dev/null @@ -1,41 +0,0 @@ -import ngModule from '../module'; -import Summary from 'salix/components/summary'; -import './style.scss'; - -class Controller extends Summary { - setSummary() { - this.$http.get(`Orders/${this.order.id}/summary`) - .then(res => this.summary = res.data); - } - - get formattedAddress() { - if (!this.summary) return null; - - let address = this.summary.address; - let province = address.province ? `(${address.province.name})` : ''; - - return `${address.street} - ${address.city} ${province}`; - } - - $onChanges() { - if (this.order && this.order.id) - this.setSummary(); - } - - save() { - this.$http.post(`Orders/${this.order.id}/confirm`).then(() => { - this.vnApp.showSuccess(this.$t('Order confirmed')); - this.$state.go(`ticket.index`, { - q: JSON.stringify({clientFk: this.order.clientFk}) - }); - }); - } -} - -ngModule.vnComponent('vnOrderSummary', { - template: require('./index.html'), - controller: Controller, - bindings: { - order: '<' - } -}); diff --git a/modules/order/front/summary/index.spec.js b/modules/order/front/summary/index.spec.js deleted file mode 100644 index 0c04593e1..000000000 --- a/modules/order/front/summary/index.spec.js +++ /dev/null @@ -1,47 +0,0 @@ -import './index'; - -describe('Order', () => { - describe('Component vnOrderSummary', () => { - let controller; - let $httpBackend; - - beforeEach(ngModule('order')); - - beforeEach(inject(($componentController, _$httpBackend_) => { - $httpBackend = _$httpBackend_; - const $element = angular.element(''); - controller = $componentController('vnOrderSummary', {$element}); - controller.order = {id: 1}; - })); - - describe('getSummary()', () => { - it('should now perform a GET query and define the summary property', () => { - let res = { - id: 1, - nickname: 'Batman' - }; - $httpBackend.expectGET(`Orders/1/summary`).respond(res); - controller.setSummary(); - $httpBackend.flush(); - - expect(controller.summary).toEqual(res); - }); - }); - - describe('formattedAddress()', () => { - it('should return a full fromatted address with city and province', () => { - controller.summary = { - address: { - province: { - name: 'Gotham' - }, - street: '1007 Mountain Drive', - city: 'Gotham' - } - }; - - expect(controller.formattedAddress).toEqual('1007 Mountain Drive - Gotham (Gotham)'); - }); - }); - }); -}); diff --git a/modules/order/front/summary/style.scss b/modules/order/front/summary/style.scss deleted file mode 100644 index a2537c58f..000000000 --- a/modules/order/front/summary/style.scss +++ /dev/null @@ -1,20 +0,0 @@ -@import "./variables"; - -vn-order-summary .summary{ - max-width: $width-lg; - - & > vn-horizontal > vn-one { - min-width: 160px; - - &.taxes { - border: $border-thin-light; - text-align: right; - padding: 8px; - - & > p { - font-size: 1.2rem; - margin: 3px; - } - } - } -} \ No newline at end of file diff --git a/modules/order/front/volume/index.html b/modules/order/front/volume/index.html deleted file mode 100644 index e0053f9ed..000000000 --- a/modules/order/front/volume/index.html +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - - - - - - - - - - Item - Description - Quantity - m³ per quantity - - - - - - - {{::row.itemFk}} - - - -
- {{::row.item.name}} - -

{{::row.item.subName}}

-
-
- - -
- {{::row.quantity}} - {{::row.volume | number:3}} -
-
-
-
-
- - - diff --git a/modules/order/front/volume/index.js b/modules/order/front/volume/index.js deleted file mode 100644 index c1bc5ec7d..000000000 --- a/modules/order/front/volume/index.js +++ /dev/null @@ -1,37 +0,0 @@ -import ngModule from '../module'; -import Section from 'salix/components/section'; -import './style.scss'; - -class Controller extends Section { - constructor($element, $) { - super($element, $); - this.filter = { - include: { - relation: 'item' - }, - order: 'itemFk' - }; - this.order = {}; - this.ticketVolumes = []; - } - - onDataChange() { - this.$http.get(`Orders/${this.$params.id}/getVolumes`) - .then(res => { - this.$.model.data.forEach(order => { - res.data.volumes.forEach(volume => { - if (order.itemFk === volume.itemFk) - order.volume = volume.volume; - }); - }); - }); - } -} - -ngModule.vnComponent('vnOrderVolume', { - template: require('./index.html'), - controller: Controller, - bindings: { - order: '<' - } -}); diff --git a/modules/order/front/volume/index.spec.js b/modules/order/front/volume/index.spec.js deleted file mode 100644 index 6d7b18865..000000000 --- a/modules/order/front/volume/index.spec.js +++ /dev/null @@ -1,42 +0,0 @@ -import './index'; - -describe('Order', () => { - describe('Component vnOrderVolume', () => { - let controller; - let $httpBackend; - let $scope; - - beforeEach(ngModule('order')); - - beforeEach(inject(($componentController, $state, _$httpBackend_, $rootScope) => { - $httpBackend = _$httpBackend_; - $scope = $rootScope.$new(); - $scope.model = { - data: [ - {itemFk: 1}, - {itemFk: 2} - ] - }; - - $state.params.id = 1; - const $element = angular.element(''); - controller = $componentController('vnOrderVolume', {$element, $scope}); - })); - - it('should join the sale volumes to its respective sale', () => { - let response = { - volumes: [ - {itemFk: 1, volume: 0.008}, - {itemFk: 2, volume: 0.003} - ] - }; - - $httpBackend.expectGET(`Orders/1/getVolumes`).respond(response); - controller.onDataChange(); - $httpBackend.flush(); - - expect(controller.$.model.data[0].volume).toBe(0.008); - expect(controller.$.model.data[1].volume).toBe(0.003); - }); - }); -}); diff --git a/modules/order/front/volume/style.scss b/modules/order/front/volume/style.scss deleted file mode 100644 index da13eca0d..000000000 --- a/modules/order/front/volume/style.scss +++ /dev/null @@ -1,12 +0,0 @@ - -@import "./variables"; - -vn-order-volume { - .header { - text-align: right; - - & > div { - margin-bottom: $spacing-xs; - } - } -} diff --git a/modules/route/back/methods/route/driverRouteEmail.js b/modules/route/back/methods/route/driverRouteEmail.js index 62147db87..bbac2b0e8 100644 --- a/modules/route/back/methods/route/driverRouteEmail.js +++ b/modules/route/back/methods/route/driverRouteEmail.js @@ -39,8 +39,6 @@ module.exports = Self => { const {reportMail} = agencyMode(); let user; let account; - let userEmail; - ctx.args.recipients = reportMail ? reportMail.split(',').map(email => email.trim()) : []; if (workerFk) { user = await models.VnUser.findById(workerFk, { @@ -50,17 +48,10 @@ module.exports = Self => { account = await models.Account.findById(workerFk); } - if (user?.active && account) - userEmail = user.emailUser().email; - - if (userEmail) - ctx.args.recipients.push(userEmail); - - ctx.args.recipients = [...new Set(ctx.args.recipients)]; - - if (!ctx.args.recipients.length) - throw new UserError('An email is necessary'); + if (user?.active && account) ctx.args.recipient = user.emailUser().email; + else ctx.args.recipient = reportMail; + if (!ctx.args.recipient) throw new UserError('An email is necessary'); return Self.sendTemplate(ctx, 'driver-route'); }; }; diff --git a/modules/shelving/back/models/sector.json b/modules/shelving/back/models/sector.json index 61d8d0628..16aa0ba6a 100644 --- a/modules/shelving/back/models/sector.json +++ b/modules/shelving/back/models/sector.json @@ -59,6 +59,9 @@ "isReserve": { "type": "boolean", "required": true + }, + "isOnReservationMode": { + "type": "boolean" } } -} +} \ No newline at end of file diff --git a/modules/supplier/back/methods/supplier/getWithPackaging.js b/modules/supplier/back/methods/supplier/getWithPackaging.js new file mode 100644 index 000000000..07e563412 --- /dev/null +++ b/modules/supplier/back/methods/supplier/getWithPackaging.js @@ -0,0 +1,45 @@ +module.exports = Self => { + Self.remoteMethod('getWithPackaging', { + description: 'Returns the list of suppliers with an entry of type packaging', + accessType: 'READ', + returns: { + type: 'object', + root: true + }, + http: { + path: `/getWithPackaging`, + verb: 'GET' + }, + nolimit: true + }); + Self.getWithPackaging = async options => { + const models = Self.app.models; + const myOptions = {}; + const oneYearAgo = new Date(); + oneYearAgo.setFullYear(oneYearAgo.getFullYear() - 1); + + if (typeof options == 'object') + Object.assign(myOptions, options); + + const entries = await models.Entry.find({ + where: { + typeFk: 'packaging', + created: {gte: oneYearAgo} + }, + include: { + relation: 'supplier', + scope: { + fields: ['id', 'name'] + } + }, + fields: {supplierFk: true} + }, myOptions); + + const result = entries.map(item => ({ + id: item.supplier().id, + name: item.supplier().name + })); + return Array.from(new Map(result.map(entry => [entry.id, entry])).values()); + }; +}; + diff --git a/modules/supplier/back/methods/supplier/specs/getWithPackaging.spec.js b/modules/supplier/back/methods/supplier/specs/getWithPackaging.spec.js new file mode 100644 index 000000000..bd30d7437 --- /dev/null +++ b/modules/supplier/back/methods/supplier/specs/getWithPackaging.spec.js @@ -0,0 +1,33 @@ +const {models} = require('vn-loopback/server/server'); + +describe('Supplier getWithPackaging()', () => { + it('should return a list of suppliers with an entry of type packaging', async() => { + const typeFk = 'packaging'; + + const tx = await models.Supplier.beginTransaction({}); + const myOptions = {transaction: tx}; + + try { + const entry = await models.Entry.findOne( + { + where: { + id: 1 + }, + myOptions + }); + + await entry.updateAttributes({ + typeFk: typeFk, + created: new Date() + }); + + const result = await models.Supplier.getWithPackaging(myOptions); + + expect(result.length).toEqual(1); + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); +}); diff --git a/modules/supplier/back/models/supplier.js b/modules/supplier/back/models/supplier.js index 2d3ffef3e..7e6908d57 100644 --- a/modules/supplier/back/models/supplier.js +++ b/modules/supplier/back/models/supplier.js @@ -12,6 +12,7 @@ module.exports = Self => { require('../methods/supplier/campaignMetricsEmail')(Self); require('../methods/supplier/newSupplier')(Self); require('../methods/supplier/getItemsPackaging')(Self); + require('../methods/supplier/getWithPackaging')(Self); Self.validatesPresenceOf('name', { message: 'The social name cannot be empty' diff --git a/modules/ticket/back/methods/ticket/closeAll.js b/modules/ticket/back/methods/ticket/closeAll.js index 143c0a3f0..4fd72d454 100644 --- a/modules/ticket/back/methods/ticket/closeAll.js +++ b/modules/ticket/back/methods/ticket/closeAll.js @@ -53,8 +53,9 @@ module.exports = Self => { JOIN province p ON p.id = c.provinceFk JOIN country co ON co.id = p.countryFk LEFT JOIN account.emailUser eu ON eu.userFk = c.salesPersonFk + JOIN ticketConfig tc ON TRUE WHERE (al.code = 'PACKED' OR (am.code = 'refund' AND al.code <> 'delivered')) - AND DATE(t.shipped) BETWEEN ? - INTERVAL 2 DAY AND util.dayEnd(?) + AND t.shipped BETWEEN ? - INTERVAL tc.closureDaysAgo DAY AND util.dayEnd(?) AND t.refFk IS NULL GROUP BY t.id `, [toDate, toDate]); @@ -108,6 +109,7 @@ module.exports = Self => { JOIN alertLevel al ON al.id = ts.alertLevel JOIN client c ON c.id = t.clientFk JOIN province p ON p.id = c.provinceFk + JOIN ticketConfig tc ON TRUE LEFT JOIN autonomy a ON a.id = p.autonomyFk JOIN country co ON co.id = p.countryFk LEFT JOIN account.emailUser eu ON eu.userFk = c.salesPersonFk @@ -116,7 +118,7 @@ module.exports = Self => { LEFT JOIN vn.invoiceOutSerial ios ON ios.taxAreaFk = 'WORLD' AND ios.code = invoiceSerial(t.clientFk, t.companyFk, 'multiple') WHERE (al.code = 'PACKED' OR (am.code = 'refund' AND al.code <> 'delivered')) - AND DATE(t.shipped) BETWEEN ? - INTERVAL 2 DAY AND util.dayEnd(?) + AND t.shipped BETWEEN ? - INTERVAL tc.closureDaysAgo DAY AND util.dayEnd(?) AND t.refFk IS NULL AND IFNULL(a.hasDailyInvoice, co.hasDailyInvoice) GROUP BY ticketFk @@ -141,9 +143,10 @@ module.exports = Self => { JOIN alertLevel al ON al.id = ts.alertLevel JOIN agencyMode am ON am.id = t.agencyModeFk JOIN deliveryMethod dm ON dm.id = am.deliveryMethodFk + JOIN ticketConfig tc ON TRUE LEFT JOIN ticketObservation tob ON tob.ticketFk = t.id SET t.routeFk = NULL - WHERE DATE(t.shipped) BETWEEN ? - INTERVAL 2 DAY AND util.dayEnd(?) + WHERE t.shipped BETWEEN ? - INTERVAL tc.closureDaysAgo DAY AND util.dayEnd(?) AND al.code NOT IN ('DELIVERED', 'PACKED') AND NOT t.packages AND tob.id IS NULL diff --git a/modules/ticket/back/methods/ticket/closure.js b/modules/ticket/back/methods/ticket/closure.js index a75596bac..56bd6eccd 100644 --- a/modules/ticket/back/methods/ticket/closure.js +++ b/modules/ticket/back/methods/ticket/closure.js @@ -12,16 +12,15 @@ module.exports = async function(ctx, Self, tickets, options) { Object.assign(myOptions, options); let tx; - if (!myOptions.transaction) { - tx = await Self.beginTransaction({}); - myOptions.transaction = tx; - } + // IMPORTANT: Due to its high cost in production, wrapping this process in a transaction may cause timeouts. if (tickets.length == 0) return; const failedtickets = []; for (const ticket of tickets) { try { + await Self.rawSql(`CALL util.debugAdd('invoicingTicket', ?)`, [ticket.id], {userId}); + await Self.app.models.InvoiceOut.getSerial(ticket.clientFk, ticket.companyFk, ticket.addressFk, 'quick'); await Self.rawSql( `CALL vn.ticket_closeByTicket(?)`, @@ -149,6 +148,11 @@ module.exports = async function(ctx, Self, tickets, options) { myOptions); } } catch (error) { + await Self.rawSql(` + INSERT INTO util.debug (variable, value) + VALUES ('invoicingTicketError', ?) + `, [ticket.id + ' - ' + error]); + if (error.responseCode == 450) { await invalidEmail(ticket); continue; diff --git a/modules/ticket/back/methods/ticket/filter.js b/modules/ticket/back/methods/ticket/filter.js index 06781c3c8..d3e53c702 100644 --- a/modules/ticket/back/methods/ticket/filter.js +++ b/modules/ticket/back/methods/ticket/filter.js @@ -228,52 +228,57 @@ module.exports = Self => { stmt = new ParameterizedSQL(` CREATE OR REPLACE TEMPORARY TABLE tmp.filter (INDEX (id)) - ENGINE = MEMORY + ENGINE = InnoDB SELECT t.id, - t.shipped, - CAST(DATE(t.shipped) AS CHAR) shippedDate, - HOUR(t.shipped) shippedHour, - t.nickname, - t.refFk, - t.routeFk, - t.warehouseFk, - t.clientFk, - t.totalWithoutVat, - t.totalWithVat, - io.id invoiceOutId, - a.provinceFk, - p.name province, - w.name warehouse, - am.name agencyMode, - am.id agencyModeFk, - st.name state, - st.classColor, - wk.lastName salesPerson, - ts.stateFk stateFk, - ts.alertLevel alertLevel, - ts.code alertLevelCode, - u.name userName, - c.salesPersonFk, - z.hour zoneLanding, - HOUR(z.hour) zoneHour, - MINUTE(z.hour) zoneMinute, - z.name zoneName, - z.id zoneFk, - CAST(z.hour AS CHAR) hour, - a.nickname addressNickname - FROM ticket t - LEFT JOIN invoiceOut io ON t.refFk = io.ref - LEFT JOIN zone z ON z.id = t.zoneFk - LEFT JOIN address a ON a.id = t.addressFk - LEFT JOIN province p ON p.id = a.provinceFk - LEFT JOIN warehouse w ON w.id = t.warehouseFk - LEFT JOIN agencyMode am ON am.id = t.agencyModeFk - LEFT JOIN ticketState ts ON ts.ticketFk = t.id - LEFT JOIN state st ON st.id = ts.stateFk - LEFT JOIN client c ON c.id = t.clientFk - LEFT JOIN worker wk ON wk.id = c.salesPersonFk - LEFT JOIN account.user u ON u.id = wk.id - LEFT JOIN route r ON r.id = t.routeFk + t.shipped, + CAST(DATE(t.shipped) AS CHAR) shippedDate, + HOUR(t.shipped) shippedHour, + t.nickname, + t.refFk, + t.routeFk, + t.warehouseFk, + t.clientFk, + t.totalWithoutVat, + t.totalWithVat, + io.id invoiceOutId, + a.provinceFk, + p.name province, + w.name warehouse, + am.name agencyMode, + am.id agencyModeFk, + st.name state, + st.classColor, + wk.lastName salesPerson, + ts.stateFk stateFk, + ts.alertLevel alertLevel, + ts.code alertLevelCode, + u.name userName, + c.salesPersonFk, + z.hour zoneLanding, + HOUR(z.hour) zoneHour, + MINUTE(z.hour) zoneMinute, + z.name zoneName, + z.id zoneFk, + CAST(z.hour AS CHAR) hour, + a.nickname addressNickname, + (SELECT GROUP_CONCAT(DISTINCT i2.itemPackingTypeFk ORDER BY i2.itemPackingTypeFk SEPARATOR ',') + FROM sale s2 + JOIN item i2 ON i2.id = s2.itemFk + WHERE s2.ticketFk = t.id + ) AS packing + FROM ticket t + LEFT JOIN invoiceOut io ON t.refFk = io.ref + LEFT JOIN zone z ON z.id = t.zoneFk + LEFT JOIN address a ON a.id = t.addressFk + LEFT JOIN province p ON p.id = a.provinceFk + LEFT JOIN warehouse w ON w.id = t.warehouseFk + LEFT JOIN agencyMode am ON am.id = t.agencyModeFk + LEFT JOIN ticketState ts ON ts.ticketFk = t.id + LEFT JOIN state st ON st.id = ts.stateFk + LEFT JOIN client c ON c.id = t.clientFk + LEFT JOIN worker wk ON wk.id = c.salesPersonFk + LEFT JOIN account.user u ON u.id = wk.id + LEFT JOIN route r ON r.id = t.routeFk `); if (args.orderFk) { @@ -292,6 +297,7 @@ module.exports = Self => { } stmt.merge(conn.makeWhere(filter.where)); + stmts.push(stmt); stmt = new ParameterizedSQL(` diff --git a/modules/ticket/back/methods/ticket/specs/closure.spec.js b/modules/ticket/back/methods/ticket/specs/closure.spec.js index 303c38233..cafe178cb 100644 --- a/modules/ticket/back/methods/ticket/specs/closure.spec.js +++ b/modules/ticket/back/methods/ticket/specs/closure.spec.js @@ -50,9 +50,9 @@ describe('Ticket closure functionality', () => { expect(ticketStateBefore.code).not.toBe(ticketStateAfter.code); - const ticketAfter = await models.TicketState.findById(ticketId, null, options); + const ticketAfter = await models.Ticket.findById(ticketId, null, options); - expect(ticketAfter.refFk).toBeUndefined(); + expect(ticketAfter.refFk).toBeNull(); }); it('should send Incoterms authorization email on first order', async() => { diff --git a/modules/travel/front/routes.json b/modules/travel/front/routes.json index 6ae61bd02..6891a46cf 100644 --- a/modules/travel/front/routes.json +++ b/modules/travel/front/routes.json @@ -3,7 +3,7 @@ "name": "Travels", "icon": "local_airport", "validations": true, - "dependencies": ["worker"], + "dependencies": ["worker", "entry"], "menus": { "main": [ {"state": "travel.index", "icon": "local_airport"}, diff --git a/modules/worker/back/methods/device/handle-user.js b/modules/worker/back/methods/device/handle-user.js index 55302c1cb..abafffd55 100644 --- a/modules/worker/back/methods/device/handle-user.js +++ b/modules/worker/back/methods/device/handle-user.js @@ -87,7 +87,7 @@ module.exports = Self => { { relation: 'sector', scope: { - fields: ['warehouseFk', 'description'], + fields: ['warehouseFk', 'description', 'isOnReservationMode'], } }, { relation: 'printer', diff --git a/modules/worker/back/methods/worker/filter.js b/modules/worker/back/methods/worker/filter.js index 2f328d28f..52c60572a 100644 --- a/modules/worker/back/methods/worker/filter.js +++ b/modules/worker/back/methods/worker/filter.js @@ -67,6 +67,12 @@ module.exports = Self => { type: 'String', description: 'The worker user name', http: {source: 'query'} + }, + { + arg: 'email', + type: 'String', + description: 'The user email', + http: {source: 'query'} } ], returns: { @@ -99,6 +105,8 @@ module.exports = Self => { return {'w.firstName': {like: `%${value}%`}}; case 'lastName': return {'w.lastName': {like: `%${value}%`}}; + case 'nickname': + return {'u.nickname': {like: `%${value}%`}}; case 'extension': return {'p.extension': value}; case 'fi': @@ -107,6 +115,8 @@ module.exports = Self => { return {'d.id': value}; case 'userName': return {'u.name': {like: `%${value}%`}}; + case 'email': + return {'eu.email': {like: `%${value}%`}}; } }); @@ -116,15 +126,23 @@ module.exports = Self => { let stmt; stmt = new ParameterizedSQL( - `SELECT w.id, u.email, p.extension, u.name as userName, - d.name AS department, w.lastName, u.nickname, mu.email + `SELECT w.id, + w.lastName, + w.firstName, + u.email, + u.nickname, + p.extension, + u.name as userName, + d.name AS department, + eu.email, + c.fi FROM worker w LEFT JOIN workerDepartment wd ON wd.workerFk = w.id LEFT JOIN department d ON d.id = wd.departmentFk LEFT JOIN client c ON c.id = w.id LEFT JOIN account.user u ON u.id = w.id LEFT JOIN pbx.sip p ON p.user_id = u.id - LEFT JOIN account.emailUser mu ON mu.userFk = u.id` + LEFT JOIN account.emailUser eu ON eu.userFk = u.id` ); stmt.merge(conn.makeSuffix(filter)); diff --git a/modules/worker/back/methods/worker/new.js b/modules/worker/back/methods/worker/new.js index bb43fba99..7da8a8da2 100644 --- a/modules/worker/back/methods/worker/new.js +++ b/modules/worker/back/methods/worker/new.js @@ -217,6 +217,7 @@ module.exports = Self => { const code = e.code; const message = e.sqlMessage; + if (e.message && e.message.includes('Invalid email')) throw new UserError('Invalid email'); if (e.message && e.message.includes(`Email already exists`)) throw new UserError(`This personal mail already exists`); if (code === 'ER_DUP_ENTRY' && message.includes(`CodigoTrabajador_UNIQUE`)) throw new UserError(`This worker code already exists`); if (code === 'ER_DUP_ENTRY' && message.includes(`PRIMARY`)) throw new UserError(`This worker already exists`); diff --git a/modules/worker/back/models/operator.json b/modules/worker/back/models/operator.json index d4832bccf..b75bf6732 100644 --- a/modules/worker/back/models/operator.json +++ b/modules/worker/back/models/operator.json @@ -24,13 +24,28 @@ "warehouseFk": { "type": "number" }, + "sectorFk": { + "type": "number" + }, "labelerFk": { "type": "number" }, "isOnReservationMode": { "type": "boolean", "required": true - } + }, + "machineFk": { + "type": "number" + }, + "linesLimit": { + "type": "number" + }, + "volumeLimit": { + "type": "number" + }, + "sizeLimit": { + "type": "number" + } }, "relations": { "sector": { @@ -53,6 +68,11 @@ "model": "ItemPackingType", "foreignKey": "itemPackingTypeFk", "primaryKey": "code" - } + }, + "machine": { + "type": "belongsTo", + "model": "Machine", + "foreignKey": "machineFk" + } } -} \ No newline at end of file +} diff --git a/modules/worker/back/models/worker.json b/modules/worker/back/models/worker.json index b00f8037e..d6afca8ea 100644 --- a/modules/worker/back/models/worker.json +++ b/modules/worker/back/models/worker.json @@ -263,7 +263,18 @@ "relation": "client" }, { - "relation": "sip" + "relation": "sip", + "scope": { + "include": { + "relation": "queueMember", + "scope": { + "fields": [ + "queue", + "extension" + ] + } + } + } } ] }, diff --git a/modules/zone/back/methods/zone/deleteZone.js b/modules/zone/back/methods/zone/deleteZone.js index a75302703..ffe23c9b9 100644 --- a/modules/zone/back/methods/zone/deleteZone.js +++ b/modules/zone/back/methods/zone/deleteZone.js @@ -1,3 +1,4 @@ +const UserError = require('vn-loopback/util/user-error'); module.exports = Self => { Self.remoteMethodCtx('deleteZone', { description: 'Delete a zone', @@ -49,26 +50,12 @@ module.exports = Self => { } } }; - const promises = []; const ticketList = await models.Ticket.find(filter, myOptions); - const fixingState = await models.State.findOne({where: {code: 'FIXING'}}, myOptions); - const worker = await models.Worker.findOne({ - where: {id: userId} - }, myOptions); - await models.Ticket.rawSql('UPDATE ticket SET zoneFk = NULL WHERE zoneFk = ?', [id], myOptions); + if (ticketList.length > 0) + throw new UserError('There are tickets for this area, delete them first'); - for (ticket of ticketList) { - if (ticket.ticketState().alertLevel == 0) { - promises.push(models.Ticket.state(ctx, { - ticketFk: ticket.id, - stateFk: fixingState.id, - userFk: worker.id - }, myOptions)); - } - } - await Promise.all(promises); await models.Zone.destroyById(id, myOptions); if (tx) await tx.commit(); diff --git a/modules/zone/back/methods/zone/specs/deleteZone.spec.js b/modules/zone/back/methods/zone/specs/deleteZone.spec.js index 08dafd181..aef7fd290 100644 --- a/modules/zone/back/methods/zone/specs/deleteZone.spec.js +++ b/modules/zone/back/methods/zone/specs/deleteZone.spec.js @@ -8,9 +8,9 @@ describe('zone deletezone()', () => { __: value => value }; const ctx = {req: activeCtx}; - const zoneId = 9; + const zoneId = 4; + const zoneId2 = 3; let ticketIDs; - let originalTicketStates; beforeAll(async() => { spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({ @@ -35,18 +35,8 @@ describe('zone deletezone()', () => { await models.Zone.deleteZone(ctx, zoneId, options); const updatedZone = await models.Zone.findById(zoneId, null, options); - const anUpdatedTicket = await models.Ticket.findById(ticketIDs[0], null, options); - - const updatedTicketStates = await models.TicketState.find({ - where: { - ticketFk: {inq: ticketIDs}, - code: 'FIXING' - } - }, options); expect(updatedZone).toBeNull(); - expect(anUpdatedTicket.zoneFk).toBeNull(); - expect(updatedTicketStates.length).toBeGreaterThan(originalTicketStates.length); await tx.rollback(); } catch (e) { @@ -54,4 +44,20 @@ describe('zone deletezone()', () => { throw e; } }); + + it('should not delete the zone if it has tickets', async() => { + const tx = await models.Zone.beginTransaction({}); + + let error; + try { + const options = {transaction: tx}; + await models.Zone.deleteZone(ctx, zoneId2, options); + await tx.rollback(); + } catch (e) { + error = e.message; + await tx.rollback(); + } + + expect(error).toEqual('There are tickets for this area, delete them first'); + }); }); diff --git a/package.json b/package.json index 8f9670903..767ec231e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "salix-back", - "version": "24.42.0", + "version": "24.44.0", "author": "Verdnatura Levante SL", "description": "Salix backend", "license": "GPL-3.0", @@ -60,7 +60,7 @@ "@babel/register": "^7.7.7", "@commitlint/cli": "^19.2.1", "@commitlint/config-conventional": "^19.1.0", - "@verdnatura/myt": "^1.6.11", + "@verdnatura/myt": "^1.6.12", "angular-mocks": "^1.7.9", "babel-jest": "^26.0.1", "babel-loader": "^8.2.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e2480cf4a..042b91fe0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -143,8 +143,8 @@ devDependencies: specifier: ^19.1.0 version: 19.1.0 '@verdnatura/myt': - specifier: ^1.6.11 - version: 1.6.11 + specifier: ^1.6.12 + version: 1.6.12 angular-mocks: specifier: ^1.7.9 version: 1.8.3 @@ -2846,8 +2846,8 @@ packages: dev: false optional: true - /@verdnatura/myt@1.6.11: - resolution: {integrity: sha512-uqdbSJSznBBzAoRkvBt600nUMEPL1PJ2v73eWMZbaoGUMiZiNAehYjs4gIrObP1cxC85JOx97XoLpG0BzPsaig==} + /@verdnatura/myt@1.6.12: + resolution: {integrity: sha512-t/SiDuQW9KJkcjhwQ9AkrcoTwghxQ7IyQ56e+88eYdoMi24l6bQGF0wHzMaIPRfQAoR8hqgfMOief4OAqW4Iqw==} hasBin: true dependencies: '@sqltools/formatter': 1.2.5 @@ -6548,7 +6548,7 @@ packages: resolution: {integrity: sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==} engines: {node: '>= 4.0'} os: [darwin] - deprecated: The v1 package contains DANGEROUS / INSECURE binaries. Upgrade to safe fsevents v2 + deprecated: Upgrade to fsevents v2 to mitigate potential security issues requiresBuild: true dependencies: bindings: 1.5.0 @@ -10485,7 +10485,7 @@ packages: engines: {node: '>=10'} requiresBuild: true dependencies: - semver: 7.5.4 + semver: 7.6.0 dev: false optional: true @@ -12501,6 +12501,7 @@ packages: hasBin: true dependencies: lru-cache: 6.0.0 + dev: true /semver@7.6.0: resolution: {integrity: sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==} @@ -12508,7 +12509,6 @@ packages: hasBin: true dependencies: lru-cache: 6.0.0 - dev: true /send@0.18.0(supports-color@6.1.0): resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==} diff --git a/print/templates/reports/delivery-note/delivery-note.html b/print/templates/reports/delivery-note/delivery-note.html index c1701e084..89bc07488 100644 --- a/print/templates/reports/delivery-note/delivery-note.html +++ b/print/templates/reports/delivery-note/delivery-note.html @@ -58,6 +58,7 @@ {{$t('reference')}} {{$t('quantity')}} {{$t('concept')}} + {{$t('producer')}} {{$t('price')}} {{$t('discount')}} {{$t('vat')}} @@ -69,6 +70,7 @@ {{sale.itemFk}} {{sale.quantity}} {{sale.concept}} + {{sale.subName}} {{sale.price | currency('EUR', $i18n.locale)}} {{(sale.discount / 100) | percentage}} {{sale.vatType}} @@ -81,7 +83,6 @@ {{sale.tag5}} {{sale.value5}} {{sale.tag6}} {{sale.value6}} {{sale.tag7}} {{sale.value7}} - {{$t('producer')}} {{ sale.subName }}