Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix into 3605-invoiceIn_intrastat3
gitea/salix/pipeline/head This commit looks good Details

This commit is contained in:
Vicent Llopis 2022-03-30 07:30:39 +02:00
commit d06b2e8bb7
263 changed files with 25883 additions and 20858 deletions

View File

@ -0,0 +1,55 @@
const axios = require('axios');
const tokenLifespan = 10;
module.exports = Self => {
Self.remoteMethodCtx('getServiceAuth', {
description: 'Authenticates with the service and request a new token',
accessType: 'READ',
accepts: [],
returns: {
type: 'object',
root: true
},
http: {
path: `/getServiceAuth`,
verb: 'GET'
}
});
Self.getServiceAuth = async() => {
if (!this.login)
this.login = await requestToken();
if (!this.login) return;
if (Date.now() > this.login.expires)
this.login = await requestToken();
return this.login;
};
/**
* Requests a new Rocketchat token
*/
async function requestToken() {
const models = Self.app.models;
const chatConfig = await models.ChatConfig.findOne();
const {data} = await axios.post(`${chatConfig.api}/login`, {
user: chatConfig.user,
password: chatConfig.password
});
const requestData = data.data;
if (requestData) {
return {
host: chatConfig.host,
api: chatConfig.api,
auth: {
userId: requestData.userId,
token: requestData.authToken
},
expires: Date.now() + (1000 * 60 * tokenLifespan)
};
}
}
};

View File

