Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix into 5976-transferSale_call_setDeleted
gitea/salix/pipeline/head This commit looks good
Details
gitea/salix/pipeline/head This commit looks good
Details
This commit is contained in:
commit
0d5c6ffdbe
31
CHANGELOG.md
31
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/),
|
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).
|
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
|
### Added
|
||||||
|
|
||||||
|
@ -14,6 +14,35 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
### Fixed
|
### 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
|
## [2328.01] - 2023-07-13
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
const axios = require('axios');
|
|
||||||
|
|
||||||
module.exports = Self => {
|
module.exports = Self => {
|
||||||
Self.remoteMethodCtx('checkFile', {
|
Self.remoteMethod('checkFile', {
|
||||||
description: 'Check if exist docuware file',
|
description: 'Check if exist docuware file',
|
||||||
accessType: 'READ',
|
accessType: 'READ',
|
||||||
accepts: [
|
accepts: [
|
||||||
|
@ -17,12 +15,16 @@ module.exports = Self => {
|
||||||
required: true,
|
required: true,
|
||||||
description: 'The fileCabinet name'
|
description: 'The fileCabinet name'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
arg: 'filter',
|
||||||
|
type: 'object',
|
||||||
|
description: 'The filter'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
arg: 'signed',
|
arg: 'signed',
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
required: true,
|
|
||||||
description: 'If pdf is necessary to be signed'
|
description: 'If pdf is necessary to be signed'
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
returns: {
|
returns: {
|
||||||
type: 'object',
|
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 models = Self.app.models;
|
||||||
const action = 'find';
|
const action = 'find';
|
||||||
|
|
||||||
|
@ -45,39 +47,34 @@ module.exports = Self => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const searchFilter = {
|
if (!filter) {
|
||||||
condition: [
|
filter = {
|
||||||
{
|
condition: [
|
||||||
DBName: docuwareInfo.findById,
|
{
|
||||||
|
DBName: docuwareInfo.findById,
|
||||||
Value: [id]
|
Value: [id]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
sortOrder: [
|
sortOrder: [
|
||||||
{
|
{
|
||||||
Field: 'FILENAME',
|
Field: 'FILENAME',
|
||||||
Direction: 'Desc'
|
Direction: 'Desc'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
if (signed) {
|
||||||
|
filter.condition.push({
|
||||||
|
DBName: 'ESTADO',
|
||||||
|
Value: ['Firmado']
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const options = await Self.getOptions();
|
const response = await Self.get(fileCabinet, filter);
|
||||||
|
const [documents] = response.Items;
|
||||||
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;
|
|
||||||
if (!documents) return false;
|
if (!documents) return false;
|
||||||
|
|
||||||
const state = documents.Fields.find(field => field.FieldName == 'ESTADO');
|
|
||||||
if (signed && state.Item != 'Firmado') return false;
|
|
||||||
|
|
||||||
return {id: documents.Id};
|
return {id: documents.Id};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -1,59 +1,6 @@
|
||||||
const axios = require('axios');
|
const axios = require('axios');
|
||||||
|
|
||||||
module.exports = Self => {
|
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
|
* Returns basic headers
|
||||||
*
|
*
|
||||||
|
@ -75,4 +22,139 @@ module.exports = Self => {
|
||||||
headers
|
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)));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,7 +3,7 @@ const axios = require('axios');
|
||||||
const UserError = require('vn-loopback/util/user-error');
|
const UserError = require('vn-loopback/util/user-error');
|
||||||
|
|
||||||
module.exports = Self => {
|
module.exports = Self => {
|
||||||
Self.remoteMethodCtx('download', {
|
Self.remoteMethod('download', {
|
||||||
description: 'Download an docuware PDF',
|
description: 'Download an docuware PDF',
|
||||||
accessType: 'READ',
|
accessType: 'READ',
|
||||||
accepts: [
|
accepts: [
|
||||||
|
@ -16,8 +16,12 @@ module.exports = Self => {
|
||||||
{
|
{
|
||||||
arg: 'fileCabinet',
|
arg: 'fileCabinet',
|
||||||
type: 'string',
|
type: 'string',
|
||||||
description: 'The file cabinet',
|
description: 'The file cabinet'
|
||||||
http: {source: 'path'}
|
},
|
||||||
|
{
|
||||||
|
arg: 'filter',
|
||||||
|
type: 'object',
|
||||||
|
description: 'The filter'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
returns: [
|
returns: [
|
||||||
|
@ -36,14 +40,15 @@ module.exports = Self => {
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
http: {
|
http: {
|
||||||
path: `/:id/download/:fileCabinet`,
|
path: `/:id/download`,
|
||||||
verb: 'GET'
|
verb: 'GET'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Self.download = async function(ctx, id, fileCabinet) {
|
Self.download = async function(id, fileCabinet, filter) {
|
||||||
const models = Self.app.models;
|
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');
|
if (!docuwareFile) throw new UserError('The DOCUWARE PDF document does not exists');
|
||||||
|
|
||||||
const fileCabinetId = await Self.getFileCabinet(fileCabinet);
|
const fileCabinetId = await Self.getFileCabinet(fileCabinet);
|
||||||
|
|
|
@ -1,57 +1,15 @@
|
||||||
const models = require('vn-loopback/server/server').models;
|
const models = require('vn-loopback/server/server').models;
|
||||||
const axios = require('axios');
|
|
||||||
|
|
||||||
describe('docuware download()', () => {
|
describe('docuware download()', () => {
|
||||||
const ticketId = 1;
|
const ticketId = 1;
|
||||||
const userId = 9;
|
|
||||||
const ctx = {
|
|
||||||
req: {
|
|
||||||
|
|
||||||
accessToken: {userId: userId},
|
|
||||||
headers: {origin: 'http://localhost:5000'},
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const docuwareModel = models.Docuware;
|
const docuwareModel = models.Docuware;
|
||||||
const fileCabinetName = 'deliveryNote';
|
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() => {
|
it('should return false if there are no documents', async() => {
|
||||||
const response = {
|
spyOn(docuwareModel, 'get').and.returnValue((new Promise(resolve => resolve({Items: []}))));
|
||||||
data: {
|
|
||||||
Items: []
|
|
||||||
}
|
|
||||||
};
|
|
||||||
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);
|
|
||||||
});
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
expect(result).toEqual(false);
|
expect(result).toEqual(false);
|
||||||
});
|
});
|
||||||
|
@ -59,23 +17,21 @@ describe('docuware download()', () => {
|
||||||
it('should return the document data', async() => {
|
it('should return the document data', async() => {
|
||||||
const docuwareId = 1;
|
const docuwareId = 1;
|
||||||
const response = {
|
const response = {
|
||||||
data: {
|
Items: [
|
||||||
Items: [
|
{
|
||||||
{
|
Id: docuwareId,
|
||||||
Id: docuwareId,
|
Fields: [
|
||||||
Fields: [
|
{
|
||||||
{
|
FieldName: 'ESTADO',
|
||||||
FieldName: 'ESTADO',
|
Item: 'Firmado'
|
||||||
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);
|
expect(result.id).toEqual(docuwareId);
|
||||||
});
|
});
|
||||||
|
|
|
@ -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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -39,7 +39,7 @@ describe('docuware download()', () => {
|
||||||
spyOn(docuwareModel, 'checkFile').and.returnValue({});
|
spyOn(docuwareModel, 'checkFile').and.returnValue({});
|
||||||
spyOn(axios, 'get').and.returnValue(new stream.PassThrough({objectMode: true}));
|
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[1]).toEqual('application/pdf');
|
||||||
expect(result[2]).toEqual(`filename="${ticketId}.pdf"`);
|
expect(result[2]).toEqual(`filename="${ticketId}.pdf"`);
|
||||||
|
|
|
@ -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;
|
||||||
|
};
|
||||||
|
};
|
|
@ -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;
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,52 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
|
||||||
|
<soap12:Body>
|
||||||
|
<PutExpedicionInternacional xmlns="http://82.223.6.71:82">
|
||||||
|
<ObjetoEnvio>
|
||||||
|
<Peso><%= viaexpressConfig.defaultWeight %></Peso>
|
||||||
|
<Bultos>1</Bultos>
|
||||||
|
<Reembolso>0</Reembolso>
|
||||||
|
<Fecha><%= shipped %></Fecha>
|
||||||
|
<ConRetorno>0</ConRetorno>
|
||||||
|
<Tipo><%= viaexpressConfig.deliveryType %></Tipo>
|
||||||
|
<Debidos>0</Debidos>
|
||||||
|
<Asegurado>0</Asegurado>
|
||||||
|
<Imprimir>0</Imprimir>
|
||||||
|
<ConDevolucionAlbaran>0</ConDevolucionAlbaran>
|
||||||
|
<Intradia>0</Intradia>
|
||||||
|
<Observaciones></Observaciones>
|
||||||
|
<AlbaranRemitente></AlbaranRemitente>
|
||||||
|
<Modo>0</Modo>
|
||||||
|
<TextoAgencia></TextoAgencia>
|
||||||
|
<Terminal></Terminal>
|
||||||
|
<ObjetoRemitente>
|
||||||
|
<RazonSocial><%= sender.socialName %></RazonSocial>
|
||||||
|
<Domicilio><%= senderAddress.street %></Domicilio>
|
||||||
|
<Cpostal><%= senderAddress.postalCode %></Cpostal>
|
||||||
|
<Poblacion><%= senderAddress.city %></Poblacion>
|
||||||
|
<Provincia><%= senderAddress.province().name %></Provincia>
|
||||||
|
<Contacto></Contacto>
|
||||||
|
<Telefono><%= senderAddress.mobile || senderAddress.phone || sender.mobile || sender.phone %></Telefono>
|
||||||
|
<Email><%= sender.email %></Email>
|
||||||
|
</ObjetoRemitente>
|
||||||
|
<ObjetoDestinatario>
|
||||||
|
<RazonSocial><%= address.nickname %></RazonSocial>
|
||||||
|
<Domicilio><%= address.street %></Domicilio>
|
||||||
|
<Cpostal><%= address.postalCode %></Cpostal>
|
||||||
|
<Poblacion><%= address.city %></Poblacion>
|
||||||
|
<Municipio></Municipio>
|
||||||
|
<Provincia><%= address.province().name %></Provincia>
|
||||||
|
<Contacto></Contacto>
|
||||||
|
<Telefono><%= address.mobile || address.phone || client.mobile || client.phone %></Telefono>
|
||||||
|
<Email><%= client.email %></Email>
|
||||||
|
<Pais><%= address.province().country().code %></Pais>
|
||||||
|
</ObjetoDestinatario>
|
||||||
|
<ObjetoLogin>
|
||||||
|
<IdCliente><%= viaexpressConfig.client %></IdCliente>
|
||||||
|
<Usuario><%= viaexpressConfig.user %></Usuario>
|
||||||
|
<Password><%= viaexpressConfig.password %></Password>
|
||||||
|
</ObjetoLogin>
|
||||||
|
</ObjetoEnvio>
|
||||||
|
</PutExpedicionInternacional>
|
||||||
|
</soap12:Body>
|
||||||
|
</soap12:Envelope>
|
|
@ -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);
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -47,7 +47,7 @@ module.exports = Self => {
|
||||||
const user = await Self.findById(userId, {fields: ['hasGrant']}, myOptions);
|
const user = await Self.findById(userId, {fields: ['hasGrant']}, myOptions);
|
||||||
|
|
||||||
const userToUpdate = await Self.findById(id, {
|
const userToUpdate = await Self.findById(id, {
|
||||||
fields: ['id', 'name', 'hasGrant', 'roleFk', 'password'],
|
fields: ['id', 'name', 'hasGrant', 'roleFk', 'password', 'email'],
|
||||||
include: {
|
include: {
|
||||||
relation: 'role',
|
relation: 'role',
|
||||||
scope: {
|
scope: {
|
||||||
|
|
|
@ -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);
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -150,6 +150,9 @@
|
||||||
},
|
},
|
||||||
"PrintConfig": {
|
"PrintConfig": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
|
},
|
||||||
|
"ViaexpressConfig": {
|
||||||
|
"dataSource": "vn"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,11 +18,21 @@
|
||||||
},
|
},
|
||||||
"expired": {
|
"expired": {
|
||||||
"type": "date"
|
"type": "date"
|
||||||
|
},
|
||||||
|
"supplierAccountFk": {
|
||||||
|
"type": "number"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"scope": {
|
"scope": {
|
||||||
"where" :{
|
"where" :{
|
||||||
"expired": null
|
"expired": null
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"relations": {
|
||||||
|
"client": {
|
||||||
|
"type": "belongsTo",
|
||||||
|
"model": "Client",
|
||||||
|
"foreignKey": "clientFk"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,9 @@
|
||||||
},
|
},
|
||||||
"isUeeMember": {
|
"isUeeMember": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"isSocialNameUnique": {
|
||||||
|
"type": "boolean"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"relations": {
|
"relations": {
|
||||||
|
@ -39,4 +42,4 @@
|
||||||
"permission": "ALLOW"
|
"permission": "ALLOW"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,5 +28,12 @@
|
||||||
"findById": {
|
"findById": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"relations": {
|
||||||
|
"dmsType": {
|
||||||
|
"type": "belongsTo",
|
||||||
|
"model": "DmsType",
|
||||||
|
"foreignKey": "dmsTypeFk"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
module.exports = Self => {
|
||||||
|
require('../methods/viaexpress-config/internationalExpedition')(Self);
|
||||||
|
require('../methods/viaexpress-config/renderer')(Self);
|
||||||
|
};
|
|
@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,8 +12,6 @@ module.exports = function(Self) {
|
||||||
require('../methods/vn-user/privileges')(Self);
|
require('../methods/vn-user/privileges')(Self);
|
||||||
require('../methods/vn-user/validate-auth')(Self);
|
require('../methods/vn-user/validate-auth')(Self);
|
||||||
require('../methods/vn-user/renew-token')(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');
|
Self.definition.settings.acls = Self.definition.settings.acls.filter(acl => acl.property !== 'create');
|
||||||
|
|
||||||
|
@ -22,7 +20,7 @@ module.exports = function(Self) {
|
||||||
Self.validatesFormatOf('email', {
|
Self.validatesFormatOf('email', {
|
||||||
message: 'Invalid email',
|
message: 'Invalid email',
|
||||||
allowNull: true,
|
allowNull: true,
|
||||||
allowBlank: true,
|
allowBlank: false,
|
||||||
with: /^[\w|.|-]+@[\w|-]+(\.[\w|-]+)*(,[\w|.|-]+@[\w|-]+(\.[\w|-]+)*)*$/
|
with: /^[\w|.|-]+@[\w|-]+(\.[\w|-]+)*(,[\w|.|-]+@[\w|-]+(\.[\w|-]+)*)*$/
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -117,6 +115,14 @@ module.exports = function(Self) {
|
||||||
Self.validateLogin = async function(user, password) {
|
Self.validateLogin = async function(user, password) {
|
||||||
let loginInfo = Object.assign({password}, Self.userUses(user));
|
let loginInfo = Object.assign({password}, Self.userUses(user));
|
||||||
token = await Self.login(loginInfo, '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};
|
return {token: token.id, ttl: token.ttl};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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');
|
|
|
@ -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');
|
|
@ -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');
|
|
@ -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');
|
|
@ -0,0 +1 @@
|
||||||
|
ALTER TABLE `vn`.`company` MODIFY COLUMN sage200Company int(2) DEFAULT 10 NOT NULL;
|
|
@ -0,0 +1,3 @@
|
||||||
|
INSERT INTO `salix`.`ACL` (`model`,`property`,`accessType`,`permission`,`principalId`)
|
||||||
|
VALUES
|
||||||
|
('Vehicle','sorted','WRITE','ALLOW','employee');
|
|
@ -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 ;
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
ALTER TABLE `vn`.`country`
|
||||||
|
ADD COLUMN `isSocialNameUnique` tinyint(1) NOT NULL DEFAULT 1;
|
|
@ -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`.`roadmap` MODIFY COLUMN etd datetime NOT NULL;
|
||||||
|
|
||||||
ALTER TABLE `vn`.`expeditionTruck` COMMENT='Distintas paradas que hacen los trocales';
|
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;
|
|
|
@ -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');
|
|
@ -0,0 +1,2 @@
|
||||||
|
INSERT INTO `salix`.`ACL` (`model`,`property`,`accessType`,`permission`,`principalType`,`principalId`)
|
||||||
|
VALUES ('Ticket','transferClient','WRITE','ALLOW','ROLE','administrative');
|
|
@ -0,0 +1,2 @@
|
||||||
|
INSERT INTO `salix`.`ACL` (`model`,`property`,`accessType`,`permission`,`principalType`,`principalId`)
|
||||||
|
VALUES ('Ticket','canEditWeekly','WRITE','ALLOW','ROLE','buyer');
|
|
@ -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;
|
|
@ -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/');
|
||||||
|
|
|
@ -37,7 +37,7 @@ ALTER TABLE `vn`.`ticket` AUTO_INCREMENT = 1;
|
||||||
|
|
||||||
INSERT INTO `salix`.`AccessToken` (`id`, `ttl`, `created`, `userId`)
|
INSERT INTO `salix`.`AccessToken` (`id`, `ttl`, `created`, `userId`)
|
||||||
VALUES
|
VALUES
|
||||||
('DEFAULT_TOKEN', '1209600', util.VN_CURDATE(), 66);
|
('DEFAULT_TOKEN', '1209600', CURDATE(), 66);
|
||||||
|
|
||||||
INSERT INTO `salix`.`printConfig` (`id`, `itRecipient`, `incidencesEmail`)
|
INSERT INTO `salix`.`printConfig` (`id`, `itRecipient`, `incidencesEmail`)
|
||||||
VALUES
|
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`)
|
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
|
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'),
|
(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'),
|
(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'),
|
(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'),
|
(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'),
|
(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'),
|
(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'),
|
(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'),
|
(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'),
|
(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'),
|
(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
|
VALUES
|
||||||
(241, 442, 'ES111122333344111122221111', 128);
|
(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
|
VALUES
|
||||||
(69 , 'CCs', NULL, 30, NULL, 0, NULL, 1, NULL),
|
(69 , 'CCs', NULL, 30, NULL, 0, NULL, 1, NULL , NULL),
|
||||||
(442 , 'VNL', 241, 30, 2 , 1, NULL, 2, 'VNL Company - Plant passport'),
|
(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'),
|
(567 , 'VNH', NULL, 30, NULL, 4, NULL, 1, 'VNH Company - Plant passport' , NULL),
|
||||||
(791 , 'FTH', NULL, 30, NULL, 3, '2015-11-30', 1, 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');
|
(1381, 'ORN', NULL, 30, NULL, 7, NULL, 1, 'ORN Company - Plant passport' , NULL);
|
||||||
|
|
||||||
INSERT INTO `vn`.`taxArea` (`code`, `claveOperacionFactura`, `CodigoTransaccion`)
|
INSERT INTO `vn`.`taxArea` (`code`, `claveOperacionFactura`, `CodigoTransaccion`)
|
||||||
VALUES
|
VALUES
|
||||||
|
@ -2953,3 +2953,8 @@ INSERT INTO `vn`.`invoiceInSerial` (`code`, `description`, `cplusTerIdNifFk`, `t
|
||||||
('E', 'Midgard', 1, 'CEE'),
|
('E', 'Midgard', 1, 'CEE'),
|
||||||
('R', 'Jotunheim', 1, 'NATIONAL'),
|
('R', 'Jotunheim', 1, 'NATIONAL'),
|
||||||
('W', 'Vanaheim', 1, 'WORLD');
|
('W', 'Vanaheim', 1, 'WORLD');
|
||||||
|
|
||||||
|
|
||||||
|
INSERT INTO `hedera`.`imageConfig` (`id`, `maxSize`, `useXsendfile`, `url`)
|
||||||
|
VALUES
|
||||||
|
(1, 0, 0, 'marvel.com');
|
||||||
|
|
|
@ -77831,7 +77831,7 @@ BEGIN
|
||||||
LEAVE cur1Loop;
|
LEAVE cur1Loop;
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
CALL zone_getLeaves2(vZoneFk, NULL, NULL);
|
CALL zone_getLeaves(vZoneFk, NULL, NULL, TRUE);
|
||||||
|
|
||||||
myLoop: LOOP
|
myLoop: LOOP
|
||||||
SET vGeoFk = NULL;
|
SET vGeoFk = NULL;
|
||||||
|
@ -77844,7 +77844,7 @@ BEGIN
|
||||||
LEAVE myLoop;
|
LEAVE myLoop;
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
CALL zone_getLeaves2(vZoneFk, vGeoFk, NULL);
|
CALL zone_getLeaves(vZoneFk, vGeoFk, NULL, TRUE);
|
||||||
UPDATE tmp.zoneNodes
|
UPDATE tmp.zoneNodes
|
||||||
SET isChecked = TRUE
|
SET isChecked = TRUE
|
||||||
WHERE geoFk = vGeoFk;
|
WHERE geoFk = vGeoFk;
|
||||||
|
@ -78130,55 +78130,58 @@ DELIMITER ;
|
||||||
/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
|
/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
|
||||||
/*!50003 SET sql_mode = 'IGNORE_SPACE,NO_ENGINE_SUBSTITUTION' */ ;
|
/*!50003 SET sql_mode = 'IGNORE_SPACE,NO_ENGINE_SUBSTITUTION' */ ;
|
||||||
DELIMITER ;;
|
DELIMITER ;;
|
||||||
CREATE DEFINER=`root`@`localhost` PROCEDURE `zone_getLeaves`(vSelf INT, vParentFk INT, vSearch VARCHAR(255))
|
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`zone_getLeaves`(
|
||||||
BEGIN
|
vSelf INT,
|
||||||
|
vParentFk INT,
|
||||||
|
vSearch VARCHAR(255),
|
||||||
|
vHasInsert BOOL
|
||||||
|
)
|
||||||
|
BEGIN
|
||||||
/**
|
/**
|
||||||
* Devuelve las ubicaciones incluidas en la ruta y que sean hijos de parentFk.
|
* Devuelve las ubicaciones incluidas en la ruta y que sean hijos de parentFk.
|
||||||
* @param vSelf Id de la zona
|
* @param vSelf Id de la zona
|
||||||
* @param vParentFk Id del geo a calcular
|
* @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 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 OR REPLACE TEMPORARY TABLE tNodes
|
||||||
CREATE TEMPORARY TABLE tNodes
|
|
||||||
(UNIQUE (id))
|
(UNIQUE (id))
|
||||||
ENGINE = MEMORY
|
ENGINE = MEMORY
|
||||||
SELECT id
|
SELECT id
|
||||||
FROM zoneGeo
|
FROM zoneGeo
|
||||||
LIMIT 0;
|
LIMIT 0;
|
||||||
|
|
||||||
IF vIsSearch THEN
|
IF vIsSearch THEN
|
||||||
SET vIsNumber = vSearch REGEXP '^[0-9]+$';
|
SET vIsNumber = vSearch REGEXP '^[0-9]+$';
|
||||||
|
|
||||||
INSERT INTO tNodes
|
INSERT INTO tNodes
|
||||||
SELECT id
|
SELECT id
|
||||||
FROM zoneGeo
|
FROM zoneGeo
|
||||||
WHERE (vIsNumber AND `name` = vSearch)
|
WHERE (vIsNumber AND `name` = vSearch)
|
||||||
OR (!vIsNumber AND `name` LIKE CONCAT('%', vSearch, '%'))
|
OR (!vIsNumber AND `name` LIKE CONCAT('%', vSearch, '%'))
|
||||||
LIMIT 1000;
|
LIMIT 1000;
|
||||||
|
|
||||||
ELSEIF vParentFk IS NULL THEN
|
ELSEIF vParentFk IS NULL THEN
|
||||||
INSERT INTO tNodes
|
INSERT INTO tNodes
|
||||||
SELECT geoFk
|
SELECT geoFk
|
||||||
FROM zoneIncluded
|
FROM zoneIncluded
|
||||||
WHERE zoneFk = vSelf;
|
WHERE zoneFk = vSelf;
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
IF vParentFk IS NULL THEN
|
IF vParentFk IS NULL THEN
|
||||||
DROP TEMPORARY TABLE IF EXISTS tChilds;
|
CREATE OR REPLACE TEMPORARY TABLE tChilds
|
||||||
CREATE TEMPORARY TABLE tChilds
|
(INDEX(id))
|
||||||
ENGINE = MEMORY
|
ENGINE = MEMORY
|
||||||
SELECT id
|
SELECT id FROM tNodes;
|
||||||
FROM tNodes;
|
|
||||||
|
|
||||||
DROP TEMPORARY TABLE IF EXISTS tParents;
|
CREATE OR REPLACE TEMPORARY TABLE tParents
|
||||||
CREATE TEMPORARY TABLE tParents
|
(INDEX(id))
|
||||||
ENGINE = MEMORY
|
ENGINE = MEMORY
|
||||||
SELECT id
|
SELECT id FROM zoneGeo LIMIT 0;
|
||||||
FROM zoneGeo
|
|
||||||
LIMIT 0;
|
|
||||||
|
|
||||||
myLoop: LOOP
|
myLoop: LOOP
|
||||||
DELETE FROM tParents;
|
DELETE FROM tParents;
|
||||||
|
@ -78186,43 +78189,67 @@ BEGIN
|
||||||
SELECT parentFk id
|
SELECT parentFk id
|
||||||
FROM zoneGeo g
|
FROM zoneGeo g
|
||||||
JOIN tChilds c ON c.id = g.id
|
JOIN tChilds c ON c.id = g.id
|
||||||
WHERE g.parentFk IS NOT NULL;
|
WHERE g.parentFk IS NOT NULL;
|
||||||
|
|
||||||
INSERT IGNORE INTO tNodes
|
INSERT IGNORE INTO tNodes
|
||||||
SELECT id
|
SELECT id FROM tParents;
|
||||||
FROM tParents;
|
|
||||||
|
IF NOT ROW_COUNT() THEN
|
||||||
IF ROW_COUNT() = 0 THEN
|
|
||||||
LEAVE myLoop;
|
LEAVE myLoop;
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
DELETE FROM tChilds;
|
DELETE FROM tChilds;
|
||||||
INSERT INTO tChilds
|
INSERT INTO tChilds
|
||||||
SELECT id
|
SELECT id FROM tParents;
|
||||||
FROM tParents;
|
|
||||||
END LOOP;
|
END LOOP;
|
||||||
|
|
||||||
DROP TEMPORARY TABLE tChilds, tParents;
|
DROP TEMPORARY TABLE tChilds, tParents;
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
IF !vIsSearch THEN
|
IF NOT vIsSearch THEN
|
||||||
INSERT IGNORE INTO tNodes
|
INSERT IGNORE INTO tNodes
|
||||||
SELECT id
|
SELECT id
|
||||||
FROM zoneGeo
|
FROM zoneGeo
|
||||||
WHERE parentFk <=> vParentFk;
|
WHERE parentFk <=> vParentFk;
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
SELECT g.id,
|
CREATE OR REPLACE TEMPORARY TABLE tZones
|
||||||
g.name,
|
SELECT g.id,
|
||||||
g.parentFk,
|
g.name,
|
||||||
g.sons,
|
g.parentFk,
|
||||||
isIncluded selected
|
g.sons,
|
||||||
FROM zoneGeo g
|
NOT g.sons OR `type` = 'country' isChecked,
|
||||||
JOIN tNodes n ON n.id = g.id
|
i.isIncluded selected,
|
||||||
LEFT JOIN zoneIncluded i ON i.geoFk = g.id AND i.zoneFk = vSelf
|
g.`depth`,
|
||||||
ORDER BY `depth`, selected DESC, name;
|
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 ;;
|
END ;;
|
||||||
DELIMITER ;
|
DELIMITER ;
|
||||||
/*!50003 SET sql_mode = @saved_sql_mode */ ;
|
/*!50003 SET sql_mode = @saved_sql_mode */ ;
|
||||||
|
@ -78540,7 +78567,7 @@ BEGIN
|
||||||
INDEX(geoFk))
|
INDEX(geoFk))
|
||||||
ENGINE = MEMORY;
|
ENGINE = MEMORY;
|
||||||
|
|
||||||
CALL zone_getLeaves2(vSelf, NULL , NULL);
|
CALL zone_getLeaves(vSelf, NULL , NULL, TRUE);
|
||||||
|
|
||||||
UPDATE tmp.zoneNodes zn
|
UPDATE tmp.zoneNodes zn
|
||||||
SET isChecked = 0
|
SET isChecked = 0
|
||||||
|
@ -78553,7 +78580,7 @@ BEGIN
|
||||||
WHERE NOT isChecked
|
WHERE NOT isChecked
|
||||||
LIMIT 1;
|
LIMIT 1;
|
||||||
|
|
||||||
CALL zone_getLeaves2(vSelf, vGeoFk, NULL);
|
CALL zone_getLeaves(vSelf, vGeoFk, NULL, TRUE);
|
||||||
UPDATE tmp.zoneNodes
|
UPDATE tmp.zoneNodes
|
||||||
SET isChecked = TRUE
|
SET isChecked = TRUE
|
||||||
WHERE geoFk = vGeoFk;
|
WHERE geoFk = vGeoFk;
|
||||||
|
|
|
@ -875,7 +875,7 @@ export default {
|
||||||
|
|
||||||
},
|
},
|
||||||
routeTickets: {
|
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',
|
firstTicketCheckbox: 'vn-route-tickets vn-tr:nth-child(1) vn-check',
|
||||||
buscamanButton: 'vn-route-tickets vn-button[icon="icon-buscaman"]',
|
buscamanButton: 'vn-route-tickets vn-button[icon="icon-buscaman"]',
|
||||||
firstTicketDeleteButton: 'vn-route-tickets vn-tr:nth-child(1) vn-icon[icon="delete"]',
|
firstTicketDeleteButton: 'vn-route-tickets vn-tr:nth-child(1) vn-icon[icon="delete"]',
|
||||||
|
|
|
@ -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() => {
|
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.name, 'Carol Danvers');
|
||||||
await page.write(selectors.createClientView.socialName, 'AVG tax');
|
await page.write(selectors.createClientView.socialName, 'AVG TAX');
|
||||||
await page.write(selectors.createClientView.street, 'Many places');
|
await page.write(selectors.createClientView.street, 'MANY PLACES');
|
||||||
await page.clearInput(selectors.createClientView.email);
|
await page.clearInput(selectors.createClientView.email);
|
||||||
await page.write(selectors.createClientView.email, 'incorrect email format');
|
await page.write(selectors.createClientView.email, 'incorrect email format');
|
||||||
await page.waitToClick(selectors.createClientView.createButton);
|
await page.waitToClick(selectors.createClientView.createButton);
|
||||||
|
|
|
@ -61,7 +61,7 @@ describe('Client Edit fiscalData path', () => {
|
||||||
await page.clearInput(selectors.clientFiscalData.fiscalId);
|
await page.clearInput(selectors.clientFiscalData.fiscalId);
|
||||||
await page.write(selectors.clientFiscalData.fiscalId, 'INVALID!');
|
await page.write(selectors.clientFiscalData.fiscalId, 'INVALID!');
|
||||||
await page.clearInput(selectors.clientFiscalData.address);
|
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.country, 'España');
|
||||||
await page.autocompleteSearch(selectors.clientFiscalData.province, 'Province one');
|
await page.autocompleteSearch(selectors.clientFiscalData.province, 'Province one');
|
||||||
await page.clearInput(selectors.clientFiscalData.city);
|
await page.clearInput(selectors.clientFiscalData.city);
|
||||||
|
@ -190,7 +190,7 @@ describe('Client Edit fiscalData path', () => {
|
||||||
const verifiedData = await page.checkboxState(selectors.clientFiscalData.verifiedDataCheckbox);
|
const verifiedData = await page.checkboxState(selectors.clientFiscalData.verifiedDataCheckbox);
|
||||||
|
|
||||||
expect(fiscalId).toEqual('94980061C');
|
expect(fiscalId).toEqual('94980061C');
|
||||||
expect(address).toEqual('Somewhere edited');
|
expect(address).toEqual('SOMEWHERE EDITED');
|
||||||
expect(postcode).toContain('46000');
|
expect(postcode).toContain('46000');
|
||||||
expect(sageTax).toEqual('Operaciones no sujetas');
|
expect(sageTax).toEqual('Operaciones no sujetas');
|
||||||
expect(sageTransaction).toEqual('Regularización de inversiones');
|
expect(sageTransaction).toEqual('Regularización de inversiones');
|
||||||
|
|
|
@ -28,7 +28,7 @@ describe('Client lock verified data path', () => {
|
||||||
it('should edit the social name', async() => {
|
it('should edit the social name', async() => {
|
||||||
await page.waitForSelector(selectors.clientFiscalData.socialName);
|
await page.waitForSelector(selectors.clientFiscalData.socialName);
|
||||||
await page.clearInput(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);
|
await page.waitToClick(selectors.clientFiscalData.saveButton);
|
||||||
const message = await page.waitForSnackbar();
|
const message = await page.waitForSnackbar();
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ describe('Client lock verified data path', () => {
|
||||||
await page.reloadSection('client.card.fiscalData');
|
await page.reloadSection('client.card.fiscalData');
|
||||||
const result = await page.waitToGetProperty(selectors.clientFiscalData.socialName, 'value');
|
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');
|
await page.reloadSection('client.card.fiscalData');
|
||||||
const result = await page.waitToGetProperty(selectors.clientFiscalData.socialName, 'value');
|
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');
|
await page.reloadSection('client.card.fiscalData');
|
||||||
const result = await page.waitToGetProperty(selectors.clientFiscalData.socialName, 'value');
|
const result = await page.waitToGetProperty(selectors.clientFiscalData.socialName, 'value');
|
||||||
|
|
||||||
expect(result).toEqual('new social name edition');
|
expect(result).toEqual('NEW SOCIAL NAME EDITION');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@ describe('Client summary path', () => {
|
||||||
it('should display fiscal address details', async() => {
|
it('should display fiscal address details', async() => {
|
||||||
const result = await page.waitToGetProperty(selectors.clientSummary.street, 'innerText');
|
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() => {
|
it('should display some fiscal data', async() => {
|
||||||
|
|
|
@ -23,7 +23,7 @@ describe('Worker create path', () => {
|
||||||
await page.write(selectors.workerCreate.fi, '78457139E');
|
await page.write(selectors.workerCreate.fi, '78457139E');
|
||||||
await page.write(selectors.workerCreate.phone, '12356789');
|
await page.write(selectors.workerCreate.phone, '12356789');
|
||||||
await page.write(selectors.workerCreate.postcode, '46680');
|
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.email, 'doctorDoom@marvel.com');
|
||||||
await page.write(selectors.workerCreate.iban, 'ES9121000418450200051332');
|
await page.write(selectors.workerCreate.iban, 'ES9121000418450200051332');
|
||||||
|
|
||||||
|
|
|
@ -18,8 +18,7 @@ describe('Route tickets path', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should modify the first ticket priority', async() => {
|
it('should modify the first ticket priority', async() => {
|
||||||
await page.clearInput(selectors.routeTickets.firstTicketPriority);
|
await page.writeOnEditableTD(selectors.routeTickets.firstTicketPriority, '9');
|
||||||
await page.type(selectors.routeTickets.firstTicketPriority, '9');
|
|
||||||
await page.keyboard.press('Enter');
|
await page.keyboard.press('Enter');
|
||||||
const message = await page.waitForSnackbar();
|
const message = await page.waitForSnackbar();
|
||||||
|
|
||||||
|
|
|
@ -339,8 +339,9 @@ export default class SmartTable extends Component {
|
||||||
if (!header) return;
|
if (!header) return;
|
||||||
|
|
||||||
const tbody = this.element.querySelector('tbody');
|
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');
|
const hasSearchRow = tbody.querySelector('tr#searchRow');
|
||||||
if (hasSearchRow) {
|
if (hasSearchRow) {
|
||||||
if (this.$inputsScope)
|
if (this.$inputsScope)
|
||||||
|
|
|
@ -66,7 +66,11 @@ export default class App {
|
||||||
|
|
||||||
return this.logger.$http.get('Urls/findOne', {filter})
|
return this.logger.$http.get('Urls/findOne', {filter})
|
||||||
.then(res => {
|
.then(res => {
|
||||||
return res.data.url + route;
|
if (res && res.data)
|
||||||
|
return res.data.url + route;
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
this.showError('Direction not found');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
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
|
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
|
Session has expired: Tu sesión ha expirado, por favor vuelve a iniciar sesión
|
||||||
Access denied: Acción no permitida
|
Access denied: Acción no permitida
|
||||||
|
Direction not found: Dirección no encontrada
|
||||||
|
|
|
@ -179,5 +179,11 @@
|
||||||
"You can not use the same password": "You can not use the same password",
|
"You can not use the same password": "You can not use the same password",
|
||||||
"Valid priorities": "Valid priorities: %d",
|
"Valid priorities": "Valid priorities: %d",
|
||||||
"Negative basis of tickets": "Negative basis of tickets: {{ticketsIds}}",
|
"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."
|
||||||
}
|
}
|
||||||
|
|
|
@ -306,5 +306,14 @@
|
||||||
"Valid priorities": "Prioridades válidas: %d",
|
"Valid priorities": "Prioridades válidas: %d",
|
||||||
"Negative basis of tickets": "Base negativa para los tickets: {{ticketsIds}}",
|
"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",
|
"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"
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
};
|
||||||
|
};
|
|
@ -21,11 +21,12 @@ export default class Controller extends Section {
|
||||||
}
|
}
|
||||||
|
|
||||||
onAddClick() {
|
onAddClick() {
|
||||||
|
this.addData = {account: this.$params.id};
|
||||||
this.$.dialog.show();
|
this.$.dialog.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
onAddSave() {
|
onAddSave() {
|
||||||
return this.$http.post(`VnUsers/${this.$params.id}/addAlias`, this.addData)
|
return this.$http.post(`MailAliasAccounts`, this.addData)
|
||||||
.then(() => this.refresh())
|
.then(() => this.refresh())
|
||||||
.then(() => this.vnApp.showSuccess(
|
.then(() => this.vnApp.showSuccess(
|
||||||
this.$t('Subscribed to alias!'))
|
this.$t('Subscribed to alias!'))
|
||||||
|
@ -33,12 +34,11 @@ export default class Controller extends Section {
|
||||||
}
|
}
|
||||||
|
|
||||||
onRemove(row) {
|
onRemove(row) {
|
||||||
const params = {
|
return this.$http.delete(`MailAliasAccounts/${row.id}`)
|
||||||
mailAlias: row.mailAlias
|
.then(() => {
|
||||||
};
|
this.$.data.splice(this.$.data.indexOf(row), 1);
|
||||||
return this.$http.post(`VnUsers/${this.$params.id}/removeAlias`, params)
|
this.vnApp.showSuccess(this.$t('Unsubscribed from alias!'));
|
||||||
.then(() => this.refresh())
|
});
|
||||||
.then(() => this.vnApp.showSuccess(this.$t('Data saved!')));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,9 +25,8 @@ describe('component vnUserAliases', () => {
|
||||||
describe('onAddSave()', () => {
|
describe('onAddSave()', () => {
|
||||||
it('should add the new row', () => {
|
it('should add the new row', () => {
|
||||||
controller.addData = {account: 1};
|
controller.addData = {account: 1};
|
||||||
controller.$params = {id: 1};
|
|
||||||
|
|
||||||
$httpBackend.expectPOST('VnUsers/1/addAlias').respond();
|
$httpBackend.expectPOST('MailAliasAccounts').respond();
|
||||||
$httpBackend.expectGET('MailAliasAccounts').respond('foo');
|
$httpBackend.expectGET('MailAliasAccounts').respond('foo');
|
||||||
controller.onAddSave();
|
controller.onAddSave();
|
||||||
$httpBackend.flush();
|
$httpBackend.flush();
|
||||||
|
@ -42,14 +41,12 @@ describe('component vnUserAliases', () => {
|
||||||
{id: 1, alias: 'foo'},
|
{id: 1, alias: 'foo'},
|
||||||
{id: 2, alias: 'bar'}
|
{id: 2, alias: 'bar'}
|
||||||
];
|
];
|
||||||
controller.$params = {id: 1};
|
|
||||||
|
|
||||||
$httpBackend.expectPOST('VnUsers/1/removeAlias').respond();
|
$httpBackend.expectDELETE('MailAliasAccounts/1').respond();
|
||||||
$httpBackend.expectGET('MailAliasAccounts').respond(controller.$.data[1]);
|
|
||||||
controller.onRemove(controller.$.data[0]);
|
controller.onRemove(controller.$.data[0]);
|
||||||
$httpBackend.flush();
|
$httpBackend.flush();
|
||||||
|
|
||||||
expect(controller.$.data).toEqual({id: 2, alias: 'bar'});
|
expect(controller.$.data).toEqual([{id: 2, alias: 'bar'}]);
|
||||||
expect(controller.vnApp.showSuccess).toHaveBeenCalled();
|
expect(controller.vnApp.showSuccess).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
const UserError = require('vn-loopback/util/user-error');
|
||||||
|
|
||||||
module.exports = function(Self) {
|
module.exports = function(Self) {
|
||||||
Self.remoteMethodCtx('canBeInvoiced', {
|
Self.remoteMethodCtx('canBeInvoiced', {
|
||||||
description: 'Change property isEqualizated in all client addresses',
|
description: 'Change property isEqualizated in all client addresses',
|
||||||
|
@ -9,6 +11,12 @@ module.exports = function(Self) {
|
||||||
required: true,
|
required: true,
|
||||||
description: 'Client id',
|
description: 'Client id',
|
||||||
http: {source: 'path'}
|
http: {source: 'path'}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arg: 'companyFk',
|
||||||
|
description: 'The company id',
|
||||||
|
type: 'number',
|
||||||
|
required: true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
returns: {
|
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 models = Self.app.models;
|
||||||
|
|
||||||
const myOptions = {};
|
const myOptions = {};
|
||||||
|
|
||||||
if (typeof options == 'object')
|
if (typeof options == 'object')
|
||||||
Object.assign(myOptions, options);
|
Object.assign(myOptions, options);
|
||||||
|
|
||||||
const client = await models.Client.findById(id, {
|
const client = await models.Client.findById(id, {
|
||||||
fields: ['id', 'isTaxDataChecked', 'hasToInvoice']
|
fields: ['id', 'isTaxDataChecked', 'hasToInvoice', 'payMethodFk'],
|
||||||
|
include:
|
||||||
|
{
|
||||||
|
relation: 'payMethod',
|
||||||
|
scope: {
|
||||||
|
fields: ['code']
|
||||||
|
}
|
||||||
|
}
|
||||||
}, myOptions);
|
}, 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)
|
if (client.isTaxDataChecked && client.hasToInvoice)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ module.exports = Self => {
|
||||||
arg: 'id',
|
arg: 'id',
|
||||||
type: 'number',
|
type: 'number',
|
||||||
required: true,
|
required: true,
|
||||||
description: 'The ticket id',
|
description: 'The client id',
|
||||||
http: {source: 'path'}
|
http: {source: 'path'}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -33,6 +33,12 @@ module.exports = Self => {
|
||||||
Self.sendSms = async(ctx, id, destination, message) => {
|
Self.sendSms = async(ctx, id, destination, message) => {
|
||||||
const models = Self.app.models;
|
const models = Self.app.models;
|
||||||
const sms = await models.Sms.send(ctx, destination, message);
|
const sms = await models.Sms.send(ctx, destination, message);
|
||||||
|
|
||||||
|
await models.ClientSms.create({
|
||||||
|
clientFk: id,
|
||||||
|
smsFk: sms.id
|
||||||
|
});
|
||||||
|
|
||||||
return sms;
|
return sms;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,6 +4,7 @@ const LoopBackContext = require('loopback-context');
|
||||||
describe('client canBeInvoiced()', () => {
|
describe('client canBeInvoiced()', () => {
|
||||||
const userId = 19;
|
const userId = 19;
|
||||||
const clientId = 1101;
|
const clientId = 1101;
|
||||||
|
const companyId = 442;
|
||||||
const activeCtx = {
|
const activeCtx = {
|
||||||
accessToken: {userId: userId}
|
accessToken: {userId: userId}
|
||||||
};
|
};
|
||||||
|
@ -23,7 +24,7 @@ describe('client canBeInvoiced()', () => {
|
||||||
const client = await models.Client.findById(clientId, null, options);
|
const client = await models.Client.findById(clientId, null, options);
|
||||||
await client.updateAttribute('isTaxDataChecked', false, 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);
|
expect(canBeInvoiced).toEqual(false);
|
||||||
|
|
||||||
|
@ -43,7 +44,7 @@ describe('client canBeInvoiced()', () => {
|
||||||
const client = await models.Client.findById(clientId, null, options);
|
const client = await models.Client.findById(clientId, null, options);
|
||||||
await client.updateAttribute('hasToInvoice', false, 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);
|
expect(canBeInvoiced).toEqual(false);
|
||||||
|
|
||||||
|
@ -60,7 +61,7 @@ describe('client canBeInvoiced()', () => {
|
||||||
try {
|
try {
|
||||||
const options = {transaction: tx};
|
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);
|
expect(canBeInvoiced).toEqual(true);
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,8 @@ describe('Client Create', () => {
|
||||||
email: 'Deadpool@marvel.com',
|
email: 'Deadpool@marvel.com',
|
||||||
fi: '16195279J',
|
fi: '16195279J',
|
||||||
name: 'Wade',
|
name: 'Wade',
|
||||||
socialName: 'Deadpool Marvel',
|
socialName: 'DEADPOOL MARVEL',
|
||||||
street: 'Wall Street',
|
street: 'WALL STREET',
|
||||||
city: 'New York',
|
city: 'New York',
|
||||||
businessTypeFk: 'florist',
|
businessTypeFk: 'florist',
|
||||||
provinceFk: 1
|
provinceFk: 1
|
||||||
|
|
|
@ -70,11 +70,12 @@ module.exports = Self => {
|
||||||
c.creditInsurance,
|
c.creditInsurance,
|
||||||
d.defaulterSinced,
|
d.defaulterSinced,
|
||||||
cn.country,
|
cn.country,
|
||||||
|
c.countryFk,
|
||||||
pm.name payMethod
|
pm.name payMethod
|
||||||
FROM vn.defaulter d
|
FROM vn.defaulter d
|
||||||
JOIN vn.client c ON c.id = d.clientFk
|
JOIN vn.client c ON c.id = d.clientFk
|
||||||
JOIN vn.country cn ON cn.id = c.countryFk
|
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 vn.clientObservation co ON co.clientFk = c.id
|
||||||
LEFT JOIN account.user u ON u.id = c.salesPersonFk
|
LEFT JOIN account.user u ON u.id = c.salesPersonFk
|
||||||
LEFT JOIN account.user uw ON uw.id = co.workerFk
|
LEFT JOIN account.user uw ON uw.id = co.workerFk
|
||||||
|
|
|
@ -95,6 +95,9 @@
|
||||||
"ClientSample": {
|
"ClientSample": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
|
"ClientSms": {
|
||||||
|
"dataSource": "vn"
|
||||||
|
},
|
||||||
"Sms": {
|
"Sms": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
|
|
|
@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -36,12 +36,37 @@ module.exports = Self => {
|
||||||
min: 3, max: 10
|
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, {
|
Self.validateAsync('socialName', socialNameIsUnique, {
|
||||||
message: 'The company name must be unique'
|
message: 'The company name must be unique'
|
||||||
});
|
});
|
||||||
|
|
||||||
async function socialNameIsUnique(err, done) {
|
async function socialNameIsUnique(err, done) {
|
||||||
|
if (!this.countryFk)
|
||||||
|
return done();
|
||||||
|
|
||||||
const filter = {
|
const filter = {
|
||||||
|
include: {
|
||||||
|
relation: 'country',
|
||||||
|
scope: {
|
||||||
|
fields: {
|
||||||
|
isSocialNameUnique: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
where: {
|
where: {
|
||||||
and: [
|
and: [
|
||||||
{socialName: this.socialName},
|
{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();
|
err();
|
||||||
|
|
||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -181,6 +181,11 @@
|
||||||
"model": "Country",
|
"model": "Country",
|
||||||
"foreignKey": "countryFk"
|
"foreignKey": "countryFk"
|
||||||
},
|
},
|
||||||
|
"isSocialNameUnique": {
|
||||||
|
"type": "belongsTo",
|
||||||
|
"model": "Country",
|
||||||
|
"foreignKey": "countryFk"
|
||||||
|
},
|
||||||
"contactChannel": {
|
"contactChannel": {
|
||||||
"type": "belongsTo",
|
"type": "belongsTo",
|
||||||
"model": "ContactChannel",
|
"model": "ContactChannel",
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
"country": {
|
"country": {
|
||||||
"type": "belongsTo",
|
"type": "belongsTo",
|
||||||
"model": "Country",
|
"model": "Country",
|
||||||
"foreignKey": "country"
|
"foreignKey": "countryFk"
|
||||||
},
|
},
|
||||||
"payMethod": {
|
"payMethod": {
|
||||||
"type": "belongsTo",
|
"type": "belongsTo",
|
||||||
|
@ -41,4 +41,4 @@
|
||||||
"foreignKey": "payMethod"
|
"foreignKey": "payMethod"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,7 @@
|
||||||
<th field="salesPersonFk">
|
<th field="salesPersonFk">
|
||||||
<span translate>Comercial</span>
|
<span translate>Comercial</span>
|
||||||
</th>
|
</th>
|
||||||
<th field="country">
|
<th field="countryFk">
|
||||||
<span translate>Country</span>
|
<span translate>Country</span>
|
||||||
</th>
|
</th>
|
||||||
<th field="payMethod"
|
<th field="payMethod"
|
||||||
|
@ -132,7 +132,7 @@
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{{::defaulter.payMethod}}
|
{{::defaulter.payMethod}}
|
||||||
</td>
|
</td>
|
||||||
<td>{{::defaulter.amount | currency: 'EUR': 2}}</td>
|
<td>{{::defaulter.amount | currency: 'EUR': 2}}</td>
|
||||||
<td>
|
<td>
|
||||||
<span
|
<span
|
||||||
|
|
|
@ -31,10 +31,11 @@ export default class Controller extends Section {
|
||||||
valueField: 'id',
|
valueField: 'id',
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
field: 'country',
|
field: 'countryFk',
|
||||||
autocomplete: {
|
autocomplete: {
|
||||||
|
url: 'Countries',
|
||||||
showField: 'country',
|
showField: 'country',
|
||||||
valueField: 'country'
|
valueField: 'id'
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
field: 'payMethodFk',
|
field: 'payMethodFk',
|
||||||
|
@ -167,7 +168,7 @@ export default class Controller extends Section {
|
||||||
case 'amount':
|
case 'amount':
|
||||||
case 'clientFk':
|
case 'clientFk':
|
||||||
case 'workerFk':
|
case 'workerFk':
|
||||||
case 'country':
|
case 'countryFk':
|
||||||
case 'payMethod':
|
case 'payMethod':
|
||||||
case 'salesPersonFk':
|
case 'salesPersonFk':
|
||||||
return {[`d.${param}`]: value};
|
return {[`d.${param}`]: value};
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
ng-model="$ctrl.client.socialName"
|
ng-model="$ctrl.client.socialName"
|
||||||
info="Only letters, numbers and spaces can be used"
|
info="Only letters, numbers and spaces can be used"
|
||||||
required="true"
|
required="true"
|
||||||
|
ng-keyup="$ctrl.client.socialName = $ctrl.client.socialName.toUpperCase()"
|
||||||
rule>
|
rule>
|
||||||
</vn-textfield>
|
</vn-textfield>
|
||||||
<vn-textfield
|
<vn-textfield
|
||||||
|
@ -46,6 +47,7 @@
|
||||||
vn-two
|
vn-two
|
||||||
label="Street"
|
label="Street"
|
||||||
ng-model="$ctrl.client.street"
|
ng-model="$ctrl.client.street"
|
||||||
|
ng-keyup="$ctrl.client.street = $ctrl.client.street.toUpperCase()"
|
||||||
rule>
|
rule>
|
||||||
</vn-textfield>
|
</vn-textfield>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
|
|
|
@ -48,4 +48,5 @@ import './notification';
|
||||||
import './unpaid';
|
import './unpaid';
|
||||||
import './extended-list';
|
import './extended-list';
|
||||||
import './credit-management';
|
import './credit-management';
|
||||||
|
import './sms';
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
{"state": "client.card.recovery.index", "icon": "icon-recovery"},
|
{"state": "client.card.recovery.index", "icon": "icon-recovery"},
|
||||||
{"state": "client.card.webAccess", "icon": "cloud"},
|
{"state": "client.card.webAccess", "icon": "cloud"},
|
||||||
{"state": "client.card.log", "icon": "history"},
|
{"state": "client.card.log", "icon": "history"},
|
||||||
|
{"state": "client.card.sms", "icon": "sms"},
|
||||||
{
|
{
|
||||||
"description": "Credit management",
|
"description": "Credit management",
|
||||||
"icon": "monetization_on",
|
"icon": "monetization_on",
|
||||||
|
@ -373,6 +374,12 @@
|
||||||
"component": "vn-client-log",
|
"component": "vn-client-log",
|
||||||
"description": "Log"
|
"description": "Log"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"url" : "/sms",
|
||||||
|
"state": "client.card.sms",
|
||||||
|
"component": "vn-client-sms",
|
||||||
|
"description": "Sms"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"url": "/dms",
|
"url": "/dms",
|
||||||
"state": "client.card.dms",
|
"state": "client.card.dms",
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
<vn-crud-model
|
||||||
|
vn-id="model"
|
||||||
|
url="ClientSms"
|
||||||
|
link="{clientFk: $ctrl.$params.id}"
|
||||||
|
filter="::$ctrl.filter"
|
||||||
|
data="clientSmsList"
|
||||||
|
limit="20"
|
||||||
|
auto-load="true">
|
||||||
|
</vn-crud-model>
|
||||||
|
<vn-data-viewer model="model">
|
||||||
|
<vn-card class="vn-w-md">
|
||||||
|
<vn-table model="model" auto-load="false">
|
||||||
|
<vn-thead>
|
||||||
|
<vn-tr>
|
||||||
|
<vn-th field="senderFk">Sender</vn-th>
|
||||||
|
<vn-th field="destination" number>Destination</vn-th>
|
||||||
|
<vn-th field="message">Message</vn-th>
|
||||||
|
<vn-th field="status">Status</vn-th>
|
||||||
|
<vn-th field="created" expand>Created</vn-th>
|
||||||
|
</vn-tr>
|
||||||
|
</vn-thead>
|
||||||
|
<vn-tbody>
|
||||||
|
<vn-tr ng-repeat="clientSms in clientSmsList">
|
||||||
|
<vn-td>
|
||||||
|
<span class="link" ng-click="workerDescriptor.show($event, clientSms.sms.senderFk)">
|
||||||
|
{{::clientSms.sms.sender.name}}
|
||||||
|
</span>
|
||||||
|
</vn-td>
|
||||||
|
<vn-td number expand>{{::clientSms.sms.destination}}</vn-td>
|
||||||
|
<vn-td>{{::clientSms.sms.message}}</vn-td>
|
||||||
|
<vn-td>{{::clientSms.sms.status}}</vn-td>
|
||||||
|
<vn-td shrink-datetime>{{::clientSms.sms.created | date:'dd/MM/yyyy HH:mm'}}</vn-td>
|
||||||
|
</vn-tr>
|
||||||
|
</vn-tbody>
|
||||||
|
</vn-table>
|
||||||
|
</vn-card>
|
||||||
|
</vn-data-viewer>
|
||||||
|
<vn-worker-descriptor-popover
|
||||||
|
vn-id="worker-descriptor">
|
||||||
|
</vn-worker-descriptor-popover>
|
|
@ -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: '<'
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,2 @@
|
||||||
|
Sender: Remitente
|
||||||
|
Number sender: Número remitente
|
|
@ -39,7 +39,7 @@
|
||||||
label="Recovery email"
|
label="Recovery email"
|
||||||
ng-model="$ctrl.account.email"
|
ng-model="$ctrl.account.email"
|
||||||
info="This email is used for user to regain access their account."
|
info="This email is used for user to regain access their account."
|
||||||
rule="VnUser.name">
|
rule="VnUser.email">
|
||||||
</vn-textfield>
|
</vn-textfield>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
</vn-card>
|
</vn-card>
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -1,3 +1,5 @@
|
||||||
|
const UserError = require('vn-loopback/util/user-error');
|
||||||
|
|
||||||
module.exports = Self => {
|
module.exports = Self => {
|
||||||
require('../methods/invoice-in/filter')(Self);
|
require('../methods/invoice-in/filter')(Self);
|
||||||
require('../methods/invoice-in/summary')(Self);
|
require('../methods/invoice-in/summary')(Self);
|
||||||
|
@ -7,4 +9,9 @@ module.exports = Self => {
|
||||||
require('../methods/invoice-in/invoiceInPdf')(Self);
|
require('../methods/invoice-in/invoiceInPdf')(Self);
|
||||||
require('../methods/invoice-in/invoiceInEmail')(Self);
|
require('../methods/invoice-in/invoiceInEmail')(Self);
|
||||||
require('../methods/invoice-in/getSerial')(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;
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -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;
|
||||||
|
};
|
||||||
|
};
|
|
@ -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);
|
||||||
|
});
|
||||||
|
});
|
|
@ -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);
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,3 +1,4 @@
|
||||||
module.exports = Self => {
|
module.exports = Self => {
|
||||||
require('../methods/item-shelving/deleteItemShelvings')(Self);
|
require('../methods/item-shelving/deleteItemShelvings')(Self);
|
||||||
|
require('../methods/item-shelving/getInventory')(Self);
|
||||||
};
|
};
|
||||||
|
|
|
@ -23,6 +23,12 @@
|
||||||
},
|
},
|
||||||
"isChecked": {
|
"isChecked": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"visible": {
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
"userFk": {
|
||||||
|
"type": "number"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"relations": {
|
"relations": {
|
||||||
|
|
|
@ -14,7 +14,6 @@ module.exports = Self => {
|
||||||
require('../methods/item/getWasteByWorker')(Self);
|
require('../methods/item/getWasteByWorker')(Self);
|
||||||
require('../methods/item/getWasteByItem')(Self);
|
require('../methods/item/getWasteByItem')(Self);
|
||||||
require('../methods/item/createIntrastat')(Self);
|
require('../methods/item/createIntrastat')(Self);
|
||||||
require('../methods/item/activeBuyers')(Self);
|
|
||||||
require('../methods/item/buyerWasteEmail')(Self);
|
require('../methods/item/buyerWasteEmail')(Self);
|
||||||
require('../methods/item/labelPdf')(Self);
|
require('../methods/item/labelPdf')(Self);
|
||||||
|
|
||||||
|
|
|
@ -1,40 +1,40 @@
|
||||||
<vn-horizontal>
|
<vn-horizontal>
|
||||||
<vn-auto>
|
<vn-auto>
|
||||||
<section
|
<section
|
||||||
class="inline-tag ellipsize"
|
class="inline-tag ellipsize"
|
||||||
ng-class="::{empty: !$ctrl.item.value5}"
|
ng-class="::{empty: !$ctrl.item.tag5}"
|
||||||
title="{{::$ctrl.item.tag5}}: {{::$ctrl.item.value5}}">
|
title="{{::$ctrl.item.tag5}}: {{::$ctrl.item.value5}}">
|
||||||
{{::$ctrl.item.value5}}
|
{{::$ctrl.item.value5}}
|
||||||
</section>
|
</section>
|
||||||
<section
|
<section
|
||||||
class="inline-tag ellipsize"
|
class="inline-tag ellipsize"
|
||||||
ng-class="::{empty: !$ctrl.item.value6}"
|
ng-class="::{empty: !$ctrl.item.tag6}"
|
||||||
title="{{::$ctrl.item.tag6}}: {{::$ctrl.item.value6}}">
|
title="{{::$ctrl.item.tag6}}: {{::$ctrl.item.value6}}">
|
||||||
{{::$ctrl.item.value6}}
|
{{::$ctrl.item.value6}}
|
||||||
</section>
|
</section>
|
||||||
<section
|
<section
|
||||||
class="inline-tag ellipsize"
|
class="inline-tag ellipsize"
|
||||||
ng-class="::{empty: !$ctrl.item.value7}"
|
ng-class="::{empty: !$ctrl.item.tag7}"
|
||||||
title="{{::$ctrl.item.tag7}}: {{::$ctrl.item.value7}}">
|
title="{{::$ctrl.item.tag7}}: {{::$ctrl.item.value7}}">
|
||||||
{{::$ctrl.item.value7}}
|
{{::$ctrl.item.value7}}
|
||||||
</section>
|
</section>
|
||||||
<section
|
<section
|
||||||
class="inline-tag ellipsize"
|
class="inline-tag ellipsize"
|
||||||
ng-class="::{empty: !$ctrl.item.value8}"
|
ng-class="::{empty: !$ctrl.item.tag8}"
|
||||||
title="{{::$ctrl.item.tag8}}: {{::$ctrl.item.value8}}">
|
title="{{::$ctrl.item.tag8}}: {{::$ctrl.item.value8}}">
|
||||||
{{::$ctrl.item.value8}}
|
{{::$ctrl.item.value8}}
|
||||||
</section>
|
</section>
|
||||||
<section
|
<section
|
||||||
class="inline-tag ellipsize"
|
class="inline-tag ellipsize"
|
||||||
ng-class="::{empty: !$ctrl.item.value9}"
|
ng-class="::{empty: !$ctrl.item.tag9}"
|
||||||
title="{{::$ctrl.item.tag9}}: {{::$ctrl.item.value9}}">
|
title="{{::$ctrl.item.tag9}}: {{::$ctrl.item.value9}}">
|
||||||
{{::$ctrl.item.value9}}
|
{{::$ctrl.item.value9}}
|
||||||
</section>
|
</section>
|
||||||
<section
|
<section
|
||||||
class="inline-tag ellipsize"
|
class="inline-tag ellipsize"
|
||||||
ng-class="::{empty: !$ctrl.item.value10}"
|
ng-class="::{empty: !$ctrl.item.tag10}"
|
||||||
title="{{::$ctrl.item.tag10}}: {{::$ctrl.item.value10}}">
|
title="{{::$ctrl.item.tag10}}: {{::$ctrl.item.value10}}">
|
||||||
{{::$ctrl.item.value10}}
|
{{::$ctrl.item.value10}}
|
||||||
</section>
|
</section>
|
||||||
</vn-auto>
|
</vn-auto>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
vn-fetched-tags {
|
vn-fetched-tags {
|
||||||
& > vn-horizontal {
|
& > vn-horizontal {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
max-width: 210px;
|
||||||
& > vn-auto {
|
& > vn-auto {
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
@ -43,19 +43,19 @@ vn-fetched-tags {
|
||||||
& > .inline-tag {
|
& > .inline-tag {
|
||||||
color: $color-font-secondary;
|
color: $color-font-secondary;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: .75rem;
|
font-size: .8rem;
|
||||||
height: 12px;
|
height: 13px;
|
||||||
padding: 1px;
|
padding: 1px;
|
||||||
width: 64px;
|
width: 64px;
|
||||||
min-width: 64px;
|
min-width: 64px;
|
||||||
max-width: 64px;
|
max-width: 64px;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
border: 1px solid $color-spacer;
|
border: 1px solid $color-font-secondary;
|
||||||
|
|
||||||
&.empty {
|
&.empty {
|
||||||
border: 1px solid $color-spacer-light;
|
border: 1px solid darken($color-font-secondary, 30%);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,7 +85,7 @@
|
||||||
show-field="id"
|
show-field="id"
|
||||||
value-field="id"
|
value-field="id"
|
||||||
search-function="$ctrl.itemSearchFunc($search)"
|
search-function="$ctrl.itemSearchFunc($search)"
|
||||||
on-change="$ctrl.upsertPrice(price, true)"
|
ng-change="$ctrl.upsertPrice(price, true)"
|
||||||
order="id DESC"
|
order="id DESC"
|
||||||
tabindex="1">
|
tabindex="1">
|
||||||
<tpl-item>
|
<tpl-item>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<div class="search-panel">
|
<div class="search-panel">
|
||||||
<vn-crud-model
|
<vn-crud-model
|
||||||
auto-load="true"
|
auto-load="true"
|
||||||
url="Warehouses"
|
url="Warehouses"
|
||||||
data="warehouses">
|
data="warehouses">
|
||||||
</vn-crud-model>
|
</vn-crud-model>
|
||||||
<form id="manifold-form" ng-submit="$ctrl.onSearch()">
|
<form id="manifold-form" ng-submit="$ctrl.onSearch()">
|
||||||
|
@ -26,7 +26,7 @@
|
||||||
search-function="{firstName: $search}"
|
search-function="{firstName: $search}"
|
||||||
value-field="id"
|
value-field="id"
|
||||||
where="{role: {inq: ['logistic', 'buyer']}}"
|
where="{role: {inq: ['logistic', 'buyer']}}"
|
||||||
label="Atender">
|
label="Buyer">
|
||||||
<tpl-item>{{nickname}}</tpl-item>
|
<tpl-item>{{nickname}}</tpl-item>
|
||||||
</vn-autocomplete>
|
</vn-autocomplete>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
|
@ -57,7 +57,7 @@
|
||||||
<tpl-item>{{firstName}} {{lastName}}</tpl-item>
|
<tpl-item>{{firstName}} {{lastName}}</tpl-item>
|
||||||
</vn-autocomplete>
|
</vn-autocomplete>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
|
|
||||||
<section class="vn-px-md">
|
<section class="vn-px-md">
|
||||||
<vn-horizontal class="manifold-panel vn-pa-md">
|
<vn-horizontal class="manifold-panel vn-pa-md">
|
||||||
<vn-date-picker
|
<vn-date-picker
|
||||||
|
@ -89,9 +89,9 @@
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
</section>
|
</section>
|
||||||
<vn-horizontal class="vn-px-lg">
|
<vn-horizontal class="vn-px-lg">
|
||||||
<vn-check vn-one
|
<vn-check vn-one
|
||||||
triple-state="true"
|
triple-state="true"
|
||||||
label="For me"
|
label="For me"
|
||||||
ng-model="filter.mine">
|
ng-model="filter.mine">
|
||||||
</vn-check>
|
</vn-check>
|
||||||
<vn-autocomplete
|
<vn-autocomplete
|
||||||
|
|
|
@ -38,13 +38,13 @@
|
||||||
</vn-autocomplete>
|
</vn-autocomplete>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
<vn-horizontal>
|
<vn-horizontal>
|
||||||
<vn-autocomplete
|
<vn-autocomplete
|
||||||
vn-one
|
vn-one
|
||||||
ng-model="filter.buyerFk"
|
ng-model="filter.buyerFk"
|
||||||
url="Items/activeBuyers"
|
url="TicketRequests/getItemTypeWorker"
|
||||||
|
search-function="{firstName: $search}"
|
||||||
show-field="nickname"
|
show-field="nickname"
|
||||||
search-function="{nickname: {like: '%'+ $search +'%'}}"
|
value-field="id"
|
||||||
value-field="workerFk"
|
|
||||||
label="Buyer">
|
label="Buyer">
|
||||||
</vn-autocomplete>
|
</vn-autocomplete>
|
||||||
<vn-autocomplete
|
<vn-autocomplete
|
||||||
|
@ -88,7 +88,7 @@
|
||||||
label="Value"
|
label="Value"
|
||||||
ng-model="itemTag.value">
|
ng-model="itemTag.value">
|
||||||
</vn-textfield>
|
</vn-textfield>
|
||||||
<vn-autocomplete
|
<vn-autocomplete
|
||||||
vn-one
|
vn-one
|
||||||
ng-show="tag.selection.isFree === false"
|
ng-show="tag.selection.isFree === false"
|
||||||
url="{{'Tags/' + itemTag.tagFk + '/filterValue'}}"
|
url="{{'Tags/' + itemTag.tagFk + '/filterValue'}}"
|
||||||
|
@ -167,7 +167,7 @@
|
||||||
</vn-icon-button>
|
</vn-icon-button>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
<vn-horizontal>
|
<vn-horizontal>
|
||||||
<vn-check
|
<vn-check
|
||||||
vn-one
|
vn-one
|
||||||
label="Floramondo"
|
label="Floramondo"
|
||||||
ng-model="filter.isFloramondo"
|
ng-model="filter.isFloramondo"
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
module.exports = Self => {
|
||||||
|
Self.remoteMethodCtx('cmr', {
|
||||||
|
description: 'Returns the cmr',
|
||||||
|
accessType: 'READ',
|
||||||
|
accepts: [
|
||||||
|
{
|
||||||
|
arg: 'id',
|
||||||
|
type: 'number',
|
||||||
|
required: true,
|
||||||
|
description: 'The cmr 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/cmr',
|
||||||
|
verb: 'GET'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Self.cmr = (ctx, id) => Self.printReport(ctx, id, 'cmr');
|
||||||
|
};
|
|
@ -0,0 +1,27 @@
|
||||||
|
module.exports = Self => {
|
||||||
|
Self.remoteMethod('sorted', {
|
||||||
|
description: 'Sort the vehicles by warehouse',
|
||||||
|
accessType: 'WRITE',
|
||||||
|
accepts: [{
|
||||||
|
arg: 'warehouseFk',
|
||||||
|
type: 'number'
|
||||||
|
}],
|
||||||
|
returns: {
|
||||||
|
type: ['object'],
|
||||||
|
root: true
|
||||||
|
},
|
||||||
|
http: {
|
||||||
|
path: `/sorted`,
|
||||||
|
verb: `POST`
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Self.sorted = async warehouseFk => {
|
||||||
|
return Self.rawSql(`
|
||||||
|
SELECT v.id, v.warehouseFk, v.numberPlate, w.name
|
||||||
|
FROM vehicle v
|
||||||
|
JOIN warehouse w ON w.id = v.warehouseFk
|
||||||
|
ORDER BY v.warehouseFk = ? DESC, w.id, v.numberPlate ASC;
|
||||||
|
`, [warehouseFk]);
|
||||||
|
};
|
||||||
|
};
|
|
@ -14,6 +14,7 @@ module.exports = Self => {
|
||||||
require('../methods/route/driverRouteEmail')(Self);
|
require('../methods/route/driverRouteEmail')(Self);
|
||||||
require('../methods/route/sendSms')(Self);
|
require('../methods/route/sendSms')(Self);
|
||||||
require('../methods/route/downloadZip')(Self);
|
require('../methods/route/downloadZip')(Self);
|
||||||
|
require('../methods/route/cmr')(Self);
|
||||||
|
|
||||||
Self.validate('kmStart', validateDistance, {
|
Self.validate('kmStart', validateDistance, {
|
||||||
message: 'Distance must be lesser than 1000'
|
message: 'Distance must be lesser than 1000'
|
||||||
|
@ -28,5 +29,5 @@ module.exports = Self => {
|
||||||
const routeMaxKm = 1000;
|
const routeMaxKm = 1000;
|
||||||
if (routeTotalKm > routeMaxKm || this.kmStart > this.kmEnd)
|
if (routeTotalKm > routeMaxKm || this.kmStart > this.kmEnd)
|
||||||
err();
|
err();
|
||||||
}
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
module.exports = Self => {
|
||||||
|
require('../methods/vehicle/sorted')(Self);
|
||||||
|
};
|
|
@ -23,19 +23,21 @@
|
||||||
</tpl-item>
|
</tpl-item>
|
||||||
</vn-autocomplete>
|
</vn-autocomplete>
|
||||||
<vn-autocomplete
|
<vn-autocomplete
|
||||||
|
label="Vehicle"
|
||||||
ng-model="$ctrl.route.vehicleFk"
|
ng-model="$ctrl.route.vehicleFk"
|
||||||
url="Vehicles"
|
data="$ctrl.vehicles"
|
||||||
show-field="numberPlate"
|
show-field="numberPlate"
|
||||||
value-field="id"
|
value-field="id"
|
||||||
label="Vehicle"
|
order="false"
|
||||||
vn-name="vehicle">
|
vn-name="vehicle">
|
||||||
|
<tpl-item>{{::numberPlate}} - {{::name}}</tpl-item>
|
||||||
</vn-autocomplete>
|
</vn-autocomplete>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
<vn-horizontal>
|
<vn-horizontal>
|
||||||
<vn-date-picker
|
<vn-date-picker
|
||||||
label="Created"
|
label="Created"
|
||||||
ng-model="$ctrl.route.created"
|
ng-model="$ctrl.route.created"
|
||||||
vn-name="created">
|
vn-name="created">
|
||||||
</vn-date-picker>
|
</vn-date-picker>
|
||||||
<vn-autocomplete
|
<vn-autocomplete
|
||||||
ng-model="$ctrl.route.agencyModeFk"
|
ng-model="$ctrl.route.agencyModeFk"
|
||||||
|
|
|
@ -2,6 +2,13 @@ import ngModule from '../module';
|
||||||
import Section from 'salix/components/section';
|
import Section from 'salix/components/section';
|
||||||
|
|
||||||
class Controller extends Section {
|
class Controller extends Section {
|
||||||
|
$onInit() {
|
||||||
|
this.$http.post(`Vehicles/sorted`, {warehouseFk: this.vnConfig.warehouseFk})
|
||||||
|
.then(res => {
|
||||||
|
this.vehicles = res.data;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
onSubmit() {
|
onSubmit() {
|
||||||
this.$.watcher.submit().then(() =>
|
this.$.watcher.submit().then(() =>
|
||||||
this.card.reload()
|
this.card.reload()
|
||||||
|
|
|
@ -84,14 +84,21 @@
|
||||||
tabindex="-1">
|
tabindex="-1">
|
||||||
</vn-icon-button>
|
</vn-icon-button>
|
||||||
</vn-td>
|
</vn-td>
|
||||||
<vn-td>
|
<vn-td-editable number>
|
||||||
<vn-input-number
|
<text>
|
||||||
on-change="$ctrl.setPriority(ticket.id, ticket.priority)"
|
<strong>{{ticket.priority}}</strong>
|
||||||
ng-model="ticket.priority"
|
</text>
|
||||||
rule="Ticket"
|
<field>
|
||||||
class="dense">
|
<vn-input-number
|
||||||
</vn-input-number>
|
rule="Ticket"
|
||||||
</vn-td>
|
ng-model="ticket.priority"
|
||||||
|
on-change="$ctrl.setPriority(ticket.id, ticket.priority)"
|
||||||
|
step="1"
|
||||||
|
class="dense"
|
||||||
|
vn-focus>
|
||||||
|
</vn-input-number>
|
||||||
|
</field>
|
||||||
|
</vn-td-editable>
|
||||||
<vn-td expand title="{{::ticket.street}}">{{::ticket.street}}</vn-td>
|
<vn-td expand title="{{::ticket.street}}">{{::ticket.street}}</vn-td>
|
||||||
<vn-td
|
<vn-td
|
||||||
expand
|
expand
|
||||||
|
|
|
@ -68,9 +68,9 @@ module.exports = Self => {
|
||||||
};
|
};
|
||||||
const country = await Self.app.models.Country.findOne(filter);
|
const country = await Self.app.models.Country.findOne(filter);
|
||||||
const code = country ? country.code.toLowerCase() : null;
|
const code = country ? country.code.toLowerCase() : null;
|
||||||
const countryCode = this.nif.toLowerCase().substring(0, 2);
|
const countryCode = this.nif?.toLowerCase().substring(0, 2);
|
||||||
|
|
||||||
if (!this.nif || !validateTin(this.nif, code) || (this.isVies && countryCode == code))
|
if (!validateTin(this.nif, code) || (this.isVies && countryCode == code))
|
||||||
err();
|
err();
|
||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
|
@ -122,7 +122,7 @@ module.exports = Self => {
|
||||||
});
|
});
|
||||||
|
|
||||||
async function hasSupplierSameName(err, done) {
|
async function hasSupplierSameName(err, done) {
|
||||||
if (!this.name || !this.countryFk) done();
|
if (!this.name || !this.countryFk) return done();
|
||||||
const supplier = await Self.app.models.Supplier.findOne(
|
const supplier = await Self.app.models.Supplier.findOne(
|
||||||
{
|
{
|
||||||
where: {
|
where: {
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue