diff --git a/CHANGELOG.md b/CHANGELOG.md
index 76527ac83..80d8517de 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
-## [2330.01] - 2023-07-27
+## [2334.01] - 2023-08-24
### Added
@@ -14,6 +14,35 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
+## [2332.01] - 2023-08-09
+
+### Added
+- (Trabajadores -> Gestión documental) Soporte para Docuware
+- (General -> Agencia) Soporte para Viaexpress
+
+### Changed
+- (General -> Tickets) Devuelve el motivo por el cual no es editable
+- (Desplegables -> Trabajadores) Mejorados
+
+### Fixed
+
+
+## [2330.01] - 2023-07-27
+
+### Added
+- (Artículos -> Vista Previa) Añadido campo "Plástico reciclado"
+- (Rutas -> Troncales) Nueva sección
+- (Tickets -> Opciones) Opción establecer peso
+- (Clientes -> SMS) Nueva sección
+
+### Changed
+- (General -> Iconos) Añadidos nuevos iconos
+- (Clientes -> Razón social) Permite crear clientes con la misma razón social según el país
+
+
+### Fixed
+
+
## [2328.01] - 2023-07-13
### Added
diff --git a/back/methods/docuware/checkFile.js b/back/methods/docuware/checkFile.js
index c0a4e8ef3..19224057c 100644
--- a/back/methods/docuware/checkFile.js
+++ b/back/methods/docuware/checkFile.js
@@ -1,7 +1,5 @@
-const axios = require('axios');
-
module.exports = Self => {
- Self.remoteMethodCtx('checkFile', {
+ Self.remoteMethod('checkFile', {
description: 'Check if exist docuware file',
accessType: 'READ',
accepts: [
@@ -17,12 +15,16 @@ module.exports = Self => {
required: true,
description: 'The fileCabinet name'
},
+ {
+ arg: 'filter',
+ type: 'object',
+ description: 'The filter'
+ },
{
arg: 'signed',
type: 'boolean',
- required: true,
description: 'If pdf is necessary to be signed'
- }
+ },
],
returns: {
type: 'object',
@@ -34,7 +36,7 @@ module.exports = Self => {
}
});
- Self.checkFile = async function(ctx, id, fileCabinet, signed) {
+ Self.checkFile = async function(id, fileCabinet, filter, signed) {
const models = Self.app.models;
const action = 'find';
@@ -45,39 +47,34 @@ module.exports = Self => {
}
});
- const searchFilter = {
- condition: [
- {
- DBName: docuwareInfo.findById,
-
- Value: [id]
- }
- ],
- sortOrder: [
- {
- Field: 'FILENAME',
- Direction: 'Desc'
- }
- ]
- };
+ if (!filter) {
+ filter = {
+ condition: [
+ {
+ DBName: docuwareInfo.findById,
+ Value: [id]
+ }
+ ],
+ sortOrder: [
+ {
+ Field: 'FILENAME',
+ Direction: 'Desc'
+ }
+ ]
+ };
+ }
+ if (signed) {
+ filter.condition.push({
+ DBName: 'ESTADO',
+ Value: ['Firmado']
+ });
+ }
try {
- const options = await Self.getOptions();
-
- const fileCabinetId = await Self.getFileCabinet(fileCabinet);
- const dialogId = await Self.getDialog(fileCabinet, action, fileCabinetId);
-
- const response = await axios.post(
- `${options.url}/FileCabinets/${fileCabinetId}/Query/DialogExpression?dialogId=${dialogId}`,
- searchFilter,
- options.headers
- );
- const [documents] = response.data.Items;
+ const response = await Self.get(fileCabinet, filter);
+ const [documents] = response.Items;
if (!documents) return false;
- const state = documents.Fields.find(field => field.FieldName == 'ESTADO');
- if (signed && state.Item != 'Firmado') return false;
-
return {id: documents.Id};
} catch (error) {
return false;
diff --git a/back/methods/docuware/core.js b/back/methods/docuware/core.js
index 2053ddf85..74d922236 100644
--- a/back/methods/docuware/core.js
+++ b/back/methods/docuware/core.js
@@ -1,59 +1,6 @@
const axios = require('axios');
module.exports = Self => {
- /**
- * Returns the dialog id
- *
- * @param {string} code - The fileCabinet name
- * @param {string} action - The fileCabinet name
- * @param {string} fileCabinetId - Optional The fileCabinet name
- * @return {number} - The fileCabinet id
- */
- Self.getDialog = async(code, action, fileCabinetId) => {
- const docuwareInfo = await Self.app.models.Docuware.findOne({
- where: {
- code: code,
- action: action
- }
- });
- if (!fileCabinetId) fileCabinetId = await Self.getFileCabinet(code);
-
- const options = await Self.getOptions();
-
- if (!process.env.NODE_ENV)
- return Math.round();
-
- const response = await axios.get(`${options.url}/FileCabinets/${fileCabinetId}/dialogs`, options.headers);
- const dialogs = response.data.Dialog;
- const dialogId = dialogs.find(dialogs => dialogs.DisplayName === docuwareInfo.dialogName).Id;
-
- return dialogId;
- };
-
- /**
- * Returns the fileCabinetId
- *
- * @param {string} code - The fileCabinet code
- * @return {number} - The fileCabinet id
- */
- Self.getFileCabinet = async code => {
- const options = await Self.getOptions();
- const docuwareInfo = await Self.app.models.Docuware.findOne({
- where: {
- code: code
- }
- });
-
- if (!process.env.NODE_ENV)
- return Math.round();
-
- const fileCabinetResponse = await axios.get(`${options.url}/FileCabinets`, options.headers);
- const fileCabinets = fileCabinetResponse.data.FileCabinet;
- const fileCabinetId = fileCabinets.find(fileCabinet => fileCabinet.Name === docuwareInfo.fileCabinetName).Id;
-
- return fileCabinetId;
- };
-
/**
* Returns basic headers
*
@@ -75,4 +22,139 @@ module.exports = Self => {
headers
};
};
+
+ /**
+ * Returns the dialog id
+ *
+ * @param {string} code - The fileCabinet name
+ * @param {string} action - The fileCabinet name
+ * @param {string} fileCabinetId - Optional The fileCabinet name
+ * @return {number} - The fileCabinet id
+ */
+ Self.getDialog = async(code, action, fileCabinetId) => {
+ if (!process.env.NODE_ENV)
+ return Math.floor(Math.random() + 100);
+
+ const docuwareInfo = await Self.app.models.Docuware.findOne({
+ where: {
+ code,
+ action
+ }
+ });
+ if (!fileCabinetId) fileCabinetId = await Self.getFileCabinet(code);
+
+ const options = await Self.getOptions();
+
+ const response = await axios.get(`${options.url}/FileCabinets/${fileCabinetId}/dialogs`, options.headers);
+ const dialogs = response.data.Dialog;
+ const dialogId = dialogs.find(dialogs => dialogs.DisplayName === docuwareInfo.dialogName).Id;
+
+ return dialogId;
+ };
+
+ /**
+ * Returns the fileCabinetId
+ *
+ * @param {string} code - The fileCabinet code
+ * @return {number} - The fileCabinet id
+ */
+ Self.getFileCabinet = async code => {
+ if (!process.env.NODE_ENV)
+ return Math.floor(Math.random() + 100);
+
+ const options = await Self.getOptions();
+ const docuwareInfo = await Self.app.models.Docuware.findOne({
+ where: {
+ code
+ }
+ });
+
+ const fileCabinetResponse = await axios.get(`${options.url}/FileCabinets`, options.headers);
+ const fileCabinets = fileCabinetResponse.data.FileCabinet;
+ const fileCabinetId = fileCabinets.find(fileCabinet => fileCabinet.Name === docuwareInfo.fileCabinetName).Id;
+
+ return fileCabinetId;
+ };
+
+ /**
+ * Returns docuware data
+ *
+ * @param {string} code - The fileCabinet code
+ * @param {object} filter - The filter for docuware
+ * @param {object} parse - The fields parsed
+ * @return {object} - The data
+ */
+ Self.get = async(code, filter, parse) => {
+ if (!process.env.NODE_ENV) return;
+
+ const options = await Self.getOptions();
+ const fileCabinetId = await Self.getFileCabinet(code);
+ const dialogId = await Self.getDialog(code, 'find', fileCabinetId);
+
+ const data = await axios.post(
+ `${options.url}/FileCabinets/${fileCabinetId}/Query/DialogExpression?dialogId=${dialogId}`,
+ filter,
+ options.headers
+ );
+ return parser(data.data, parse);
+ };
+
+ /**
+ * Returns docuware data
+ *
+ * @param {string} code - The fileCabinet code
+ * @param {any} id - The id of docuware
+ * @param {object} parse - The fields parsed
+ * @return {object} - The data
+ */
+ Self.getById = async(code, id, parse) => {
+ if (!process.env.NODE_ENV) return;
+
+ const docuwareInfo = await Self.app.models.Docuware.findOne({
+ fields: ['findById'],
+ where: {
+ code,
+ action: 'find'
+ }
+ });
+ const filter = {
+ condition: [
+ {
+ DBName: docuwareInfo.findById,
+ Value: [id]
+ }
+ ]
+ };
+
+ return Self.get(code, filter, parse);
+ };
+
+ /**
+ * Returns docuware data filtered
+ *
+ * @param {array} data - The data
+ * @param {object} parse - The fields parsed
+ * @return {object} - The data parsed
+ */
+ function parser(data, parse) {
+ if (!(data && data.Items)) return data;
+
+ const parsed = [];
+ for (item of data.Items) {
+ const itemParsed = {};
+ item.Fields.map(field => {
+ if (field.ItemElementName.includes('Date')) field.Item = toDate(field.Item);
+ if (!parse) return itemParsed[field.FieldLabel] = field.Item;
+ if (parse[field.FieldLabel])
+ itemParsed[parse[field.FieldLabel]] = field.Item;
+ });
+ parsed.push(itemParsed);
+ }
+ return parsed;
+ }
+
+ function toDate(value) {
+ if (!value) return;
+ return new Date(Number(value.substring(6, 19)));
+ }
};
diff --git a/back/methods/docuware/download.js b/back/methods/docuware/download.js
index 56d006ee7..a0d72ce01 100644
--- a/back/methods/docuware/download.js
+++ b/back/methods/docuware/download.js
@@ -3,7 +3,7 @@ const axios = require('axios');
const UserError = require('vn-loopback/util/user-error');
module.exports = Self => {
- Self.remoteMethodCtx('download', {
+ Self.remoteMethod('download', {
description: 'Download an docuware PDF',
accessType: 'READ',
accepts: [
@@ -16,8 +16,12 @@ module.exports = Self => {
{
arg: 'fileCabinet',
type: 'string',
- description: 'The file cabinet',
- http: {source: 'path'}
+ description: 'The file cabinet'
+ },
+ {
+ arg: 'filter',
+ type: 'object',
+ description: 'The filter'
}
],
returns: [
@@ -36,14 +40,15 @@ module.exports = Self => {
}
],
http: {
- path: `/:id/download/:fileCabinet`,
+ path: `/:id/download`,
verb: 'GET'
}
});
- Self.download = async function(ctx, id, fileCabinet) {
+ Self.download = async function(id, fileCabinet, filter) {
const models = Self.app.models;
- const docuwareFile = await models.Docuware.checkFile(ctx, id, fileCabinet, true);
+
+ const docuwareFile = await models.Docuware.checkFile(id, fileCabinet, filter);
if (!docuwareFile) throw new UserError('The DOCUWARE PDF document does not exists');
const fileCabinetId = await Self.getFileCabinet(fileCabinet);
diff --git a/back/methods/docuware/specs/checkFile.spec.js b/back/methods/docuware/specs/checkFile.spec.js
index dd11951cc..8460bb561 100644
--- a/back/methods/docuware/specs/checkFile.spec.js
+++ b/back/methods/docuware/specs/checkFile.spec.js
@@ -1,57 +1,15 @@
const models = require('vn-loopback/server/server').models;
-const axios = require('axios');
describe('docuware download()', () => {
const ticketId = 1;
- const userId = 9;
- const ctx = {
- req: {
-
- accessToken: {userId: userId},
- headers: {origin: 'http://localhost:5000'},
- }
- };
const docuwareModel = models.Docuware;
const fileCabinetName = 'deliveryNote';
- beforeAll(() => {
- spyOn(docuwareModel, 'getFileCabinet').and.returnValue((new Promise(resolve => resolve(Math.random()))));
- spyOn(docuwareModel, 'getDialog').and.returnValue((new Promise(resolve => resolve(Math.random()))));
- });
-
it('should return false if there are no documents', async() => {
- const response = {
- data: {
- Items: []
- }
- };
- spyOn(axios, 'post').and.returnValue(new Promise(resolve => resolve(response)));
+ spyOn(docuwareModel, 'get').and.returnValue((new Promise(resolve => resolve({Items: []}))));
- const result = await models.Docuware.checkFile(ctx, ticketId, fileCabinetName, true);
-
- expect(result).toEqual(false);
- });
-
- it('should return false if the document is unsigned', async() => {
- const response = {
- data: {
- Items: [
- {
- Id: 1,
- Fields: [
- {
- FieldName: 'ESTADO',
- Item: 'Unsigned'
- }
- ]
- }
- ]
- }
- };
- spyOn(axios, 'post').and.returnValue(new Promise(resolve => resolve(response)));
-
- const result = await models.Docuware.checkFile(ctx, ticketId, fileCabinetName, true);
+ const result = await models.Docuware.checkFile(ticketId, fileCabinetName, null, true);
expect(result).toEqual(false);
});
@@ -59,23 +17,21 @@ describe('docuware download()', () => {
it('should return the document data', async() => {
const docuwareId = 1;
const response = {
- data: {
- Items: [
- {
- Id: docuwareId,
- Fields: [
- {
- FieldName: 'ESTADO',
- Item: 'Firmado'
- }
- ]
- }
- ]
- }
+ Items: [
+ {
+ Id: docuwareId,
+ Fields: [
+ {
+ FieldName: 'ESTADO',
+ Item: 'Firmado'
+ }
+ ]
+ }
+ ]
};
- spyOn(axios, 'post').and.returnValue(new Promise(resolve => resolve(response)));
+ spyOn(docuwareModel, 'get').and.returnValue((new Promise(resolve => resolve(response))));
- const result = await models.Docuware.checkFile(ctx, ticketId, fileCabinetName, true);
+ const result = await models.Docuware.checkFile(ticketId, fileCabinetName, null, true);
expect(result.id).toEqual(docuwareId);
});
diff --git a/back/methods/docuware/specs/core.spec.js b/back/methods/docuware/specs/core.spec.js
new file mode 100644
index 000000000..cdf8a3b62
--- /dev/null
+++ b/back/methods/docuware/specs/core.spec.js
@@ -0,0 +1,135 @@
+const axios = require('axios');
+const models = require('vn-loopback/server/server').models;
+
+describe('Docuware core', () => {
+ beforeAll(() => {
+ 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();
+ });
+ });
+
+ 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');
+
+ 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: {
+ 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: {
+ Items: [{
+ Fields: [
+ {
+ ItemElementName: 'integer',
+ FieldLabel: 'firstRequiredField',
+ Item: 1
+ },
+ {
+ ItemElementName: 'string',
+ FieldLabel: 'secondRequiredField',
+ Item: 'myName'
+ },
+ {
+ ItemElementName: 'integer',
+ FieldLabel: 'notRequiredField',
+ Item: 2
+ }
+ ]
+ }]
+ }
+ };
+ 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);
+ expect(result.name).toEqual('myName');
+ expect(result.notRequiredField).not.toBeDefined();
+ });
+ });
+
+ 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);
+
+ expect(result.id).toEqual(1);
+ });
+ });
+});
diff --git a/back/methods/docuware/specs/download.spec.js b/back/methods/docuware/specs/download.spec.js
index fcc1671a6..bc580a079 100644
--- a/back/methods/docuware/specs/download.spec.js
+++ b/back/methods/docuware/specs/download.spec.js
@@ -39,7 +39,7 @@ describe('docuware download()', () => {
spyOn(docuwareModel, 'checkFile').and.returnValue({});
spyOn(axios, 'get').and.returnValue(new stream.PassThrough({objectMode: true}));
- const result = await models.Docuware.download(ctx, ticketId, fileCabinetName);
+ const result = await models.Docuware.download(ticketId, fileCabinetName);
expect(result[1]).toEqual('application/pdf');
expect(result[2]).toEqual(`filename="${ticketId}.pdf"`);
diff --git a/back/methods/viaexpress-config/internationalExpedition.js b/back/methods/viaexpress-config/internationalExpedition.js
new file mode 100644
index 000000000..698bb1dac
--- /dev/null
+++ b/back/methods/viaexpress-config/internationalExpedition.js
@@ -0,0 +1,45 @@
+const axios = require('axios');
+const {DOMParser} = require('xmldom');
+
+module.exports = Self => {
+ Self.remoteMethod('internationalExpedition', {
+ description: 'Create an expedition and return a label',
+ accessType: 'WRITE',
+ accepts: [{
+ arg: 'expeditionFk',
+ type: 'number',
+ required: true
+ }],
+ returns: {
+ type: ['object'],
+ root: true
+ },
+ http: {
+ path: `/internationalExpedition`,
+ verb: 'POST'
+ }
+ });
+
+ Self.internationalExpedition = async expeditionFk => {
+ const models = Self.app.models;
+
+ const viaexpressConfig = await models.ViaexpressConfig.findOne({
+ fields: ['url']
+ });
+
+ const renderedXml = await models.ViaexpressConfig.renderer(expeditionFk);
+ const response = await axios.post(`${viaexpressConfig.url}ServicioVxClientes.asmx`, renderedXml, {
+ headers: {
+ 'Content-Type': 'application/soap+xml; charset=utf-8'
+ }
+ });
+
+ const xmlString = response.data;
+ const parser = new DOMParser();
+ const xmlDoc = parser.parseFromString(xmlString, 'text/xml');
+ const referenciaVxElement = xmlDoc.getElementsByTagName('ReferenciaVx')[0];
+ const referenciaVx = referenciaVxElement.textContent;
+
+ return referenciaVx;
+ };
+};
diff --git a/back/methods/viaexpress-config/renderer.js b/back/methods/viaexpress-config/renderer.js
new file mode 100644
index 000000000..e9abce5ca
--- /dev/null
+++ b/back/methods/viaexpress-config/renderer.js
@@ -0,0 +1,126 @@
+const fs = require('fs');
+const ejs = require('ejs');
+
+module.exports = Self => {
+ Self.remoteMethod('renderer', {
+ description: 'Renders the data from an XML',
+ accessType: 'READ',
+ accepts: [{
+ arg: 'expeditionFk',
+ type: 'number',
+ required: true
+ }],
+ returns: {
+ type: ['object'],
+ root: true
+ },
+ http: {
+ path: `/renderer`,
+ verb: 'GET'
+ }
+ });
+
+ Self.renderer = async expeditionFk => {
+ const models = Self.app.models;
+
+ const viaexpressConfig = await models.ViaexpressConfig.findOne({
+ fields: ['client', 'user', 'password', 'defaultWeight', 'deliveryType']
+ });
+
+ const expedition = await models.Expedition.findOne({
+ fields: ['id', 'ticketFk'],
+ where: {id: expeditionFk},
+ include: [
+ {
+ relation: 'ticket',
+ scope: {
+ fields: ['shipped', 'addressFk', 'clientFk', 'companyFk'],
+ include: [
+ {
+ relation: 'client',
+ scope: {
+ fields: ['mobile', 'phone', 'email']
+ }
+ },
+ {
+ relation: 'address',
+ scope: {
+ fields: [
+ 'nickname',
+ 'street',
+ 'postalCode',
+ 'city',
+ 'mobile',
+ 'phone',
+ 'provinceFk'
+ ],
+ include: {
+ relation: 'province',
+ scope: {
+ fields: ['name', 'countryFk'],
+ include: {
+ relation: 'country',
+ scope: {
+ fields: ['code'],
+ }
+ }
+
+ }
+ }
+ }
+ },
+ {
+ relation: 'company',
+ scope: {
+ fields: ['clientFk'],
+ include: {
+ relation: 'client',
+ scope: {
+ fields: ['socialName', 'mobile', 'phone', 'email', 'defaultAddressFk'],
+ include: {
+ relation: 'defaultAddress',
+ scope: {
+ fields: [
+ 'street',
+ 'postalCode',
+ 'city',
+ 'mobile',
+ 'phone',
+ 'provinceFk'
+ ],
+ include: {
+ relation: 'province',
+ scope: {
+ fields: ['name']
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ }
+
+ }
+ ]
+ });
+
+ const ticket = expedition.ticket();
+ const sender = ticket.company().client();
+ const shipped = ticket.shipped.toISOString();
+ const data = {
+ viaexpressConfig,
+ sender,
+ senderAddress: sender.defaultAddress(),
+ client: ticket.client(),
+ address: ticket.address(),
+ shipped
+ };
+
+ const template = fs.readFileSync(__dirname + '/template.ejs', 'utf-8');
+ const renderedXml = ejs.render(template, data);
+ return renderedXml;
+ };
+};
diff --git a/back/methods/viaexpress-config/template.ejs b/back/methods/viaexpress-config/template.ejs
new file mode 100644
index 000000000..0b6eb468c
--- /dev/null
+++ b/back/methods/viaexpress-config/template.ejs
@@ -0,0 +1,52 @@
+
+
+
+
+
+ <%= viaexpressConfig.defaultWeight %>
+ 1
+ 0
+ <%= shipped %>
+ 0
+ <%= viaexpressConfig.deliveryType %>
+ 0
+ 0
+ 0
+ 0
+ 0
+
+
+ 0
+
+
+
+ <%= sender.socialName %>
+ <%= senderAddress.street %>
+ <%= senderAddress.postalCode %>
+ <%= senderAddress.city %>
+ <%= senderAddress.province().name %>
+
+ <%= senderAddress.mobile || senderAddress.phone || sender.mobile || sender.phone %>
+ <%= sender.email %>
+
+
+ <%= address.nickname %>
+ <%= address.street %>
+ <%= address.postalCode %>
+ <%= address.city %>
+
+ <%= address.province().name %>
+
+ <%= address.mobile || address.phone || client.mobile || client.phone %>
+ <%= client.email %>
+ <%= address.province().country().code %>
+
+
+ <%= viaexpressConfig.client %>
+ <%= viaexpressConfig.user %>
+ <%= viaexpressConfig.password %>
+
+
+
+
+
diff --git a/back/methods/vn-user/addAlias.js b/back/methods/vn-user/addAlias.js
deleted file mode 100644
index 9fe43e713..000000000
--- a/back/methods/vn-user/addAlias.js
+++ /dev/null
@@ -1,68 +0,0 @@
-const UserError = require('vn-loopback/util/user-error');
-
-module.exports = Self => {
- Self.remoteMethod('addAlias', {
- description: 'Add an alias if the user has the grant',
- accessType: 'WRITE',
- accepts: [
- {
- arg: 'ctx',
- type: 'Object',
- http: {source: 'context'}
- },
- {
- arg: 'id',
- type: 'number',
- required: true,
- description: 'The user id',
- http: {source: 'path'}
- },
- {
- arg: 'mailAlias',
- type: 'number',
- description: 'The new alias for user',
- required: true
- }
- ],
- http: {
- path: `/:id/addAlias`,
- verb: 'POST'
- }
- });
-
- Self.addAlias = async function(ctx, id, mailAlias, options) {
- const models = Self.app.models;
- const userId = ctx.req.accessToken.userId;
-
- const myOptions = {};
-
- if (typeof options == 'object')
- Object.assign(myOptions, options);
-
- const user = await Self.findById(userId, {fields: ['hasGrant']}, myOptions);
-
- if (!user.hasGrant)
- throw new UserError(`You don't have grant privilege`);
-
- const account = await models.Account.findById(userId, {
- fields: ['id'],
- include: {
- relation: 'aliases',
- scope: {
- fields: ['mailAlias']
- }
- }
- }, myOptions);
-
- const aliases = account.aliases().map(alias => alias.mailAlias);
-
- const hasAlias = aliases.includes(mailAlias);
- if (!hasAlias)
- throw new UserError(`You cannot assign an alias that you are not assigned to`);
-
- return models.MailAliasAccount.create({
- mailAlias: mailAlias,
- account: id
- }, myOptions);
- };
-};
diff --git a/back/methods/vn-user/privileges.js b/back/methods/vn-user/privileges.js
index 690ce74a3..08cfaaae8 100644
--- a/back/methods/vn-user/privileges.js
+++ b/back/methods/vn-user/privileges.js
@@ -47,7 +47,7 @@ module.exports = Self => {
const user = await Self.findById(userId, {fields: ['hasGrant']}, myOptions);
const userToUpdate = await Self.findById(id, {
- fields: ['id', 'name', 'hasGrant', 'roleFk', 'password'],
+ fields: ['id', 'name', 'hasGrant', 'roleFk', 'password', 'email'],
include: {
relation: 'role',
scope: {
diff --git a/back/methods/vn-user/removeAlias.js b/back/methods/vn-user/removeAlias.js
deleted file mode 100644
index 0424c3e96..000000000
--- a/back/methods/vn-user/removeAlias.js
+++ /dev/null
@@ -1,55 +0,0 @@
-const UserError = require('vn-loopback/util/user-error');
-
-module.exports = Self => {
- Self.remoteMethod('removeAlias', {
- description: 'Remove alias if the user has the grant',
- accessType: 'WRITE',
- accepts: [
- {
- arg: 'ctx',
- type: 'Object',
- http: {source: 'context'}
- },
- {
- arg: 'id',
- type: 'number',
- required: true,
- description: 'The user id',
- http: {source: 'path'}
- },
- {
- arg: 'mailAlias',
- type: 'number',
- description: 'The alias to delete',
- required: true
- }
- ],
- http: {
- path: `/:id/removeAlias`,
- verb: 'POST'
- }
- });
-
- Self.removeAlias = async function(ctx, id, mailAlias, options) {
- const models = Self.app.models;
- const userId = ctx.req.accessToken.userId;
-
- const myOptions = {};
-
- if (typeof options == 'object')
- Object.assign(myOptions, options);
-
- const canRemoveAlias = await models.ACL.checkAccessAcl(ctx, 'VnUser', 'canRemoveAlias', 'WRITE');
-
- if (userId != id && !canRemoveAlias) throw new UserError(`You don't have grant privilege`);
-
- const mailAliasAccount = await models.MailAliasAccount.findOne({
- where: {
- mailAlias: mailAlias,
- account: id
- }
- }, myOptions);
-
- await mailAliasAccount.destroy(myOptions);
- };
-};
diff --git a/back/model-config.json b/back/model-config.json
index 0e37bf527..b88956dee 100644
--- a/back/model-config.json
+++ b/back/model-config.json
@@ -150,6 +150,9 @@
},
"PrintConfig": {
"dataSource": "vn"
+ },
+ "ViaexpressConfig": {
+ "dataSource": "vn"
}
}
diff --git a/back/models/company.json b/back/models/company.json
index f16c5762f..d7e88cd11 100644
--- a/back/models/company.json
+++ b/back/models/company.json
@@ -18,11 +18,21 @@
},
"expired": {
"type": "date"
+ },
+ "supplierAccountFk": {
+ "type": "number"
}
},
"scope": {
"where" :{
"expired": null
}
+ },
+ "relations": {
+ "client": {
+ "type": "belongsTo",
+ "model": "Client",
+ "foreignKey": "clientFk"
+ }
}
}
diff --git a/back/models/country.json b/back/models/country.json
index 8fa25b88e..fd540d819 100644
--- a/back/models/country.json
+++ b/back/models/country.json
@@ -22,6 +22,9 @@
},
"isUeeMember": {
"type": "boolean"
+ },
+ "isSocialNameUnique": {
+ "type": "boolean"
}
},
"relations": {
@@ -39,4 +42,4 @@
"permission": "ALLOW"
}
]
-}
\ No newline at end of file
+}
diff --git a/back/models/docuware.json b/back/models/docuware.json
index dec20eede..b1a6a8bce 100644
--- a/back/models/docuware.json
+++ b/back/models/docuware.json
@@ -28,5 +28,12 @@
"findById": {
"type": "string"
}
+ },
+ "relations": {
+ "dmsType": {
+ "type": "belongsTo",
+ "model": "DmsType",
+ "foreignKey": "dmsTypeFk"
+ }
}
}
diff --git a/back/models/viaexpress-config.js b/back/models/viaexpress-config.js
new file mode 100644
index 000000000..d0335b28b
--- /dev/null
+++ b/back/models/viaexpress-config.js
@@ -0,0 +1,4 @@
+module.exports = Self => {
+ require('../methods/viaexpress-config/internationalExpedition')(Self);
+ require('../methods/viaexpress-config/renderer')(Self);
+};
diff --git a/back/models/viaexpress-config.json b/back/models/viaexpress-config.json
new file mode 100644
index 000000000..8df24201b
--- /dev/null
+++ b/back/models/viaexpress-config.json
@@ -0,0 +1,34 @@
+{
+ "name": "ViaexpressConfig",
+ "base": "VnModel",
+ "options": {
+ "mysql": {
+ "table": "viaexpressConfig"
+ }
+ },
+ "properties": {
+ "id": {
+ "type": "number",
+ "required": true
+ },
+ "url": {
+ "type": "string",
+ "required": true
+ },
+ "client": {
+ "type": "string"
+ },
+ "user": {
+ "type": "string"
+ },
+ "password": {
+ "type": "string"
+ },
+ "defaultWeight": {
+ "type": "number"
+ },
+ "deliveryType": {
+ "type": "string"
+ }
+ }
+}
diff --git a/back/models/vn-user.js b/back/models/vn-user.js
index 11d4bf250..68a556d77 100644
--- a/back/models/vn-user.js
+++ b/back/models/vn-user.js
@@ -12,8 +12,6 @@ module.exports = function(Self) {
require('../methods/vn-user/privileges')(Self);
require('../methods/vn-user/validate-auth')(Self);
require('../methods/vn-user/renew-token')(Self);
- require('../methods/vn-user/addAlias')(Self);
- require('../methods/vn-user/removeAlias')(Self);
Self.definition.settings.acls = Self.definition.settings.acls.filter(acl => acl.property !== 'create');
@@ -22,7 +20,7 @@ module.exports = function(Self) {
Self.validatesFormatOf('email', {
message: 'Invalid email',
allowNull: true,
- allowBlank: true,
+ allowBlank: false,
with: /^[\w|.|-]+@[\w|-]+(\.[\w|-]+)*(,[\w|.|-]+@[\w|-]+(\.[\w|-]+)*)*$/
});
@@ -117,6 +115,14 @@ module.exports = function(Self) {
Self.validateLogin = async function(user, password) {
let loginInfo = Object.assign({password}, Self.userUses(user));
token = await Self.login(loginInfo, 'user');
+
+ const userToken = await token.user.get();
+ try {
+ await Self.app.models.Account.sync(userToken.name, password);
+ } catch (err) {
+ console.warn(err);
+ }
+
return {token: token.id, ttl: token.ttl};
};
diff --git a/db/changes/232601/00-aclAddAlias.sql b/db/changes/232601/00-aclAddAlias.sql
deleted file mode 100644
index cc96f5ad8..000000000
--- a/db/changes/232601/00-aclAddAlias.sql
+++ /dev/null
@@ -1,11 +0,0 @@
-INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId)
- VALUES
- ('VnUser', 'addAlias', 'WRITE', 'ALLOW', 'ROLE', 'employee');
-
-INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId)
- VALUES
- ('VnUser', 'removeAlias', 'WRITE', 'ALLOW', 'ROLE', 'employee');
-
-INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId)
- VALUES
- ('VnUser', 'canRemoveAlias', 'WRITE', 'ALLOW', 'ROLE', 'itManagement');
diff --git a/db/changes/232602/01-aclAddAlias.sql b/db/changes/232602/01-aclAddAlias.sql
new file mode 100644
index 000000000..d4df3cd44
--- /dev/null
+++ b/db/changes/232602/01-aclAddAlias.sql
@@ -0,0 +1,8 @@
+DELETE FROM `salix`.`ACL` WHERE model = 'MailAliasAccount';
+
+INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId)
+ VALUES
+ ('MailAliasAccount', '*', 'READ', 'ALLOW', 'ROLE', 'employee'),
+ ('MailAliasAccount', 'create', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
+ ('MailAliasAccount', 'deleteById', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
+ ('MailAliasAccount', 'canEditAlias', 'WRITE', 'ALLOW', 'ROLE', 'itManagement');
diff --git a/db/changes/232802/01-aclWorkerDisable.sql b/db/changes/232802/01-aclWorkerDisable.sql
new file mode 100644
index 000000000..149dd6f15
--- /dev/null
+++ b/db/changes/232802/01-aclWorkerDisable.sql
@@ -0,0 +1,4 @@
+INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId)
+ VALUES
+ ('WorkerDisableExcluded', '*', 'READ', 'ALLOW', 'ROLE', 'itManagement'),
+ ('WorkerDisableExcluded', '*', 'WRITE', 'ALLOW', 'ROLE', 'itManagement');
diff --git a/db/changes/233001/00-clientSms.sql b/db/changes/233001/00-clientSms.sql
new file mode 100644
index 000000000..e1e34f6b2
--- /dev/null
+++ b/db/changes/233001/00-clientSms.sql
@@ -0,0 +1,15 @@
+CREATE TABLE `vn`.`clientSms` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `clientFk` int(11) NOT NULL,
+ `smsFk` mediumint(8) unsigned NOT NULL,
+ PRIMARY KEY (`id`),
+ KEY `clientSms_FK` (`clientFk`),
+ KEY `clientSms_FK_1` (`smsFk`),
+ CONSTRAINT `clientSms_FK` FOREIGN KEY (`clientFk`) REFERENCES `client` (`id`) ON UPDATE CASCADE,
+ CONSTRAINT `clientSms_FK_1` FOREIGN KEY (`smsFk`) REFERENCES `sms` (`id`) ON UPDATE CASCADE
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
+
+INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
+ VALUES
+ ('ClientSms', 'find', 'READ', 'ALLOW', 'ROLE', 'employee'),
+ ('ClientSms', 'create', 'WRITE', 'ALLOW', 'ROLE', 'employee');
diff --git a/db/changes/233001/00-company.sql b/db/changes/233001/00-company.sql
new file mode 100644
index 000000000..a3b61b9cc
--- /dev/null
+++ b/db/changes/233001/00-company.sql
@@ -0,0 +1 @@
+ALTER TABLE `vn`.`company` MODIFY COLUMN sage200Company int(2) DEFAULT 10 NOT NULL;
diff --git a/db/changes/233001/00-fixACLVehicle.sql b/db/changes/233001/00-fixACLVehicle.sql
new file mode 100644
index 000000000..6625f0d5c
--- /dev/null
+++ b/db/changes/233001/00-fixACLVehicle.sql
@@ -0,0 +1,3 @@
+INSERT INTO `salix`.`ACL` (`model`,`property`,`accessType`,`permission`,`principalId`)
+ VALUES
+ ('Vehicle','sorted','WRITE','ALLOW','employee');
\ No newline at end of file
diff --git a/db/changes/233001/00-itemShelving_inventory.sql b/db/changes/233001/00-itemShelving_inventory.sql
new file mode 100644
index 000000000..b0b080ef3
--- /dev/null
+++ b/db/changes/233001/00-itemShelving_inventory.sql
@@ -0,0 +1,64 @@
+
+DELIMITER $$
+CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`itemShelving_inventory`(vParkingFromFk VARCHAR(8), vParkingToFk VARCHAR(8))
+BEGIN
+/**
+ * Devuelve un listado de ubicaciones a revisar
+ *
+ * @param vParkingFromFk Parking de partida, identificador de parking
+ * @param vParkingToFk Parking de llegada, identificador de parking
+*/
+
+ DECLARE vSectorFk INT;
+ DECLARE vPickingOrderFrom INT;
+ DECLARE vPickingOrderTo INT;
+
+ SELECT p.sectorFk, p.pickingOrder INTO vSectorFk, vPickingOrderFrom
+ FROM parking p
+ WHERE p.code = vParkingFromFk COLLATE 'utf8mb3_general_ci';
+
+ SELECT p.pickingOrder INTO vPickingOrderTo
+ FROM parking p
+ WHERE p.code = vParkingToFk COLLATE 'utf8mb3_general_ci';
+
+ CALL visible_getMisfit(vSectorFk);
+
+ SELECT ish.id,
+ p.pickingOrder,
+ p.code parking,
+ ish.shelvingFk,
+ ish.itemFk,
+ i.longName,
+ ish.visible,
+ p.sectorFk,
+ it.workerFk buyer,
+ CONCAT('http:',ic.url, '/catalog/1600x900/',i.image) urlImage,
+ ish.isChecked,
+ CASE
+ WHEN s.notPrepared > sm.parked THEN 0
+ WHEN sm.visible > sm.parked THEN 1
+ ELSE 2
+ END priority
+ FROM itemShelving ish
+ JOIN item i ON i.id = ish.itemFk
+ JOIN itemType it ON it.id = i.typeFk
+ JOIN tmp.stockMisfit sm ON sm.itemFk = ish.itemFk
+ JOIN shelving sh ON sh.code = ish.shelvingFk
+ JOIN parking p ON p.id = sh.parkingFk
+ JOIN (SELECT s.itemFk, sum(s.quantity) notPrepared
+ FROM sale s
+ JOIN ticket t ON t.id = s.ticketFk
+ JOIN warehouse w ON w.id = t.warehouseFk
+ JOIN config c ON c.mainWarehouseFk = w.id
+ WHERE t.shipped BETWEEN util.VN_CURDATE()
+ AND util.dayEnd(util.VN_CURDATE())
+ AND s.isPicked = FALSE
+ GROUP BY s.itemFk) s ON s.itemFk = i.id
+ JOIN hedera.imageConfig ic
+ WHERE p.pickingOrder BETWEEN vPickingOrderFrom AND vPickingOrderTo
+ AND p.sectorFk = vSectorFk
+ ORDER BY p.pickingOrder;
+
+END$$
+DELIMITER ;
+
diff --git a/db/changes/233001/00-noUniqueSocialName.sql b/db/changes/233001/00-noUniqueSocialName.sql
new file mode 100644
index 000000000..0dc4c832f
--- /dev/null
+++ b/db/changes/233001/00-noUniqueSocialName.sql
@@ -0,0 +1,2 @@
+ALTER TABLE `vn`.`country`
+ADD COLUMN `isSocialNameUnique` tinyint(1) NOT NULL DEFAULT 1;
diff --git a/db/changes/232801/00-roadmap.sql b/db/changes/233001/00-roadmap.sql
similarity index 69%
rename from db/changes/232801/00-roadmap.sql
rename to db/changes/233001/00-roadmap.sql
index a2835160f..9b5db54eb 100644
--- a/db/changes/232801/00-roadmap.sql
+++ b/db/changes/233001/00-roadmap.sql
@@ -6,5 +6,3 @@ ALTER TABLE `vn`.`roadmap` CHANGE name name varchar(45) CHARACTER SET utf8mb3 CO
ALTER TABLE `vn`.`roadmap` MODIFY COLUMN etd datetime NOT NULL;
ALTER TABLE `vn`.`expeditionTruck` COMMENT='Distintas paradas que hacen los trocales';
-ALTER TABLE `vn`.`expeditionTruck` DROP FOREIGN KEY expeditionTruck_FK_2;
-ALTER TABLE `vn`.`expeditionTruck` ADD CONSTRAINT expeditionTruck_FK_2 FOREIGN KEY (roadmapFk) REFERENCES vn.roadmap(id) ON DELETE CASCADE ON UPDATE CASCADE;
diff --git a/db/changes/232801/00-roadmapACL.sql b/db/changes/233001/00-roadmapACL.sql
similarity index 100%
rename from db/changes/232801/00-roadmapACL.sql
rename to db/changes/233001/00-roadmapACL.sql
diff --git a/db/changes/233201/.gitkeep b/db/changes/233201/.gitkeep
new file mode 100644
index 000000000..e69de29bb
diff --git a/db/changes/233201/00-acl_viaexpressConfig.sql b/db/changes/233201/00-acl_viaexpressConfig.sql
new file mode 100644
index 000000000..d4c186dd4
--- /dev/null
+++ b/db/changes/233201/00-acl_viaexpressConfig.sql
@@ -0,0 +1,4 @@
+INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
+ VALUES
+ ('ViaexpressConfig', 'internationalExpedition', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
+ ('ViaexpressConfig', 'renderer', 'READ', 'ALLOW', 'ROLE', 'employee');
diff --git a/db/changes/233201/00-transferClient.sql b/db/changes/233201/00-transferClient.sql
new file mode 100644
index 000000000..8a7ce0543
--- /dev/null
+++ b/db/changes/233201/00-transferClient.sql
@@ -0,0 +1,2 @@
+INSERT INTO `salix`.`ACL` (`model`,`property`,`accessType`,`permission`,`principalType`,`principalId`)
+ VALUES ('Ticket','transferClient','WRITE','ALLOW','ROLE','administrative');
\ No newline at end of file
diff --git a/db/changes/233201/00-updatePrice.sql b/db/changes/233201/00-updatePrice.sql
new file mode 100644
index 000000000..959943d6f
--- /dev/null
+++ b/db/changes/233201/00-updatePrice.sql
@@ -0,0 +1,2 @@
+INSERT INTO `salix`.`ACL` (`model`,`property`,`accessType`,`permission`,`principalType`,`principalId`)
+ VALUES ('Ticket','canEditWeekly','WRITE','ALLOW','ROLE','buyer');
diff --git a/db/changes/233201/00-viaexpress.sql b/db/changes/233201/00-viaexpress.sql
new file mode 100644
index 000000000..42cf3b647
--- /dev/null
+++ b/db/changes/233201/00-viaexpress.sql
@@ -0,0 +1,10 @@
+CREATE TABLE `vn`.`viaexpressConfig` (
+ id int auto_increment NOT NULL,
+ url varchar(100) NOT NULL,
+ client varchar(100) NOT NULL,
+ user varchar(100) NOT NULL,
+ password varchar(100) NOT NULL,
+ defaultWeight decimal(10,2) NOT NULL,
+ deliveryType varchar(5) NOT NULL,
+ CONSTRAINT viaexpressConfig_PK PRIMARY KEY (id)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
diff --git a/db/changes/233201/00-workerDocuware.sql b/db/changes/233201/00-workerDocuware.sql
new file mode 100644
index 000000000..2f2c4a1cd
--- /dev/null
+++ b/db/changes/233201/00-workerDocuware.sql
@@ -0,0 +1,10 @@
+ALTER TABLE `vn`.`docuware` ADD dmsTypeFk INT(11) DEFAULT NULL NULL;
+ALTER TABLE `vn`.`docuware` ADD CONSTRAINT docuware_FK FOREIGN KEY (dmsTypeFk) REFERENCES `vn`.`dmsType`(id) ON DELETE RESTRICT ON UPDATE CASCADE;
+INSERT INTO `vn`.`docuware` (code, fileCabinetName, `action`, dialogName, findById, dmsTypeFk)
+ VALUES
+ ('hr', 'RRHH', 'find', 'Búsqueda', 'N__DOCUMENTO', NULL); -- set dmsTypeFk 3 when deploy in production
+
+INSERT INTO `salix`.`url` (appName, environment, url)
+ VALUES
+ ('docuware', 'production', 'https://verdnatura.docuware.cloud/DocuWare/Platform/');
+
diff --git a/db/changes/233401/.gitkeep b/db/changes/233401/.gitkeep
new file mode 100644
index 000000000..e69de29bb
diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql
index fe11d5b64..7a572fb04 100644
--- a/db/dump/fixtures.sql
+++ b/db/dump/fixtures.sql
@@ -37,7 +37,7 @@ ALTER TABLE `vn`.`ticket` AUTO_INCREMENT = 1;
INSERT INTO `salix`.`AccessToken` (`id`, `ttl`, `created`, `userId`)
VALUES
- ('DEFAULT_TOKEN', '1209600', util.VN_CURDATE(), 66);
+ ('DEFAULT_TOKEN', '1209600', CURDATE(), 66);
INSERT INTO `salix`.`printConfig` (`id`, `itRecipient`, `incidencesEmail`)
VALUES
@@ -360,13 +360,13 @@ INSERT INTO `vn`.`contactChannel`(`id`, `name`)
INSERT INTO `vn`.`client`(`id`,`name`,`fi`,`socialName`,`contact`,`street`,`city`,`postcode`,`phone`,`mobile`,`isRelevant`,`email`,`iban`,`dueDay`,`accountingAccount`,`isEqualizated`,`provinceFk`,`hasToInvoice`,`credit`,`countryFk`,`isActive`,`gestdocFk`,`quality`,`payMethodFk`,`created`,`isToBeMailed`,`contactChannelFk`,`hasSepaVnl`,`hasCoreVnl`,`hasCoreVnh`,`riskCalculated`,`clientTypeFk`, `hasToInvoiceByAddress`,`isTaxDataChecked`,`isFreezed`,`creditInsurance`,`isCreatedAsServed`,`hasInvoiceSimplified`,`salesPersonFk`,`isVies`,`eypbc`, `businessTypeFk`)
VALUES
- (1101, 'Bruce Wayne', '84612325V', 'Batman', 'Alfred', '1007 Mountain Drive, Gotham', 'Gotham', 46460, 1111111111, 222222222, 1, 'BruceWayne@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist'),
- (1102, 'Petter Parker', '87945234L', 'Spider man', 'Aunt May', '20 Ingram Street, Queens, USA', 'Gotham', 46460, 1111111111, 222222222, 1, 'PetterParker@mydomain.com', NULL, 0, 1234567890, 0, 2, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist'),
+ (1101, 'Bruce Wayne', '84612325V', 'BATMAN', 'Alfred', '1007 MOUNTAIN DRIVE, GOTHAM', 'Gotham', 46460, 1111111111, 222222222, 1, 'BruceWayne@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist'),
+ (1102, 'Petter Parker', '87945234L', 'SPIDER MAN', 'Aunt May', '20 INGRAM STREET, QUEENS, USA', 'Gotham', 46460, 1111111111, 222222222, 1, 'PetterParker@mydomain.com', NULL, 0, 1234567890, 0, 2, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist'),
(1103, 'Clark Kent', '06815934E', 'Super man', 'lois lane', '344 Clinton Street, Apartament 3-D', 'Gotham', 46460, 1111111111, 222222222, 1, 'ClarkKent@mydomain.com', NULL, 0, 1234567890, 0, 3, 1, 0, 19, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist'),
(1104, 'Tony Stark', '06089160W', 'Iron man', 'Pepper Potts', '10880 Malibu Point, 90265', 'Gotham', 46460, 1111111111, 222222222, 1, 'TonyStark@mydomain.com', NULL, 0, 1234567890, 0, 2, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist'),
(1105, 'Max Eisenhardt', '251628698', 'Magneto', 'Rogue', 'Unknown Whereabouts', 'Gotham', 46460, 1111111111, 222222222, 1, 'MaxEisenhardt@mydomain.com', NULL, 0, 1234567890, 0, 3, 1, 300, 8, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 1, NULL, 0, 0, 18, 0, 1, 'florist'),
- (1106, 'DavidCharlesHaller', '53136686Q', 'Legion', 'Charles Xavier', 'City of New York, New York, USA', 'Gotham', 46460, 1111111111, 222222222, 1, 'DavidCharlesHaller@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 0, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 0, NULL, 0, 0, 19, 0, 1, 'florist'),
- (1107, 'Hank Pym', '09854837G', 'Ant man', 'Hawk', 'Anthill, San Francisco, California', 'Gotham', 46460, 1111111111, 222222222, 1, 'HankPym@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 0, 0, NULL, 0, 0, 19, 0, 1, 'florist'),
+ (1106, 'DavidCharlesHaller', '53136686Q', 'LEGION', 'Charles Xavier', 'CITY OF NEW YORK, NEW YORK, USA', 'Gotham', 46460, 1111111111, 222222222, 1, 'DavidCharlesHaller@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 0, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 0, NULL, 0, 0, 19, 0, 1, 'florist'),
+ (1107, 'Hank Pym', '09854837G', 'ANT MAN', 'Hawk', 'ANTHILL, SAN FRANCISCO, CALIFORNIA', 'Gotham', 46460, 1111111111, 222222222, 1, 'HankPym@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 0, 0, NULL, 0, 0, 19, 0, 1, 'florist'),
(1108, 'Charles Xavier', '22641921P', 'Professor X', 'Beast', '3800 Victory Pkwy, Cincinnati, OH 45207, USA', 'Gotham', 46460, 1111111111, 222222222, 1, 'CharlesXavier@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 1, NULL, 0, 0, 19, 0, 1, 'florist'),
(1109, 'Bruce Banner', '16104829E', 'Hulk', 'Black widow', 'Somewhere in New York', 'Gotham', 46460, 1111111111, 222222222, 1, 'BruceBanner@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 0, 0, NULL, 0, 0, 9, 0, 1, 'florist'),
(1110, 'Jessica Jones', '58282869H', 'Jessica Jones', 'Luke Cage', 'NYCC 2015 Poster', 'Gotham', 46460, 1111111111, 222222222, 1, 'JessicaJones@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5, util.VN_CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 0, 0, NULL, 0, 0, NULL, 0, 1, 'florist'),
@@ -579,13 +579,13 @@ INSERT INTO `vn`.`supplierAccount`(`id`, `supplierFk`, `iban`, `bankEntityFk`)
VALUES
(241, 442, 'ES111122333344111122221111', 128);
-INSERT INTO `vn`.`company`(`id`, `code`, `supplierAccountFk`, `workerManagerFk`, `companyCode`, `sage200Company`, `expired`, `companyGroupFk`, `phytosanitary`)
+INSERT INTO `vn`.`company`(`id`, `code`, `supplierAccountFk`, `workerManagerFk`, `companyCode`, `sage200Company`, `expired`, `companyGroupFk`, `phytosanitary` , `clientFk`)
VALUES
- (69 , 'CCs', NULL, 30, NULL, 0, NULL, 1, NULL),
- (442 , 'VNL', 241, 30, 2 , 1, NULL, 2, 'VNL Company - Plant passport'),
- (567 , 'VNH', NULL, 30, NULL, 4, NULL, 1, 'VNH Company - Plant passport'),
- (791 , 'FTH', NULL, 30, NULL, 3, '2015-11-30', 1, NULL),
- (1381, 'ORN', NULL, 30, NULL, 7, NULL, 1, 'ORN Company - Plant passport');
+ (69 , 'CCs', NULL, 30, NULL, 0, NULL, 1, NULL , NULL),
+ (442 , 'VNL', 241, 30, 2 , 1, NULL, 2, 'VNL Company - Plant passport' , 1101),
+ (567 , 'VNH', NULL, 30, NULL, 4, NULL, 1, 'VNH Company - Plant passport' , NULL),
+ (791 , 'FTH', NULL, 30, NULL, 3, '2015-11-30', 1, NULL , NULL),
+ (1381, 'ORN', NULL, 30, NULL, 7, NULL, 1, 'ORN Company - Plant passport' , NULL);
INSERT INTO `vn`.`taxArea` (`code`, `claveOperacionFactura`, `CodigoTransaccion`)
VALUES
@@ -2953,3 +2953,8 @@ INSERT INTO `vn`.`invoiceInSerial` (`code`, `description`, `cplusTerIdNifFk`, `t
('E', 'Midgard', 1, 'CEE'),
('R', 'Jotunheim', 1, 'NATIONAL'),
('W', 'Vanaheim', 1, 'WORLD');
+
+
+INSERT INTO `hedera`.`imageConfig` (`id`, `maxSize`, `useXsendfile`, `url`)
+ VALUES
+ (1, 0, 0, 'marvel.com');
diff --git a/db/dump/structure.sql b/db/dump/structure.sql
index ee5fb40a1..4e7127310 100644
--- a/db/dump/structure.sql
+++ b/db/dump/structure.sql
@@ -77831,7 +77831,7 @@ BEGIN
LEAVE cur1Loop;
END IF;
- CALL zone_getLeaves2(vZoneFk, NULL, NULL);
+ CALL zone_getLeaves(vZoneFk, NULL, NULL, TRUE);
myLoop: LOOP
SET vGeoFk = NULL;
@@ -77844,7 +77844,7 @@ BEGIN
LEAVE myLoop;
END IF;
- CALL zone_getLeaves2(vZoneFk, vGeoFk, NULL);
+ CALL zone_getLeaves(vZoneFk, vGeoFk, NULL, TRUE);
UPDATE tmp.zoneNodes
SET isChecked = TRUE
WHERE geoFk = vGeoFk;
@@ -78130,55 +78130,58 @@ DELIMITER ;
/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
/*!50003 SET sql_mode = 'IGNORE_SPACE,NO_ENGINE_SUBSTITUTION' */ ;
DELIMITER ;;
-CREATE DEFINER=`root`@`localhost` PROCEDURE `zone_getLeaves`(vSelf INT, vParentFk INT, vSearch VARCHAR(255))
-BEGIN
+CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`zone_getLeaves`(
+ vSelf INT,
+ vParentFk INT,
+ vSearch VARCHAR(255),
+ vHasInsert BOOL
+)
+BEGIN
/**
* Devuelve las ubicaciones incluidas en la ruta y que sean hijos de parentFk.
* @param vSelf Id de la zona
* @param vParentFk Id del geo a calcular
- * @param vSearch cadena a buscar
+ * @param vSearch Cadena a buscar
+ * @param vHasInsert Indica si inserta en tmp.zoneNodes
+ * Optional @table tmp.zoneNodes(geoFk, name, parentFk, sons, isChecked, zoneFk)
*/
DECLARE vIsNumber BOOL;
- DECLARE vIsSearch BOOL DEFAULT vSearch IS NOT NULL AND vSearch != '';
+ DECLARE vIsSearch BOOL DEFAULT vSearch IS NOT NULL AND vSearch <> '';
- DROP TEMPORARY TABLE IF EXISTS tNodes;
- CREATE TEMPORARY TABLE tNodes
+ CREATE OR REPLACE TEMPORARY TABLE tNodes
(UNIQUE (id))
ENGINE = MEMORY
- SELECT id
- FROM zoneGeo
+ SELECT id
+ FROM zoneGeo
LIMIT 0;
IF vIsSearch THEN
SET vIsNumber = vSearch REGEXP '^[0-9]+$';
-
+
INSERT INTO tNodes
- SELECT id
+ SELECT id
FROM zoneGeo
WHERE (vIsNumber AND `name` = vSearch)
OR (!vIsNumber AND `name` LIKE CONCAT('%', vSearch, '%'))
LIMIT 1000;
-
+
ELSEIF vParentFk IS NULL THEN
INSERT INTO tNodes
- SELECT geoFk
+ SELECT geoFk
FROM zoneIncluded
WHERE zoneFk = vSelf;
END IF;
IF vParentFk IS NULL THEN
- DROP TEMPORARY TABLE IF EXISTS tChilds;
- CREATE TEMPORARY TABLE tChilds
+ CREATE OR REPLACE TEMPORARY TABLE tChilds
+ (INDEX(id))
ENGINE = MEMORY
- SELECT id
- FROM tNodes;
+ SELECT id FROM tNodes;
- DROP TEMPORARY TABLE IF EXISTS tParents;
- CREATE TEMPORARY TABLE tParents
+ CREATE OR REPLACE TEMPORARY TABLE tParents
+ (INDEX(id))
ENGINE = MEMORY
- SELECT id
- FROM zoneGeo
- LIMIT 0;
+ SELECT id FROM zoneGeo LIMIT 0;
myLoop: LOOP
DELETE FROM tParents;
@@ -78186,43 +78189,67 @@ BEGIN
SELECT parentFk id
FROM zoneGeo g
JOIN tChilds c ON c.id = g.id
- WHERE g.parentFk IS NOT NULL;
-
+ WHERE g.parentFk IS NOT NULL;
+
INSERT IGNORE INTO tNodes
- SELECT id
- FROM tParents;
-
- IF ROW_COUNT() = 0 THEN
+ SELECT id FROM tParents;
+
+ IF NOT ROW_COUNT() THEN
LEAVE myLoop;
END IF;
-
+
DELETE FROM tChilds;
INSERT INTO tChilds
- SELECT id
- FROM tParents;
+ SELECT id FROM tParents;
END LOOP;
-
+
DROP TEMPORARY TABLE tChilds, tParents;
END IF;
- IF !vIsSearch THEN
+ IF NOT vIsSearch THEN
INSERT IGNORE INTO tNodes
- SELECT id
+ SELECT id
FROM zoneGeo
WHERE parentFk <=> vParentFk;
END IF;
- SELECT g.id,
- g.name,
- g.parentFk,
- g.sons,
- isIncluded selected
- FROM zoneGeo g
- JOIN tNodes n ON n.id = g.id
- LEFT JOIN zoneIncluded i ON i.geoFk = g.id AND i.zoneFk = vSelf
- ORDER BY `depth`, selected DESC, name;
+ CREATE OR REPLACE TEMPORARY TABLE tZones
+ SELECT g.id,
+ g.name,
+ g.parentFk,
+ g.sons,
+ NOT g.sons OR `type` = 'country' isChecked,
+ i.isIncluded selected,
+ g.`depth`,
+ vSelf
+ FROM zoneGeo g
+ JOIN tNodes n ON n.id = g.id
+ LEFT JOIN zoneIncluded i ON i.geoFk = g.id
+ AND i.zoneFk = vSelf
+ ORDER BY g.`depth`, selected DESC, g.name;
- DROP TEMPORARY TABLE tNodes;
+ IF vHasInsert THEN
+ INSERT IGNORE INTO tmp.zoneNodes(geoFk, name, parentFk, sons, isChecked, zoneFk)
+ SELECT id,
+ name,
+ parentFk,
+ sons,
+ isChecked,
+ vSelf
+ FROM tZones
+ WHERE selected
+ OR (selected IS NULL AND vParentFk IS NOT NULL);
+ ELSE
+ SELECT id,
+ name,
+ parentFk,
+ sons,
+ selected
+ FROM tZones
+ ORDER BY `depth`, selected DESC, name;
+ END IF;
+
+ DROP TEMPORARY TABLE tNodes, tZones;
END ;;
DELIMITER ;
/*!50003 SET sql_mode = @saved_sql_mode */ ;
@@ -78540,7 +78567,7 @@ BEGIN
INDEX(geoFk))
ENGINE = MEMORY;
- CALL zone_getLeaves2(vSelf, NULL , NULL);
+ CALL zone_getLeaves(vSelf, NULL , NULL, TRUE);
UPDATE tmp.zoneNodes zn
SET isChecked = 0
@@ -78553,7 +78580,7 @@ BEGIN
WHERE NOT isChecked
LIMIT 1;
- CALL zone_getLeaves2(vSelf, vGeoFk, NULL);
+ CALL zone_getLeaves(vSelf, vGeoFk, NULL, TRUE);
UPDATE tmp.zoneNodes
SET isChecked = TRUE
WHERE geoFk = vGeoFk;
diff --git a/e2e/helpers/selectors.js b/e2e/helpers/selectors.js
index 977c8a837..93288efa7 100644
--- a/e2e/helpers/selectors.js
+++ b/e2e/helpers/selectors.js
@@ -875,7 +875,7 @@ export default {
},
routeTickets: {
- firstTicketPriority: 'vn-route-tickets vn-tr:nth-child(1) vn-input-number[ng-model="ticket.priority"]',
+ firstTicketPriority: 'vn-route-tickets vn-tr:nth-child(1) vn-td-editable',
firstTicketCheckbox: 'vn-route-tickets vn-tr:nth-child(1) vn-check',
buscamanButton: 'vn-route-tickets vn-button[icon="icon-buscaman"]',
firstTicketDeleteButton: 'vn-route-tickets vn-tr:nth-child(1) vn-icon[icon="delete"]',
diff --git a/e2e/paths/02-client/01_create_client.spec.js b/e2e/paths/02-client/01_create_client.spec.js
index ff2aac6b9..3274ae8f1 100644
--- a/e2e/paths/02-client/01_create_client.spec.js
+++ b/e2e/paths/02-client/01_create_client.spec.js
@@ -73,8 +73,8 @@ describe('Client create path', () => {
it(`should attempt to create a new user with all it's data but wrong email`, async() => {
await page.write(selectors.createClientView.name, 'Carol Danvers');
- await page.write(selectors.createClientView.socialName, 'AVG tax');
- await page.write(selectors.createClientView.street, 'Many places');
+ await page.write(selectors.createClientView.socialName, 'AVG TAX');
+ await page.write(selectors.createClientView.street, 'MANY PLACES');
await page.clearInput(selectors.createClientView.email);
await page.write(selectors.createClientView.email, 'incorrect email format');
await page.waitToClick(selectors.createClientView.createButton);
diff --git a/e2e/paths/02-client/03_edit_fiscal_data.spec.js b/e2e/paths/02-client/03_edit_fiscal_data.spec.js
index 0babb5396..9098e816f 100644
--- a/e2e/paths/02-client/03_edit_fiscal_data.spec.js
+++ b/e2e/paths/02-client/03_edit_fiscal_data.spec.js
@@ -61,7 +61,7 @@ describe('Client Edit fiscalData path', () => {
await page.clearInput(selectors.clientFiscalData.fiscalId);
await page.write(selectors.clientFiscalData.fiscalId, 'INVALID!');
await page.clearInput(selectors.clientFiscalData.address);
- await page.write(selectors.clientFiscalData.address, 'Somewhere edited');
+ await page.write(selectors.clientFiscalData.address, 'SOMEWHERE EDITED');
await page.autocompleteSearch(selectors.clientFiscalData.country, 'España');
await page.autocompleteSearch(selectors.clientFiscalData.province, 'Province one');
await page.clearInput(selectors.clientFiscalData.city);
@@ -190,7 +190,7 @@ describe('Client Edit fiscalData path', () => {
const verifiedData = await page.checkboxState(selectors.clientFiscalData.verifiedDataCheckbox);
expect(fiscalId).toEqual('94980061C');
- expect(address).toEqual('Somewhere edited');
+ expect(address).toEqual('SOMEWHERE EDITED');
expect(postcode).toContain('46000');
expect(sageTax).toEqual('Operaciones no sujetas');
expect(sageTransaction).toEqual('Regularización de inversiones');
diff --git a/e2e/paths/02-client/12_lock_of_verified_data.spec.js b/e2e/paths/02-client/12_lock_of_verified_data.spec.js
index 139af0cea..2d7ab7541 100644
--- a/e2e/paths/02-client/12_lock_of_verified_data.spec.js
+++ b/e2e/paths/02-client/12_lock_of_verified_data.spec.js
@@ -28,7 +28,7 @@ describe('Client lock verified data path', () => {
it('should edit the social name', async() => {
await page.waitForSelector(selectors.clientFiscalData.socialName);
await page.clearInput(selectors.clientFiscalData.socialName);
- await page.write(selectors.clientFiscalData.socialName, 'Captain America Civil War');
+ await page.write(selectors.clientFiscalData.socialName, 'CAPTAIN AMERICA CIVIL WAR');
await page.waitToClick(selectors.clientFiscalData.saveButton);
const message = await page.waitForSnackbar();
@@ -39,7 +39,7 @@ describe('Client lock verified data path', () => {
await page.reloadSection('client.card.fiscalData');
const result = await page.waitToGetProperty(selectors.clientFiscalData.socialName, 'value');
- expect(result).toEqual('Captain America Civil War');
+ expect(result).toEqual('CAPTAIN AMERICA CIVIL WAR');
});
});
@@ -88,7 +88,7 @@ describe('Client lock verified data path', () => {
await page.reloadSection('client.card.fiscalData');
const result = await page.waitToGetProperty(selectors.clientFiscalData.socialName, 'value');
- expect(result).toEqual('Ant man and the Wasp');
+ expect(result).toEqual('ANT MAN AND THE WASP');
});
});
@@ -142,7 +142,7 @@ describe('Client lock verified data path', () => {
await page.reloadSection('client.card.fiscalData');
const result = await page.waitToGetProperty(selectors.clientFiscalData.socialName, 'value');
- expect(result).toEqual('new social name edition');
+ expect(result).toEqual('NEW SOCIAL NAME EDITION');
});
});
diff --git a/e2e/paths/02-client/19_summary.spec.js b/e2e/paths/02-client/19_summary.spec.js
index ab39154cf..b3bf43c5c 100644
--- a/e2e/paths/02-client/19_summary.spec.js
+++ b/e2e/paths/02-client/19_summary.spec.js
@@ -36,7 +36,7 @@ describe('Client summary path', () => {
it('should display fiscal address details', async() => {
const result = await page.waitToGetProperty(selectors.clientSummary.street, 'innerText');
- expect(result).toContain('20 Ingram Street');
+ expect(result).toContain('20 INGRAM STREET');
});
it('should display some fiscal data', async() => {
diff --git a/e2e/paths/03-worker/06_create.spec.js b/e2e/paths/03-worker/06_create.spec.js
index 11d36b3cf..07eb57fe4 100644
--- a/e2e/paths/03-worker/06_create.spec.js
+++ b/e2e/paths/03-worker/06_create.spec.js
@@ -23,7 +23,7 @@ describe('Worker create path', () => {
await page.write(selectors.workerCreate.fi, '78457139E');
await page.write(selectors.workerCreate.phone, '12356789');
await page.write(selectors.workerCreate.postcode, '46680');
- await page.write(selectors.workerCreate.street, 'S/ Doomstadt');
+ await page.write(selectors.workerCreate.street, 'S/ DOOMSTADT');
await page.write(selectors.workerCreate.email, 'doctorDoom@marvel.com');
await page.write(selectors.workerCreate.iban, 'ES9121000418450200051332');
diff --git a/e2e/paths/08-route/04_tickets.spec.js b/e2e/paths/08-route/04_tickets.spec.js
index ccd5562c2..c890162a1 100644
--- a/e2e/paths/08-route/04_tickets.spec.js
+++ b/e2e/paths/08-route/04_tickets.spec.js
@@ -18,8 +18,7 @@ describe('Route tickets path', () => {
});
it('should modify the first ticket priority', async() => {
- await page.clearInput(selectors.routeTickets.firstTicketPriority);
- await page.type(selectors.routeTickets.firstTicketPriority, '9');
+ await page.writeOnEditableTD(selectors.routeTickets.firstTicketPriority, '9');
await page.keyboard.press('Enter');
const message = await page.waitForSnackbar();
diff --git a/front/core/components/smart-table/index.js b/front/core/components/smart-table/index.js
index c3b927c62..63a9f6488 100644
--- a/front/core/components/smart-table/index.js
+++ b/front/core/components/smart-table/index.js
@@ -339,8 +339,9 @@ export default class SmartTable extends Component {
if (!header) return;
const tbody = this.element.querySelector('tbody');
- const columns = header.querySelectorAll('th');
+ if (!tbody) return;
+ const columns = header.querySelectorAll('th');
const hasSearchRow = tbody.querySelector('tr#searchRow');
if (hasSearchRow) {
if (this.$inputsScope)
diff --git a/front/core/services/app.js b/front/core/services/app.js
index fb0a08777..6c80fafcc 100644
--- a/front/core/services/app.js
+++ b/front/core/services/app.js
@@ -66,7 +66,11 @@ export default class App {
return this.logger.$http.get('Urls/findOne', {filter})
.then(res => {
- return res.data.url + route;
+ if (res && res.data)
+ return res.data.url + route;
+ })
+ .catch(() => {
+ this.showError('Direction not found');
});
}
}
diff --git a/front/core/services/locale/es.yml b/front/core/services/locale/es.yml
index cf8801b52..e9811e38f 100644
--- a/front/core/services/locale/es.yml
+++ b/front/core/services/locale/es.yml
@@ -3,4 +3,5 @@ Could not contact the server: No se ha podido contactar con el servidor, asegura
Please enter your username: Por favor introduce tu nombre de usuario
It seems that the server has fall down: Parece que el servidor se ha caído, espera unos minutos e inténtalo de nuevo
Session has expired: Tu sesión ha expirado, por favor vuelve a iniciar sesión
-Access denied: Acción no permitida
\ No newline at end of file
+Access denied: Acción no permitida
+Direction not found: Dirección no encontrada
diff --git a/loopback/locale/en.json b/loopback/locale/en.json
index dde24ddc6..46b48e2ea 100644
--- a/loopback/locale/en.json
+++ b/loopback/locale/en.json
@@ -179,5 +179,11 @@
"You can not use the same password": "You can not use the same password",
"Valid priorities": "Valid priorities: %d",
"Negative basis of tickets": "Negative basis of tickets: {{ticketsIds}}",
- "This ticket cannot be left empty.": "This ticket cannot be left empty. %s"
+ "This ticket cannot be left empty.": "This ticket cannot be left empty. %s",
+ "Social name should be uppercase": "Social name should be uppercase",
+ "Street should be uppercase": "Street should be uppercase",
+ "You don't have enough privileges.": "You don't have enough privileges.",
+ "This ticket is locked.": "This ticket is locked.",
+ "This ticket is not editable.": "This ticket is not editable.",
+ "The ticket doesn't exist.": "The ticket doesn't exist."
}
diff --git a/loopback/locale/es.json b/loopback/locale/es.json
index c12b980fa..195b683ad 100644
--- a/loopback/locale/es.json
+++ b/loopback/locale/es.json
@@ -306,5 +306,14 @@
"Valid priorities": "Prioridades válidas: %d",
"Negative basis of tickets": "Base negativa para los tickets: {{ticketsIds}}",
"You cannot assign an alias that you are not assigned to": "No puede asignar un alias que no tenga asignado",
- "This ticket cannot be left empty.": "Este ticket no se puede dejar vacío. %s"
+ "This ticket cannot be left empty.": "Este ticket no se puede dejar vacío. %s",
+ "The company has not informed the supplier account for bank transfers": "La empresa no tiene informado la cuenta de proveedor para transferencias bancarias",
+ "You cannot assign/remove an alias that you are not assigned to": "No puede asignar/eliminar un alias que no tenga asignado",
+ "This invoice has a linked vehicle.": "Esta factura tiene un vehiculo vinculado",
+ "You don't have enough privileges.": "No tienes suficientes permisos.",
+ "This ticket is locked.": "Este ticket está bloqueado.",
+ "This ticket is not editable.": "Este ticket no es editable.",
+ "The ticket doesn't exist.": "No existe el ticket.",
+ "Social name should be uppercase": "La razón social debe ir en mayúscula",
+ "Street should be uppercase": "La dirección fiscal debe ir en mayúscula"
}
diff --git a/modules/account/back/models/mail-alias-account.js b/modules/account/back/models/mail-alias-account.js
new file mode 100644
index 000000000..6f5213f24
--- /dev/null
+++ b/modules/account/back/models/mail-alias-account.js
@@ -0,0 +1,55 @@
+
+const UserError = require('vn-loopback/util/user-error');
+
+module.exports = Self => {
+ Self.observe('before save', async ctx => {
+ const changes = ctx.currentInstance || ctx.instance;
+
+ await Self.hasGrant(ctx, changes.mailAlias);
+ });
+
+ Self.observe('before delete', async ctx => {
+ const mailAliasAccount = await Self.findById(ctx.where.id);
+
+ await Self.hasGrant(ctx, mailAliasAccount.mailAlias);
+ });
+
+ /**
+ * Checks if current user has
+ * grant to add/remove alias
+ *
+ * @param {Object} ctx - Request context
+ * @param {Interger} mailAlias - mailAlias id
+ * @return {Boolean} True for user with grant
+ */
+ Self.hasGrant = async function(ctx, mailAlias) {
+ const models = Self.app.models;
+ const accessToken = {req: {accessToken: ctx.options.accessToken}};
+ const userId = accessToken.req.accessToken.userId;
+
+ const canEditAlias = await models.ACL.checkAccessAcl(accessToken, 'MailAliasAccount', 'canEditAlias', 'WRITE');
+ if (canEditAlias) return true;
+
+ const user = await models.VnUser.findById(userId, {fields: ['hasGrant']});
+ if (!user.hasGrant)
+ throw new UserError(`You don't have grant privilege`);
+
+ const account = await models.Account.findById(userId, {
+ fields: ['id'],
+ include: {
+ relation: 'aliases',
+ scope: {
+ fields: ['mailAlias']
+ }
+ }
+ });
+
+ const aliases = account.aliases().map(alias => alias.mailAlias);
+
+ const hasAlias = aliases.includes(mailAlias);
+ if (!hasAlias)
+ throw new UserError(`You cannot assign/remove an alias that you are not assigned to`);
+
+ return true;
+ };
+};
diff --git a/modules/account/front/aliases/index.js b/modules/account/front/aliases/index.js
index e0c738ee4..0fc806a71 100644
--- a/modules/account/front/aliases/index.js
+++ b/modules/account/front/aliases/index.js
@@ -21,11 +21,12 @@ export default class Controller extends Section {
}
onAddClick() {
+ this.addData = {account: this.$params.id};
this.$.dialog.show();
}
onAddSave() {
- return this.$http.post(`VnUsers/${this.$params.id}/addAlias`, this.addData)
+ return this.$http.post(`MailAliasAccounts`, this.addData)
.then(() => this.refresh())
.then(() => this.vnApp.showSuccess(
this.$t('Subscribed to alias!'))
@@ -33,12 +34,11 @@ export default class Controller extends Section {
}
onRemove(row) {
- const params = {
- mailAlias: row.mailAlias
- };
- return this.$http.post(`VnUsers/${this.$params.id}/removeAlias`, params)
- .then(() => this.refresh())
- .then(() => this.vnApp.showSuccess(this.$t('Data saved!')));
+ return this.$http.delete(`MailAliasAccounts/${row.id}`)
+ .then(() => {
+ this.$.data.splice(this.$.data.indexOf(row), 1);
+ this.vnApp.showSuccess(this.$t('Unsubscribed from alias!'));
+ });
}
}
diff --git a/modules/account/front/aliases/index.spec.js b/modules/account/front/aliases/index.spec.js
index 61f71949c..466f1e1e9 100644
--- a/modules/account/front/aliases/index.spec.js
+++ b/modules/account/front/aliases/index.spec.js
@@ -25,9 +25,8 @@ describe('component vnUserAliases', () => {
describe('onAddSave()', () => {
it('should add the new row', () => {
controller.addData = {account: 1};
- controller.$params = {id: 1};
- $httpBackend.expectPOST('VnUsers/1/addAlias').respond();
+ $httpBackend.expectPOST('MailAliasAccounts').respond();
$httpBackend.expectGET('MailAliasAccounts').respond('foo');
controller.onAddSave();
$httpBackend.flush();
@@ -42,14 +41,12 @@ describe('component vnUserAliases', () => {
{id: 1, alias: 'foo'},
{id: 2, alias: 'bar'}
];
- controller.$params = {id: 1};
- $httpBackend.expectPOST('VnUsers/1/removeAlias').respond();
- $httpBackend.expectGET('MailAliasAccounts').respond(controller.$.data[1]);
+ $httpBackend.expectDELETE('MailAliasAccounts/1').respond();
controller.onRemove(controller.$.data[0]);
$httpBackend.flush();
- expect(controller.$.data).toEqual({id: 2, alias: 'bar'});
+ expect(controller.$.data).toEqual([{id: 2, alias: 'bar'}]);
expect(controller.vnApp.showSuccess).toHaveBeenCalled();
});
});
diff --git a/modules/client/back/methods/client/canBeInvoiced.js b/modules/client/back/methods/client/canBeInvoiced.js
index 567d491f1..843e9549f 100644
--- a/modules/client/back/methods/client/canBeInvoiced.js
+++ b/modules/client/back/methods/client/canBeInvoiced.js
@@ -1,3 +1,5 @@
+const UserError = require('vn-loopback/util/user-error');
+
module.exports = function(Self) {
Self.remoteMethodCtx('canBeInvoiced', {
description: 'Change property isEqualizated in all client addresses',
@@ -9,6 +11,12 @@ module.exports = function(Self) {
required: true,
description: 'Client id',
http: {source: 'path'}
+ },
+ {
+ arg: 'companyFk',
+ description: 'The company id',
+ type: 'number',
+ required: true
}
],
returns: {
@@ -22,18 +30,29 @@ module.exports = function(Self) {
}
});
- Self.canBeInvoiced = async(id, options) => {
+ Self.canBeInvoiced = async(id, companyFk, options) => {
const models = Self.app.models;
-
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
const client = await models.Client.findById(id, {
- fields: ['id', 'isTaxDataChecked', 'hasToInvoice']
+ fields: ['id', 'isTaxDataChecked', 'hasToInvoice', 'payMethodFk'],
+ include:
+ {
+ relation: 'payMethod',
+ scope: {
+ fields: ['code']
+ }
+ }
}, myOptions);
+ const company = await models.Company.findById(companyFk, {fields: ['supplierAccountFk']}, myOptions);
+
+ if (client.payMethod().code === 'wireTransfer' && !company.supplierAccountFk)
+ throw new UserError('The company has not informed the supplier account for bank transfers');
+
if (client.isTaxDataChecked && client.hasToInvoice)
return true;
diff --git a/modules/client/back/methods/client/sendSms.js b/modules/client/back/methods/client/sendSms.js
index 83b7c8d6e..270d7e5b5 100644
--- a/modules/client/back/methods/client/sendSms.js
+++ b/modules/client/back/methods/client/sendSms.js
@@ -7,7 +7,7 @@ module.exports = Self => {
arg: 'id',
type: 'number',
required: true,
- description: 'The ticket id',
+ description: 'The client id',
http: {source: 'path'}
},
{
@@ -33,6 +33,12 @@ module.exports = Self => {
Self.sendSms = async(ctx, id, destination, message) => {
const models = Self.app.models;
const sms = await models.Sms.send(ctx, destination, message);
+
+ await models.ClientSms.create({
+ clientFk: id,
+ smsFk: sms.id
+ });
+
return sms;
};
};
diff --git a/modules/client/back/methods/client/specs/canBeInvoiced.spec.js b/modules/client/back/methods/client/specs/canBeInvoiced.spec.js
index 2f11d8013..397be3c92 100644
--- a/modules/client/back/methods/client/specs/canBeInvoiced.spec.js
+++ b/modules/client/back/methods/client/specs/canBeInvoiced.spec.js
@@ -4,6 +4,7 @@ const LoopBackContext = require('loopback-context');
describe('client canBeInvoiced()', () => {
const userId = 19;
const clientId = 1101;
+ const companyId = 442;
const activeCtx = {
accessToken: {userId: userId}
};
@@ -23,7 +24,7 @@ describe('client canBeInvoiced()', () => {
const client = await models.Client.findById(clientId, null, options);
await client.updateAttribute('isTaxDataChecked', false, options);
- const canBeInvoiced = await models.Client.canBeInvoiced(clientId, options);
+ const canBeInvoiced = await models.Client.canBeInvoiced(clientId, companyId, options);
expect(canBeInvoiced).toEqual(false);
@@ -43,7 +44,7 @@ describe('client canBeInvoiced()', () => {
const client = await models.Client.findById(clientId, null, options);
await client.updateAttribute('hasToInvoice', false, options);
- const canBeInvoiced = await models.Client.canBeInvoiced(clientId, options);
+ const canBeInvoiced = await models.Client.canBeInvoiced(clientId, companyId, options);
expect(canBeInvoiced).toEqual(false);
@@ -60,7 +61,7 @@ describe('client canBeInvoiced()', () => {
try {
const options = {transaction: tx};
- const canBeInvoiced = await models.Client.canBeInvoiced(clientId, options);
+ const canBeInvoiced = await models.Client.canBeInvoiced(clientId, companyId, options);
expect(canBeInvoiced).toEqual(true);
diff --git a/modules/client/back/methods/client/specs/createWithUser.spec.js b/modules/client/back/methods/client/specs/createWithUser.spec.js
index 69440c1d1..03106acc1 100644
--- a/modules/client/back/methods/client/specs/createWithUser.spec.js
+++ b/modules/client/back/methods/client/specs/createWithUser.spec.js
@@ -7,8 +7,8 @@ describe('Client Create', () => {
email: 'Deadpool@marvel.com',
fi: '16195279J',
name: 'Wade',
- socialName: 'Deadpool Marvel',
- street: 'Wall Street',
+ socialName: 'DEADPOOL MARVEL',
+ street: 'WALL STREET',
city: 'New York',
businessTypeFk: 'florist',
provinceFk: 1
diff --git a/modules/client/back/methods/defaulter/filter.js b/modules/client/back/methods/defaulter/filter.js
index 56afb64db..220cb957b 100644
--- a/modules/client/back/methods/defaulter/filter.js
+++ b/modules/client/back/methods/defaulter/filter.js
@@ -70,11 +70,12 @@ module.exports = Self => {
c.creditInsurance,
d.defaulterSinced,
cn.country,
+ c.countryFk,
pm.name payMethod
FROM vn.defaulter d
JOIN vn.client c ON c.id = d.clientFk
JOIN vn.country cn ON cn.id = c.countryFk
- JOIN vn.payMethod pm ON pm.id = c.payMethodFk
+ JOIN vn.payMethod pm ON pm.id = c.payMethodFk
LEFT JOIN vn.clientObservation co ON co.clientFk = c.id
LEFT JOIN account.user u ON u.id = c.salesPersonFk
LEFT JOIN account.user uw ON uw.id = co.workerFk
diff --git a/modules/client/back/model-config.json b/modules/client/back/model-config.json
index 1e06ea1c0..bc48ec360 100644
--- a/modules/client/back/model-config.json
+++ b/modules/client/back/model-config.json
@@ -95,6 +95,9 @@
"ClientSample": {
"dataSource": "vn"
},
+ "ClientSms": {
+ "dataSource": "vn"
+ },
"Sms": {
"dataSource": "vn"
},
diff --git a/modules/client/back/models/client-sms.json b/modules/client/back/models/client-sms.json
new file mode 100644
index 000000000..b2244ebbb
--- /dev/null
+++ b/modules/client/back/models/client-sms.json
@@ -0,0 +1,26 @@
+{
+ "name": "ClientSms",
+ "base": "VnModel",
+ "options": {
+ "mysql": {
+ "table": "clientSms"
+ }
+ },
+ "properties": {
+ "id": {
+ "type": "number",
+ "id": true,
+ "description": "Identifier"
+ },
+ "clientFk": {
+ "type": "number"
+ }
+ },
+ "relations": {
+ "sms": {
+ "type": "belongsTo",
+ "model": "Sms",
+ "foreignKey": "smsFk"
+ }
+ }
+}
diff --git a/modules/client/back/models/client.js b/modules/client/back/models/client.js
index ca279ef71..129924b78 100644
--- a/modules/client/back/models/client.js
+++ b/modules/client/back/models/client.js
@@ -36,12 +36,37 @@ module.exports = Self => {
min: 3, max: 10
});
+ Self.validatesFormatOf('street', {
+ message: 'Street should be uppercase',
+ allowNull: false,
+ allowBlank: false,
+ with: /^[^a-z]*$/
+ });
+
+ Self.validatesFormatOf('socialName', {
+ message: 'Social name should be uppercase',
+ allowNull: false,
+ allowBlank: false,
+ with: /^[^a-z]*$/
+ });
+
Self.validateAsync('socialName', socialNameIsUnique, {
message: 'The company name must be unique'
});
async function socialNameIsUnique(err, done) {
+ if (!this.countryFk)
+ return done();
+
const filter = {
+ include: {
+ relation: 'country',
+ scope: {
+ fields: {
+ isSocialNameUnique: true,
+ },
+ },
+ },
where: {
and: [
{socialName: this.socialName},
@@ -50,9 +75,13 @@ module.exports = Self => {
]
}
};
- const client = await Self.app.models.Client.findOne(filter);
- if (client)
+
+ const client = await Self.app.models.Country.findById(this.countryFk, {fields: ['isSocialNameUnique']});
+ const existingClient = await Self.findOne(filter);
+
+ if (existingClient && (existingClient.country().isSocialNameUnique || client.isSocialNameUnique))
err();
+
done();
}
diff --git a/modules/client/back/models/client.json b/modules/client/back/models/client.json
index 5f56a1ed2..66a67ec2e 100644
--- a/modules/client/back/models/client.json
+++ b/modules/client/back/models/client.json
@@ -181,6 +181,11 @@
"model": "Country",
"foreignKey": "countryFk"
},
+ "isSocialNameUnique": {
+ "type": "belongsTo",
+ "model": "Country",
+ "foreignKey": "countryFk"
+ },
"contactChannel": {
"type": "belongsTo",
"model": "ContactChannel",
diff --git a/modules/client/back/models/defaulter.json b/modules/client/back/models/defaulter.json
index 03d68ea71..ef22c2429 100644
--- a/modules/client/back/models/defaulter.json
+++ b/modules/client/back/models/defaulter.json
@@ -33,7 +33,7 @@
"country": {
"type": "belongsTo",
"model": "Country",
- "foreignKey": "country"
+ "foreignKey": "countryFk"
},
"payMethod": {
"type": "belongsTo",
@@ -41,4 +41,4 @@
"foreignKey": "payMethod"
}
}
-}
\ No newline at end of file
+}
diff --git a/modules/client/front/defaulter/index.html b/modules/client/front/defaulter/index.html
index 3ea88088b..33bb751f1 100644
--- a/modules/client/front/defaulter/index.html
+++ b/modules/client/front/defaulter/index.html
@@ -60,7 +60,7 @@
Comercial
|
-
+ |
Country
|
|
{{::defaulter.payMethod}}
- |
+
{{::defaulter.amount | currency: 'EUR': 2}} |
diff --git a/modules/client/front/index.js b/modules/client/front/index.js
index c7e39ea5d..62076459b 100644
--- a/modules/client/front/index.js
+++ b/modules/client/front/index.js
@@ -48,4 +48,5 @@ import './notification';
import './unpaid';
import './extended-list';
import './credit-management';
+import './sms';
diff --git a/modules/client/front/routes.json b/modules/client/front/routes.json
index 01d1b53bf..63d6709e5 100644
--- a/modules/client/front/routes.json
+++ b/modules/client/front/routes.json
@@ -23,6 +23,7 @@
{"state": "client.card.recovery.index", "icon": "icon-recovery"},
{"state": "client.card.webAccess", "icon": "cloud"},
{"state": "client.card.log", "icon": "history"},
+ {"state": "client.card.sms", "icon": "sms"},
{
"description": "Credit management",
"icon": "monetization_on",
@@ -373,6 +374,12 @@
"component": "vn-client-log",
"description": "Log"
},
+ {
+ "url" : "/sms",
+ "state": "client.card.sms",
+ "component": "vn-client-sms",
+ "description": "Sms"
+ },
{
"url": "/dms",
"state": "client.card.dms",
diff --git a/modules/client/front/sms/index.html b/modules/client/front/sms/index.html
new file mode 100644
index 000000000..9abadd312
--- /dev/null
+++ b/modules/client/front/sms/index.html
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+ Sender
+ Destination
+ Message
+ Status
+ Created
+
+
+
+
+
+
+ {{::clientSms.sms.sender.name}}
+
+
+ {{::clientSms.sms.destination}}
+ {{::clientSms.sms.message}}
+ {{::clientSms.sms.status}}
+ {{::clientSms.sms.created | date:'dd/MM/yyyy HH:mm'}}
+
+
+
+
+
+
+
diff --git a/modules/client/front/sms/index.js b/modules/client/front/sms/index.js
new file mode 100644
index 000000000..6ad64282e
--- /dev/null
+++ b/modules/client/front/sms/index.js
@@ -0,0 +1,39 @@
+import ngModule from '../module';
+import Section from 'salix/components/section';
+
+export default class Controller extends Section {
+ constructor($element, $) {
+ super($element, $);
+
+ this.filter = {
+ fields: ['id', 'smsFk'],
+ include: {
+ relation: 'sms',
+ scope: {
+ fields: [
+ 'senderFk',
+ 'sender',
+ 'destination',
+ 'message',
+ 'statusCode',
+ 'status',
+ 'created'],
+ include: {
+ relation: 'sender',
+ scope: {
+ fields: ['name']
+ }
+ }
+ }
+ }
+ };
+ }
+}
+
+ngModule.vnComponent('vnClientSms', {
+ template: require('./index.html'),
+ controller: Controller,
+ bindings: {
+ client: '<'
+ }
+});
diff --git a/modules/client/front/sms/locale/es.yml b/modules/client/front/sms/locale/es.yml
new file mode 100644
index 000000000..6d1e9e147
--- /dev/null
+++ b/modules/client/front/sms/locale/es.yml
@@ -0,0 +1,2 @@
+Sender: Remitente
+Number sender: Número remitente
diff --git a/modules/client/front/web-access/index.html b/modules/client/front/web-access/index.html
index 74407ba5c..bf3d34c79 100644
--- a/modules/client/front/web-access/index.html
+++ b/modules/client/front/web-access/index.html
@@ -39,7 +39,7 @@
label="Recovery email"
ng-model="$ctrl.account.email"
info="This email is used for user to regain access their account."
- rule="VnUser.name">
+ rule="VnUser.email">
diff --git a/modules/invoiceIn/back/locale/invoiceIn/en.yml b/modules/invoiceIn/back/locale/invoiceIn/en.yml
new file mode 100644
index 000000000..ec9a824b6
--- /dev/null
+++ b/modules/invoiceIn/back/locale/invoiceIn/en.yml
@@ -0,0 +1,20 @@
+name: invoice in
+columns:
+ id: id
+ serialNumber: serial number
+ serial: serial
+ supplierFk: supplier
+ issued: issued
+ supplierRef: supplierRef
+ isBooked: is booked
+ currencyFk: currency
+ created: created
+ companyFk: company
+ docFk: document
+ booked: booked
+ operated: operated
+ bookEntried: book entried
+ isVatDeductible: is VAT deductible
+ withholdingSageFk: withholding
+ expenceFkDeductible: expence deductible
+ editorFk: editor
\ No newline at end of file
diff --git a/modules/invoiceIn/back/locale/invoiceIn/es.yml b/modules/invoiceIn/back/locale/invoiceIn/es.yml
new file mode 100644
index 000000000..64e96b379
--- /dev/null
+++ b/modules/invoiceIn/back/locale/invoiceIn/es.yml
@@ -0,0 +1,20 @@
+name: factura recibida
+columns:
+ id: id
+ serialNumber: número de serie
+ serial: serie
+ supplierFk: proveedor
+ issued: fecha emisión
+ supplierRef: referéncia proveedor
+ isBooked: facturado
+ currencyFk: moneda
+ created: creado
+ companyFk: empresa
+ docFk: documento
+ booked: fecha contabilización
+ operated: fecha entrega
+ bookEntried: fecha asiento
+ isVatDeductible: impuesto deducible
+ withholdingSageFk: código de retención
+ expenceFkDeductible: gasto deducible
+ editorFk: editor
\ No newline at end of file
diff --git a/modules/invoiceIn/back/locale/invoiceInDueDay/en.yml b/modules/invoiceIn/back/locale/invoiceInDueDay/en.yml
new file mode 100644
index 000000000..7a6c0dfaf
--- /dev/null
+++ b/modules/invoiceIn/back/locale/invoiceInDueDay/en.yml
@@ -0,0 +1,9 @@
+name: invoice in due day
+columns:
+ id: id
+ invoiceInFk: invoice in
+ dueDated: due date
+ bankFk: bank
+ amount: amount
+ foreignValue : foreign amount
+ created: created
diff --git a/modules/invoiceIn/back/locale/invoiceInDueDay/es.yml b/modules/invoiceIn/back/locale/invoiceInDueDay/es.yml
new file mode 100644
index 000000000..993437b05
--- /dev/null
+++ b/modules/invoiceIn/back/locale/invoiceInDueDay/es.yml
@@ -0,0 +1,9 @@
+name: vencimientos factura recibida
+columns:
+ id: id
+ invoiceInFk: factura
+ dueDated: fecha vto.
+ bankFk: banco
+ amount: importe
+ foreignValue : importe divisa
+ created: creado
diff --git a/modules/invoiceIn/back/locale/invoiceInTax/en.yml b/modules/invoiceIn/back/locale/invoiceInTax/en.yml
new file mode 100644
index 000000000..c0d12c37d
--- /dev/null
+++ b/modules/invoiceIn/back/locale/invoiceInTax/en.yml
@@ -0,0 +1,12 @@
+name: invoice in tax
+columns:
+ id: id
+ invoiceInFk: invoice in
+ taxCodeFk: tax
+ taxableBase: taxable base
+ expenceFk: expence
+ foreignValue: foreign amount
+ taxTypeSageFk: tax type
+ transactionTypeSageFk: transaction type
+ created: created
+ editorFk: editor
diff --git a/modules/invoiceIn/back/locale/invoiceInTax/es.yml b/modules/invoiceIn/back/locale/invoiceInTax/es.yml
new file mode 100644
index 000000000..7cb847ed8
--- /dev/null
+++ b/modules/invoiceIn/back/locale/invoiceInTax/es.yml
@@ -0,0 +1,12 @@
+name: factura recibida impuesto
+columns:
+ id: id
+ invoiceInFk: factura recibida
+ taxCodeFk: código IVA
+ taxableBase: base imponible
+ expenceFk: código gasto
+ foreignValue: importe divisa
+ taxTypeSageFk: código impuesto
+ transactionTypeSageFk: código transacción
+ created: creado
+ editorFk: editor
\ No newline at end of file
diff --git a/modules/invoiceIn/back/models/invoice-in.js b/modules/invoiceIn/back/models/invoice-in.js
index 51905ccb8..82e0bf078 100644
--- a/modules/invoiceIn/back/models/invoice-in.js
+++ b/modules/invoiceIn/back/models/invoice-in.js
@@ -1,3 +1,5 @@
+const UserError = require('vn-loopback/util/user-error');
+
module.exports = Self => {
require('../methods/invoice-in/filter')(Self);
require('../methods/invoice-in/summary')(Self);
@@ -7,4 +9,9 @@ module.exports = Self => {
require('../methods/invoice-in/invoiceInPdf')(Self);
require('../methods/invoice-in/invoiceInEmail')(Self);
require('../methods/invoice-in/getSerial')(Self);
+ Self.rewriteDbError(function(err) {
+ if (err.code === 'ER_ROW_IS_REFERENCED_2' && err.sqlMessage.includes('vehicleInvoiceIn'))
+ return new UserError(`This invoice has a linked vehicle.`);
+ return err;
+ });
};
diff --git a/modules/item/back/methods/item-shelving/getInventory.js b/modules/item/back/methods/item-shelving/getInventory.js
new file mode 100644
index 000000000..144bd83e7
--- /dev/null
+++ b/modules/item/back/methods/item-shelving/getInventory.js
@@ -0,0 +1,37 @@
+module.exports = Self => {
+ Self.remoteMethod('getInventory', {
+ description: 'Get list of itemShelving to review between two parking code',
+ accessType: 'WRITE',
+ accepts: [{
+ arg: 'parkingFrom',
+ type: 'string',
+ required: true,
+ description: 'Parking code from'
+ },
+ {
+ arg: 'parkingTo',
+ type: 'string',
+ required: true,
+ description: 'Parking code to'
+ }],
+ returns: {
+ type: ['object'],
+ root: true
+ },
+ http: {
+ path: `/getInventory`,
+ verb: 'POST'
+ }
+ });
+
+ Self.getInventory = async(parkingFrom, parkingTo, options) => {
+ const myOptions = {};
+
+ if (typeof options == 'object')
+ Object.assign(myOptions, options);
+
+ const [result] = await Self.rawSql(`CALL vn.itemShelving_inventory(?, ?)`, [parkingFrom, parkingTo], myOptions);
+
+ return result;
+ };
+};
diff --git a/modules/item/back/methods/item-shelving/specs/getInventory.spec.js b/modules/item/back/methods/item-shelving/specs/getInventory.spec.js
new file mode 100644
index 000000000..6a8c9804c
--- /dev/null
+++ b/modules/item/back/methods/item-shelving/specs/getInventory.spec.js
@@ -0,0 +1,24 @@
+const models = require('vn-loopback/server/server').models;
+
+describe('itemShelving getInventory()', () => {
+ it('should return a list of itemShelvings', async() => {
+ const tx = await models.ItemShelving.beginTransaction({});
+
+ let response;
+ try {
+ const options = {transaction: tx};
+ await models.ItemShelving.rawSql(`
+ UPDATE vn.config
+ SET mainWarehouseFk=1
+ WHERE id=1
+ `, null, options);
+ response = await models.ItemShelving.getInventory('100-01', 'LR-02-3', options);
+ await tx.rollback();
+ } catch (e) {
+ await tx.rollback();
+ throw e;
+ }
+
+ expect(response.length).toEqual(2);
+ });
+});
diff --git a/modules/item/back/methods/item/activeBuyers.js b/modules/item/back/methods/item/activeBuyers.js
deleted file mode 100644
index e16ff877b..000000000
--- a/modules/item/back/methods/item/activeBuyers.js
+++ /dev/null
@@ -1,44 +0,0 @@
-const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
-const mergeFilters = require('vn-loopback/util/filter').mergeFilters;
-
-module.exports = Self => {
- Self.remoteMethod('activeBuyers', {
- description: 'Returns a list of buyers for the given item type',
- accepts: [{
- arg: 'filter',
- type: 'object',
- description: `Filter defining where, order, offset, and limit - must be a JSON-encoded string`
- }],
- returns: {
- type: ['object'],
- root: true
- },
- http: {
- path: `/activeBuyers`,
- verb: 'GET'
- }
- });
-
- Self.activeBuyers = async(filter, options) => {
- const conn = Self.dataSource.connector;
- const where = {isActive: true};
- const myOptions = {};
-
- if (typeof options == 'object')
- Object.assign(myOptions, options);
-
- filter = mergeFilters(filter, {where});
-
- let stmt = new ParameterizedSQL(
- `SELECT DISTINCT w.id workerFk, w.firstName, w.lastName, u.name, u.nickname
- FROM worker w
- JOIN itemType it ON it.workerFk = w.id
- JOIN account.user u ON u.id = w.id
- JOIN item i ON i.typeFk = it.id`,
- null, myOptions);
-
- stmt.merge(conn.makeSuffix(filter));
-
- return conn.executeStmt(stmt);
- };
-};
diff --git a/modules/item/back/methods/item/specs/activeBuyers.spec.js b/modules/item/back/methods/item/specs/activeBuyers.spec.js
deleted file mode 100644
index 5bf36756f..000000000
--- a/modules/item/back/methods/item/specs/activeBuyers.spec.js
+++ /dev/null
@@ -1,24 +0,0 @@
-const models = require('vn-loopback/server/server').models;
-
-describe('Worker activeBuyers', () => {
- it('should return the buyers in itemType as result', async() => {
- const tx = await models.Item.beginTransaction({});
-
- try {
- const options = {transaction: tx};
- const filter = {};
- const result = await models.Item.activeBuyers(filter, options);
- const firstWorker = result[0];
- const secondWorker = result[1];
-
- expect(result.length).toEqual(2);
- expect(firstWorker.nickname).toEqual('logisticBossNick');
- expect(secondWorker.nickname).toEqual('buyerNick');
-
- await tx.rollback();
- } catch (e) {
- await tx.rollback();
- throw e;
- }
- });
-});
diff --git a/modules/item/back/models/item-shelving.js b/modules/item/back/models/item-shelving.js
index 5f372a3be..98ff18931 100644
--- a/modules/item/back/models/item-shelving.js
+++ b/modules/item/back/models/item-shelving.js
@@ -1,3 +1,4 @@
module.exports = Self => {
require('../methods/item-shelving/deleteItemShelvings')(Self);
+ require('../methods/item-shelving/getInventory')(Self);
};
diff --git a/modules/item/back/models/item-shelving.json b/modules/item/back/models/item-shelving.json
index 49bebcb6b..8628bfeee 100644
--- a/modules/item/back/models/item-shelving.json
+++ b/modules/item/back/models/item-shelving.json
@@ -23,6 +23,12 @@
},
"isChecked": {
"type": "boolean"
+ },
+ "visible": {
+ "type": "number"
+ },
+ "userFk": {
+ "type": "number"
}
},
"relations": {
diff --git a/modules/item/back/models/item.js b/modules/item/back/models/item.js
index b8baa97ea..61c5c2588 100644
--- a/modules/item/back/models/item.js
+++ b/modules/item/back/models/item.js
@@ -14,7 +14,6 @@ module.exports = Self => {
require('../methods/item/getWasteByWorker')(Self);
require('../methods/item/getWasteByItem')(Self);
require('../methods/item/createIntrastat')(Self);
- require('../methods/item/activeBuyers')(Self);
require('../methods/item/buyerWasteEmail')(Self);
require('../methods/item/labelPdf')(Self);
diff --git a/modules/item/front/fetched-tags/index.html b/modules/item/front/fetched-tags/index.html
index 472fa676b..df5936871 100644
--- a/modules/item/front/fetched-tags/index.html
+++ b/modules/item/front/fetched-tags/index.html
@@ -1,40 +1,40 @@
-
-
-
\ No newline at end of file
+
diff --git a/modules/item/front/fetched-tags/style.scss b/modules/item/front/fetched-tags/style.scss
index 2cd7afbb2..250ca07ab 100644
--- a/modules/item/front/fetched-tags/style.scss
+++ b/modules/item/front/fetched-tags/style.scss
@@ -28,7 +28,7 @@
vn-fetched-tags {
& > vn-horizontal {
align-items: center;
-
+ max-width: 210px;
& > vn-auto {
flex-wrap: wrap;
@@ -43,19 +43,19 @@ vn-fetched-tags {
& > .inline-tag {
color: $color-font-secondary;
text-align: center;
- font-size: .75rem;
- height: 12px;
+ font-size: .8rem;
+ height: 13px;
padding: 1px;
width: 64px;
min-width: 64px;
max-width: 64px;
flex: 1;
- border: 1px solid $color-spacer;
-
+ border: 1px solid $color-font-secondary;
+
&.empty {
- border: 1px solid $color-spacer-light;
+ border: 1px solid darken($color-font-secondary, 30%);
}
}
}
}
-}
\ No newline at end of file
+}
diff --git a/modules/item/front/fixed-price/index.html b/modules/item/front/fixed-price/index.html
index d9a955fe1..f1f6e1419 100644
--- a/modules/item/front/fixed-price/index.html
+++ b/modules/item/front/fixed-price/index.html
@@ -85,7 +85,7 @@
show-field="id"
value-field="id"
search-function="$ctrl.itemSearchFunc($search)"
- on-change="$ctrl.upsertPrice(price, true)"
+ ng-change="$ctrl.upsertPrice(price, true)"
order="id DESC"
tabindex="1">
diff --git a/modules/item/front/request-search-panel/index.html b/modules/item/front/request-search-panel/index.html
index a76684776..9d35fbca4 100644
--- a/modules/item/front/request-search-panel/index.html
+++ b/modules/item/front/request-search-panel/index.html
@@ -1,7 +1,7 @@
|
+
+
{{::ticket.id}}
diff --git a/modules/travel/front/search-panel/index.js b/modules/travel/front/search-panel/index.js
index 089953127..f53c15ca8 100644
--- a/modules/travel/front/search-panel/index.js
+++ b/modules/travel/front/search-panel/index.js
@@ -38,10 +38,12 @@ class Controller extends SearchPanel {
applyFilters(param) {
if (typeof this.filter.scopeDays === 'number') {
- const shippedFrom = Date.vnNew();
+ const today = Date.vnNew();
+ const shippedFrom = new Date(today.getTime());
+ shippedFrom.setDate(today.getDate() - 30);
shippedFrom.setHours(0, 0, 0, 0);
- const shippedTo = new Date(shippedFrom.getTime());
+ const shippedTo = new Date(today.getTime());
shippedTo.setDate(shippedTo.getDate() + this.filter.scopeDays);
shippedTo.setHours(23, 59, 59, 999);
Object.assign(this.filter, {shippedFrom, shippedTo});
diff --git a/modules/worker/back/methods/worker-dms/docuwareDownload.js b/modules/worker/back/methods/worker-dms/docuwareDownload.js
new file mode 100644
index 000000000..c64c159ed
--- /dev/null
+++ b/modules/worker/back/methods/worker-dms/docuwareDownload.js
@@ -0,0 +1,45 @@
+module.exports = Self => {
+ Self.remoteMethod('docuwareDownload', {
+ description: 'Download a worker document',
+ accessType: 'READ',
+ accepts: [
+ {
+ arg: 'id',
+ type: 'Number',
+ description: 'The document id',
+ http: {source: 'path'}
+ }
+ ],
+ returns: [
+ {
+ arg: 'body',
+ type: 'file',
+ root: true
+ }, {
+ arg: 'Content-Type',
+ type: 'String',
+ http: {target: 'header'}
+ }, {
+ arg: 'Content-Disposition',
+ type: 'String',
+ http: {target: 'header'}
+ }
+ ],
+ http: {
+ path: `/:id/docuwareDownload`,
+ verb: 'GET'
+ }
+ });
+
+ Self.docuwareDownload = async id => {
+ const filter = {
+ condition: [
+ {
+ DBName: 'FILENAME',
+ Value: [id]
+ }
+ ]
+ };
+ return Self.app.models.Docuware.download(id, 'hr', filter);
+ };
+};
diff --git a/modules/worker/back/methods/worker-dms/filter.js b/modules/worker/back/methods/worker-dms/filter.js
index c16b2bbb1..9d8554484 100644
--- a/modules/worker/back/methods/worker-dms/filter.js
+++ b/modules/worker/back/methods/worker-dms/filter.js
@@ -5,6 +5,12 @@ module.exports = Self => {
description: 'Find all instances of the model matched by filter from the data source.',
accessType: 'READ',
accepts: [
+ {
+ arg: 'id',
+ type: 'Number',
+ description: 'The worker id',
+ http: {source: 'path'}
+ },
{
arg: 'filter',
type: 'Object',
@@ -17,16 +23,17 @@ module.exports = Self => {
root: true
},
http: {
- path: `/filter`,
+ path: `/:id/filter`,
verb: 'GET'
}
});
- Self.filter = async(ctx, filter) => {
+ Self.filter = async(ctx, id, filter) => {
const conn = Self.dataSource.connector;
const userId = ctx.req.accessToken.userId;
+ const models = Self.app.models;
- const account = await Self.app.models.VnUser.findById(userId);
+ const account = await models.VnUser.findById(userId);
const stmt = new ParameterizedSQL(
`SELECT d.id dmsFk, d.reference, d.description, d.file, d.created, d.hardCopyNumber, d.hasFile
FROM workerDocument wd
@@ -47,7 +54,39 @@ module.exports = Self => {
}]
}, oldWhere]};
stmt.merge(conn.makeSuffix(filter));
+ const workerDms = await conn.executeStmt(stmt);
- return await conn.executeStmt(stmt);
+ // Get docuware info
+ const docuware = await models.Docuware.findOne({
+ fields: ['dmsTypeFk'],
+ where: {code: 'hr', action: 'find'}
+ });
+ const docuwareDmsType = docuware.dmsTypeFk;
+ let workerDocuware = [];
+ if (!docuwareDmsType || (docuwareDmsType && await models.DmsType.hasReadRole(ctx, docuwareDmsType))) {
+ const worker = await models.Worker.findById(id, {fields: ['fi', 'firstName', 'lastName']});
+ const docuwareParse = {
+ 'Filename': 'dmsFk',
+ 'Tipo Documento': 'description',
+ 'Stored on': 'created',
+ 'Document ID': 'id'
+ };
+
+ workerDocuware =
+ await models.Docuware.getById('hr', worker.lastName + ' ' + worker.firstName, docuwareParse) ?? [];
+ for (document of workerDocuware) {
+ const defaultData = {
+ file: 'dw' + document.id + '.png',
+ isDocuware: true,
+ hardCopyNumber: null,
+ hasFile: false,
+ reference: worker.fi,
+ dmsFk: 'DW' + document.id
+ };
+
+ document = Object.assign(document, defaultData);
+ }
+ }
+ return workerDms.concat(workerDocuware);
};
};
diff --git a/modules/worker/back/methods/worker-time-control/filter.js b/modules/worker/back/methods/worker-time-control/filter.js
index 041c6cbfb..6d0880253 100644
--- a/modules/worker/back/methods/worker-time-control/filter.js
+++ b/modules/worker/back/methods/worker-time-control/filter.js
@@ -36,9 +36,9 @@ module.exports = Self => {
if (isSubordinate === false)
throw new UserError(`You don't have enough privileges`);
- const subordinate = await Worker.findById(ctx.args.workerFk);
+ const subordinate = await Worker.findById(ctx.args.workerFk, {fields: ['id']});
filter = mergeFilters(filter, {where: {
- userFk: subordinate.userFk
+ userFk: subordinate.id
}});
return Self.find(filter);
diff --git a/modules/worker/back/methods/worker/specs/new.spec.js b/modules/worker/back/methods/worker/specs/new.spec.js
index b2804c203..d0830b00f 100644
--- a/modules/worker/back/methods/worker/specs/new.spec.js
+++ b/modules/worker/back/methods/worker/specs/new.spec.js
@@ -20,11 +20,11 @@ describe('Worker new', () => {
const employeeId = 1;
const defaultWorker = {
fi: '78457139E',
- name: 'defaultWorker',
- firstName: 'default',
- lastNames: 'worker',
+ name: 'DEFAULTERWORKER',
+ firstName: 'DEFAULT',
+ lastNames: 'WORKER',
email: 'defaultWorker@mydomain.com',
- street: 'S/ defaultWorkerStreet',
+ street: 'S/ DEFAULTWORKERSTREET',
city: 'defaultWorkerCity',
provinceFk: 1,
companyFk: 442,
diff --git a/modules/worker/back/models/worker-dms.js b/modules/worker/back/models/worker-dms.js
index b9d6f9a77..6343e902e 100644
--- a/modules/worker/back/models/worker-dms.js
+++ b/modules/worker/back/models/worker-dms.js
@@ -2,6 +2,7 @@ module.exports = Self => {
require('../methods/worker-dms/downloadFile')(Self);
require('../methods/worker-dms/removeFile')(Self);
require('../methods/worker-dms/filter')(Self);
+ require('../methods/worker-dms/docuwareDownload')(Self);
Self.isMine = async function(ctx, dmsId) {
const myUserId = ctx.req.accessToken.userId;
diff --git a/modules/worker/back/models/worker.json b/modules/worker/back/models/worker.json
index 6d23c1b66..6e1371055 100644
--- a/modules/worker/back/models/worker.json
+++ b/modules/worker/back/models/worker.json
@@ -25,8 +25,7 @@
"type" : "string"
},
"userFk": {
- "type" : "number",
- "required": true
+ "type" : "number"
},
"bossFk": {
"type" : "number"
diff --git a/modules/worker/front/calendar/index.html b/modules/worker/front/calendar/index.html
index 877add57b..08f63ddf9 100644
--- a/modules/worker/front/calendar/index.html
+++ b/modules/worker/front/calendar/index.html
@@ -3,7 +3,7 @@
data="absenceTypes"
auto-load="true">
-
+
Autonomous worker
@@ -73,41 +73,39 @@
value-field="businessFk"
order="businessFk DESC"
limit="5">
-
- #{{businessFk}}
-
- {{started | date: 'dd/MM/yyyy'}} - {{ended ? (ended | date: 'dd/MM/yyyy') : 'Indef.'}}
-
-
-
-
-
-
-
-
-
- {{absenceType.name}}
-
-
-
-
-
-
- Festive
-
-
-
-
- Current day
-
-
+
+ #{{businessFk}}
+
+ {{started | date: 'dd/MM/yyyy'}} - {{ended ? (ended | date: 'dd/MM/yyyy') : 'Indef.'}}
+
+
+
+
+
+
+
+
+ {{absenceType.name}}
+
+
+
+
+
+
+ Festive
+
+
+
+
+ Current day
+
+
+
+
-
diff --git a/modules/worker/front/calendar/index.js b/modules/worker/front/calendar/index.js
index 87e806cc3..5606ad0ce 100644
--- a/modules/worker/front/calendar/index.js
+++ b/modules/worker/front/calendar/index.js
@@ -31,6 +31,8 @@ class Controller extends Section {
}
set businessId(value) {
+ if (!this.card.hasWorkCenter) return;
+
this._businessId = value;
if (value) {
this.refresh()
@@ -64,7 +66,7 @@ class Controller extends Section {
set worker(value) {
this._worker = value;
- if (value && value.hasWorkCenter) {
+ if (value) {
this.getIsSubordinate();
this.getActiveContract();
}
@@ -293,5 +295,8 @@ ngModule.vnComponent('vnWorkerCalendar', {
controller: Controller,
bindings: {
worker: '<'
+ },
+ require: {
+ card: '^vnWorkerCard'
}
});
diff --git a/modules/worker/front/calendar/index.spec.js b/modules/worker/front/calendar/index.spec.js
index 4b78d883b..5d7ae0795 100644
--- a/modules/worker/front/calendar/index.spec.js
+++ b/modules/worker/front/calendar/index.spec.js
@@ -20,6 +20,9 @@ describe('Worker', () => {
controller.absenceType = {id: 1, name: 'Holiday', code: 'holiday', rgb: 'red'};
controller.$params.id = 1106;
controller._worker = {id: 1106};
+ controller.card = {
+ hasWorkCenter: true
+ };
}));
describe('year() getter', () => {
@@ -74,7 +77,7 @@ describe('Worker', () => {
let yesterday = new Date(today.getTime());
yesterday.setDate(yesterday.getDate() - 1);
- controller.worker = {id: 1107, hasWorkCenter: true};
+ controller.worker = {id: 1107};
expect(controller.getIsSubordinate).toHaveBeenCalledWith();
expect(controller.getActiveContract).toHaveBeenCalledWith();
diff --git a/modules/worker/front/card/index.js b/modules/worker/front/card/index.js
index 35f331764..b8b533c5d 100644
--- a/modules/worker/front/card/index.js
+++ b/modules/worker/front/card/index.js
@@ -3,7 +3,7 @@ import ModuleCard from 'salix/components/module-card';
class Controller extends ModuleCard {
reload() {
- let filter = {
+ const filter = {
include: [
{
relation: 'user',
@@ -32,13 +32,12 @@ class Controller extends ModuleCard {
]
};
- this.$http.get(`Workers/${this.$params.id}`, {filter})
- .then(res => this.worker = res.data)
- .then(() =>
- this.$http.get(`Workers/${this.$params.id}/activeContract`)
- .then(res => {
- if (res.data) this.worker.hasWorkCenter = res.data.workCenterFk;
- }));
+ return Promise.all([
+ this.$http.get(`Workers/${this.$params.id}`, {filter})
+ .then(res => this.worker = res.data),
+ this.$http.get(`Workers/${this.$params.id}/activeContract`)
+ .then(res => this.hasWorkCenter = res.data?.workCenterFk)
+ ]);
}
}
diff --git a/modules/worker/front/department/descriptor/index.js b/modules/worker/front/department/descriptor/index.js
index 5ab1059d9..388a7f776 100644
--- a/modules/worker/front/department/descriptor/index.js
+++ b/modules/worker/front/department/descriptor/index.js
@@ -32,6 +32,28 @@ class Controller extends Descriptor {
this.vnApp.showSuccess(this.$t('Department deleted.'));
});
}
+
+ loadData() {
+ const filter = {
+ fields: ['id', 'name', 'code', 'workerFk', 'isProduction', 'chatName',
+ 'isTeleworking', 'notificationEmail', 'hasToRefill', 'hasToSendMail', 'hasToMistake', 'clientFk'],
+ include: [
+ {relation: 'client',
+ scope: {
+ fields: ['id', 'name']
+ }},
+ {
+ relation: 'worker',
+ scope: {
+ fields: ['id', 'firstName', 'lastName']
+ }
+ }
+ ]
+ };
+
+ return this.getData(`Departments/${this.id}`, {filter})
+ .then(res => this.entity = res.data);
+ }
}
Controller.$inject = ['$element', '$scope', '$rootScope'];
diff --git a/modules/worker/front/descriptor/index.html b/modules/worker/front/descriptor/index.html
index 58ac3d9e6..ea005e1a2 100644
--- a/modules/worker/front/descriptor/index.html
+++ b/modules/worker/front/descriptor/index.html
@@ -5,8 +5,8 @@
-
- Click to exclude the user from getting disabled
-
-
- Click to allow the user to be disabled
-
+
+ {{$ctrl.workerExcluded
+ ? 'Click to allow the user to be disabled'
+ : 'Click to exclude the user from getting disabled'}}
+
@@ -84,7 +77,7 @@
-
-
\ No newline at end of file
+
diff --git a/modules/worker/front/descriptor/index.js b/modules/worker/front/descriptor/index.js
index ef2f64e85..a53528ef2 100644
--- a/modules/worker/front/descriptor/index.js
+++ b/modules/worker/front/descriptor/index.js
@@ -18,28 +18,19 @@ class Controller extends Descriptor {
this.getIsExcluded();
}
- get excluded() {
- return this.entity.excluded;
- }
-
- set excluded(value) {
- this.entity.excluded = value;
- }
-
getIsExcluded() {
- this.$http.get(`workerDisableExcludeds/${this.entity.id}/exists`).then(data => {
- this.excluded = data.data.exists;
+ this.$http.get(`WorkerDisableExcludeds/${this.entity.id}/exists`).then(data => {
+ this.workerExcluded = data.data.exists;
});
}
handleExcluded() {
- if (this.excluded) {
- this.$http.delete(`workerDisableExcludeds/${this.entity.id}`);
- this.excluded = false;
- } else {
- this.$http.post(`workerDisableExcludeds`, {workerFk: this.entity.id, dated: new Date});
- this.excluded = true;
- }
+ if (this.workerExcluded)
+ this.$http.delete(`WorkerDisableExcludeds/${this.entity.id}`);
+ else
+ this.$http.post(`WorkerDisableExcludeds`, {workerFk: this.entity.id, dated: new Date});
+
+ this.workerExcluded = !this.workerExcluded;
}
loadData() {
diff --git a/modules/worker/front/dms/index/index.html b/modules/worker/front/dms/index/index.html
index 1404336a2..aefbbcf34 100644
--- a/modules/worker/front/dms/index/index.html
+++ b/modules/worker/front/dms/index/index.html
@@ -1,6 +1,6 @@
-
+ ng-click="$ctrl.downloadFile(document.dmsFk, document.isDocuware)">
{{::document.file}}
@@ -63,16 +63,14 @@
+ ng-click="$ctrl.downloadFile(document.dmsFk, document.isDocuware)">
-
+
-
-
+
+
+
+
@@ -91,9 +97,9 @@
fixed-bottom-right>
-
-
\ No newline at end of file
+
diff --git a/modules/worker/front/dms/index/index.js b/modules/worker/front/dms/index/index.js
index 9bb3c896a..489fe1732 100644
--- a/modules/worker/front/dms/index/index.js
+++ b/modules/worker/front/dms/index/index.js
@@ -17,9 +17,15 @@ class Controller extends Component {
});
}
- downloadFile(dmsId) {
+ downloadFile(dmsId, isDocuware) {
+ if (isDocuware) return this.vnFile.download(`api/workerDms/${dmsId}/docuwareDownload`);
this.vnFile.download(`api/workerDms/${dmsId}/downloadFile`);
}
+
+ async openDocuware() {
+ const url = await this.vnApp.getUrl(`WebClient`, 'docuware');
+ if (url) window.open(url).focus();
+ }
}
Controller.$inject = ['$element', '$scope', 'vnFile'];
diff --git a/modules/worker/front/time-control/index.html b/modules/worker/front/time-control/index.html
index 5f0855ee6..b77acbddc 100644
--- a/modules/worker/front/time-control/index.html
+++ b/modules/worker/front/time-control/index.html
@@ -4,7 +4,7 @@
filter="::$ctrl.filter"
data="$ctrl.hours">
-
+
@@ -106,12 +106,6 @@
-
- Autonomous worker
-
@@ -136,6 +130,7 @@
+
{
+ if (!this.card.hasWorkCenter) return;
+
this.getWorkedHours(this.started, this.ended);
this.getAbsences();
});
@@ -151,7 +153,6 @@ class Controller extends Section {
}
getAbsences() {
- if (!this.worker.hasWorkerCenter) return;
const fullYear = this.started.getFullYear();
let params = {
workerFk: this.$params.id,
@@ -486,5 +487,8 @@ ngModule.vnComponent('vnWorkerTimeControl', {
controller: Controller,
bindings: {
worker: '<'
+ },
+ require: {
+ card: '^vnWorkerCard'
}
});
diff --git a/modules/worker/front/time-control/index.spec.js b/modules/worker/front/time-control/index.spec.js
index 0132f50fe..6d8510ba8 100644
--- a/modules/worker/front/time-control/index.spec.js
+++ b/modules/worker/front/time-control/index.spec.js
@@ -16,9 +16,8 @@ describe('Component vnWorkerTimeControl', () => {
$scope = $rootScope.$new();
$element = angular.element('');
controller = $componentController('vnWorkerTimeControl', {$element, $scope});
- controller.worker = {
- hasWorkerCenter: true
-
+ controller.card = {
+ hasWorkCenter: true
};
}));
diff --git a/modules/zone/back/methods/zone/getLeaves.js b/modules/zone/back/methods/zone/getLeaves.js
index a6db3b711..aeed9f3a2 100644
--- a/modules/zone/back/methods/zone/getLeaves.js
+++ b/modules/zone/back/methods/zone/getLeaves.js
@@ -38,7 +38,7 @@ module.exports = Self => {
Object.assign(myOptions, options);
const [res] = await Self.rawSql(
- `CALL zone_getLeaves(?, ?, ?)`,
+ `CALL zone_getLeaves(?, ?, ?, FALSE)`,
[id, parentId, search],
myOptions
);
diff --git a/package-lock.json b/package-lock.json
index ee6d4e0fa..f87e3f64b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "salix-back",
- "version": "23.30.01",
+ "version": "23.34.01",
"lockfileVersion": 2,
"requires": true,
"packages": {
diff --git a/package.json b/package.json
index 66e341ad5..2aa37379e 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "salix-back",
- "version": "23.30.01",
+ "version": "23.34.01",
"author": "Verdnatura Levante SL",
"description": "Salix backend",
"license": "GPL-3.0",
diff --git a/print/core/smtp.js b/print/core/smtp.js
index 276b85401..8c07e7eca 100644
--- a/print/core/smtp.js
+++ b/print/core/smtp.js
@@ -10,16 +10,17 @@ module.exports = {
async send(options) {
options.from = `${config.app.senderName} <${config.app.senderEmail}>`;
- if (!process.env.NODE_ENV)
- options.to = config.app.senderEmail;
+ const env = process.env.NODE_ENV;
+ const canSend = env === 'production' || !env || options.force;
- if (process.env.NODE_ENV !== 'production' && !options.force) {
+ if (!canSend || !config.smtp.auth.user) {
const notProductionError = {message: 'This not production, this email not sended'};
await this.mailLog(options, notProductionError);
+ return Promise.resolve(true);
}
- if (!config.smtp.auth.user)
- return Promise.resolve(true);
+ if (!env)
+ options.to = config.app.senderEmail;
let res;
let error;
diff --git a/print/templates/email/printer-setup/assets/files/model.ezp b/print/templates/email/printer-setup/assets/files/model.ezpx
similarity index 95%
rename from print/templates/email/printer-setup/assets/files/model.ezp
rename to print/templates/email/printer-setup/assets/files/model.ezpx
index dba98e0ee..739593447 100644
--- a/print/templates/email/printer-setup/assets/files/model.ezp
+++ b/print/templates/email/printer-setup/assets/files/model.ezpx
@@ -539,9 +539,9 @@
2
4
-
+
false
- false
+ true
4294967295
5
W5
@@ -571,15 +571,15 @@
2896
- 187
- 24
+ 138
+ 32
426
2896
- 187
- 24
+ 138
+ 32
426
2896
@@ -621,14 +621,14 @@
New label
-Lang:(es-ES) OS:Microsoft Windows NT 10.0.22000.0(Win32NT)
+Lang:(es-ES) OS:Microsoft Windows NT 10.0.19045.0(Win32NT)
Mm
203
EZPL
- GODEX G300#132207AB
- None
+ 00000000
+ COM1
USB
2886794855
9100
diff --git a/print/templates/email/printer-setup/attachments.json b/print/templates/email/printer-setup/attachments.json
index 1e1f710c3..969fdd23a 100644
--- a/print/templates/email/printer-setup/attachments.json
+++ b/print/templates/email/printer-setup/attachments.json
@@ -1,9 +1,9 @@
[
{
- "filename": "model.ezp",
+ "filename": "model.ezpx",
"component": "printer-setup",
- "path": "/assets/files/model.ezp",
- "cid": "model.ezp"
+ "path": "/assets/files/model.ezpx",
+ "cid": "model.ezpx"
},
{
"filename": "port.png",
@@ -11,4 +11,4 @@
"path": "/assets/files/port.png",
"cid": "port.png"
}
-]
\ No newline at end of file
+]
diff --git a/print/templates/reports/cmr/assets/css/import.js b/print/templates/reports/cmr/assets/css/import.js
new file mode 100644
index 000000000..37a98dfdd
--- /dev/null
+++ b/print/templates/reports/cmr/assets/css/import.js
@@ -0,0 +1,12 @@
+const Stylesheet = require(`vn-print/core/stylesheet`);
+
+const path = require('path');
+const vnPrintPath = path.resolve('print');
+
+module.exports = new Stylesheet([
+ `${vnPrintPath}/common/css/spacing.css`,
+ `${vnPrintPath}/common/css/misc.css`,
+ `${vnPrintPath}/common/css/layout.css`,
+ `${vnPrintPath}/common/css/report.css`,
+ `${__dirname}/style.css`])
+ .mergeStyles();
diff --git a/print/templates/reports/cmr/assets/css/style.css b/print/templates/reports/cmr/assets/css/style.css
new file mode 100644
index 000000000..201afc3b6
--- /dev/null
+++ b/print/templates/reports/cmr/assets/css/style.css
@@ -0,0 +1,101 @@
+html {
+ font-family: "Roboto", "Helvetica", "Arial", sans-serif;
+ margin: 10px;
+ font-size: 22px;
+}
+.mainTable, .specialTable, .categoryTable {
+ width: 100%;
+ border-collapse: collapse;
+ font-size: inherit;
+}
+.mainTable td {
+ width: 50%;
+ border: 1px solid black;
+ vertical-align: top;
+ padding: 15px;
+ font-size: inherit;
+}
+.signTable {
+ height: 12%;
+}
+.signTable td {
+ width: calc(100% / 3);
+ border: 1px solid black;
+ vertical-align: top;
+ font-size: inherit;
+ padding: 15px;
+ border-top: none;
+}
+#title {
+ font-weight: bold;
+ font-size: 85px;
+}
+hr {
+ border: 1px solid #cccccc;
+ height: 0px;
+ border-radius: 25px;
+}
+#cellHeader {
+ border: 0px;
+ text-align: center;
+ vertical-align: middle;
+}
+#label, #merchandiseLabels {
+ font-size: 13px;
+}
+#merchandiseLabels {
+ border: none;
+}
+.imgSection {
+ text-align: center;
+ height: 200px;
+ overflow: hidden;
+}
+img {
+ object-fit: contain;
+ width: 100%;
+ height: 100%;
+}
+#lineBreak {
+ white-space: pre-line;
+}
+.specialTable td {
+ border: 1px solid black;
+ vertical-align: top;
+ padding: 15px;
+ font-size: inherit;
+ border-top: none;
+ border-bottom: none;
+}
+.specialTable #itemCategoryList {
+ width: 70%;
+ padding-top: 10px;
+}
+.categoryTable {
+ padding-bottom: none;
+}
+.categoryTable td {
+ vertical-align: top;
+ font-size: inherit;
+ border: none;
+ padding: 5px;
+ overflow: hidden;
+}
+.categoryTable #merchandiseLabels {
+ border-bottom: 4px solid #cccccc;
+ padding: none;
+}
+#merchandiseDetail {
+ font-weight: bold;
+ padding-top: 10px;
+}
+#merchandiseData {
+ font-weight: bold;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+#merchandiseLabels td {
+ padding-bottom: 11px;
+ max-width: 300px;
+}
\ No newline at end of file
diff --git a/print/templates/reports/cmr/cmr.html b/print/templates/reports/cmr/cmr.html
new file mode 100644
index 000000000..c6a9e79d6
--- /dev/null
+++ b/print/templates/reports/cmr/cmr.html
@@ -0,0 +1,212 @@
+
+
+
+
+
+
+
+ 1. Remitente / Expediteur / Sender
+
+ {{data.senderName}}
+ {{data.senderStreet}}
+ {{data.senderPostCode}} {{data.senderCity}} {{(data.senderCountry) ? `(${data.senderCountry})` : null}}
+ |
+
+
+
+
+ 2. Consignatario / Destinataire / Consignee
+
+ {{data.deliveryAddressFk}}
+ {{data.deliveryName}}
+ {{data.deliveryPhone || data.clientPhone}}
+ {{((data.deliveryPhone || data.clientPhone) && data.deliveryMobile) ? '/' : null}}
+ {{data.deliveryMobile}}
+ |
+
+ 16. Transportista / Transporteur / Carrier
+
+ {{data.carrierName}}
+ {{data.carrierStreet}}
+ {{data.carrierPostalCode}} {{data.carrierCity}} {{(data.carrierCountry) ? `(${data.carrierCountry})` : null}}
+ |
+
+
+
+
+ 3. Lugar y fecha de entrega /
+ Lieu et date de livraison /
+ Place and date of delivery
+
+
+ {{data.deliveryStreet}}
+ {{data.deliveryPostalCode}} {{data.deliveryCity}} {{(data.deliveryCountry) ? `(${data.deliveryCountry})` : null}}
+ {{(data.ead) ? formatDate(data.ead, '%d/%m/%Y') : null}}
+
+ |
+
+ 17. Porteadores sucesivos / Transporteurs succesifs / Succesive Carriers
+
+ |
+
+
+
+
+ 4. Lugar y fecha de carga /
+ Lieu et date del prise en charge de la merchandise /
+ Place and date of taking over the goods
+
+
+ {{data.loadStreet}}
+ {{data.loadPostalCode}} {{data.loadCity}} {{(data.loadCountry) ? `(${data.loadCountry})` : null}}
+ {{formatDate(data.created, '%d/%m/%Y')}}
+ |
+
+
+ 18. Obervaciones del transportista /
+ Reserves et observations du transporteur /
+ Carrier's reservations and observations
+
+
+ {{data.truckPlate}}
+ {{data.observations}}
+ |
+
+
+
+ 5. Documentos anexos / Documents annexes / Documents attached
+
+ |
+
+
+
+
+
+
+ 7 & 8. Número de bultos y clase de embalage /
+ Number of packages and packaging class /
+ Nombre de colis et classe d'emballage
+
+
+
+ {{data.packagesList}}
+
+ |
+
+
+
+ 6. Marcas y números / Brands and numbers / Marques et numéros |
+ 9. Naturaleza de la merc. / Nature of goods / Nature des marchandises |
+ 10. nº Estadístico / Statistical no. / n° statistique |
+ 11. Peso bruto / Gross weight / Poids brut (kg) |
+ 12. Volumen / Volume (m3) |
+
+
+ {{merchandise.ticketFk}} |
+ {{merchandise.name}} |
+ N/A |
+ {{merchandise.weight}} |
+ {{merchandise.volume}} |
+
+
+
+ {{data.merchandiseDetail}}
+
+ |
+
+
+
+
+
+
+ 13. Instrucciones del remitente /
+ Instrunstions de l'expèditeur / Sender
+ instruccions
+
+
+ {{data.senderInstruccions}}
+ |
+
+
+ 19. Estipulaciones particulares /
+ Conventions particulieres /
+ Special agreements
+
+
+ {{data.specialAgreements}}
+ |
+
+
+
+
+ 14. Forma de pago /
+ Prescriptions d'affranchissement /
+ Instruction as to payment for carriage
+
+
+ {{data.paymentInstruccions}}
+ |
+
+ 20. A pagar por / Être payé pour / To be paid by
+
+ |
+
+
+
+ 21. Formalizado en / Etabile a / Estabilshed in
+
+ {{data.loadStreet}}
+ {{data.loadPostalCode}} {{data.loadCity}} {{(data.loadCountry) ? `(${data.loadCountry})` : null}}
+ |
+
+ 15. Reembolso / Remboursement / Cash on delivery
+
+ |
+
+
+
+
+
+
+
+
+
+ 22. Firma y sello del remitente /
+ Signature et timbre de l'expèditeur /
+ Signature and stamp of the sender
+
+
+
+
+
+ |
+
+
+ 23. Firma y sello del transportista /
+ Signature et timbre du transporteur /
+ Signature and stamp of the carrier
+
+
+
+
+
+ |
+
+
+ 24. Firma y sello del consignatario /
+ Signature et timbre du destinataire /
+ Signature and stamp of the consignee
+
+
+
+
+
+ |
+
+
+
+
+
\ No newline at end of file
diff --git a/print/templates/reports/cmr/cmr.js b/print/templates/reports/cmr/cmr.js
new file mode 100644
index 000000000..c939e5152
--- /dev/null
+++ b/print/templates/reports/cmr/cmr.js
@@ -0,0 +1,45 @@
+const config = require(`vn-print/core/config`);
+const vnReport = require('../../../core/mixins/vn-report.js');
+const md5 = require('md5');
+const fs = require('fs-extra');
+
+const prefixBase64 = 'data:image/png;base64,';
+
+module.exports = {
+ name: 'cmr',
+ mixins: [vnReport],
+ async serverPrefetch() {
+ this.data = await this.findOneFromDef('data', [this.id]);
+ if (this.data.ticketFk) {
+ this.merchandises = await this.rawSqlFromDef('merchandise', [this.data.ticketFk]);
+ this.signature = await this.findOneFromDef('signature', [this.data.ticketFk]);
+ } else
+ this.merchandises = null;
+
+ this.senderStamp = (this.data.senderStamp)
+ ? `${prefixBase64} ${this.data.senderStamp.toString('base64')}`
+ : null;
+ this.deliveryStamp = (this.data.deliveryStamp)
+ ? `${prefixBase64} ${this.data.deliveryStamp.toString('base64')}`
+ : null;
+ },
+ props: {
+ id: {
+ type: Number,
+ required: true,
+ description: 'The cmr id'
+ },
+ },
+ computed: {
+ signPath() {
+ if (!this.signature) return;
+
+ const signatureName = this.signature.signature
+ const hash = md5(signatureName.toString()).substring(0, 3);
+ const file = `${config.storage.root}/${hash}/${signatureName}.png`;
+ if (!fs.existsSync(file)) return null;
+
+ return `${prefixBase64} ${Buffer.from(fs.readFileSync(file), 'utf8').toString('base64')}`;
+ },
+ }
+};
\ No newline at end of file
diff --git a/print/templates/reports/cmr/locale/es.yml b/print/templates/reports/cmr/locale/es.yml
new file mode 100644
index 000000000..79f481b35
--- /dev/null
+++ b/print/templates/reports/cmr/locale/es.yml
@@ -0,0 +1 @@
+reportName: cmr
\ No newline at end of file
diff --git a/print/templates/reports/cmr/options.json b/print/templates/reports/cmr/options.json
new file mode 100644
index 000000000..9151ca63b
--- /dev/null
+++ b/print/templates/reports/cmr/options.json
@@ -0,0 +1,3 @@
+{
+ "format": "A4"
+}
\ No newline at end of file
diff --git a/print/templates/reports/cmr/sql/data.sql b/print/templates/reports/cmr/sql/data.sql
new file mode 100644
index 000000000..9708c4483
--- /dev/null
+++ b/print/templates/reports/cmr/sql/data.sql
@@ -0,0 +1,52 @@
+SELECT c.id cmrFk,
+ t.id ticketFk,
+ c.truckPlate,
+ c.observations,
+ c.senderInstruccions,
+ c.paymentInstruccions,
+ c.specialAgreements,
+ c.created,
+ c.packagesList,
+ c.merchandiseDetail,
+ c.ead,
+ s.name carrierName,
+ s.street carrierStreet,
+ s.postCode carrierPostCode,
+ s.city carrierCity,
+ cou.country carrierCountry,
+ s2.name senderName,
+ s2.street senderStreet,
+ s2.postCode senderPostCode,
+ s2.city senderCity,
+ cou2.country senderCountry,
+ a.street deliveryStreet,
+ a.id deliveryAddressFk,
+ a.postalCode deliveryPostalCode,
+ a.city deliveryCity,
+ a.nickname deliveryName,
+ a.phone deliveryPhone,
+ a.mobile deliveryMobile,
+ cou3.country deliveryCountry,
+ cl.phone clientPhone,
+ a2.street loadStreet,
+ a2.postalCode loadPostalCode,
+ a2.city loadCity,
+ cou4.country loadCountry,
+ co.stamp senderStamp,
+ s.stamp deliveryStamp
+ FROM cmr c
+ LEFT JOIN supplier s ON s.id = c.supplierFk
+ LEFT JOIN country cou ON cou.id = s.countryFk
+ LEFT JOIN company co ON co.id = c.companyFk
+ LEFT JOIN supplierAccount sa ON sa.id = co.supplierAccountFk
+ LEFT JOIN supplier s2 ON s2.id = sa.supplierFk
+ LEFT JOIN country cou2 ON cou2.id = s2.countryFk
+ LEFT JOIN `address` a ON a.id = c.addressToFk
+ LEFT JOIN province p ON p.id = a.provinceFk
+ LEFT JOIN country cou3 ON cou3.id = p.countryFk
+ LEFT JOIN client cl ON cl.id = a.clientFk
+ LEFT JOIN `address` a2 ON a2.id = c.addressFromFk
+ LEFT JOIN province p2 ON p2.id = a2.provinceFk
+ LEFT JOIN country cou4 ON cou4.id = p2.countryFk
+ LEFT JOIN ticket t ON t.cmrFk = c.id
+ WHERE c.id = ?
\ No newline at end of file
diff --git a/print/templates/reports/cmr/sql/merchandise.sql b/print/templates/reports/cmr/sql/merchandise.sql
new file mode 100644
index 000000000..cab597caa
--- /dev/null
+++ b/print/templates/reports/cmr/sql/merchandise.sql
@@ -0,0 +1,11 @@
+SELECT s.ticketFk,
+ ic.name,
+ CAST(SUM(sv.weight) AS DECIMAL(10,2)) `weight`,
+ CAST(SUM(sv.volume) AS DECIMAL(10,3)) volume
+ FROM sale s
+ JOIN saleVolume sv ON sv.saleFk = s.id
+ JOIN item i ON i.id = s.itemFk
+ JOIN itemType it ON it.id = i.typeFk
+ JOIN itemCategory ic ON ic.id = it.categoryFk
+ WHERE sv.ticketFk = ?
+ GROUP BY ic.id
\ No newline at end of file
diff --git a/print/templates/reports/cmr/sql/signature.sql b/print/templates/reports/cmr/sql/signature.sql
new file mode 100644
index 000000000..7ec7380a5
--- /dev/null
+++ b/print/templates/reports/cmr/sql/signature.sql
@@ -0,0 +1,5 @@
+SELECT dc.id `signature`
+ FROM ticket t
+ JOIN ticketDms dt ON dt.ticketFk = t.id
+ LEFT JOIN dms dc ON dc.id = dt.dmsFk
+ WHERE t.id = ?
\ No newline at end of file
diff --git a/print/templates/reports/invoice/sql/sales.sql b/print/templates/reports/invoice/sql/sales.sql
index f5721a594..3833a3700 100644
--- a/print/templates/reports/invoice/sql/sales.sql
+++ b/print/templates/reports/invoice/sql/sales.sql
@@ -1,31 +1,19 @@
-SELECT
+SELECT
io.ref,
- c.socialName,
- sa.iban,
- pm.name AS payMethod,
- t.clientFk,
- t.shipped,
- t.nickname,
s.ticketFk,
- s.itemFk,
- s.concept,
- s.quantity,
- s.price,
+ ib.ediBotanic botanical,
+ s.quantity,
+ s.price,
s.discount,
- i.tag5,
- i.value5,
- i.tag6,
- i.value6,
- i.tag7,
- i.value7,
- tc.code AS vatType,
- ib.ediBotanic botanical
+ s.itemFk,
+ s.concept,
+ tc.code vatType
FROM vn.invoiceOut io
JOIN vn.ticket t ON t.refFk = io.ref
JOIN vn.supplier su ON su.id = io.companyFk
- JOIN vn.client c ON c.id = t.clientFk
+ JOIN vn.client c ON c.id = t.clientFk
JOIN vn.payMethod pm ON pm.id = c.payMethodFk
- JOIN vn.company co ON co.id = io.companyFk
+ JOIN vn.company co ON co.id = io.companyFk
JOIN vn.supplierAccount sa ON sa.id = co.supplierAccountFk
JOIN vn.sale s ON s.ticketFk = t.id
JOIN item i ON i.id = s.itemFk
@@ -38,35 +26,23 @@ SELECT
AND itc.itemFk = s.itemFk
JOIN vn.taxClass tc ON tc.id = itc.taxClassFk
WHERE t.refFk = ?
- UNION ALL
-SELECT
+ UNION ALL
+SELECT
io.ref,
- c.socialName,
- sa.iban,
- pm.name AS payMethod,
- t.clientFk,
- t.shipped,
- t.nickname,
- t.id AS ticketFk,
+ t.id ticketFk,
+ NULL botanical,
+ ts.quantity,
+ ts.price,
+ 0 discount,
'',
- ts.description concept,
- ts.quantity,
- ts.price,
- 0 discount,
- NULL AS tag5,
- NULL AS value5,
- NULL AS tag6,
- NULL AS value6,
- NULL AS tag7,
- NULL AS value7,
- tc.code AS vatType,
- NULL AS botanical
+ ts.description concept,
+ tc.code vatType
FROM vn.invoiceOut io
JOIN vn.ticket t ON t.refFk = io.ref
JOIN vn.ticketService ts ON ts.ticketFk = t.id
- JOIN vn.client c ON c.id = t.clientFk
+ JOIN vn.client c ON c.id = t.clientFk
JOIN vn.payMethod pm ON pm.id = c.payMethodFk
- JOIN vn.company co ON co.id = io.companyFk
+ JOIN vn.company co ON co.id = io.companyFk
JOIN vn.supplierAccount sa ON sa.id = co.supplierAccountFk
JOIN vn.taxClass tc ON tc.id = ts.taxClassFk
- WHERE t.refFk = ?
\ No newline at end of file
+ WHERE t.refFk = ?
|