@ -1,4 +1,4 @@
const got = require('got');
const axios = require('axios');
module.exports = Self => {
Self.remoteMethodCtx('send', {
description: 'Send a RocketChat message',
@ -30,122 +30,35 @@ module.exports = Self => {
const sender = await models.Account.findById(accessToken.userId);
const recipient = to.replace('@', '');
if (sender.name != recipient) {
let {body} = await sendMessage(sender, to, message);
if (body)
body = JSON.parse(body);
else
body = false;
return body;
}
return false;
if (sender.name != recipient)
return sendMessage(sender, to, message);
};
async function sendMessage(sender, channel, message) {
const config = await getConfig();
const avatar = `${config.host}/avatar/${sender.name}`;
const uri = `${config.api}/chat.postMessage`;
return sendAuth(uri, {
'channel': channel,
'avatar': avatar,
'alias': sender.nickname,
'text': message
}).catch(async error => {
if (error.statusCode === 401) {
this.auth = null;
return sendMessage(sender, channel, message);
}
throw new Error(error.message);
});
}
/**
* Returns a rocketchat token
* @return {Object} userId and authToken
*/
async function getAuthToken() {
if (!this.auth || this.auth && !this.auth.authToken) {
const config = await getConfig();
const uri = `${config.api}/login`;
let {body} = await send(uri, {
user: config.user,
password: config.password
});
if (body) {
body = JSON.parse(body);
this.auth = body.data;
}
}
return this.auth;
}
/**
* Returns a rocketchat config
* @return {Object} Auth config
*/
async function getConfig() {
if (!this.chatConfig) {
const models = Self.app.models;
this.chatConfig = await models.ChatConfig.findOne();
}
return this.chatConfig;
}
/**
* Send unauthenticated request
* @param {*} uri - Request uri
* @param {*} params - Request params
* @param {*} options - Request options
*
* @return {Object} Request response
*/
async function send(uri, params, options = {}) {
if (process.env.NODE_ENV !== 'production') {
return new Promise(resolve => {
return resolve({
body: JSON.stringify(
{statusCode: 200, message: 'Fake notification sent'}
)
statusCode: 200,
message: 'Fake notification sent'
});
});
}
const defaultOptions = {
form: params
};
const login = await Self.getServiceAuth();
const avatar = `${login.host}/avatar/${sender.name}`;
if (options) Object.assign(defaultOptions, options);
return got.post(uri, defaultOptions);
}
/**
* Send authenticated request
* @param {*} uri - Request uri
* @param {*} body - Request params
*
* @return {Object} Request response
*/
async function sendAuth(uri, body) {
const login = await getAuthToken();
const options = {
headers: {}
headers: {
'X-Auth-Token': login.auth.token,
'X-User-Id': login.auth.userId
},
};
if (login) {
options.headers['X-Auth-Token'] = login.authToken;
options.headers['X-User-Id'] = login.userId;
}
return send(uri, body, options);
return axios.post(`${login.api}/chat.postMessage`, {
'channel': channel,
'avatar': avatar,
'alias': sender.nickname,
'text': message
}, options);
}
};

View File

@ -1,21 +1,23 @@
const axios = require('axios');
module.exports = Self => {
Self.remoteMethodCtx('sendCheckingPresence', {
description: 'Sends a RocketChat message to a working worker or department channel',
description: 'Sends a RocketChat message to a connected user or department channel',
accessType: 'WRITE',
accepts: [{
arg: 'workerId',
type: 'Number',
arg: 'recipientId',
type: 'number',
required: true,
description: 'The worker id of the destinatary'
description: 'The recipient user id'
},
{
arg: 'message',
type: 'String',
type: 'string',
required: true,
description: 'The message'
}],
returns: {
type: 'Object',
type: 'object',
root: true
},
http: {
@ -33,30 +35,61 @@ module.exports = Self => {
Object.assign(myOptions, options);
const models = Self.app.models;
const account = await models.Account.findById(recipientId, null, myOptions);
const userId = ctx.req.accessToken.userId;
const recipient = await models.Account.findById(recipientId, null, myOptions);
// Prevent sending messages to yourself
if (recipientId == userId) return false;
if (!account)
if (!recipient)
throw new Error(`Could not send message "${message}" to worker id ${recipientId} from user ${userId}`);
const query = `SELECT worker_isWorking(?) isWorking`;
const [result] = await Self.rawSql(query, [recipientId], myOptions);
const {data} = await Self.getUserStatus(recipient.name);
if (data) {
if (data.status === 'offline') {
// Send message to department room
const workerDepartment = await models.WorkerDepartment.findById(recipientId, {
include: {
relation: 'department'
}
}, myOptions);
const department = workerDepartment && workerDepartment.department();
const channelName = department && department.chatName;
if (!result.isWorking) {
const workerDepartment = await models.WorkerDepartment.findById(recipientId, {
include: {
relation: 'department'
}
}, myOptions);
const department = workerDepartment && workerDepartment.department();
const channelName = department && department.chatName;
if (channelName)
return Self.send(ctx, `#${channelName}`, `@${recipient.name}${message}`);
} else
return Self.send(ctx, `@${recipient.name}`, message);
}
};
if (channelName)
return Self.send(ctx, `#${channelName}`, `@${account.name}${message}`);
/**
* Returns the current user status on Rocketchat
*
* @param {string} username - The recipient user name
* @return {Promise} - The request promise
*/
Self.getUserStatus = async function getUserStatus(username) {
if (process.env.NODE_ENV !== 'production') {
return new Promise(resolve => {
return resolve({
data: {
status: 'online'
}
});
});
}
return Self.send(ctx, `@${account.name}`, message);
const login = await Self.getServiceAuth();
const options = {
params: {username},
headers: {
'X-Auth-Token': login.auth.token,
'X-User-Id': login.auth.userId
},
};
return axios.get(`${login.api}/users.getStatus`, options);
};
};

View File

@ -1,46 +1,62 @@
const app = require('vn-loopback/server/server');
const models = require('vn-loopback/server/server').models;
describe('Chat sendCheckingPresence()', () => {
const today = new Date();
today.setHours(6, 0);
const ctx = {req: {accessToken: {userId: 1}}};
const chatModel = app.models.Chat;
const chatModel = models.Chat;
const departmentId = 23;
const workerId = 1107;
it(`should call send() method with the worker name if he's currently working then return a response`, async() => {
it(`should call to send() method with "@HankPym" as recipient argument`, async() => {
spyOn(chatModel, 'send').and.callThrough();
const timeEntry = await app.models.WorkerTimeControl.create({
userFk: workerId,
timed: today,
manual: false,
direction: 'in'
});
spyOn(chatModel, 'getUserStatus').and.returnValue(
new Promise(resolve => {
return resolve({
data: {
status: 'online'
}
});
})
);
const response = await chatModel.sendCheckingPresence(ctx, workerId, 'I changed something');
expect(response.statusCode).toEqual(200);
expect(response.message).toEqual('Fake notification sent');
expect(chatModel.send).toHaveBeenCalledWith(ctx, '@HankPym', 'I changed something');
// restores
await app.models.WorkerTimeControl.destroyById(timeEntry.id);
});
it(`should call to send() method with the worker department channel if he's not currently working then return a response`, async() => {
it(`should call to send() method with "#cooler" as recipient argument`, async() => {
spyOn(chatModel, 'send').and.callThrough();
spyOn(chatModel, 'getUserStatus').and.returnValue(
new Promise(resolve => {
return resolve({
data: {
status: 'offline'
}
});
})
);
const department = await app.models.Department.findById(departmentId);
await department.updateAttribute('chatName', 'cooler');
const tx = await models.Claim.beginTransaction({});
const response = await chatModel.sendCheckingPresence(ctx, workerId, 'I changed something');
try {
const options = {transaction: tx};
expect(response.statusCode).toEqual(200);
expect(response.message).toEqual('Fake notification sent');
expect(chatModel.send).toHaveBeenCalledWith(ctx, '#cooler', '@HankPym ➔ I changed something');
const department = await models.Department.findById(departmentId, null, options);
await department.updateAttribute('chatName', 'cooler');
// restores
await department.updateAttribute('chatName', null);
const response = await chatModel.sendCheckingPresence(ctx, workerId, 'I changed something');
expect(response.statusCode).toEqual(200);
expect(response.message).toEqual('Fake notification sent');
expect(chatModel.send).toHaveBeenCalledWith(ctx, '#cooler', '@HankPym ➔ I changed something');
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});

View File

@ -9,35 +9,35 @@ module.exports = Self => {
accepts: [
{
arg: 'warehouseId',
type: 'Number',
type: 'number',
description: 'The warehouse id',
required: true
}, {
arg: 'companyId',
type: 'Number',
type: 'number',
description: 'The company id',
required: true
}, {
arg: 'dmsTypeId',
type: 'Number',
type: 'number',
description: 'The dms type id',
required: true
}, {
arg: 'reference',
type: 'String',
type: 'string',
required: true
}, {
arg: 'description',
type: 'String',
type: 'string',
required: true
}, {
arg: 'hasFile',
type: 'Boolean',
type: 'boolean',
description: 'True if has an attached file',
required: true
}],
returns: {
type: 'Object',
type: 'object',
root: true
},
http: {

View File

@ -0,0 +1,93 @@
const got = require('got');
module.exports = Self => {
Self.remoteMethodCtx('checkFile', {
description: 'Check if exist docuware file',
accessType: 'READ',
accepts: [
{
arg: 'id',
type: 'number',
description: 'The id',
http: {source: 'path'}
},
{
arg: 'fileCabinet',
type: 'string',
required: true,
description: 'The fileCabinet name'
},
{
arg: 'dialog',
type: 'string',
required: true,
description: 'The dialog name'
}
],
returns: {
type: 'boolean',
root: true
},
http: {
path: `/:id/checkFile`,
verb: 'POST'
}
});
Self.checkFile = async function(ctx, id, fileCabinet, dialog) {
const myUserId = ctx.req.accessToken.userId;
if (!myUserId)
return false;
const models = Self.app.models;
const docuwareConfig = await models.DocuwareConfig.findOne();
const docuwareInfo = await models.Docuware.findOne({
where: {
code: fileCabinet,
dialogName: dialog
}
});
const docuwareUrl = docuwareConfig.url;
const cookie = docuwareConfig.token;
const fileCabinetName = docuwareInfo.fileCabinetName;
const find = docuwareInfo.find;
const options = {
'headers': {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Cookie': cookie
}
};
const searchFilter = {
condition: [
{
DBName: find,
Value: [id]
}
]
};
try {
// get fileCabinetId
const fileCabinetResponse = await got.get(`${docuwareUrl}/FileCabinets`, options);
const fileCabinetJson = JSON.parse(fileCabinetResponse.body).FileCabinet;
const fileCabinetId = fileCabinetJson.find(dialogs => dialogs.Name === fileCabinetName).Id;
// get dialog
const dialogResponse = await got.get(`${docuwareUrl}/FileCabinets/${fileCabinetId}/dialogs`, options);
const dialogJson = JSON.parse(dialogResponse.body).Dialog;
const dialogId = dialogJson.find(dialogs => dialogs.DisplayName === 'find').Id;
// get docuwareID
Object.assign(options, {'body': JSON.stringify(searchFilter)});
const response = await got.post(
`${docuwareUrl}/FileCabinets/${fileCabinetId}/Query/DialogExpression?dialogId=${dialogId}`, options);
JSON.parse(response.body).Items[0].Id;
return true;
} catch (error) {
return false;
}
};
};

View File

@ -0,0 +1,120 @@
/* eslint max-len: ["error", { "code": 180 }]*/
const got = require('got');
const UserError = require('vn-loopback/util/user-error');
module.exports = Self => {
Self.remoteMethodCtx('download', {
description: 'Download an docuware PDF',
accessType: 'READ',
accepts: [
{
arg: 'id',
type: 'number',
description: 'The id',
http: {source: 'path'}
},
{
arg: 'fileCabinet',
type: 'string',
description: 'The id',
http: {source: 'path'}
},
{
arg: 'dialog',
type: 'string',
description: 'The 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/download/:fileCabinet/:dialog`,
verb: 'GET'
}
});
Self.download = async function(ctx, id, fileCabinet, dialog) {
const myUserId = ctx.req.accessToken.userId;
if (!myUserId)
throw new UserError(`You don't have enough privileges`);
const models = Self.app.models;
const docuwareConfig = await models.DocuwareConfig.findOne();
const docuwareInfo = await models.Docuware.findOne({
where: {
code: fileCabinet,
dialogName: dialog
}
});
const docuwareUrl = docuwareConfig.url;
const cookie = docuwareConfig.token;
const fileCabinetName = docuwareInfo.fileCabinetName;
const find = docuwareInfo.find;
const options = {
'headers': {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Cookie': cookie
}
};
const searchFilter = {
condition: [
{
DBName: find,
Value: [id]
}
]
};
try {
// get fileCabinetId
const fileCabinetResponse = await got.get(`${docuwareUrl}/FileCabinets`, options);
const fileCabinetJson = JSON.parse(fileCabinetResponse.body).FileCabinet;
const fileCabinetId = fileCabinetJson.find(dialogs => dialogs.Name === fileCabinetName).Id;
// get dialog
const dialogResponse = await got.get(`${docuwareUrl}/FileCabinets/${fileCabinetId}/dialogs`, options);
const dialogJson = JSON.parse(dialogResponse.body).Dialog;
const dialogId = dialogJson.find(dialogs => dialogs.DisplayName === 'find').Id;
// get docuwareID
Object.assign(options, {'body': JSON.stringify(searchFilter)});
const response = await got.post(`${docuwareUrl}/FileCabinets/${fileCabinetId}/Query/DialogExpression?dialogId=${dialogId}`, options);
const docuwareId = JSON.parse(response.body).Items[0].Id;
// download & save file
const fileName = `filename="${id}.pdf"`;
const contentType = 'application/pdf';
const downloadUri = `${docuwareUrl}/FileCabinets/${fileCabinetId}/Documents/${docuwareId}/FileDownload?targetFileType=Auto&keepAnnotations=false`;
const downloadOptions = {
'headers': {
'Cookie': cookie
}
};
const stream = got.stream(downloadUri, downloadOptions);
return [stream, contentType, fileName];
} catch (error) {
if (error.code === 'ENOENT')
throw new UserError('The DOCUWARE PDF document does not exists');
throw error;
}
};
};

View File

@ -0,0 +1,64 @@
const models = require('vn-loopback/server/server').models;
const got = require('got');
describe('docuware download()', () => {
const ticketId = 1;
const userId = 9;
const ctx = {
req: {
accessToken: {userId: userId},
headers: {origin: 'http://localhost:5000'},
}
};
const fileCabinetName = 'deliveryClientTest';
const dialogDisplayName = 'find';
const dialogName = 'findTest';
const gotGetResponse = {
body: JSON.stringify(
{
FileCabinet: [
{Id: 12, Name: fileCabinetName}
],
Dialog: [
{Id: 34, DisplayName: dialogDisplayName}
]
})
};
it('should return exist file in docuware', async() => {
const gotPostResponse = {
body: JSON.stringify(
{
Items: [
{Id: 56}
],
})
};
spyOn(got, 'get').and.returnValue(new Promise(resolve => resolve(gotGetResponse)));
spyOn(got, 'post').and.returnValue(new Promise(resolve => resolve(gotPostResponse)));
const result = await models.Docuware.checkFile(ctx, ticketId, fileCabinetName, dialogName);
expect(result).toEqual(true);
});
it('should return not exist file in docuware', async() => {
const gotPostResponse = {
body: JSON.stringify(
{
Items: [],
})
};
spyOn(got, 'get').and.returnValue(new Promise(resolve => resolve(gotGetResponse)));
spyOn(got, 'post').and.returnValue(new Promise(resolve => resolve(gotPostResponse)));
const result = await models.Docuware.checkFile(ctx, ticketId, fileCabinetName, dialogName);
expect(result).toEqual(false);
});
});

View File

@ -0,0 +1,50 @@
const models = require('vn-loopback/server/server').models;
const got = require('got');
const stream = require('stream');
describe('docuware download()', () => {
const userId = 9;
const ticketId = 1;
const ctx = {
req: {
accessToken: {userId: userId},
headers: {origin: 'http://localhost:5000'},
}
};
it('should return the downloaded file name', async() => {
const fileCabinetName = 'deliveryClientTest';
const dialogDisplayName = 'find';
const dialogName = 'findTest';
const gotGetResponse = {
body: JSON.stringify(
{
FileCabinet: [
{Id: 12, Name: fileCabinetName}
],
Dialog: [
{Id: 34, DisplayName: dialogDisplayName}
]
})
};
const gotPostResponse = {
body: JSON.stringify(
{
Items: [
{Id: 56}
],
})
};
spyOn(got, 'get').and.returnValue(new Promise(resolve => resolve(gotGetResponse)));
spyOn(got, 'post').and.returnValue(new Promise(resolve => resolve(gotPostResponse)));
spyOn(got, 'stream').and.returnValue(new stream.PassThrough({objectMode: true}));
const result = await models.Docuware.download(ctx, ticketId, fileCabinetName, dialogName);
expect(result[1]).toEqual('application/pdf');
expect(result[2]).toEqual(`filename="${ticketId}.pdf"`);
});
});

View File

@ -44,6 +44,12 @@
"DmsType": {
"dataSource": "vn"
},
"Docuware": {
"dataSource": "vn"
},
"DocuwareConfig": {
"dataSource": "vn"
},
"EmailUser": {
"dataSource": "vn"
},

View File

@ -1,4 +1,5 @@
module.exports = Self => {
require('../methods/chat/getServiceAuth')(Self);
require('../methods/chat/send')(Self);
require('../methods/chat/sendCheckingPresence')(Self);
require('../methods/chat/notifyIssues')(Self);

View File

@ -18,9 +18,6 @@
},
"expired": {
"type": "date"
},
"isOfficial": {
"type": "boolean"
}
},

View File

@ -0,0 +1,32 @@
{
"name": "DocuwareConfig",
"description": "Docuware config",
"base": "VnModel",
"options": {
"mysql": {
"table": "docuwareConfig"
}
},
"properties": {
"id": {
"type": "number",
"id": true,
"description": "Identifier"
},
"url": {
"type": "string"
},
"token": {
"type": "string"
}
},
"acls": [
{
"property": "*",
"accessType": "*",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW"
}
]
}

4
back/models/docuware.js Normal file
View File

@ -0,0 +1,4 @@
module.exports = Self => {
require('../methods/docuware/download')(Self);
require('../methods/docuware/checkFile')(Self);
};

38
back/models/docuware.json Normal file
View File

@ -0,0 +1,38 @@
{
"name": "Docuware",
"description": "Docuware sections",
"base": "VnModel",
"options": {
"mysql": {
"table": "docuware"
}
},
"properties": {
"id": {
"type": "number",
"id": true,
"description": "Identifier"
},
"code": {
"type": "string"
},
"fileCabinetName": {
"type": "string"
},
"dialogName": {
"type": "string"
},
"find": {
"type": "string"
}
},
"acls": [
{
"property": "*",
"accessType": "*",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW"
}
]
}

View File

@ -1,3 +0,0 @@
UPDATE vn.absenceType
SET code='halfPaidLeave'
WHERE id=15 AND name='Permiso retribuido 1/2 día' AND rgb='#5151c0' AND code IS NULL AND permissionRate=NULL AND holidayEntitlementRate=0.50 AND discountRate=0.00;

View File

@ -1,27 +0,0 @@
INSERT INTO `salix`.`ACL`
(model, property, accessType, permission, principalType, principalId)
VALUES
('EntryObservation', '*', '*', 'ALLOW', 'ROLE', 'buyer'),
('LdapConfig', '*', '*', 'ALLOW', 'ROLE', 'sysadmin'),
('SambaConfig', '*', '*', 'ALLOW', 'ROLE', 'sysadmin'),
('ACL', '*', '*', 'ALLOW', 'ROLE', 'developer'),
('AccessToken', '*', '*', 'ALLOW', 'ROLE', 'developer'),
('MailAliasAccount', '*', '*', 'ALLOW', 'ROLE', 'marketing'),
('MailAliasAccount', '*', '*', 'ALLOW', 'ROLE', 'hr'),
('MailAlias', '*', '*', 'ALLOW', 'ROLE', 'hr'),
('MailForward', '*', '*', 'ALLOW', 'ROLE', 'marketing'),
('MailForward', '*', '*', 'ALLOW', 'ROLE', 'hr'),
('RoleInherit', '*', '*', 'ALLOW', 'ROLE', 'it'),
('RoleRole', '*', '*', 'ALLOW', 'ROLE', 'it'),
('AccountConfig', '*', '*', 'ALLOW', 'ROLE', 'sysadmin');
UPDATE `salix`.`ACL`
SET accessType='*', principalId='it'
WHERE model = 'Role';
DELETE FROM `salix`.`ACL`
WHERE id IN (280, 281);
UPDATE `salix`.`ACL`
SET accessType='*', principalId='marketing'
WHERE id=279;

View File

@ -1,5 +0,0 @@
UPDATE `salix`.`defaultViewConfig`
SET `columns` = '{"intrastat":false,"description":false,"density":false,"isActive":false,
"freightValue":false,"packageValue":false,"isIgnored":false,"price2":false,"ektFk":false,"weight":false,
"size":false,"comissionValue":false,"landing":false}'
WHERE tableCode = 'latestBuys'

View File

@ -1,33 +0,0 @@
UPDATE vn.department
SET notificationEmail='direccioncomercial@verdnatura.es'
WHERE id=96;
UPDATE vn.department
SET notificationEmail='direccioncomercial@verdnatura.es'
WHERE id=95;
UPDATE vn.department
SET notificationEmail='direccioncomercial@verdnatura.es'
WHERE id=115;
UPDATE vn.department
SET notificationEmail='direccioncomercial@verdnatura.es'
WHERE id=123;
UPDATE vn.department
SET notificationEmail='direccioncomercial@verdnatura.es'
WHERE id=94;
UPDATE vn.department
SET notificationEmail='direccioncomercial@verdnatura.es'
WHERE id=101;
UPDATE vn.department
SET notificationEmail='direccioncomercial@verdnatura.es'
WHERE id=80;
UPDATE vn.department
SET notificationEmail='direccioncomercial@verdnatura.es'
WHERE id=125;
UPDATE vn.department
SET notificationEmail='direccioncomercial@verdnatura.es'
WHERE id=98;
UPDATE vn.department
SET notificationEmail='direccioncomercial@verdnatura.es'
WHERE id=92;
UPDATE vn.department
SET notificationEmail=''
WHERE id=43;

View File

@ -1,142 +0,0 @@
DROP PROCEDURE IF EXISTS `vn`.`item_getBalance`;
DELIMITER $$
$$
CREATE DEFINER=`root`@`%` PROCEDURE `vn`.`item_getBalance`(IN vItemId int, IN vWarehouse int)
BEGIN
DECLARE vDateInventory DATETIME;
DECLARE vCurdate DATE DEFAULT CURDATE();
DECLARE vDayEnd DATETIME DEFAULT util.dayEnd(vCurdate);
SELECT inventoried INTO vDateInventory FROM config;
SET @a = 0;
SET @currentLineFk = 0;
SET @shipped = '';
SELECT DATE(@shipped:= shipped) shipped,
alertLevel,
stateName,
origin,
reference,
clientFk,
name,
`in` AS invalue,
`out`,
@a := @a + IFNULL(`in`,0) - IFNULL(`out`,0) as balance,
@currentLineFk := IF (@shipped < CURDATE()
OR (@shipped = CURDATE() AND (isPicked OR alertLevel >= 2)),
lineFk,@currentLineFk) lastPreparedLineFk,
isTicket,
lineFk,
isPicked,
clientType,
claimFk
FROM
( SELECT tr.landed AS shipped,
b.quantity AS `in`,
NULL AS `out`,
al.id AS alertLevel,
st.name AS stateName,
s.name AS name,
e.ref AS reference,
e.id AS origin,
s.id AS clientFk,
IF(al.id = 3, TRUE, FALSE) isPicked,
FALSE AS isTicket,
b.id lineFk,
NULL `order`,
NULL AS clientType,
NULL AS claimFk
FROM buy b
JOIN entry e ON e.id = b.entryFk
JOIN travel tr ON tr.id = e.travelFk
JOIN supplier s ON s.id = e.supplierFk
JOIN alertLevel al ON al.id =
CASE
WHEN tr.shipped < CURDATE() THEN 3
WHEN tr.shipped = CURDATE() AND tr.isReceived = TRUE THEN 3
ELSE 0
END
JOIN state st ON st.code = al.code
WHERE tr.landed >= vDateInventory
AND vWarehouse = tr.warehouseInFk
AND b.itemFk = vItemId
AND e.isInventory = FALSE
AND e.isRaid = FALSE
UNION ALL
SELECT tr.shipped,
NULL,
b.quantity,
al.id,
st.name,
s.name,
e.ref,
e.id,
s.id,
IF(al.id = 3, TRUE, FALSE),
FALSE,
b.id,
NULL,
NULL,
NULL
FROM buy b
JOIN entry e ON e.id = b.entryFk
JOIN travel tr ON tr.id = e.travelFk
JOIN warehouse w ON w.id = tr.warehouseOutFk
JOIN supplier s ON s.id = e.supplierFk
JOIN alertLevel al ON al.id =
CASE
WHEN tr.shipped < CURDATE() THEN 3
WHEN tr.shipped = CURDATE() AND tr.isReceived = TRUE THEN 3
ELSE 0
END
JOIN state st ON st.code = al.code
WHERE tr.shipped >= vDateInventory
AND vWarehouse =tr.warehouseOutFk
AND s.id <> 4
AND b.itemFk = vItemId
AND e.isInventory = FALSE
AND w.isFeedStock = FALSE
AND e.isRaid = FALSE
UNION ALL
SELECT DATE(t.shipped),
NULL,
s.quantity,
al.id,
st.name,
t.nickname,
t.refFk,
t.id,
t.clientFk,
stk.id,
TRUE,
s.id,
st.`order`,
ct.code,
cb.claimFk
FROM sale s
JOIN ticket t ON t.id = s.ticketFk
LEFT JOIN ticketState ts ON ts.ticket = t.id
LEFT JOIN state st ON st.code = ts.code
JOIN client c ON c.id = t.clientFk
JOIN clientType ct ON ct.id = c.clientTypeFk
JOIN alertLevel al ON al.id =
CASE
WHEN t.shipped < curdate() THEN 3
WHEN t.shipped > util.dayEnd(curdate()) THEN 0
ELSE IFNULL(ts.alertLevel, 0)
END
LEFT JOIN state stPrep ON stPrep.`code` = 'PREPARED'
LEFT JOIN saleTracking stk ON stk.saleFk = s.id AND stk.stateFk = stPrep.id
LEFT JOIN claimBeginning cb ON s.id = cb.saleFk
WHERE t.shipped >= vDateInventory
AND s.itemFk = vItemId
AND vWarehouse =t.warehouseFk
ORDER BY shipped, alertLevel DESC, isTicket, `order` DESC, isPicked DESC, `in` DESC, `out` DESC
) AS itemDiary;
END;
$$
DELIMITER ;

View File

@ -1,2 +0,0 @@
ALTER TABLE vn.payMethod CHANGE ibanRequiredForClients isIbanRequiredForClients tinyint(3) DEFAULT 0 NULL;
ALTER TABLE vn.payMethod CHANGE ibanRequiredForSuppliers isIbanRequiredForSuppliers tinyint(3) DEFAULT 0 NULL;

View File

@ -1,120 +0,0 @@
DROP PROCEDURE IF EXISTS `vn`.`sale_recalcComponent`;
DELIMITER $$
$$
CREATE DEFINER=`root`@`%` PROCEDURE `vn`.`sale_recalcComponent`(vOption INT)
proc: BEGIN
/**
* Actualiza los componentes
*
* @table tmp.recalculateSales
*/
DECLARE vShipped DATE;
DECLARE vWarehouseFk SMALLINT;
DECLARE vAgencyModeFk INT;
DECLARE vAddressFk INT;
DECLARE vTicketFk BIGINT;
DECLARE vItemFk BIGINT;
DECLARE vLanded DATE;
DECLARE vIsEditable BOOLEAN;
DECLARE vZoneFk INTEGER;
DECLARE vOption INTEGER;
DECLARE vSale INTEGER;
DECLARE vDone BOOL DEFAULT FALSE;
DECLARE vCur CURSOR FOR
SELECT id from tmp.recalculateSales;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = TRUE;
OPEN vCur;
l: LOOP
SET vDone = FALSE;
FETCH vCur INTO vSale;
IF vDone THEN
LEAVE l;
END IF;
SELECT t.refFk IS NULL AND (IFNULL(ts.alertLevel, 0) = 0 OR s.price = 0),
s.ticketFk,
s.itemFk ,
t.zoneFk,
t.warehouseFk,
t.shipped,
t.addressFk,
t.agencyModeFk,
t.landed
INTO vIsEditable,
vTicketFk,
vItemFk,
vZoneFk,
vWarehouseFk,
vShipped,
vAddressFk,
vAgencyModeFk,
vLanded
FROM ticket t
JOIN sale s ON s.ticketFk = t.id
LEFT JOIN ticketState ts ON ts.ticketFk = t.id
WHERE s.id = vSale;
CALL zone_getLanded(vShipped, vAddressFk, vAgencyModeFk, vWarehouseFk, TRUE);
IF (SELECT COUNT(*) FROM tmp.zoneGetLanded LIMIT 1) = 0 THEN
CALL util.throw('There is no zone for these parameters');
END IF;
IF vLanded IS NULL OR vZoneFk IS NULL THEN
UPDATE ticket t
SET t.landed = (SELECT landed FROM tmp.zoneGetLanded LIMIT 1)
WHERE t.id = vTicketFk AND t.landed IS NULL;
IF vZoneFk IS NULL THEN
SELECT zoneFk INTO vZoneFk FROM tmp.zoneGetLanded LIMIT 1;
UPDATE ticket t
SET t.zoneFk = vZoneFk
WHERE t.id = vTicketFk AND t.zoneFk IS NULL;
END IF;
END IF;
DROP TEMPORARY TABLE tmp.zoneGetLanded;
-- rellena la tabla buyUltimate con la ultima compra
CALL buyUltimate (vWarehouseFk, vShipped);
DELETE FROM tmp.buyUltimate WHERE itemFk != vItemFk;
DROP TEMPORARY TABLE IF EXISTS tmp.ticketLot;
CREATE TEMPORARY TABLE tmp.ticketLot
SELECT vWarehouseFk warehouseFk, NULL available, vItemFk itemFk, buyFk, vZoneFk zoneFk
FROM tmp.buyUltimate
WHERE itemFk = vItemFk;
CALL catalog_componentPrepare();
CALL catalog_componentCalculate(vZoneFk, vAddressFk, vShipped, vWarehouseFk);
DROP TEMPORARY TABLE IF EXISTS tmp.sale;
CREATE TEMPORARY TABLE tmp.sale
(PRIMARY KEY (saleFk)) ENGINE = MEMORY
SELECT vSale saleFk,vWarehouseFk warehouseFk;
IF vOption IS NULL THEN
SET vOption = IF(vIsEditable, 1, 6);
END IF;
CALL ticketComponentUpdateSale(vOption);
CALL catalog_componentPurge();
DROP TEMPORARY TABLE tmp.buyUltimate;
DROP TEMPORARY TABLE tmp.sale;
END LOOP;
CLOSE vCur;
END$$
DELIMITER ;

View File

@ -1,23 +0,0 @@
DROP PROCEDURE IF EXISTS `vn`.`sale_calculateComponent`;
DELIMITER $$
$$
CREATE DEFINER=`root`@`%` PROCEDURE `vn`.`sale_calculateComponent`(vSale INT, vOption INT)
proc: BEGIN
/**
* Crea tabla temporal para vn.sale_recalcComponent() para recalcular los componentes
*
* @param vSale Id de la venta
* @param vOption indica en que componente pone el descuadre, NULL en casos habituales
*/
DROP TEMPORARY TABLE IF EXISTS tmp.recalculateSales;
CREATE TEMPORARY TABLE tmp.recalculateSales
SELECT s.id
FROM sale s
WHERE s.id = vSale;
CALL vn.sale_recalcComponent(vOption);
DROP TEMPORARY TABLE tmp.recalculateSales;
END$$
DELIMITER ;

View File

@ -1,2 +0,0 @@
INSERT INTO salix.ACL (model,property,accessType,permission,principalType,principalId)
VALUES ('Sale','payBack','WRITE','ALLOW','ROLE','employee');

View File

@ -1 +0,0 @@
ALTER TABLE `vn`.`payMethod` ADD hasVerified TINYINT(1) DEFAULT 0 NULL;

View File

@ -1,90 +0,0 @@
DROP PROCEDURE IF EXISTS `vn`.`ticket_doRefund`;
DELIMITER $$
$$
CREATE DEFINER=`root`@`localhost` PROCEDURE `vn`.`ticket_doRefund`(IN vOriginTicket INT, OUT vNewTicket INT)
BEGIN
DECLARE vDone BIT DEFAULT 0;
DECLARE vCustomer MEDIUMINT;
DECLARE vWarehouse TINYINT;
DECLARE vCompany MEDIUMINT;
DECLARE vAddress MEDIUMINT;
DECLARE vRefundAgencyMode INT;
DECLARE vItemFk INT;
DECLARE vQuantity DECIMAL (10,2);
DECLARE vConcept VARCHAR(50);
DECLARE vPrice DECIMAL (10,2);
DECLARE vDiscount TINYINT;
DECLARE vSaleNew INT;
DECLARE vSaleMain INT;
DECLARE vZoneFk INT;
DECLARE vRsMainTicket CURSOR FOR
SELECT *
FROM tmp.sale;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = 1;
SELECT id INTO vRefundAgencyMode
FROM agencyMode WHERE `name` = 'ABONO';
SELECT clientFk, warehouseFk, companyFk, addressFk
INTO vCustomer, vWarehouse, vCompany, vAddress
FROM ticket
WHERE id = vOriginTicket;
SELECT id INTO vZoneFk
FROM zone WHERE agencyModeFk = vRefundAgencyMode
LIMIT 1;
INSERT INTO vn.ticket (
clientFk,
shipped,
addressFk,
agencyModeFk,
nickname,
warehouseFk,
companyFk,
landed,
zoneFk
)
SELECT
vCustomer,
CURDATE(),
vAddress,
vRefundAgencyMode,
a.nickname,
vWarehouse,
vCompany,
CURDATE(),
vZoneFk
FROM address a
WHERE a.id = vAddress;
SET vNewTicket = LAST_INSERT_ID();
SET vDone := 0;
OPEN vRsMainTicket ;
FETCH vRsMainTicket INTO vSaleMain, vItemFk, vQuantity, vConcept, vPrice, vDiscount;
WHILE NOT vDone DO
INSERT INTO vn.sale(ticketFk, itemFk, quantity, concept, price, discount)
VALUES( vNewTicket, vItemFk, vQuantity, vConcept, vPrice, vDiscount );
SET vSaleNew = LAST_INSERT_ID();
INSERT INTO vn.saleComponent(saleFk,componentFk,`value`)
SELECT vSaleNew,componentFk,`value`
FROM vn.saleComponent
WHERE saleFk = vSaleMain;
FETCH vRsMainTicket INTO vSaleMain, vItemFk, vQuantity, vConcept, vPrice, vDiscount;
END WHILE;
CLOSE vRsMainTicket;
END;
$$
DELIMITER ;

View File

@ -1,3 +0,0 @@
UPDATE `vn`.`department`
SET `notificationEmail` = 'finanzas@verdnatura.es'
WHERE `name` = 'FINANZAS';

View File

@ -1,2 +0,0 @@
UPDATE `vn`.`supplier`
SET isPayMethodChecked = TRUE;

View File

@ -1,33 +0,0 @@
DELIMITER $$
$$
CREATE DEFINER=`root`@`%` TRIGGER `vn`.`payment_afterInsert` AFTER INSERT ON `payment` FOR EACH ROW
BEGIN
DECLARE vIsPayMethodChecked BOOLEAN;
DECLARE vEmail VARCHAR(150);
SELECT isPayMethodChecked INTO vIsPayMethodChecked
FROM supplier
WHERE id = NEW.supplierFk;
IF vIsPayMethodChecked = FALSE THEN
SELECT notificationEmail INTO vEmail
FROM department
WHERE name = 'FINANZAS';
CALL mail_insert(
vEmail,
NULL,
'Pago con método sin verificar',
CONCAT(
'Se ha realizado el pago ',
NEW.id,
' al proveedor ',
NEW.supplierFk,
' con el método de pago sin verificar.'
)
);
END IF;
END$$
DELIMITER ;

View File

@ -1,26 +0,0 @@
DROP TRIGGER IF EXISTS `vn`.`supplier_beforeUpdate`;
DELIMITER $$
$$
CREATE DEFINER=`root`@`%` TRIGGER `vn`.`supplier_beforeUpdate`
BEFORE UPDATE ON `vn`.`supplier` FOR EACH ROW
BEGIN
DECLARE vHasChange BOOL DEFAULT FALSE;
DECLARE vPayMethodHasVerified BOOL;
SELECT hasVerified INTO vPayMethodHasVerified
FROM payMethod
WHERE id = NEW.payMethodFk;
SET vHasChange = (NEW.payDemFk <> OLD.payDemFk) OR (NEW.payDay <> OLD.payDay);
IF vPayMethodHasVerified AND !vHasChange THEN
SET vHasChange = (NEW.payMethodFk <> OLD.payMethodFk);
END IF;
IF vHasChange THEN
SET NEW.isPayMethodChecked = FALSE;
END IF;
END$$
DELIMITER ;

View File

@ -0,0 +1,2 @@
DELETE FROM salix.ACL
WHERE model = 'ClaimEnd' AND property = 'importTicketSales';

View File

@ -0,0 +1,3 @@
INSERT INTO salix.ACL
(model, property, accessType, permission, principalType, principalId)
VALUES('Docuware', '*', '*', 'ALLOW', 'ROLE', 'employee');

View File

@ -0,0 +1,11 @@
CREATE TABLE `vn`.`docuware` (
`id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
`code` varchar(50) NULL,
`fileCabinetName` varchar(50) NULL,
`dialogName` varchar(255) DEFAULT NULL,
`find` varchar(50) DEFAULT NULL
);
INSERT INTO `vn`.`docuware` (`code`, `fileCabinetName`, `dialogName` , `find`)
VALUES
('deliveryClient', 'Albaranes cliente', 'findTicket', 'N__ALBAR_N');

View File

@ -0,0 +1,9 @@
CREATE TABLE `vn`.`docuwareConfig` (
`id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
`url` varchar(75) NULL,
`token` varchar(1000) DEFAULT NULL
);
INSERT INTO `vn`.`docuwareConfig` (`url`)
VALUES
('https://verdnatura.docuware.cloud/docuware/platform');

View File

@ -6,20 +6,23 @@ CREATE DEFINER=`root`@`%` PROCEDURE `vn`.`ticket_getMovable`(vTicketFk INT, vDat
BEGIN
/**
* Cálcula el stock movible para los artículos de un ticket
* vDatedNew debe ser menor que vDatedOld, en los otros casos se
* asume que siempre es posible
*
* @param vTicketFk -> Ticket
* @param vDatedNew -> Nueva fecha
* @return Sales con Movible
*/
DECLARE vDatedOld DATETIME;
SET vDatedNew = DATE_ADD(vDatedNew, INTERVAL 1 DAY);
SELECT t.shipped INTO vDatedOld
FROM ticket t
WHERE t.id = vTicketFk;
CALL itemStock(vWarehouseFk, DATE_SUB(vDatedNew, INTERVAL 1 DAY), NULL);
CALL item_getMinacum(vWarehouseFk, vDatedNew, DATEDIFF(vDatedOld, vDatedNew), NULL);
CALL itemStock(vWarehouseFk, vDatedNew, NULL);
CALL item_getMinacum(vWarehouseFk, vDatedNew, DATEDIFF(DATE_SUB(vDatedOld, INTERVAL 1 DAY), vDatedNew), NULL);
SELECT s.id,
s.itemFk,
s.quantity,

View File

@ -0,0 +1,2 @@
INSERT INTO salix.ACL (model,property,accessType,principalId)
VALUES ('AgencyTerm','*','*','administrative');

View File

@ -0,0 +1,3 @@
INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId)
VALUES
('ClaimLog', '*', 'READ', 'ALLOW', 'ROLE', 'claimManager');

View File

@ -0,0 +1,3 @@
UPDATE `account`.`user`
SET `role` = 57
WHERE id IN (2294, 4365, 7294);

View File

@ -0,0 +1,2 @@
INSERT INTO `salix`.`ACL` (`id`, `model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
VALUES(304, 'Agency', '*', '*', 'ALLOW', 'ROLE', 'employee');

View File

@ -0,0 +1,3 @@
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
VALUES
('SupplierAgencyTerm', '*', '*', 'ALLOW', 'ROLE', 'administrative');

View File

@ -0,0 +1,10 @@
CREATE TABLE `vn`.`agencyTermConfig` (
`expenceFk` varchar(10) DEFAULT NULL,
`vatAccountSupported` varchar(15) DEFAULT NULL,
`vatPercentage` decimal(28,10) DEFAULT NULL,
`transaction` varchar(50) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `vn`.`agencyTermConfig`
(`expenceFk`, `vatAccountSupported`, `vatPercentage`, `transaction`)
VALUES('6240000000', '4721000015', 21.0000000000, 'Adquisiciones intracomunitarias de servicios');

View File

@ -0,0 +1,8 @@
CREATE TABLE `vn`.`claimConfig` (
`id` int(11) NOT NULL,
`pickupContact` varchar(250),
PRIMARY KEY (`id`)
);
INSERT INTO vn.claimConfig (id, pickupContact)
VALUES(1, 'Email: cmorenoa@logista.com Telf: 961594250 Extensión: 206');

View File

@ -0,0 +1,2 @@
ALTER TABLE `vn`.`claimState` ADD `hasToNotify` TINYINT DEFAULT 0 NULL;
UPDATE `vn`.`claimState` SET `hasToNotify` = 1 WHERE `code` IN ('canceled', 'incomplete');

View File

@ -0,0 +1 @@
ALTER TABLE vn.claim ADD packages smallint(10) unsigned DEFAULT 0 NULL COMMENT 'packages received by the client';

View File

@ -0,0 +1,48 @@
ALTER TABLE `vn`.`agencyTerm` ADD `supplierFk` INT NULL;
ALTER TABLE `vn`.`agencyTerm` CHANGE `supplierFk` `supplierFk` INT NULL AFTER `agencyFk`;
UPDATE `vn`.`agencyTerm` `at`
JOIN `vn`.`agency` `a` ON `a`.`id` = `at`.`agencyFk`
SET `at`.`supplierFk` = `a`.`supplierFk`;
ALTER TABLE `vn`.`agencyTerm` ADD CONSTRAINT `agencyTerm_FK` FOREIGN KEY (`agencyFk`) REFERENCES `vn`.`agency`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
ALTER TABLE `vn`.`agencyTerm` ADD CONSTRAINT `agencyTerm_FK_1` FOREIGN KEY (`supplierFk`) REFERENCES `vn`.`supplier`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
RENAME TABLE `vn`.`agencyTerm` TO `vn`.`supplierAgencyTerm`;
CREATE OR REPLACE
ALGORITHM = UNDEFINED
DEFINER=`root`@`localhost`
VIEW `vn`.`agencyTerm` AS
SELECT
`sat`.`agencyFk` AS `agencyFk`,
`sat`.`minimumPackages` AS `minimumPackages`,
`sat`.`kmPrice` AS `kmPrice`,
`sat`.`packagePrice` AS `packagePrice`,
`sat`.`routePrice` AS `routePrice`,
`sat`.`minimumKm` AS `minimumKm`,
`sat`.`minimumM3` AS `minimumM3`,
`sat`.`m3Price` AS `m3Price`
FROM
`vn`.`supplierAgencyTerm` `sat`;
ALTER TABLE `vn`.`agency` DROP FOREIGN KEY `agency_ibfk_4`;
ALTER TABLE `vn`.`agency` CHANGE `supplierFk` `supplierFk__` int(11) DEFAULT NULL NULL;
CREATE OR REPLACE
ALGORITHM = UNDEFINED
DEFINER=`root`@`localhost`
VIEW `vn2008`.`agency` AS
SELECT
`a`.`id` AS `agency_id`,
`a`.`name` AS `name`,
`a`.`warehouseFk` AS `warehouse_id`,
`a`.`isVolumetric` AS `por_volumen`,
`a`.`bankFk` AS `Id_Banco`,
`a`.`warehouseAliasFk` AS `warehouse_alias_id`,
`a`.`isOwn` AS `propios`,
`a`.`labelZone` AS `zone_label`,
`a`.`workCenterFk` AS `workCenterFk`,
`a`.`supplierFk__` AS `supplierFk__`
FROM
`vn`.`agency` `a`;

View File

@ -0,0 +1,3 @@
ALTER TABLE `postgresql`.`business_labour_payroll` DROP FOREIGN KEY `business_labour_payroll_cod_contrato`;
ALTER TABLE `vn`.`workerBusinessType` MODIFY COLUMN `id` int(11) NOT NULL;
ALTER TABLE `postgresql`.`business_labour_payroll` ADD CONSTRAINT `business_labour_payroll_FK` FOREIGN KEY (cod_contrato) REFERENCES `vn`.`workerBusinessType`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;

File diff suppressed because one or more lines are too long

View File

@ -32,6 +32,11 @@ INSERT INTO `vn`.`packagingConfig`(`upperGap`)
('10');
UPDATE `account`.`role` SET id = 100 WHERE id = 0;
INSERT INTO `account`.`roleConfig`(`id`, `mysqlPassword`, `rolePrefix`, `userPrefix`, `userHost`, `tplUser`)
VALUES
(1, 'mysqlPassword', '$', '!', '%', 'any');
CALL `account`.`role_sync`;
INSERT INTO `account`.`user`(`id`,`name`, `nickname`, `password`,`role`,`active`,`email`, `lang`, `image`)
@ -167,9 +172,11 @@ INSERT INTO `vn`.`accountingType`(`id`, `description`, `receiptDescription`,`cod
INSERT INTO `vn`.`bank`(`id`, `bank`, `account`, `cash`, `entityFk`, `isActive`, `currencyFk`)
VALUES
(1, 'Pay on receipt', '5720000001', 3, 0, 1, 1),
(2, 'Cash', '5700000001', 2, 0, 1, 1),
(3, 'Compensation', '4000000000', 8, 0, 1, 1);
(1, 'Pay on receipt', '5720000001', 3, 0, 1, 1),
(2, 'Cash', '5700000001', 2, 0, 1, 1),
(3, 'Compensation', '4000000000', 8, 0, 1, 1),
(3117, 'Caixa Rural d''Algemesi', '5720000000', 8, 3117, 1, 1);
INSERT INTO `vn`.`deliveryMethod`(`id`, `code`, `description`)
VALUES
@ -522,6 +529,8 @@ INSERT INTO `vn`.`expence`(`id`, `taxTypeFk`, `name`, `isWithheld`)
(4751000000, 1, 'Retenciones', 1),
(4751000000, 6, 'Retencion', 0),
(6210000567, 0, 'Alquiler VNH', 0),
(6240000000, 1, 'Transportes de ventas rutas', 0),
(6240000000, 4, 'Transportes de ventas rutas', 0),
(7001000000, 1, 'Mercaderia', 0),
(7050000000, 1, 'Prestacion de servicios', 1);
@ -803,25 +812,25 @@ INSERT INTO `vn`.`itemFamily`(`code`, `description`)
('VT', 'Sales');
INSERT INTO `vn`.`item`(`id`, `typeFk`, `size`, `inkFk`, `stems`, `originFk`, `description`, `producerFk`, `intrastatFk`, `expenceFk`,
`comment`, `relevancy`, `image`, `subName`, `minPrice`, `stars`, `family`, `isFloramondo`, `genericFk`, `itemPackingTypeFk`)
`comment`, `relevancy`, `image`, `subName`, `minPrice`, `stars`, `family`, `isFloramondo`, `genericFk`, `itemPackingTypeFk`, `hasMinPrice`)
VALUES
(1, 2, 70, 'YEL', 1, 1, NULL, 1, 06021010, 2000000000, NULL, 0, '1', NULL, 0, 1, 'VT', 0, NULL, 'V'),
(2, 2, 70, 'BLU', 1, 2, NULL, 1, 06021010, 2000000000, NULL, 0, '2', NULL, 0, 2, 'VT', 0, NULL, 'H'),
(3, 1, 60, 'YEL', 1, 3, NULL, 1, 05080000, 4751000000, NULL, 0, '3', NULL, 0, 5, 'VT', 0, NULL, NULL),
(4, 1, 60, 'YEL', 1, 1, 'Increases block', 1, 05080000, 4751000000, NULL, 0, '4', NULL, 0, 3, 'VT', 0, NULL, NULL),
(5, 3, 30, 'RED', 1, 2, NULL, 2, 06021010, 4751000000, NULL, 0, '5', NULL, 0, 3, 'VT', 0, NULL, NULL),
(6, 5, 30, 'RED', 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '6', NULL, 0, 4, 'VT', 0, NULL, NULL),
(7, 5, 90, 'BLU', 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '7', NULL, 0, 4, 'VT', 0, NULL, NULL),
(8, 2, 70, 'YEL', 1, 1, NULL, 1, 06021010, 2000000000, NULL, 0, '8', NULL, 0, 5, 'VT', 0, NULL, NULL),
(9, 2, 70, 'BLU', 1, 2, NULL, 1, 06021010, 2000000000, NULL, 0, '9', NULL, 0, 4, 'VT', 1, NULL, NULL),
(10, 1, 60, 'YEL', 1, 3, NULL, 1, 05080000, 4751000000, NULL, 0, '10', NULL, 0, 4, 'VT', 0, NULL, NULL),
(11, 1, 60, 'YEL', 1, 1, NULL, 1, 05080000, 4751000000, NULL, 0, '11', NULL, 0, 4, 'VT', 0, NULL, NULL),
(12, 3, 30, 'RED', 1, 2, NULL, 2, 06021010, 4751000000, NULL, 0, '12', NULL, 0, 3, 'VT', 0, NULL, NULL),
(13, 5, 30, 'RED', 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '13', NULL, 0, 2, 'VT', 1, NULL, NULL),
(14, 5, 90, 'BLU', 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 4, 'VT', 1, NULL, NULL),
(15, 4, NULL, NULL, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 0, 'EMB', 0, NULL, NULL),
(16, 6, NULL, NULL, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 0, 'EMB', 0, NULL, NULL),
(71, 6, NULL, NULL, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 0, 'VT', 0, NULL, NULL);
(1, 2, 70, 'YEL', 1, 1, NULL, 1, 06021010, 2000000000, NULL, 0, '1', NULL, 0, 1, 'VT', 0, NULL, 'V', 0),
(2, 2, 70, 'BLU', 1, 2, NULL, 1, 06021010, 2000000000, NULL, 0, '2', NULL, 0, 2, 'VT', 0, NULL, 'H', 0),
(3, 1, 60, 'YEL', 1, 3, NULL, 1, 05080000, 4751000000, NULL, 0, '3', NULL, 0, 5, 'VT', 0, NULL, NULL, 0),
(4, 1, 60, 'YEL', 1, 1, 'Increases block', 1, 05080000, 4751000000, NULL, 0, '4', NULL, 0, 3, 'VT', 0, NULL, NULL, 0),
(5, 3, 30, 'RED', 1, 2, NULL, 2, 06021010, 4751000000, NULL, 0, '5', NULL, 0, 3, 'VT', 0, NULL, NULL, 0),
(6, 5, 30, 'RED', 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '6', NULL, 0, 4, 'VT', 0, NULL, NULL, 0),
(7, 5, 90, 'BLU', 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '7', NULL, 0, 4, 'VT', 0, NULL, NULL, 0),
(8, 2, 70, 'YEL', 1, 1, NULL, 1, 06021010, 2000000000, NULL, 0, '8', NULL, 0, 5, 'VT', 0, NULL, NULL, 0),
(9, 2, 70, 'BLU', 1, 2, NULL, 1, 06021010, 2000000000, NULL, 0, '9', NULL, 0, 4, 'VT', 1, NULL, NULL, 0),
(10, 1, 60, 'YEL', 1, 3, NULL, 1, 05080000, 4751000000, NULL, 0, '10', NULL, 0, 4, 'VT', 0, NULL, NULL, 0),
(11, 1, 60, 'YEL', 1, 1, NULL, 1, 05080000, 4751000000, NULL, 0, '11', NULL, 0, 4, 'VT', 0, NULL, NULL, 0),
(12, 3, 30, 'RED', 1, 2, NULL, 2, 06021010, 4751000000, NULL, 0, '12', NULL, 0, 3, 'VT', 0, NULL, NULL, 0),
(13, 5, 30, 'RED', 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '13', NULL, 1, 2, 'VT', 1, NULL, NULL, 1),
(14, 5, 90, 'BLU', 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 4, 'VT', 1, NULL, NULL, 0),
(15, 4, NULL, NULL, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 0, 'EMB', 0, NULL, NULL, 0),
(16, 6, NULL, NULL, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 0, 'EMB', 0, NULL, NULL, 0),
(71, 6, NULL, NULL, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 0, 'VT', 0, NULL, NULL, 0);
-- Update the taxClass after insert of the items
UPDATE `vn`.`itemTaxCountry` SET `taxClassFk` = 2
@ -831,7 +840,7 @@ INSERT INTO `vn`.`priceFixed`(`id`, `itemFk`, `rate0`, `rate1`, `rate2`, `rate3`
VALUES
(1, 1, 0, 0, 2.5, 2, CURDATE(), DATE_ADD(CURDATE(), INTERVAL +1 MONTH), 0, 1, CURDATE()),
(2, 3, 10, 10, 10, 10, CURDATE(), DATE_ADD(CURDATE(), INTERVAL +1 MONTH), 0, 1, CURDATE()),
(3, 5, 8.5, 10, 7.5, 6, CURDATE(), DATE_ADD(CURDATE(), INTERVAL +1 MONTH), 1, 2, CURDATE());
(3, 13, 8.5, 10, 7.5, 6, CURDATE(), DATE_ADD(CURDATE(), INTERVAL +1 MONTH), 1, 2, CURDATE());
INSERT INTO `vn`.`expeditionBoxVol`(`boxFk`, `m3`, `ratio`)
VALUES
@ -1691,22 +1700,22 @@ INSERT INTO `vn`.`clientSample`(`id`, `clientFk`, `typeFk`, `created`, `workerFk
(4, 1102, 2, CURDATE(), 18, 18, 567),
(5, 1102, 3, CURDATE(), 19, 19, 567);
INSERT INTO `vn`.`claimState`(`id`, `code`, `description`, `roleFk`, `priority`)
INSERT INTO `vn`.`claimState`(`id`, `code`, `description`, `roleFk`, `priority`, `hasToNotify`)
VALUES
( 1, 'pending', 'Pendiente', 1, 1),
( 2, 'managed', 'Gestionado', 1, 5),
( 3, 'resolved', 'Resuelto', 72, 7),
( 4, 'canceled', 'Anulado', 72, 6),
( 5, 'incomplete', 'Incompleta', 72, 3),
( 6, 'mana', 'Mana', 1, 4),
( 7, 'lack', 'Faltas', 1, 2);
( 1, 'pending', 'Pendiente', 1, 1, 0),
( 2, 'managed', 'Gestionado', 1, 5, 0),
( 3, 'resolved', 'Resuelto', 72, 7, 0),
( 4, 'canceled', 'Anulado', 72, 6, 1),
( 5, 'incomplete', 'Incompleta', 72, 3, 1),
( 6, 'mana', 'Mana', 1, 4, 0),
( 7, 'lack', 'Faltas', 1, 2, 0);
INSERT INTO `vn`.`claim`(`id`, `ticketCreated`, `claimStateFk`, `observation`, `clientFk`, `workerFk`, `responsibility`, `isChargedToMana`, `created` )
INSERT INTO `vn`.`claim`(`id`, `ticketCreated`, `claimStateFk`, `observation`, `clientFk`, `workerFk`, `responsibility`, `isChargedToMana`, `created`, `packages`)
VALUES
(1, CURDATE(), 1, 'observation one', 1101, 18, 3, 0, CURDATE()),
(2, CURDATE(), 2, 'observation two', 1101, 18, 3, 0, CURDATE()),
(3, CURDATE(), 3, 'observation three', 1101, 18, 1, 1, CURDATE()),
(4, CURDATE(), 3, 'observation four', 1104, 18, 5, 0, CURDATE());
(1, CURDATE(), 1, 'Cu nam labores lobortis definiebas, ei aliquyam salutatus persequeris quo, cum eu nemore fierent dissentiunt. Per vero dolor id, vide democritum scribentur eu vim, pri erroribus temporibus ex.', 1101, 18, 3, 0, CURDATE(), 0),
(2, CURDATE(), 2, 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat.', 1101, 18, 3, 0, CURDATE(), 1),
(3, CURDATE(), 3, 'An vim commodo dolorem volutpat, cu expetendis voluptatum usu, et mutat consul adversarium his. His natum numquam legimus an, diam fabulas mei ut. Melius fabellas sadipscing vel id. Partem diceret mandamus mea ne, has te tempor nostrud. Aeque nostro eum no.', 1101, 18, 1, 1, CURDATE(), 5),
(4, CURDATE(), 3, 'Wisi forensibus mnesarchum in cum. Per id impetus abhorreant, his no magna definiebas, inani rationibus in quo. Ut vidisse dolores est, ut quis nominavi mel. Ad pri quod apeirian concludaturque.', 1104, 18, 5, 0, CURDATE(), 10);
INSERT INTO `vn`.`claimBeginning`(`id`, `claimFk`, `saleFk`, `quantity`)
VALUES
@ -1851,6 +1860,15 @@ INSERT INTO `postgresql`.`business_labour`(`business_id`, `notes`, `department_i
SELECT b.business_id, NULL, 23, 1, 0, 1, 1, 1, 1
FROM `postgresql`.`business` `b`;
INSERT INTO `postgresql`.`business` (`client_id`, `provider_id`, `date_start`, `date_end`, `workerBusiness`, `reasonEndFk`)
SELECT p.profile_id, 1000, CONCAT(YEAR(DATE_ADD(CURDATE(), INTERVAL -2 YEAR)), '-12-25'), CONCAT(YEAR(DATE_ADD(CURDATE(), INTERVAL -1 YEAR)), '-12-24'), CONCAT('E-46-',RPAD(CONCAT(p.profile_id,9),8,p.profile_id)), NULL
FROM `postgresql`.`profile` `p`
WHERE `p`.`profile_id` = 1109;
INSERT INTO `postgresql`.`business_labour` (`business_id`, `notes`, `department_id`, `professional_category_id`, `incentivo`, `calendar_labour_type_id`, `porhoras`, `labour_agreement_id`, `workcenter_id`)
VALUES
(1111, NULL, 23, 1, 0.0, 1, 1, 1, 1);
UPDATE `postgresql`.`business_labour` bl
JOIN `postgresql`.`business` b ON b.business_id = bl.business_id
JOIN `postgresql`.`profile` pr ON pr.profile_id = b.client_id
@ -1884,14 +1902,29 @@ INSERT INTO `vn`.`workCenterHoliday` (`workCenterFk`, `days`, `year`)
('1', '24.5', YEAR(DATE_ADD(CURDATE(), INTERVAL -1 YEAR))),
('5', '23', YEAR(DATE_ADD(CURDATE(), INTERVAL -1 YEAR)));
INSERT INTO `postgresql`.`calendar_state` (`calendar_state_id`, `type`, `rgb`, `code`, `holidayEntitlementRate`)
INSERT INTO `postgresql`.`calendar_state` (`calendar_state_id`, `type`, `rgb`, `code`, `holidayEntitlementRate`, `discountRate`)
VALUES
(1, 'Holidays', '#FF4444', 'holiday', 0),
(2, 'Leave of absence', '#C71585', 'absence', 0),
(6, 'Half holiday', '#E65F00', 'halfHoliday', 0),
(15, 'Half Paid Leave', '#5151c0', 'halfPaidLeave', 0),
(20, 'Furlough', '#97B92F', 'furlough', 1),
(21, 'Furlough half day', '#778899', 'halfFurlough', 0.5);
(1, 'Holidays', '#FF4444', 'holiday', 0, 0),
(2, 'Leave of absence', '#C71585', 'absence', 0, 1),
(6, 'Half holiday', '#E65F00', 'halfHoliday', 0, 0.5),
(15, 'Half Paid Leave', '#5151c0', 'halfPaidLeave', 0, 1),
(20, 'Furlough', '#97B92F', 'furlough', 1, 1),
(21, 'Furlough half day', '#778899', 'halfFurlough', 0.5, 1);
ALTER TABLE `postgresql`.`business_labour_payroll` DROP FOREIGN KEY `business_labour_payroll_cod_categoria`;
INSERT INTO `vn`.`workerBusinessType` (`id`, `name`, `isFullTime`, `isPermanent`, `hasHolidayEntitlement`)
VALUES
(1, 'CONTRATO HOLANDA', 1, 0, 1),
(100, 'INDEFINIDO A TIEMPO COMPLETO', 1, 1, 1),
(109, 'CONVERSION DE TEMPORAL EN INDEFINIDO T.COMPLETO', 1, 1, 1);
INSERT INTO `postgresql`.`business_labour_payroll` (`business_id`, `cod_tarifa`, `cod_categoria`, `cod_contrato`, `importepactado`)
VALUES
(1, 7, 12, 100, 900.50),
(1106, 7, 12, 100, 1263.03),
(1107, 7, 12, 100, 2000),
(1108, 7, 12, 100, 1500);
INSERT INTO `postgresql`.`calendar_employee` (`business_id`, `calendar_state_id`, `date`)
VALUES
@ -2450,3 +2483,63 @@ INSERT INTO `bs`.`defaulter` (`clientFk`, `amount`, `created`, `defaulterSinced`
(1103, 500, CURDATE(), CURDATE()),
(1107, 500, CURDATE(), CURDATE()),
(1109, 500, CURDATE(), CURDATE());
UPDATE `vn`.`agency`
SET `supplierFk`=1
WHERE `id`=1;
UPDATE `vn`.`agency`
SET `supplierFk`=1
WHERE `id`=2;
UPDATE `vn`.`agency`
SET `supplierFk`=2
WHERE `id`=3;
UPDATE `vn`.`route`
SET `invoiceInFk`=1
WHERE `id`=1;
UPDATE `vn`.`route`
SET `invoiceInFk`=2
WHERE `id`=2;
INSERT INTO `bs`.`salesPerson` (`workerFk`, `year`, `month`, `portfolioWeight`)
VALUES
(18, YEAR(CURDATE()), MONTH(CURDATE()), 807.23),
(19, YEAR(CURDATE()), MONTH(CURDATE()), 34.40);
INSERT INTO `bs`.`sale` (`saleFk`, `amount`, `dated`, `typeFk`, `clientFk`)
VALUES
(1, 501.95, CURDATE(), 2, 1101),
(2, 70.7, CURDATE(), 2, 1101),
(3, 200.78, CURDATE(), 2, 1101),
(4, 33.8, CURDATE(), 1, 1101),
(30, 34.4, CURDATE(), 1, 1108);
INSERT INTO `vn`.`docuware` (`code`, `fileCabinetName`, `dialogName` , `find`)
VALUES
('deliveryClientTest', 'deliveryClientTest', 'findTest', 'word');
INSERT INTO `vn`.`docuwareConfig` (`url`)
VALUES
('https://verdnatura.docuware.cloud/docuware/platform');
INSERT INTO `vn`.`calendarHolidaysName` (`id`, `name`)
VALUES
(1, 'dayOfIT');
INSERT INTO `vn`.`calendarHolidaysType` (`id`, `name`, `hexColour`)
VALUES
(1, 'National', '#4169E1');
INSERT INTO `vn`.`calendarHolidays` (`id`, `calendarHolidaysTypeFk`, `dated`, `calendarHolidaysNameFk`, `workCenterFk`)
VALUES
(1, 1, CONCAT(YEAR(CURDATE()), '-12-09'), 1, 1);
INSERT INTO `vn`.`supplierAgencyTerm` (`agencyFk`, `supplierFk`, `minimumPackages`, `kmPrice`, `packagePrice`, `routePrice`, `minimumKm`, `minimumM3`, `m3Price`)
VALUES
(1, 1, 0, 0.00, 0.00, NULL, 0, 0.00, 23),
(2, 1, 60, 0.00, 0.00, NULL, 0, 5.00, 33),
(3, 2, 0, 15.00, 0.00, NULL, 0, 0.00, 0),
(4, 2, 0, 20.00, 0.00, NULL, 0, 0.00, 0),
(5, 442, 0, 0.00, 3.05, NULL, 0, 0.00, 0);

File diff suppressed because it is too large Load Diff

View File

@ -25,7 +25,6 @@ IGNORETABLES=(
--ignore-table=bs.productionIndicators
--ignore-table=bs.VentasPorCliente
--ignore-table=bs.v_ventas
--ignore-table=edi.supplyOffer
--ignore-table=postgresql.currentWorkersStats
--ignore-table=vn.accounting__
--ignore-table=vn.agencyModeZone

View File

@ -305,12 +305,12 @@ export default {
anyCreditInsuranceLine: 'vn-client-credit-insurance-insurance-index vn-tbody > vn-tr',
},
clientDefaulter: {
anyClient: 'vn-client-defaulter-index vn-tbody > vn-tr',
firstClientName: 'vn-client-defaulter-index vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(2) > span',
firstSalesPersonName: 'vn-client-defaulter-index vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(3) > span',
firstObservation: 'vn-client-defaulter-index vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(6) > vn-textarea[ng-model="defaulter.observation"]',
allDefaulterCheckbox: 'vn-client-defaulter-index vn-thead vn-multi-check',
addObservationButton: 'vn-client-defaulter-index vn-button[icon="icon-notes"]',
anyClient: 'vn-client-defaulter tbody > tr',
firstClientName: 'vn-client-defaulter tbody > tr:nth-child(1) > td:nth-child(2) > span',
firstSalesPersonName: 'vn-client-defaulter tbody > tr:nth-child(1) > td:nth-child(3) > span',
firstObservation: 'vn-client-defaulter tbody > tr:nth-child(1) > td:nth-child(6) > vn-textarea[ng-model="defaulter.observation"]',
allDefaulterCheckbox: 'vn-client-defaulter thead vn-multi-check',
addObservationButton: 'vn-client-defaulter vn-button[icon="icon-notes"]',
observation: '.vn-dialog.shown vn-textarea[ng-model="$ctrl.defaulter.observation"]',
saveButton: 'button[response="accept"]'
},
@ -346,16 +346,17 @@ export default {
saveFieldsButton: '.vn-popover.shown vn-button[label="Save"] > button'
},
itemFixedPrice: {
add: 'vn-fixed-price vn-icon[icon="add_circle"]',
fourthFixedPrice: 'vn-fixed-price vn-tr:nth-child(4)',
fourthItemID: 'vn-fixed-price vn-tr:nth-child(4) vn-autocomplete[ng-model="price.itemFk"]',
fourthWarehouse: 'vn-fixed-price vn-tr:nth-child(4) vn-autocomplete[ng-model="price.warehouseFk"]',
fourthPPU: 'vn-fixed-price vn-tr:nth-child(4) > vn-td-editable:nth-child(4)',
fourthPPP: 'vn-fixed-price vn-tr:nth-child(4) > vn-td-editable:nth-child(5)',
fourthMinPrice: 'vn-fixed-price vn-tr:nth-child(4) > vn-td-editable:nth-child(6)',
fourthStarted: 'vn-fixed-price vn-tr:nth-child(4) vn-date-picker[ng-model="price.started"]',
fourthEnded: 'vn-fixed-price vn-tr:nth-child(4) vn-date-picker[ng-model="price.ended"]',
fourthDeleteIcon: 'vn-fixed-price vn-tr:nth-child(4) > vn-td:nth-child(9) > vn-icon-button[icon="delete"]'
add: 'vn-fixed-price vn-icon-button[icon="add_circle"]',
fourthFixedPrice: 'vn-fixed-price tr:nth-child(5)',
fourthItemID: 'vn-fixed-price tr:nth-child(5) vn-autocomplete[ng-model="price.itemFk"]',
fourthWarehouse: 'vn-fixed-price tr:nth-child(5) vn-autocomplete[ng-model="price.warehouseFk"]',
fourthPPU: 'vn-fixed-price tr:nth-child(5) > td:nth-child(4)',
fourthPPP: 'vn-fixed-price tr:nth-child(5) > td:nth-child(5)',
fourthHasMinPrice: 'vn-fixed-price tr:nth-child(5) > td:nth-child(6) > vn-check[ng-model="price.hasMinPrice"]',
fourthMinPrice: 'vn-fixed-price tr:nth-child(5) > td:nth-child(6) > vn-input-number[ng-model="price.minPrice"]',
fourthStarted: 'vn-fixed-price tr:nth-child(5) vn-date-picker[ng-model="price.started"]',
fourthEnded: 'vn-fixed-price tr:nth-child(5) vn-date-picker[ng-model="price.ended"]',
fourthDeleteIcon: 'vn-fixed-price tr:nth-child(5) > td:nth-child(9) > vn-icon-button[icon="delete"]'
},
itemCreateView: {
temporalName: 'vn-item-create vn-textfield[ng-model="$ctrl.item.provisionalName"]',
@ -680,18 +681,19 @@ export default {
header: 'vn-claim-summary > vn-card > h5',
state: 'vn-claim-summary vn-label-value[label="State"] > section > span',
observation: 'vn-claim-summary vn-textarea[ng-model="$ctrl.summary.claim.observation"]',
firstSaleItemId: 'vn-claim-summary vn-horizontal > vn-auto:nth-child(4) vn-table > div > vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(1) > span',
firstSaleItemId: 'vn-claim-summary vn-horizontal > vn-auto:nth-child(5) vn-table > div > vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(1) > span',
firstSaleDescriptorImage: '.vn-popover.shown vn-item-descriptor img',
itemDescriptorPopover: '.vn-popover.shown vn-item-descriptor',
itemDescriptorPopoverItemDiaryButton: '.vn-popover vn-item-descriptor vn-quick-link[icon="icon-transaction"] > a',
firstDevelopmentWorker: 'vn-claim-summary vn-horizontal > vn-auto:nth-child(5) vn-table > div > vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(4) > span',
firstDevelopmentWorker: 'vn-claim-summary vn-horizontal > vn-auto:nth-child(4) vn-table > div > vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(4) > span',
firstDevelopmentWorkerGoToClientButton: '.vn-popover vn-worker-descriptor vn-quick-link[icon="person"] > a',
firstActionTicketId: 'vn-claim-summary > vn-card > vn-horizontal > vn-auto:nth-child(6) vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(2) > span',
firstActionTicketId: 'vn-claim-summary > vn-card > vn-horizontal > vn-auto:nth-child(5) vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(2) > span',
firstActionTicketDescriptor: '.vn-popover.shown vn-ticket-descriptor'
},
claimBasicData: {
claimState: 'vn-claim-basic-data vn-autocomplete[ng-model="$ctrl.claim.claimStateFk"]',
observation: 'vn-textarea[ng-model="$ctrl.claim.observation"]',
packages: 'vn-input-number[ng-model="$ctrl.claim.packages"]',
hasToPickUpCheckbox: 'vn-claim-basic-data vn-check[ng-model="$ctrl.claim.hasToPickUp"]',
saveButton: `button[type=submit]`
},
@ -722,10 +724,7 @@ export default {
},
claimAction: {
importClaimButton: 'vn-claim-action vn-button[label="Import claim"]',
importTicketButton: 'vn-claim-action vn-button[label="Import ticket"]',
secondImportableTicket: '.vn-popover.shown .content > div > vn-table > div > vn-tbody > vn-tr:nth-child(2)',
firstLineDestination: 'vn-claim-action vn-tr:nth-child(1) vn-autocomplete[ng-model="saleClaimed.claimDestinationFk"]',
secondLineDestination: 'vn-claim-action vn-tr:nth-child(2) vn-autocomplete[ng-model="saleClaimed.claimDestinationFk"]',
anyLine: 'vn-claim-action vn-tbody > vn-tr',
firstDeleteLine: 'vn-claim-action vn-tr:nth-child(1) vn-icon-button[icon="delete"]',
isPaidWithManaCheckbox: 'vn-claim-action vn-check[ng-model="$ctrl.claim.isChargedToMana"]'
},
@ -901,6 +900,7 @@ export default {
sundayWorkedHours: 'vn-worker-time-control vn-table > div > vn-tfoot > vn-tr:nth-child(1) > vn-td:nth-child(7)',
weekWorkedHours: 'vn-worker-time-control vn-side-menu vn-label-value > section > span',
nextMonthButton: 'vn-worker-time-control vn-side-menu vn-calendar vn-button[icon=keyboard_arrow_right]',
previousMonthButton: 'vn-worker-time-control vn-side-menu vn-calendar vn-button[icon=keyboard_arrow_left]',
secondWeekDay: 'vn-worker-time-control vn-side-menu vn-calendar .day:nth-child(8) > .day-number',
navigateBackToIndex: 'vn-worker-descriptor [name="goToModuleIndex"]'
},

View File

@ -9,7 +9,7 @@ describe('Client defaulter path', () => {
browser = await getBrowser();
page = browser.page;
await page.loginAndModule('insurance', 'client');
await page.accessToSection('client.defaulter.index');
await page.accessToSection('client.defaulter');
});
afterAll(async() => {
@ -28,8 +28,8 @@ describe('Client defaulter path', () => {
const salesPersonName =
await page.waitToGetProperty(selectors.clientDefaulter.firstSalesPersonName, 'innerText');
expect(clientName).toEqual('Ororo Munroe');
expect(salesPersonName).toEqual('salesPerson');
expect(clientName).toEqual('Batman');
expect(salesPersonName).toEqual('salesPersonNick');
});
it('should first observation not changed', async() => {
@ -52,7 +52,7 @@ describe('Client defaulter path', () => {
it('shoul checked all defaulters', async() => {
await page.loginAndModule('insurance', 'client');
await page.accessToSection('client.defaulter.index');
await page.accessToSection('client.defaulter');
await page.waitToClick(selectors.clientDefaulter.allDefaulterCheckbox);
});
@ -65,6 +65,7 @@ describe('Client defaulter path', () => {
it('should first observation changed', async() => {
const message = await page.waitForSnackbar();
await page.waitForSelector(selectors.clientDefaulter.firstObservation);
const result = await page.waitToGetProperty(selectors.clientDefaulter.firstObservation, 'value');
expect(message.text).toContain('Observation saved!');

View File

@ -10,6 +10,8 @@ describe('Worker time control path', () => {
await page.loginAndModule('salesBoss', 'worker');
await page.accessToSearchResult('HankPym');
await page.accessToSection('worker.card.timeControl');
await page.waitToClick(selectors.workerTimeControl.previousMonthButton);
await page.waitToClick(selectors.workerTimeControl.secondWeekDay);
});
afterAll(async() => {
@ -97,9 +99,9 @@ describe('Worker time control path', () => {
expect(result).toEqual(scanTime);
});
it(`should check Hank Pym worked 7 hours`, async() => {
await page.waitForTextInElement(selectors.workerTimeControl.mondayWorkedHours, '07:00 h.');
// 3736 check proc vn.timeControl_calculate
xit(`should check Hank Pym worked 6:40 hours`, async() => {
await page.waitForTextInElement(selectors.workerTimeControl.mondayWorkedHours, '06:40 h.');
});
});
@ -152,8 +154,8 @@ describe('Worker time control path', () => {
expect(result).toEqual(scanTime);
});
it(`should check Hank Pym worked 8 happy hours`, async() => {
await page.waitForTextInElement(selectors.workerTimeControl.tuesdayWorkedHours, '08:00 h.');
it(`should check Hank Pym worked 7:40 hours`, async() => {
await page.waitForTextInElement(selectors.workerTimeControl.tuesdayWorkedHours, '07:40 h.');
});
});
@ -206,8 +208,8 @@ describe('Worker time control path', () => {
expect(result).toEqual(scanTime);
});
it(`should check Hank Pym worked 8 cheerfull hours`, async() => {
await page.waitForTextInElement(selectors.workerTimeControl.wednesdayWorkedHours, '08:00 h.');
it(`should check Hank Pym worked 7:40 cheerfull hours`, async() => {
await page.waitForTextInElement(selectors.workerTimeControl.wednesdayWorkedHours, '07:40 h.');
});
});
@ -257,8 +259,8 @@ describe('Worker time control path', () => {
expect(result).toEqual(scanTime);
});
it(`should check Hank Pym worked 8 joyfull hours`, async() => {
await page.waitForTextInElement(selectors.workerTimeControl.thursdayWorkedHours, '08:00 h.');
it(`should check Hank Pym worked 7:40 joyfull hours`, async() => {
await page.waitForTextInElement(selectors.workerTimeControl.thursdayWorkedHours, '07:40 h.');
});
});
@ -307,8 +309,8 @@ describe('Worker time control path', () => {
expect(result).toEqual(scanTime);
});
it(`should check Hank Pym worked 8 hours with a smile on his face`, async() => {
await page.waitForTextInElement(selectors.workerTimeControl.fridayWorkedHours, '08:00 h.');
it(`should check Hank Pym worked 7:40 hours with a smile on his face`, async() => {
await page.waitForTextInElement(selectors.workerTimeControl.fridayWorkedHours, '07:40 h.');
});
});
});
@ -327,6 +329,8 @@ describe('Worker time control path', () => {
it('should access to the time control section', async() => {
await page.accessToSection('worker.card.timeControl');
await page.waitForState('worker.card.timeControl');
await page.waitToClick(selectors.workerTimeControl.previousMonthButton);
await page.waitToClick(selectors.workerTimeControl.secondWeekDay);
});
it('should lovingly scan in Hank Pym', async() => {
@ -352,8 +356,8 @@ describe('Worker time control path', () => {
expect(result).toEqual(scanTime);
});
it(`should check Hank Pym worked 8 hours with all his will`, async() => {
await page.waitForTextInElement(selectors.workerTimeControl.saturdayWorkedHours, '08:00 h.');
it(`should check Hank Pym worked 7:40 hours with all his will`, async() => {
await page.waitForTextInElement(selectors.workerTimeControl.saturdayWorkedHours, '07:40 h.');
});
});
@ -380,11 +384,11 @@ describe('Worker time control path', () => {
expect(result).toEqual(scanTime);
});
it(`should check Hank Pym worked 8 glad hours`, async() => {
await page.waitForTextInElement(selectors.workerTimeControl.sundayWorkedHours, '08:00 h.');
it(`should check Hank Pym worked 7:40 glad hours`, async() => {
await page.waitForTextInElement(selectors.workerTimeControl.sundayWorkedHours, '07:40 h.');
});
it(`should check Hank Pym doesn't have hours set on the next months first week`, async() => {
it(`should check Hank Pym doesn't have hours set on the next months second week`, async() => {
await page.waitToClick(selectors.workerTimeControl.nextMonthButton);
await page.waitToClick(selectors.workerTimeControl.secondWeekDay);
await page.waitForTextInElement(selectors.workerTimeControl.weekWorkedHours, '00:00 h.');
@ -408,10 +412,12 @@ describe('Worker time control path', () => {
await page.loginAndModule('HankPym', 'worker');
await page.accessToSearchResult('HankPym');
await page.accessToSection('worker.card.timeControl');
await page.waitToClick(selectors.workerTimeControl.previousMonthButton);
await page.waitToClick(selectors.workerTimeControl.secondWeekDay);
});
it('should check his weekly hours are alright', async() => {
await page.waitForTextInElement(selectors.workerTimeControl.weekWorkedHours, '55:00 h.');
await page.waitForTextInElement(selectors.workerTimeControl.weekWorkedHours, '52:40 h.');
});
});
});

View File

@ -9,7 +9,7 @@ describe('Worker calendar path', () => {
browser = await getBrowser();
page = browser.page;
await page.loginAndModule('hr', 'worker');
await page.accessToSearchResult('Hank Pym');
await page.accessToSearchResult('Charles Xavier');
await page.accessToSection('worker.card.calendar');
});
@ -18,12 +18,6 @@ describe('Worker calendar path', () => {
});
describe('as hr', () => {
it('should check 5 total holidays have been used so far before testing anything', async() => {
const result = await page.waitToGetProperty(selectors.workerCalendar.totalHolidaysUsed, 'innerText');
expect(result).toContain(' 5 ');
});
it('should set two days as holidays on the calendar and check the total holidays increased by 1.5', async() => {
await page.waitToClick(selectors.workerCalendar.holidays);
await page.waitForTimeout(reasonableTimeBetweenClicks);
@ -56,14 +50,14 @@ describe('Worker calendar path', () => {
const result = await page.waitToGetProperty(selectors.workerCalendar.totalHolidaysUsed, 'innerText');
expect(result).toContain(' 6.5 ');
expect(result).toContain(' 1.5 ');
});
});
describe(`as salesBoss`, () => {
it(`should log in and get to Hank's calendar`, async() => {
it(`should log in and get to Charles Xavier's calendar`, async() => {
await page.loginAndModule('salesBoss', 'worker');
await page.accessToSearchResult('Hank Pym');
await page.accessToSearchResult('Charles Xavier');
await page.accessToSection('worker.card.calendar');
});
@ -101,14 +95,14 @@ describe('Worker calendar path', () => {
it('should check the total holidays used are back to what it was', async() => {
const result = await page.waitToGetProperty(selectors.workerCalendar.totalHolidaysUsed, 'innerText');
expect(result).toContain(' 5 ');
expect(result).toContain(' 0 ');
});
});
describe(`as Hank`, () => {
describe(`as Charles Xavier`, () => {
it(`should log in and get to his calendar`, async() => {
await page.loginAndModule('HankPym', 'worker');
await page.accessToSearchResult('Hank Pym');
await page.loginAndModule('CharlesXavier', 'worker');
await page.accessToSearchResult('Charles Xavier');
await page.accessToSection('worker.card.calendar');
});
@ -122,7 +116,7 @@ describe('Worker calendar path', () => {
it('should check the total holidays used are now the initial ones', async() => {
const result = await page.waitToGetProperty(selectors.workerCalendar.totalHolidaysUsed, 'innerText');
expect(result).toContain(' 5 ');
expect(result).toContain(' 0 ');
});
it('should use the year selector to go to the previous year', async() => {

View File

@ -16,33 +16,17 @@ describe('Item fixed prices path', () => {
});
it('should click on the add new foxed price button', async() => {
await page.doSearch();
await page.waitToClick(selectors.itemFixedPrice.add);
await page.waitForSelector(selectors.itemFixedPrice.fourthFixedPrice);
});
it('should fill the fixed price data', async() => {
const now = new Date();
const searchValue = 'Chest ammo box';
await page.waitToClick(selectors.itemFixedPrice.fourthItemID);
await page.write('body > div > div > div.content > div.filter.ng-scope > vn-textfield', searchValue);
try {
await page.waitForFunction(searchValue => {
const element = document.querySelector('li.active');
if (element)
return element.innerText.toLowerCase().includes(searchValue.toLowerCase());
}, {}, searchValue);
} catch (error) {
const builtSelector = await page.selectorFormater(selectors.ticketSales.moreMenuState);
const inputValue = await page.evaluate(() => {
return document.querySelector('.vn-drop-down.shown vn-textfield input').value;
});
throw new Error(`${builtSelector} value is ${inputValue}! ${error}`);
}
await page.keyboard.press('Enter');
await page.autocompleteSearch(selectors.itemFixedPrice.fourthWarehouse, 'Warehouse one');
await page.writeOnEditableTD(selectors.itemFixedPrice.fourthPPU, '20');
await page.writeOnEditableTD(selectors.itemFixedPrice.fourthPPP, '10');
await page.writeOnEditableTD(selectors.itemFixedPrice.fourthMinPrice, '5');
await page.write(selectors.itemFixedPrice.fourthPPU, '1');
await page.write(selectors.itemFixedPrice.fourthPPP, '1');
await page.write(selectors.itemFixedPrice.fourthMinPrice, '1');
await page.pickDate(selectors.itemFixedPrice.fourthStarted, now);
await page.pickDate(selectors.itemFixedPrice.fourthEnded, now);
const message = await page.waitForSnackbar();
@ -53,7 +37,9 @@ describe('Item fixed prices path', () => {
it('should reload the section and check the created price has the expected ID', async() => {
await page.accessToSection('item.index');
await page.accessToSection('item.fixedPrice');
const result = await page.getProperty('vn-fixed-price > div > vn-card > vn-table > div > vn-tbody > vn-tr:nth-child(4) > vn-td:nth-child(1) > span', 'innerText');
await page.doSearch();
const result = await page.waitToGetProperty(selectors.itemFixedPrice.fourthItemID, 'value');
expect(result).toContain('13');
});

View File

@ -25,7 +25,7 @@ describe('Ticket Create new tracking state path', () => {
});
it(`should create a new state`, async() => {
await page.autocompleteSearch(selectors.createStateView.state, '¿Fecha?');
await page.autocompleteSearch(selectors.createStateView.state, 'OK');
await page.waitToClick(selectors.createStateView.saveStateButton);
const message = await page.waitForSnackbar();

View File

@ -24,6 +24,8 @@ describe('Claim edit basic data path', () => {
await page.autocompleteSearch(selectors.claimBasicData.claimState, 'Gestionado');
await page.clearTextarea(selectors.claimBasicData.observation);
await page.write(selectors.claimBasicData.observation, 'edited observation');
await page.clearInput(selectors.claimBasicData.packages);
await page.write(selectors.claimBasicData.packages, '2');
await page.waitToClick(selectors.claimBasicData.saveButton);
const message = await page.waitForSnackbar();
@ -64,10 +66,19 @@ describe('Claim edit basic data path', () => {
expect(result).toEqual('edited observation');
});
it('should confirm the claim packages was edited', async() => {
const result = await page
.waitToGetProperty(selectors.claimBasicData.packages, 'value');
expect(result).toEqual('2');
});
it(`should edit the claim to leave it untainted`, async() => {
await page.autocompleteSearch(selectors.claimBasicData.claimState, 'Pendiente');
await page.clearTextarea(selectors.claimBasicData.observation);
await page.write(selectors.claimBasicData.observation, 'Observation one');
await page.clearInput(selectors.claimBasicData.packages);
await page.write(selectors.claimBasicData.packages, '0');
await page.waitToClick(selectors.claimBasicData.saveButton);
const message = await page.waitForSnackbar();

View File

@ -66,7 +66,7 @@ describe('Claim development', () => {
.waitToGetProperty(selectors.claimDevelopment.firstClaimRedelivery, 'value');
expect(reason).toEqual('Calor');
expect(result).toEqual('Cocido');
expect(result).toEqual('Baboso/Cocido');
expect(responsible).toEqual('Calidad general');
expect(worker).toEqual('adminAssistantNick');
expect(redelivery).toEqual('Cliente');

View File

@ -24,22 +24,6 @@ describe('Claim action path', () => {
expect(message.text).toContain('Data saved!');
});
it('should import the second importable ticket', async() => {
await page.waitToClick(selectors.claimAction.importTicketButton);
await page.waitToClick(selectors.claimAction.secondImportableTicket);
const message = await page.waitForSnackbar();
expect(message.text).toContain('Data saved!');
});
it('should edit the second line destination field', async() => {
await page.waitForContentLoaded();
await page.autocompleteSearch(selectors.claimAction.secondLineDestination, 'Bueno');
const message = await page.waitForSnackbar();
expect(message.text).toContain('Data saved!');
});
it('should delete the first line', async() => {
await page.waitToClick(selectors.claimAction.firstDeleteLine);
const message = await page.waitForSnackbar();
@ -47,18 +31,11 @@ describe('Claim action path', () => {
expect(message.text).toContain('Data saved!');
});
it('should refresh the view to check the remaining line is the expected one', async() => {
it('should refresh the view to check not have lines', async() => {
await page.reloadSection('claim.card.action');
const result = await page.waitToGetProperty(selectors.claimAction.firstLineDestination, 'value');
const result = await page.countElement(selectors.claimAction.anyLine);
expect(result).toEqual('Bueno');
});
it('should delete the current first line', async() => {
await page.waitToClick(selectors.claimAction.firstDeleteLine);
const message = await page.waitForSnackbar();
expect(message.text).toContain('Data saved!');
expect(result).toEqual(0);
});
it('should check the "is paid with mana" checkbox', async() => {

View File

@ -1,3 +1,4 @@
import selectors from '../../helpers/selectors.js';
import getBrowser from '../../helpers/puppeteer';
@ -38,7 +39,7 @@ describe('Claim summary path', () => {
it('should display the observation', async() => {
const result = await page.waitToGetProperty(selectors.claimSummary.observation, 'value');
expect(result).toContain('observation four');
expect(result).toContain('Wisi forensibus mnesarchum in cum. Per id impetus abhorreant');
});
it('should display the claimed line(s)', async() => {

View File

@ -50,7 +50,7 @@ describe('InvoiceOut manual invoice path', () => {
});
it('should create an invoice from a client', async() => {
await page.autocompleteSearch(selectors.invoiceOutIndex.manualInvoiceClient, 'Charles Xavier');
await page.autocompleteSearch(selectors.invoiceOutIndex.manualInvoiceClient, 'Max Eisenhardt');
await page.autocompleteSearch(selectors.invoiceOutIndex.manualInvoiceSerial, 'Global nacional');
await page.autocompleteSearch(selectors.invoiceOutIndex.manualInvoiceTaxArea, 'national');
await page.waitToClick(selectors.invoiceOutIndex.saveInvoice);

View File

@ -80,7 +80,7 @@ describe('Account create and basic data path', () => {
await page.reloadSection('account.card.roles');
const rolesCount = await page.countElement(selectors.accountRoles.anyResult);
expect(rolesCount).toEqual(35);
expect(rolesCount).toEqual(61);
});
});

View File

@ -32,6 +32,9 @@ export default class SmartTable extends Component {
this._options = options;
if (!options) return;
if (options.defaultSearch)
this.displaySearch();
const activeButtons = options.activeButtons;
const missingId = activeButtons && activeButtons.shownColumns && !this.viewConfigId;
if (missingId)

View File

@ -97,7 +97,8 @@ ngModule.vnComponent('vnDescriptor', {
btnOne: '?btnOne',
btnTwo: '?btnTwo',
btnThree: '?btnThree',
btnFour: '?btnFour'
btnFour: '?btnFour',
btnFive: '?btnFive'
}
});

View File

@ -104,7 +104,7 @@ vn-descriptor-content {
align-items: center;
justify-content: center;
padding: 0 $spacing-sm;
margin: 0 $spacing-sm;
margin: 0 $spacing-xs;
& > vn-icon {
font-size: 1.75rem;

View File

@ -70,6 +70,7 @@
"Sent units from ticket": "I sent *{{quantity}}* units of [{{concept}} ({{itemId}})]({{{itemUrl}}}) to *\"{{nickname}}\"* coming from ticket id [{{ticketId}}]({{{ticketUrl}}})",
"Claim will be picked": "The product from the claim [({{claimId}})]({{{claimUrl}}}) from the client *{{clientName}}* will be picked",
"Claim state has changed to incomplete": "The state of the claim [({{claimId}})]({{{claimUrl}}}) from client *{{clientName}}* has changed to *incomplete*",
"Claim state has changed to canceled": "The state of the claim [({{claimId}})]({{{claimUrl}}}) from client *{{clientName}}* has changed to *canceled*",
"This ticket is not an stowaway anymore": "The ticket id [{{ticketId}}]({{{ticketUrl}}}) is not an stowaway anymore",
"Customs agent is required for a non UEE member": "Customs agent is required for a non UEE member",
"Incoterms is required for a non UEE member": "Incoterms is required for a non UEE member",
@ -121,5 +122,6 @@
"Deny buy request": "Purchase request for ticket id [{{ticketId}}]({{{url}}}) has been rejected. Reason: {{observation}}",
"The type of business must be filled in basic data": "The type of business must be filled in basic data",
"The worker has hours recorded that day": "The worker has hours recorded that day",
"isWithoutNegatives": "isWithoutNegatives"
"isWithoutNegatives": "isWithoutNegatives",
"routeFk": "routeFk"
}

View File

@ -137,6 +137,7 @@
"Sent units from ticket": "Envio *{{quantity}}* unidades de [{{concept}} ({{itemId}})]({{{itemUrl}}}) a *\"{{nickname}}\"* provenientes del ticket id [{{ticketId}}]({{{ticketUrl}}})",
"Claim will be picked": "Se recogerá el género de la reclamación [({{claimId}})]({{{claimUrl}}}) del cliente *{{clientName}}*",
"Claim state has changed to incomplete": "Se ha cambiado el estado de la reclamación [({{claimId}})]({{{claimUrl}}}) del cliente *{{clientName}}* a *incompleta*",
"Claim state has changed to canceled": "Se ha cambiado el estado de la reclamación [({{claimId}})]({{{claimUrl}}}) del cliente *{{clientName}}* a *anulado*",
"This ticket is not an stowaway anymore": "El ticket id [{{ticketId}}]({{{ticketUrl}}}) ha dejado de ser un polizón",
"Client checked as validated despite of duplication": "Cliente comprobado a pesar de que existe el cliente id {{clientId}}",
"ORDER_ROW_UNAVAILABLE": "No hay disponibilidad de este producto",
@ -219,5 +220,8 @@
"You can not modify is pay method checked": "No se puede modificar el campo método de pago validado",
"Can't transfer claimed sales": "No puedes transferir lineas reclamadas",
"You don't have privileges to create pay back": "No tienes permisos para crear un abono",
"The item is required": "El artículo es requerido"
"The item is required": "El artículo es requerido",
"The agency is already assigned to another autonomous": "La agencia ya está asignada a otro autónomo",
"date in the future": "Fecha en el futuro",
"reference duplicated": "Referencia duplicada"
}

View File

@ -26,7 +26,6 @@ module.exports = Self => {
Self.sync = async function(userName, password, force) {
let $ = Self.app.models;
let user = await $.Account.findOne({
fields: ['id'],
where: {name: userName}

View File

@ -1,7 +1,13 @@
module.exports = Self => {
Self.getSynchronizer = async function() {
return await Self.findOne({fields: ['id']});
let NODE_ENV = process.env.NODE_ENV;
if (!NODE_ENV || NODE_ENV == 'development')
return null;
return await Self.findOne({
fields: ['id', 'rolePrefix', 'userPrefix', 'userHost']
});
};
Object.assign(Self.prototype, {
@ -14,17 +20,16 @@ module.exports = Self => {
},
async syncUser(userName, info, password) {
const mysqlHost = '%';
let mysqlUser = userName;
if (this.dbType == 'MySQL') mysqlUser = `!${mysqlUser}`;
if (this.dbType == 'MySQL')
mysqlUser = this.userPrefix + mysqlUser;
const [row] = await Self.rawSql(
`SELECT COUNT(*) AS nRows
FROM mysql.user
WHERE User = ?
AND Host = ?`,
[mysqlUser, mysqlHost]
[mysqlUser, this.userHost]
);
let userExists = row.nRows > 0;
@ -35,11 +40,10 @@ module.exports = Self => {
FROM mysql.global_priv
WHERE User = ?
AND Host = ?`,
[mysqlUser, mysqlHost]
[mysqlUser, this.userHost]
);
const priv = row && JSON.parse(row.priv);
const role = priv && priv.default_role;
isUpdatable = !row || (role && role.startsWith('z-'));
isUpdatable = !row || (priv && priv.autogenerated);
}
if (!isUpdatable) {
@ -51,31 +55,27 @@ module.exports = Self => {
if (password) {
if (!userExists) {
await Self.rawSql('CREATE USER ?@? IDENTIFIED BY ?',
[mysqlUser, mysqlHost, password]
);
[mysqlUser, this.userHost, password]);
userExists = true;
} else {
switch (this.dbType) {
case 'MariaDB':
await Self.rawSql('ALTER USER ?@? IDENTIFIED BY ?',
[mysqlUser, mysqlHost, password]
);
[mysqlUser, this.userHost, password]);
break;
default:
await Self.rawSql('SET PASSWORD FOR ?@? = PASSWORD(?)',
[mysqlUser, mysqlHost, password]
);
[mysqlUser, this.userHost, password]);
}
}
}
if (userExists && this.dbType == 'MariaDB') {
let role = `z-${info.user.role().name}`;
let role = `${this.rolePrefix}${info.user.role().name}`;
try {
await Self.rawSql('REVOKE ALL, GRANT OPTION FROM ?@?',
[mysqlUser, mysqlHost]
);
[mysqlUser, this.userHost]);
} catch (err) {
if (err.code == 'ER_REVOKE_GRANTS')
console.warn(`${err.code}: ${err.sqlMessage}: ${err.sql}`);
@ -83,21 +83,18 @@ module.exports = Self => {
throw err;
}
await Self.rawSql('GRANT ? TO ?@?',
[role, mysqlUser, mysqlHost]
);
[role, mysqlUser, this.userHost]);
if (role) {
await Self.rawSql('SET DEFAULT ROLE ? FOR ?@?',
[role, mysqlUser, mysqlHost]
);
[role, mysqlUser, this.userHost]);
} else {
await Self.rawSql('SET DEFAULT ROLE NONE FOR ?@?',
[mysqlUser, mysqlHost]
);
[mysqlUser, this.userHost]);
}
}
} else if (userExists)
await Self.rawSql('DROP USER ?@?', [mysqlUser, mysqlHost]);
await Self.rawSql('DROP USER ?@?', [mysqlUser, this.userHost]);
}
});
};

View File

@ -16,6 +16,18 @@
},
"mysqlPassword": {
"type": "string"
},
"rolePrefix": {
"type": "string"
},
"userPrefix": {
"type": "string"
},
"userHost": {
"type": "string"
},
"tplUser": {
"type": "string"
}
}
}

View File

@ -1,61 +0,0 @@
module.exports = Self => {
Self.remoteMethodCtx('importTicketSales', {
description: 'Imports lines from claimBeginning to a new ticket with specific shipped, landed dates, agency and company',
accessType: 'WRITE',
accepts: [{
arg: 'params',
type: 'object',
http: {source: 'body'}
}],
returns: {
type: ['Object'],
root: true
},
http: {
path: `/importTicketSales`,
verb: 'POST'
}
});
Self.importTicketSales = async(ctx, params, options) => {
let models = Self.app.models;
let userId = ctx.req.accessToken.userId;
let tx;
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
try {
const worker = await models.Worker.findOne({where: {userFk: userId}}, myOptions);
let ticketSales = await models.Sale.find({
where: {ticketFk: params.ticketFk}
}, myOptions);
let claimEnds = [];
ticketSales.forEach(sale => {
claimEnds.push({
saleFk: sale.id,
claimFk: params.claimFk,
workerFk: worker.id
});
});
const createdClaimEnds = await Self.create(claimEnds, myOptions);
if (tx) await tx.commit();
return createdClaimEnds;
} catch (e) {
if (tx) await tx.rollback();
throw e;
}
};
};

View File

@ -1,26 +0,0 @@
const app = require('vn-loopback/server/server');
describe('Claim importTicketSales()', () => {
it('should import sales to a claim actions from an specific ticket', async() => {
const ctx = {req: {accessToken: {userId: 5}}};
const tx = await app.models.Entry.beginTransaction({});
try {
const options = {transaction: tx};
const claimEnds = await app.models.ClaimEnd.importTicketSales(ctx, {
claimFk: 1,
ticketFk: 1
}, options);
expect(claimEnds.length).toEqual(4);
expect(claimEnds[0].saleFk).toEqual(1);
expect(claimEnds[2].saleFk).toEqual(3);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});

View File

@ -94,19 +94,14 @@ module.exports = Self => {
? {'cl.id': value}
: {
or: [
{'c.name': {like: `%${value}%`}}
{'cl.socialName': {like: `%${value}%`}}
]
};
case 'client':
return {'c.name': {like: `%${value}%`}};
case 'id':
return {'cl.id': value};
case 'clientFk':
return {'c.id': value};
case 'claimStateFk':
return {'cl.claimStateFk': value};
case 'priority':
return {[`cl.${param}`]: value};
case 'salesPersonFk':
return {'c.salesPersonFk': value};
case 'attenderFk':
return {'cl.workerFk': value};
case 'created':
@ -123,12 +118,23 @@ module.exports = Self => {
const stmts = [];
const stmt = new ParameterizedSQL(
`SELECT cl.id, c.name, cl.clientFk, cl.workerFk, u.name AS userName, cs.description, cl.created
FROM claim cl
LEFT JOIN client c ON c.id = cl.clientFk
LEFT JOIN worker w ON w.id = cl.workerFk
LEFT JOIN account.user u ON u.id = w.userFk
LEFT JOIN claimState cs ON cs.id = cl.claimStateFk`
`SELECT *
FROM (
SELECT
cl.id,
cl.clientFk,
c.socialName,
cl.workerFk,
u.name AS workerName,
cs.description,
cl.created,
cs.priority,
cl.claimStateFk
FROM claim cl
LEFT JOIN client c ON c.id = cl.clientFk
LEFT JOIN worker w ON w.id = cl.workerFk
LEFT JOIN account.user u ON u.id = w.userFk
LEFT JOIN claimState cs ON cs.id = cl.claimStateFk ) cl`
);
stmt.merge(conn.makeSuffix(filter));

View File

@ -1,5 +1,5 @@
module.exports = Self => {
Self.remoteMethod('getSummary', {
Self.remoteMethodCtx('getSummary', {
description: 'Return the claim summary',
accessType: 'READ',
accepts: [{
@ -19,7 +19,7 @@ module.exports = Self => {
}
});
Self.getSummary = async(id, options) => {
Self.getSummary = async(ctx, id, options) => {
const myOptions = {};
if (typeof options == 'object')
@ -135,6 +135,7 @@ module.exports = Self => {
const res = await Promise.all(promises);
summary.isEditable = await Self.isEditable(ctx, id, myOptions);
[summary.claim] = res[0];
summary.salesClaimed = res[1];
summary.developments = res[2];

View File

@ -1,6 +1,7 @@
module.exports = Self => {
Self.remoteMethodCtx('regularizeClaim', {
description: 'Imports lines from claimBeginning to a new ticket with specific shipped, landed dates, agency and company',
description: `Imports lines from claimBeginning to a new ticket
with specific shipped, landed dates, agency and company`,
accessType: 'WRITE',
accepts: [{
arg: 'id',

View File

@ -57,7 +57,7 @@ describe('Claim createFromSales()', () => {
const todayMinusEightDays = new Date();
todayMinusEightDays.setDate(todayMinusEightDays.getDate() - 8);
const ticket = await models.Ticket.findById(ticketId, options);
const ticket = await models.Ticket.findById(ticketId, null, options);
await ticket.updateAttribute('landed', todayMinusEightDays, options);
const claim = await models.Claim.createFromSales(ctx, ticketId, newSale, options);
@ -88,7 +88,7 @@ describe('Claim createFromSales()', () => {
const todayMinusEightDays = new Date();
todayMinusEightDays.setDate(todayMinusEightDays.getDate() - 8);
const ticket = await models.Ticket.findById(ticketId, options);
const ticket = await models.Ticket.findById(ticketId, null, options);
await ticket.updateAttribute('landed', todayMinusEightDays, options);
await models.Claim.createFromSales(ctx, ticketId, newSale, options);

View File

@ -25,7 +25,7 @@ describe('claim filter()', () => {
try {
const options = {transaction: tx};
const result = await app.models.Claim.filter({args: {filter: {}, search: 'Tony Stark'}}, null, options);
const result = await app.models.Claim.filter({args: {filter: {}, search: 'Iron man'}}, null, options);
expect(result.length).toEqual(1);
expect(result[0].id).toEqual(4);

View File

@ -3,17 +3,24 @@ const app = require('vn-loopback/server/server');
describe('claim getSummary()', () => {
it('should return summary with claim, salesClaimed, developments and actions defined ', async() => {
const tx = await app.models.Claim.beginTransaction({});
const ctx = {
req: {
accessToken: {
userId: 9
}
}
};
try {
const options = {transaction: tx};
const result = await app.models.Claim.getSummary(1, options);
const result = await app.models.Claim.getSummary(ctx, 1, options);
const keys = Object.keys(result);
expect(keys).toContain('claim');
expect(keys).toContain('salesClaimed');
expect(keys).toContain('developments');
expect(keys).toContain('actions');
expect(keys).toContain('isEditable');
await tx.rollback();
} catch (e) {

View File

@ -1,9 +1,10 @@
const app = require('vn-loopback/server/server');
const models = require('vn-loopback/server/server').models;
describe('claim regularizeClaim()', () => {
const userId = 18;
const ctx = {
req: {
accessToken: {userId: 18},
accessToken: {userId: userId},
headers: {origin: 'http://localhost'}
}
};
@ -11,8 +12,9 @@ describe('claim regularizeClaim()', () => {
return params.nickname;
};
const chatModel = app.models.Chat;
const claimFk = 1;
const chatModel = models.Chat;
const claimId = 1;
const ticketId = 1;
const pendentState = 1;
const resolvedState = 3;
const trashDestination = 2;
@ -21,27 +23,40 @@ describe('claim regularizeClaim()', () => {
let claimEnds = [];
let trashTicket;
async function importTicket(ticketId, claimId, userId, options) {
const ticketSales = await models.Sale.find({
where: {ticketFk: ticketId}
}, options);
const claimEnds = [];
for (let sale of ticketSales) {
claimEnds.push({
saleFk: sale.id,
claimFk: claimId,
workerFk: userId
});
}
return await models.ClaimEnd.create(claimEnds, options);
}
it('should send a chat message with value "Trash" and then change claim state to resolved', async() => {
const tx = await app.models.Claim.beginTransaction({});
const tx = await models.Claim.beginTransaction({});
try {
const options = {transaction: tx};
spyOn(chatModel, 'sendCheckingPresence').and.callThrough();
claimEnds = await app.models.ClaimEnd.importTicketSales(ctx, {
claimFk: claimFk,
ticketFk: 1
}, options);
claimEnds = await importTicket(ticketId, claimId, userId, options);
for (claimEnd of claimEnds)
await claimEnd.updateAttributes({claimDestinationFk: trashDestination}, options);
let claimBefore = await app.models.Claim.findById(claimFk, null, options);
await app.models.Claim.regularizeClaim(ctx, claimFk, options);
let claimAfter = await app.models.Claim.findById(claimFk, null, options);
let claimBefore = await models.Claim.findById(claimId, null, options);
await models.Claim.regularizeClaim(ctx, claimId, options);
let claimAfter = await models.Claim.findById(claimId, null, options);
trashTicket = await app.models.Ticket.findOne({where: {addressFk: 12}}, options);
trashTicket = await models.Ticket.findOne({where: {addressFk: 12}}, options);
expect(trashTicket.addressFk).toEqual(trashAddress);
expect(claimBefore.claimStateFk).toEqual(pendentState);
@ -57,22 +72,19 @@ describe('claim regularizeClaim()', () => {
});
it('should send a chat message with value "Bueno" and then change claim state to resolved', async() => {
const tx = await app.models.Claim.beginTransaction({});
const tx = await models.Claim.beginTransaction({});
try {
const options = {transaction: tx};
spyOn(chatModel, 'sendCheckingPresence').and.callThrough();
claimEnds = await app.models.ClaimEnd.importTicketSales(ctx, {
claimFk: claimFk,
ticketFk: 1
}, options);
claimEnds = await importTicket(ticketId, claimId, userId, options);
for (claimEnd of claimEnds)
await claimEnd.updateAttributes({claimDestinationFk: okDestination}, options);
await app.models.Claim.regularizeClaim(ctx, claimFk, options);
await models.Claim.regularizeClaim(ctx, claimId, options);
expect(chatModel.sendCheckingPresence).toHaveBeenCalledWith(ctx, 18, 'Bueno');
expect(chatModel.sendCheckingPresence).toHaveBeenCalledTimes(4);
@ -85,22 +97,19 @@ describe('claim regularizeClaim()', () => {
});
it('should send a chat message to the salesPerson when claim isPickUp is enabled', async() => {
const tx = await app.models.Claim.beginTransaction({});
const tx = await models.Claim.beginTransaction({});
try {
const options = {transaction: tx};
spyOn(chatModel, 'sendCheckingPresence').and.callThrough();
claimEnds = await app.models.ClaimEnd.importTicketSales(ctx, {
claimFk: claimFk,
ticketFk: 1
}, options);
claimEnds = await importTicket(ticketId, claimId, userId, options);
for (claimEnd of claimEnds)
await claimEnd.updateAttributes({claimDestinationFk: okDestination}, options);
await app.models.Claim.regularizeClaim(ctx, claimFk, options);
await models.Claim.regularizeClaim(ctx, claimId, options);
expect(chatModel.sendCheckingPresence).toHaveBeenCalledWith(ctx, 18, 'Bueno');
expect(chatModel.sendCheckingPresence).toHaveBeenCalledTimes(4);

View File

@ -47,7 +47,7 @@ describe('Update Claim', () => {
expect(error.message).toEqual(`You don't have enough privileges to change that field`);
});
it(`should success to update the claim within privileges `, async() => {
it(`should success to update the claimState to 'canceled' and send a rocket message`, async() => {
const tx = await app.models.Claim.beginTransaction({});
try {
@ -55,13 +55,15 @@ describe('Update Claim', () => {
const newClaim = await app.models.Claim.create(originalData, options);
const chatModel = app.models.Chat;
spyOn(chatModel, 'sendCheckingPresence').and.callThrough();
const canceledState = 4;
const claimManagerId = 72;
const ctx = {
req: {
accessToken: {
userId: claimManagerId
}
accessToken: {userId: claimManagerId},
headers: {origin: 'http://localhost'}
},
args: {
observation: 'valid observation',
@ -69,11 +71,56 @@ describe('Update Claim', () => {
hasToPickUp: false
}
};
ctx.req.__ = (value, params) => {
return params.nickname;
};
await app.models.Claim.updateClaim(ctx, newClaim.id, options);
let updatedClaim = await app.models.Claim.findById(newClaim.id, null, options);
expect(updatedClaim.observation).toEqual(ctx.args.observation);
expect(chatModel.sendCheckingPresence).toHaveBeenCalled();
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it(`should success to update the claimState to 'incomplete' and send a rocket message`, async() => {
const tx = await app.models.Claim.beginTransaction({});
try {
const options = {transaction: tx};
const newClaim = await app.models.Claim.create(originalData, options);
const chatModel = app.models.Chat;
spyOn(chatModel, 'sendCheckingPresence').and.callThrough();
const incompleteState = 5;
const claimManagerId = 72;
const ctx = {
req: {
accessToken: {userId: claimManagerId},
headers: {origin: 'http://localhost'}
},
args: {
observation: 'valid observation',
claimStateFk: incompleteState,
hasToPickUp: false
}
};
ctx.req.__ = (value, params) => {
return params.nickname;
};
await app.models.Claim.updateClaim(ctx, newClaim.id, options);
let updatedClaim = await app.models.Claim.findById(newClaim.id, null, options);
expect(updatedClaim.observation).toEqual(ctx.args.observation);
expect(chatModel.sendCheckingPresence).toHaveBeenCalled();
await tx.rollback();
} catch (e) {

View File

@ -28,6 +28,10 @@ module.exports = Self => {
{
arg: 'hasToPickUp',
type: 'boolean'
},
{
arg: 'packages',
type: 'number'
}],
returns: {
type: 'object',
@ -92,9 +96,12 @@ module.exports = Self => {
// When claimState has been changed
if (args.claimStateFk) {
const newState = await models.ClaimState.findById(args.claimStateFk, null, options);
if (newState.code == 'incomplete')
notifyStateChange(ctx, salesPerson.id, claim);
if (newState.hasToNotify) {
if (newState.code == 'incomplete')
notifyStateChange(ctx, salesPerson.id, claim, newState.code);
if (newState.code == 'canceled')
notifyStateChange(ctx, claim.workerFk, claim, newState.code);
}
}
if (tx) await tx.commit();
@ -121,11 +128,12 @@ module.exports = Self => {
return canUpdate;
}
async function notifyStateChange(ctx, workerId, claim) {
const origin = ctx.req.headers.origin;
async function notifyStateChange(ctx, workerId, claim, state) {
const models = Self.app.models;
const origin = ctx.req.headers.origin;
const $t = ctx.req.__; // $translate
const message = $t('Claim state has changed to incomplete', {
const message = $t(`Claim state has changed to ${state}`, {
claimId: claim.id,
clientName: claim.client().name,
claimUrl: `${origin}/#!/claim/${claim.id}/summary`

View File

@ -1,6 +1,11 @@
{
"name": "ClaimBeginning",
"base": "VnModel",
"base": "Loggable",
"log": {
"model": "ClaimLog",
"relation": "claim",
"showField": "quantity"
},
"options": {
"mysql": {
"table": "claimBeginning"

View File

@ -1,6 +1,10 @@
{
"name": "ClaimDevelopment",
"base": "VnModel",
"base": "Loggable",
"log": {
"model": "ClaimLog",
"relation": "claim"
},
"options": {
"mysql": {
"table": "claimDevelopment"

View File

@ -1,3 +0,0 @@
module.exports = Self => {
require('../methods/claim-end/importTicketSales')(Self);
};

View File

@ -1,6 +1,10 @@
{
"name": "ClaimEnd",
"base": "VnModel",
"base": "Loggable",
"log": {
"model": "ClaimLog",
"relation": "claim"
},
"options": {
"mysql": {
"table": "claimEnd"

View File

@ -1,6 +1,11 @@
{
"name": "ClaimState",
"base": "VnModel",
"base": "Loggable",
"log": {
"model": "ClaimLog",
"relation": "claim",
"showField": "description"
},
"options": {
"mysql": {
"table": "claimState"
@ -8,20 +13,24 @@
},
"properties": {
"id": {
"type": "Number",
"type": "number",
"id": true,
"description": "Identifier"
},
"code": {
"type": "String",
"type": "string",
"required": true
},
"description": {
"type": "String",
"type": "string",
"required": true
},
"priority": {
"type": "Number",
"type": "number",
"required": true
},
"hasToNotify": {
"type": "boolean",
"required": true
}
},

View File

@ -1,6 +1,10 @@
{
"name": "Claim",
"base": "VnModel",
"base": "Loggable",
"log": {
"model": "ClaimLog",
"showField": "id"
},
"options": {
"mysql": {
"table": "claim"
@ -39,6 +43,9 @@
},
"workerFk": {
"type": "number"
},
"packages": {
"type": "number"
}
},
"relations": {

View File

@ -24,15 +24,9 @@
<vn-button
label="Import claim"
disabled="$ctrl.claim.claimStateFk == $ctrl.resolvedStateId"
vn-http-click="$ctrl.importToNewRefundTicket()"p
vn-http-click="$ctrl.importToNewRefundTicket()"
translate-attr="{title: 'Imports claim details'}">
</vn-button>
<vn-button
label="Import ticket"
disabled="$ctrl.claim.claimStateFk == $ctrl.resolvedStateId"
ng-click="$ctrl.showLastTickets($event)"
translate-attr="{title: 'Imports ticket lines'}">
</vn-button>
<vn-range
label="Responsability"
min-label="Company"
@ -121,38 +115,6 @@
</vn-button>
</vn-button-bar>
</vn-card>
<vn-crud-model
vn-id="lastTicketsModel"
url="Tickets"
limit="20"
data="lastTickets" auto-load="false">
</vn-crud-model>
<!-- Transfer Popover -->
<vn-popover class="lastTicketsPopover" vn-id="lastTicketsPopover">
<div class="ticketList vn-pa-md">
<vn-table model="lastTicketsModel" auto-load="false">
<vn-thead>
<vn-tr>
<vn-th field="id" number>ID</vn-th>
<vn-th field="shipped" default-order="DESC">F. envio</vn-th>
<vn-th>Agencia</vn-th>
<vn-th>Almacen</vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>
<vn-tr
class="clickable"
ng-repeat="ticket in lastTickets"
ng-click="$ctrl.importTicketLines(ticket.id)">
<vn-td number>{{::ticket.id}}</vn-td>
<vn-td>{{::ticket.shipped | date: 'dd/MM/yyyy'}}</vn-td>
<vn-td>{{::ticket.agencyMode.name}}</vn-td>
<vn-td>{{::ticket.warehouse.name}}</vn-td>
</vn-tr>
</vn-tbody>
</vn-table>
</div>
</vn-popover>
<vn-item-descriptor-popover
vn-id="item-descriptor"
warehouse-fk="$ctrl.vnConfig.warehouseFk">

View File

@ -60,36 +60,6 @@ export default class Controller extends Section {
});
}
showLastTickets(event) {
let pastWeek = new Date();
pastWeek.setDate(-7);
let filter = {
include: [
{relation: 'agencyMode', fields: ['name']},
{relation: 'warehouse', fields: ['name']}
],
where: {
created: {gt: pastWeek},
clientFk: this.claim.clientFk
}
};
this.$.lastTicketsModel.filter = filter;
this.$.lastTicketsModel.refresh();
this.$.lastTicketsPopover.show(event);
}
importTicketLines(ticketFk) {
let data = {claimFk: this.$params.id, ticketFk: ticketFk};
let query = `ClaimEnds/importTicketSales`;
this.$http.post(query, data).then(() => {
this.vnApp.showSuccess(this.$t('Data saved!'));
this.$.lastTicketsPopover.hide();
this.$.model.refresh();
});
}
regularize() {
const query = `Claims/${this.$params.id}/regularizeClaim`;
return this.$http.post(query).then(() => {

View File

@ -67,35 +67,6 @@ describe('claim', () => {
});
});
describe('showLastTickets()', () => {
it('should get a list of tickets and call lastTicketsPopover show() method', () => {
jest.spyOn(controller.$.lastTicketsModel, 'refresh');
jest.spyOn(controller.$.lastTicketsPopover, 'show');
controller.showLastTickets({});
expect(controller.$.lastTicketsModel.refresh).toHaveBeenCalled();
expect(controller.$.lastTicketsPopover.show).toHaveBeenCalled();
});
});
describe('importTicketLines()', () => {
it('should perform a post query and add lines from an existent ticket', () => {
jest.spyOn(controller.$.model, 'refresh');
jest.spyOn(controller.vnApp, 'showSuccess');
jest.spyOn(controller.$.lastTicketsPopover, 'hide');
let data = {claimFk: 1, ticketFk: 1};
$httpBackend.expect('POST', `ClaimEnds/importTicketSales`, data).respond({});
controller.importTicketLines(1);
$httpBackend.flush();
expect(controller.$.model.refresh).toHaveBeenCalledWith();
expect(controller.vnApp.showSuccess).toHaveBeenCalled();
expect(controller.$.lastTicketsPopover.hide).toHaveBeenCalledWith();
});
});
describe('regularize()', () => {
it('should perform a post query and reload the claim card', () => {
jest.spyOn(controller.card, 'reload');

View File

@ -3,8 +3,6 @@ Action: Actuaciones
Total claimed: Total Reclamado
Import claim: Importar reclamacion
Imports claim details: Importa detalles de la reclamacion
Import ticket: Importar ticket
Imports ticket lines: Importa las lineas de un ticket
Regularize: Regularizar
Do you want to insert greuges?: Desea insertar greuges?
Insert greuges on client card: Insertar greuges en la ficha del cliente

View File

@ -43,7 +43,14 @@
order="priority ASC"
vn-focus>
</vn-autocomplete>
</vn-horizontal>
</vn-horizontal>
<vn-horizontal>
<vn-input-number vn-one
min="0"
type="number"
label="Packages received"
ng-model="$ctrl.claim.packages">
</vn-input-number>
</vn-horizontal>
<vn-horizontal>
<vn-textarea

View File

@ -5,4 +5,5 @@ Responsability: Responsabilidad
Company: Empresa
Sales/Client: Comercial/Cliente
Pick up: Recoger
When checked will notify a pickup to the salesPerson: Cuando se marque enviará una notificación de recogida al comercial
When checked will notify a pickup to the salesPerson: Cuando se marque enviará una notificación de recogida al comercial
Packages received: Bultos recibidos

View File

@ -78,6 +78,11 @@
</vn-table>
</vn-card>
</vn-data-viewer>
<vn-button
label="Next"
class="next"
ui-sref="claim.card.photos">
</vn-button>
<vn-float-button
icon="add"
ng-if="$ctrl.isRewritable"

View File

@ -25,3 +25,6 @@
}
}
.next{
float: right;
}

View File

@ -11,3 +11,4 @@ import './development';
import './search-panel';
import './summary';
import './photos';
import './log';

View File

@ -1,59 +1,74 @@
<vn-auto-search
model="model">
</vn-auto-search>
<vn-data-viewer
model="model"
class="vn-w-lg">
<vn-card>
<vn-table model="model">
<vn-thead>
<vn-tr>
<vn-th field="id" number>Id</vn-th>
<vn-th field="clientFk">Client</vn-th>
<vn-th field="created" center shrink-date>Created</vn-th>
<vn-th field="workerFk">Worker</vn-th>
<vn-th field="claimStateFk">State</vn-th>
<vn-th></vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>
<a
ng-repeat="claim in model.data"
class="{{::$ctrl.compareDate(ticket.shipped)}} clickable vn-tr search-result"
ui-sref="claim.card.summary({id: claim.id})">
<vn-td number>{{::claim.id}}</vn-td>
<vn-td expand>
<span
vn-click-stop="clientDescriptor.show($event, claim.clientFk)"
class="link">
{{::claim.name}}
</span>
</vn-td>
<vn-td center shrink-date>{{::claim.created | date:'dd/MM/yyyy'}}</vn-td>
<vn-td expand>
<span
vn-click-stop="workerDescriptor.show($event, claim.workerFk)"
class="link" >
{{::claim.userName}}
</span>
</vn-td>
<vn-td>
<span class="chip {{::$ctrl.stateColor(claim)}}">
{{::claim.description}}
</span>
</vn-td>
<vn-td shrink>
<vn-icon-button
vn-click-stop="$ctrl.preview(claim)"
vn-tooltip="Preview"
icon="preview">
</vn-icon-button>
</vn-td>
</a>
</vn-tbody>
</vn-table>
</vn-card>
</vn-data-viewer>
<vn-card>
<smart-table
model="model"
options="$ctrl.smartTableOptions"
expr-builder="$ctrl.exprBuilder(param, value)">
<slot-table>
<table>
<thead>
<tr>
<th field="id" shrink>
<span translate>Id</span>
</th>
<th field="clientFk">
<span translate>Client</span>
</th>
<th field="created" center shrink-date>
<span translate>Created</span>
</th>
<th field="salesPersonFk">
<span translate>Worker</span>
</th>
<th field="claimStateFk">
<span translate>State</span>
</th>
<th></th>
</tr>
</thead>
<tbody>
<tr
ng-repeat="claim in model.data"
vn-anchor="::{
state: 'claim.card.summary',
params: {id: claim.id}
}">
<td>{{::claim.id}}</td>
<td>
<span
vn-click-stop="clientDescriptor.show($event, claim.clientFk)"
class="link">
{{::claim.socialName}}
</span>
</td>
<td center shrink-date>{{::claim.created | date:'dd/MM/yyyy'}}</td>
<td>
<span
vn-click-stop="workerDescriptor.show($event, claim.workerFk)"
class="link" >
{{::claim.workerName}}
</span>
</td>
<td>
<span class="chip {{::$ctrl.stateColor(claim)}}">
{{::claim.description}}
</span>
</td>
<td shrink>
<vn-icon-button
vn-click-stop="$ctrl.preview(claim)"
vn-tooltip="Preview"
icon="preview">
</vn-icon-button>
</td>
</tr>
</tbody>
</table>
</slot-table>
</smart-table>
</vn-card>
<vn-client-descriptor-popover
vn-id="clientDescriptor">
</vn-client-descriptor-popover>
@ -62,6 +77,7 @@
</vn-worker-descriptor-popover>
<vn-popup vn-id="summary">
<vn-claim-summary
claim="$ctrl.claimSelected">
claim="$ctrl.claimSelected"
parent-reload="$ctrl.reload()">
</vn-claim-summary>
</vn-popup>

View File

@ -1,7 +1,69 @@
import ngModule from '../module';
import Section from 'salix/components/section';
export default class Controller extends Section {
class Controller extends Section {
constructor($element, $) {
super($element, $);
this.smartTableOptions = {
activeButtons: {
search: true
},
columns: [
{
field: 'clientFk',
autocomplete: {
url: 'Clients',
showField: 'socialName',
valueField: 'socialName'
}
},
{
field: 'workerFk',
autocomplete: {
url: 'Workers/activeWithInheritedRole',
where: `{role: 'salesPerson'}`,
searchFunction: '{firstName: $search}',
showField: 'name',
valueField: 'id',
}
},
{
field: 'claimStateFk',
autocomplete: {
url: 'ClaimStates',
showField: 'description',
valueField: 'id',
}
},
{
field: 'created',
searchable: false
}
]
};
}
exprBuilder(param, value) {
switch (param) {
case 'clientFk':
return {['cl.socialName']: value};
case 'id':
case 'claimStateFk':
case 'priority':
return {[`cl.${param}`]: value};
case 'salesPersonFk':
case 'attenderFk':
return {'cl.workerFk': value};
case 'created':
value.setHours(0, 0, 0, 0);
to = new Date(value);
to.setHours(23, 59, 59, 999);
return {'cl.created': {between: [value, to]}};
}
}
stateColor(claim) {
switch (claim.description) {
case 'Pendiente':
@ -17,6 +79,10 @@ export default class Controller extends Section {
this.claimSelected = claim;
this.$.summary.show();
}
reload() {
this.$.model.refresh();
}
}
ngModule.vnComponent('vnClaimIndex', {

View File

@ -0,0 +1,4 @@
<vn-log
url="ClaimLogs"
origin-id="$ctrl.$params.id">
</vn-log>

View File

@ -0,0 +1,7 @@
import ngModule from '../module';
import Section from 'salix/components/section';
ngModule.vnComponent('vnClaimLog', {
template: require('./index.html'),
controller: Section,
});

Some files were not shown because too many files have changed in this diff Show More