Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix into puppeteer
This commit is contained in:
commit
f74792dbe9
|
@ -0,0 +1,138 @@
|
|||
const request = require('request-promise-native');
|
||||
module.exports = Self => {
|
||||
Self.remoteMethodCtx('send', {
|
||||
description: 'Send a RocketChat message',
|
||||
accessType: 'WRITE',
|
||||
accepts: [{
|
||||
arg: 'to',
|
||||
type: 'String',
|
||||
required: true,
|
||||
description: 'User (@) or channel (#) to send the message'
|
||||
}, {
|
||||
arg: 'message',
|
||||
type: 'String',
|
||||
required: true,
|
||||
description: 'The message'
|
||||
}],
|
||||
returns: {
|
||||
type: 'Object',
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/send`,
|
||||
verb: 'POST'
|
||||
}
|
||||
});
|
||||
|
||||
Self.send = async(ctx, to, message) => {
|
||||
const models = Self.app.models;
|
||||
const accessToken = ctx.req.accessToken;
|
||||
const sender = await models.Account.findById(accessToken.userId);
|
||||
const recipient = to.replace('@', '');
|
||||
|
||||
if (sender.name != recipient)
|
||||
return sendMessage(sender, to, `@${sender.name}: ${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,
|
||||
'text': message
|
||||
}).catch(async error => {
|
||||
if (error.statusCode === 401 && !this.resendAttempted) {
|
||||
this.resendAttempted = true;
|
||||
|
||||
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`;
|
||||
const res = await send(uri, {
|
||||
user: config.user,
|
||||
password: config.password
|
||||
});
|
||||
|
||||
this.auth = res.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 {*} body - Request params
|
||||
* @param {*} options - Request options
|
||||
*
|
||||
* @return {Object} Request response
|
||||
*/
|
||||
async function send(uri, body, options) {
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
return new Promise(resolve => {
|
||||
return resolve({statusCode: 200, message: 'Fake notification sent'});
|
||||
});
|
||||
}
|
||||
|
||||
const defaultOptions = {
|
||||
method: 'POST',
|
||||
uri: uri,
|
||||
body: body,
|
||||
headers: {'content-type': 'application/json'},
|
||||
json: true
|
||||
};
|
||||
|
||||
if (options) Object.assign(defaultOptions, options);
|
||||
|
||||
return request(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: {'content-type': 'application/json'}
|
||||
};
|
||||
|
||||
if (login) {
|
||||
options.headers['X-Auth-Token'] = login.authToken;
|
||||
options.headers['X-User-Id'] = login.userId;
|
||||
}
|
||||
|
||||
return send(uri, body, options);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,53 @@
|
|||
module.exports = Self => {
|
||||
Self.remoteMethodCtx('sendCheckingPresence', {
|
||||
description: 'Sends a RocketChat message to a working worker or department channel',
|
||||
accessType: 'WRITE',
|
||||
accepts: [{
|
||||
arg: 'workerId',
|
||||
type: 'Number',
|
||||
required: true,
|
||||
description: 'The worker id of the destinatary'
|
||||
}, {
|
||||
arg: 'message',
|
||||
type: 'String',
|
||||
required: true,
|
||||
description: 'The message'
|
||||
}],
|
||||
returns: {
|
||||
type: 'Object',
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/sendCheckingPresence`,
|
||||
verb: 'POST'
|
||||
}
|
||||
});
|
||||
|
||||
Self.sendCheckingPresence = async(ctx, workerId, message) => {
|
||||
const models = Self.app.models;
|
||||
const account = await models.Account.findById(workerId);
|
||||
|
||||
const query = `SELECT worker_isWorking(?) isWorking`;
|
||||
const [result] = await Self.rawSql(query, [workerId]);
|
||||
|
||||
let room;
|
||||
if (result.isWorking)
|
||||
room = `@${account.name}`;
|
||||
else {
|
||||
const workerDepartment = await models.WorkerDepartment.findById(workerId, {
|
||||
include: {
|
||||
relation: 'department'
|
||||
}
|
||||
});
|
||||
const department = workerDepartment.department();
|
||||
const channelName = department.chatName;
|
||||
room = `#${channelName}`;
|
||||
|
||||
if (channelName)
|
||||
room = `#${channelName}`;
|
||||
else room = `@${account.name}`;
|
||||
}
|
||||
|
||||
return Self.send(ctx, room, message);
|
||||
};
|
||||
};
|
|
@ -1,4 +1,3 @@
|
|||
const request = require('request-promise-native');
|
||||
module.exports = Self => {
|
||||
Self.remoteMethodCtx('sendMessage', {
|
||||
description: 'Send a RocketChat message',
|
||||
|
@ -24,115 +23,8 @@ module.exports = Self => {
|
|||
}
|
||||
});
|
||||
|
||||
// FIXME: Deprecate this method #2019
|
||||
Self.sendMessage = async(ctx, to, message) => {
|
||||
const models = Self.app.models;
|
||||
const accessToken = ctx.req.accessToken;
|
||||
const sender = await models.Account.findById(accessToken.userId);
|
||||
const recipient = to.replace('@', '');
|
||||
|
||||
if (sender.name != recipient)
|
||||
return sendMessage(sender, to, `@${sender.name}: ${message} `);
|
||||
return Self.send(ctx, 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,
|
||||
'text': message
|
||||
}).catch(async error => {
|
||||
if (error.statusCode === 401 && !this.resendAttempted) {
|
||||
this.resendAttempted = true;
|
||||
|
||||
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`;
|
||||
const res = await send(uri, {
|
||||
user: config.user,
|
||||
password: config.password
|
||||
});
|
||||
|
||||
this.auth = res.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 {*} body - Request params
|
||||
* @param {*} options - Request options
|
||||
*
|
||||
* @return {Object} Request response
|
||||
*/
|
||||
async function send(uri, body, options) {
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
return new Promise(resolve => {
|
||||
return resolve({statusCode: 200, message: 'Fake notification sent'});
|
||||
});
|
||||
}
|
||||
|
||||
const defaultOptions = {
|
||||
method: 'POST',
|
||||
uri: uri,
|
||||
body: body,
|
||||
headers: {'content-type': 'application/json'},
|
||||
json: true
|
||||
};
|
||||
|
||||
if (options) Object.assign(defaultOptions, options);
|
||||
|
||||
return request(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: {'content-type': 'application/json'}
|
||||
};
|
||||
|
||||
if (login) {
|
||||
options.headers['X-Auth-Token'] = login.authToken;
|
||||
options.headers['X-User-Id'] = login.userId;
|
||||
}
|
||||
|
||||
return send(uri, body, options);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
|
||||
describe('chat sendMessage()', () => {
|
||||
describe('chat send()', () => {
|
||||
it('should return a "Fake notification sent" as response', async() => {
|
||||
let ctx = {req: {accessToken: {userId: 1}}};
|
||||
let response = await app.models.Chat.sendMessage(ctx, '@salesPerson', 'I changed something');
|
||||
let response = await app.models.Chat.send(ctx, '@salesPerson', 'I changed something');
|
||||
|
||||
expect(response.statusCode).toEqual(200);
|
||||
expect(response.message).toEqual('Fake notification sent');
|
||||
|
@ -11,7 +11,7 @@ describe('chat sendMessage()', () => {
|
|||
|
||||
it('should not return a response', async() => {
|
||||
let ctx = {req: {accessToken: {userId: 18}}};
|
||||
let response = await app.models.Chat.sendMessage(ctx, '@salesPerson', 'I changed something');
|
||||
let response = await app.models.Chat.send(ctx, '@salesPerson', 'I changed something');
|
||||
|
||||
expect(response).toBeUndefined();
|
||||
});
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
|
||||
describe('chat sendCheckingPresence()', () => {
|
||||
const departmentId = 23;
|
||||
const workerId = 107;
|
||||
let timeEntry;
|
||||
|
||||
afterAll(async done => {
|
||||
const department = await app.models.Department.findById(departmentId);
|
||||
await department.updateAttribute('chatName', null);
|
||||
await app.models.WorkerTimeControl.destroyById(timeEntry.id);
|
||||
done();
|
||||
});
|
||||
|
||||
it(`should call to send() method with the worker username when no department channel is specified
|
||||
and then return a "Fake notification sent" as response`, async() => {
|
||||
const ctx = {req: {accessToken: {userId: 1}}};
|
||||
const chatModel = app.models.Chat;
|
||||
spyOn(chatModel, 'send').and.callThrough();
|
||||
|
||||
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');
|
||||
});
|
||||
|
||||
it(`should call to send() method with the worker department channel if is specified
|
||||
and then return a "Fake notification sent" as response`, async() => {
|
||||
const ctx = {req: {accessToken: {userId: 1}}};
|
||||
const chatModel = app.models.Chat;
|
||||
spyOn(chatModel, 'send').and.callThrough();
|
||||
|
||||
const department = await app.models.Department.findById(departmentId);
|
||||
await department.updateAttribute('chatName', 'cooler');
|
||||
|
||||
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', 'I changed something');
|
||||
});
|
||||
|
||||
it(`should call to send() method with the worker username when the worker is working`, async() => {
|
||||
const ctx = {req: {accessToken: {userId: 1}}};
|
||||
const chatModel = app.models.Chat;
|
||||
spyOn(chatModel, 'send').and.callThrough();
|
||||
|
||||
const today = new Date();
|
||||
today.setHours(6, 0);
|
||||
|
||||
timeEntry = await app.models.WorkerTimeControl.create({
|
||||
userFk: workerId,
|
||||
timed: today,
|
||||
manual: false,
|
||||
direction: 'in'
|
||||
});
|
||||
|
||||
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');
|
||||
});
|
||||
});
|
|
@ -22,8 +22,10 @@ module.exports = Self => {
|
|||
|
||||
Self.removeFile = async(ctx, id) => {
|
||||
const models = Self.app.models;
|
||||
const trashDmsType = await models.DmsType.findOne({where: {code: 'trash'}});
|
||||
const dms = await models.Dms.findById(id);
|
||||
const trashDmsType = await models.DmsType.findOne({
|
||||
where: {code: 'trash'}
|
||||
});
|
||||
|
||||
const hasWriteRole = await models.DmsType.hasWriteRole(ctx, dms.dmsTypeFk);
|
||||
if (!hasWriteRole)
|
||||
|
|
|
@ -1,48 +0,0 @@
|
|||
module.exports = Self => {
|
||||
Self.remoteMethodCtx('send', {
|
||||
description: 'Send message to user',
|
||||
accessType: 'WRITE',
|
||||
accepts: [{
|
||||
arg: 'data',
|
||||
type: 'object',
|
||||
required: true,
|
||||
description: 'recipientFk, message',
|
||||
http: {source: 'body'}
|
||||
}, {
|
||||
arg: 'context',
|
||||
type: 'object',
|
||||
http: function(ctx) {
|
||||
return ctx;
|
||||
}
|
||||
}],
|
||||
returns: {
|
||||
type: 'boolean',
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/:recipient/send`,
|
||||
verb: 'post'
|
||||
}
|
||||
});
|
||||
|
||||
Self.send = async(ctx, data, options) => {
|
||||
const accessToken = ctx.options && ctx.options.accessToken || ctx.req && ctx.req.accessToken;
|
||||
const userId = accessToken.userId;
|
||||
const models = Self.app.models;
|
||||
const sender = await models.Account.findById(userId, null, options);
|
||||
const recipient = await models.Account.findById(data.recipientFk, null, options);
|
||||
|
||||
await Self.create({
|
||||
sender: sender.name,
|
||||
recipient: recipient.name,
|
||||
message: data.message
|
||||
}, options);
|
||||
|
||||
return await models.MessageInbox.create({
|
||||
sender: sender.name,
|
||||
recipient: recipient.name,
|
||||
finalRecipient: recipient.name,
|
||||
message: data.message
|
||||
}, options);
|
||||
};
|
||||
};
|
|
@ -1,14 +0,0 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
|
||||
describe('message send()', () => {
|
||||
it('should return a response containing the same message in params', async() => {
|
||||
let ctx = {req: {accessToken: {userId: 1}}};
|
||||
let params = {
|
||||
recipientFk: 1,
|
||||
message: 'I changed something'
|
||||
};
|
||||
let response = await app.models.Message.send(ctx, params, {transaction: 'You'});
|
||||
|
||||
expect(response.message).toEqual(params.message);
|
||||
});
|
||||
});
|
|
@ -23,12 +23,6 @@
|
|||
"Delivery": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"Message": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"MessageInbox": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"Province": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
|
@ -59,12 +53,6 @@
|
|||
"Postcode": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"UserPhoneType": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"UserPhone": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"UserLog": {
|
||||
"dataSource": "vn"
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
module.exports = Self => {
|
||||
require('../methods/chat/send')(Self);
|
||||
require('../methods/chat/sendMessage')(Self);
|
||||
require('../methods/chat/sendCheckingPresence')(Self);
|
||||
};
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
"name": "Dms",
|
||||
"description": "Documental Managment system",
|
||||
"base": "VnModel",
|
||||
"log": {
|
||||
"showField": "reference"
|
||||
},
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "dms"
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
{
|
||||
"name": "MessageInbox",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "messageInbox"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "Number",
|
||||
"id": true,
|
||||
"description": "Identifier"
|
||||
},
|
||||
"sender": {
|
||||
"type": "String",
|
||||
"required": true
|
||||
},
|
||||
"recipient": {
|
||||
"type": "String",
|
||||
"required": true
|
||||
},
|
||||
"finalRecipient": {
|
||||
"type": "String",
|
||||
"required": true
|
||||
},
|
||||
"message": {
|
||||
"type": "String"
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
"remitter": {
|
||||
"type": "belongsTo",
|
||||
"model": "User",
|
||||
"foreignKey": "sender"
|
||||
},
|
||||
"receptor": {
|
||||
"type": "belongsTo",
|
||||
"model": "User",
|
||||
"foreignKey": "recipient"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
module.exports = Self => {
|
||||
require('../methods/message/send')(Self);
|
||||
};
|
|
@ -1,39 +0,0 @@
|
|||
{
|
||||
"name": "Message",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "message"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "Number",
|
||||
"id": true,
|
||||
"description": "Identifier"
|
||||
},
|
||||
"sender": {
|
||||
"type": "String",
|
||||
"required": true
|
||||
},
|
||||
"recipient": {
|
||||
"type": "String",
|
||||
"required": true
|
||||
},
|
||||
"message": {
|
||||
"type": "String"
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
"remitter": {
|
||||
"type": "belongsTo",
|
||||
"model": "User",
|
||||
"foreignKey": "sender"
|
||||
},
|
||||
"receptor": {
|
||||
"type": "belongsTo",
|
||||
"model": "User",
|
||||
"foreignKey": "recipient"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
{
|
||||
"name": "UserPhoneType",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "userPhoneType"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"code": {
|
||||
"id": true,
|
||||
"type": "String"
|
||||
},
|
||||
"description": {
|
||||
"type": "String"
|
||||
}
|
||||
},
|
||||
"acls": [
|
||||
{
|
||||
"accessType": "READ",
|
||||
"principalType": "ROLE",
|
||||
"principalId": "$everyone",
|
||||
"permission": "ALLOW"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
let UserError = require('vn-loopback/util/user-error');
|
||||
|
||||
module.exports = Self => {
|
||||
Self.rewriteDbError(function(err) {
|
||||
if (err.code === 'ER_DUP_ENTRY')
|
||||
return new UserError(`This phone already exists`);
|
||||
return err;
|
||||
});
|
||||
};
|
|
@ -1,39 +0,0 @@
|
|||
{
|
||||
"name": "UserPhone",
|
||||
"base": "Loggable",
|
||||
"log": {
|
||||
"model":"UserLog",
|
||||
"relation": "user"
|
||||
},
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "userPhone"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"id": true,
|
||||
"type": "Number"
|
||||
},
|
||||
"phone": {
|
||||
"type": "Number",
|
||||
"required": true
|
||||
},
|
||||
"typeFk": {
|
||||
"type": "String",
|
||||
"required": true
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
"user": {
|
||||
"type": "belongsTo",
|
||||
"model": "Account",
|
||||
"foreignKey": "userFk"
|
||||
},
|
||||
"type": {
|
||||
"type": "belongsTo",
|
||||
"model": "UserPhoneType",
|
||||
"foreignKey": "typeFk"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,3 +1,3 @@
|
|||
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('Thermograph', '*', '*', 'ALLOW', 'ROLE', 'buyer');
|
||||
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('TravelThermograph', '*', '*', 'ALLOW', 'ROLE', 'buyer');
|
||||
|
||||
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('Entry', '*', '*', 'ALLOW', 'ROLE', 'buyer');
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE `vn`.`department`
|
||||
ADD COLUMN `chatName` VARCHAR(45) NULL AFTER `path`;
|
|
@ -0,0 +1,7 @@
|
|||
ALTER TABLE `vn`.`travelThermograph`
|
||||
ADD COLUMN `id` INT NOT NULL AUTO_INCREMENT FIRST,
|
||||
DROP PRIMARY KEY,
|
||||
ADD PRIMARY KEY (`id`);
|
||||
|
||||
ALTER TABLE `vn`.`travelThermograph`
|
||||
ADD UNIQUE INDEX `thermograph_created` (`thermographFk` ASC, `created` ASC) VISIBLE;
|
|
@ -0,0 +1,29 @@
|
|||
USE `bs`;
|
||||
DROP procedure IF EXISTS `weekWaste_getDetail`;
|
||||
|
||||
DELIMITER $$
|
||||
USE `bs`$$
|
||||
CREATE DEFINER=`root`@`%` PROCEDURE `weekWaste_getDetail`()
|
||||
BEGIN
|
||||
DECLARE vLastWeek DATE;
|
||||
DECLARE vWeek INT;
|
||||
DECLARE vYear INT;
|
||||
|
||||
SET vLastWeek = TIMESTAMPADD(WEEK,-1,CURDATE());
|
||||
SET vYear = YEAR(vLastWeek);
|
||||
SET vWeek = WEEK(vLastWeek, 1);
|
||||
|
||||
SELECT *, 100 * dwindle / total AS percentage
|
||||
FROM (
|
||||
SELECT buyer,
|
||||
ws.family,
|
||||
sum(ws.saleTotal) AS total,
|
||||
sum(ws.saleWaste) AS dwindle
|
||||
FROM bs.waste ws
|
||||
WHERE year = vYear AND week = vWeek
|
||||
GROUP BY buyer, family
|
||||
) sub
|
||||
ORDER BY percentage DESC;
|
||||
END$$
|
||||
|
||||
DELIMITER ;
|
|
@ -0,0 +1,32 @@
|
|||
USE `vn`;
|
||||
DROP function IF EXISTS `worker_isWorking`;
|
||||
|
||||
DELIMITER $$
|
||||
USE `vn`$$
|
||||
CREATE DEFINER=`root`@`%` FUNCTION `worker_isWorking`(vWorkerFk INT) RETURNS tinyint(1)
|
||||
READS SQL DATA
|
||||
BEGIN
|
||||
/**
|
||||
* Comprueba si el trabajador está trabajando en el momento de la consulta
|
||||
* @return Devuelve TRUE en caso de que este trabajando. Si se encuentra en un descanso devolverá FALSE
|
||||
*/
|
||||
DECLARE vLastIn DATETIME ;
|
||||
|
||||
SELECT MAX(timed) INTO vLastIn
|
||||
FROM vn.workerTimeControl
|
||||
WHERE userFk = vWorkerFk AND
|
||||
direction = 'in';
|
||||
|
||||
IF (SELECT MOD(COUNT(*),2)
|
||||
FROM vn.workerTimeControl
|
||||
WHERE userFk = vWorkerFk AND
|
||||
timed >= vLastIn
|
||||
) THEN
|
||||
RETURN TRUE;
|
||||
ELSE
|
||||
RETURN FALSE;
|
||||
END IF;
|
||||
END$$
|
||||
|
||||
DELIMITER ;
|
||||
|
File diff suppressed because one or more lines are too long
|
@ -68,13 +68,13 @@ INSERT INTO `account`.`user`(`id`,`name`,`nickname`, `password`,`role`,`active`,
|
|||
(111, 'Missing', 'Missing', 'ac754a330530832ba1bf7687f577da91', 2, 0, NULL, 'es'),
|
||||
(112, 'Trash', 'Trash', 'ac754a330530832ba1bf7687f577da91', 2, 0, NULL, 'es');
|
||||
|
||||
INSERT INTO `vn`.`worker`(`id`, `code`, `firstName`, `lastName`, `userFk`,`bossFk`)
|
||||
INSERT INTO `vn`.`worker`(`id`, `code`, `firstName`, `lastName`, `userFk`,`bossFk`, `phone`)
|
||||
VALUES
|
||||
(106, 'LGN', 'David Charles', 'Haller', 106, 19),
|
||||
(107, 'ANT', 'Hank' , 'Pym' , 107, 19),
|
||||
(108, 'DCX', 'Charles' , 'Xavier', 108, 19),
|
||||
(109, 'HLK', 'Bruce' , 'Banner', 109, 19),
|
||||
(110, 'JJJ', 'Jessica' , 'Jones' , 110, 19);
|
||||
(106, 'LGN', 'David Charles', 'Haller', 106, 19, 432978106),
|
||||
(107, 'ANT', 'Hank' , 'Pym' , 107, 19, 432978107),
|
||||
(108, 'DCX', 'Charles' , 'Xavier', 108, 19, 432978108),
|
||||
(109, 'HLK', 'Bruce' , 'Banner', 109, 19, 432978109),
|
||||
(110, 'JJJ', 'Jessica' , 'Jones' , 110, 19, 432978110);
|
||||
|
||||
INSERT INTO `vn`.`country`(`id`, `country`, `isUeeMember`, `code`, `currencyFk`, `ibanLength`)
|
||||
VALUES
|
||||
|
@ -216,21 +216,20 @@ INSERT INTO `vn`.`contactChannel`(`id`, `name`)
|
|||
(3, 'Daily Bugle'),
|
||||
(4, 'GCN Channel'),
|
||||
(5, 'The Newspaper');
|
||||
|
||||
INSERT INTO `vn`.`client`(`id`,`name`,`fi`,`socialName`,`contact`,`street`,`city`,`postcode`,`fax`,`isRelevant`,`email`,`iban`,`dueDay`,`accountingAccount`,`isEqualizated`,`provinceFk`,`hasToInvoice`,`credit`,`countryFk`,`isActive`,`gestdocFk`,`quality`,`payMethodFk`,`created`,`isToBeMailed`,`contactChannelFk`,`hasSepaVnl`,`hasCoreVnl`,`hasCoreVnh`,`riskCalculated`,`clientTypeFk`,`mailAddress`,`cplusTerIdNifFk`,`hasToInvoiceByAddress`,`isTaxDataChecked`,`isFreezed`,`creditInsurance`,`isCreatedAsServed`,`hasInvoiceSimplified`,`salesPersonFk`,`isVies`,`eypbc`)
|
||||
INSERT INTO `vn`.`client`(`id`,`name`,`fi`,`socialName`,`contact`,`street`,`city`,`postcode`,`phone`,`mobile`,`fax`,`isRelevant`,`email`,`iban`,`dueDay`,`accountingAccount`,`isEqualizated`,`provinceFk`,`hasToInvoice`,`credit`,`countryFk`,`isActive`,`gestdocFk`,`quality`,`payMethodFk`,`created`,`isToBeMailed`,`contactChannelFk`,`hasSepaVnl`,`hasCoreVnl`,`hasCoreVnh`,`riskCalculated`,`clientTypeFk`,`mailAddress`,`cplusTerIdNifFk`,`hasToInvoiceByAddress`,`isTaxDataChecked`,`isFreezed`,`creditInsurance`,`isCreatedAsServed`,`hasInvoiceSimplified`,`salesPersonFk`,`isVies`,`eypbc`)
|
||||
VALUES
|
||||
(101, 'Bruce Wayne', '84612325V', 'Batman', 'Alfred', '1007 Mountain Drive, Gotham', 'Silla', 46460, 333333333, 1, 'BruceWayne@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1),
|
||||
(102, 'Petter Parker', '87945234L', 'Spider man', 'Aunt May', '20 Ingram Street', 'Silla', 46460, 333333333, 1, 'PetterParker@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1),
|
||||
(103, 'Clark Kent', '06815934E', 'Super man', 'lois lane', '344 Clinton Street', 'Silla', 46460, 333333333, 1, 'ClarkKent@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 0, 19, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1),
|
||||
(104, 'Tony Stark', '06089160W', 'Iron man', 'Pepper Potts', '10880 Malibu Point', 'Silla', 46460, 333333333, 1, 'TonyStark@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1),
|
||||
(105, 'Max Eisenhardt', '251628698', 'Magneto', 'Rogue', 'Unknown Whereabouts', 'Silla', 46460, 333333333, 1, 'MaxEisenhardt@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 8, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 1, 1, NULL, 0, 0, 18, 0, 1),
|
||||
(106, 'DavidCharlesHaller', '53136686Q', 'Legion', 'Charles Xavier', 'Evil hideout', 'Silla', 46460, 333333333, 1, 'DavidCharlesHaller@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 0, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 1, 0, NULL, 0, 0, 19, 0, 1),
|
||||
(107, 'Hank Pym', '09854837G', 'Ant man', 'Hawk', 'Anthill', 'Silla', 46460, 333333333, 1, 'HankPym@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 0, 0, NULL, 0, 0, 19, 0, 1),
|
||||
(108, 'Charles Xavier', '22641921P', 'Professor X', 'Beast', '3800 Victory Pkwy, Cincinnati, OH 45207, USA', 'Silla', 46460, 333333333, 1, 'CharlesXavier@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 1, 1, NULL, 0, 0, 19, 0, 1),
|
||||
(109, 'Bruce Banner', '16104829E', 'Hulk', 'Black widow', 'Somewhere in New York', 'Silla', 46460, 333333333, 1, 'BruceBanner@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 0, 0, NULL, 0, 0, 19, 0, 1),
|
||||
(110, 'Jessica Jones', '58282869H', 'Jessica Jones', 'Luke Cage', 'NYCC 2015 Poster', 'Silla', 46460, 333333333, 1, 'JessicaJones@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 0, 0, NULL, 0, 0, NULL, 0, 1),
|
||||
(111, 'Missing', NULL, 'Missing man', 'Anton', 'The space', 'Silla', 46460, 333333333, 1, NULL, NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 4, NULL, 1, 0, 1, 0, NULL, 1, 0, NULL, 0, 1),
|
||||
(112, 'Trash', NULL, 'Garbage man', 'Unknown name', 'New York city', 'Silla', 46460, 333333333, 1, NULL, NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 4, NULL, 1, 0, 1, 0, NULL, 1, 0, NULL, 0, 1);
|
||||
(101, 'Bruce Wayne', '84612325V', 'Batman', 'Alfred', '1007 Mountain Drive, Gotham', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'BruceWayne@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1),
|
||||
(102, 'Petter Parker', '87945234L', 'Spider man', 'Aunt May', '20 Ingram Street', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'PetterParker@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1),
|
||||
(103, 'Clark Kent', '06815934E', 'Super man', 'lois lane', '344 Clinton Street', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'ClarkKent@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 0, 19, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1),
|
||||
(104, 'Tony Stark', '06089160W', 'Iron man', 'Pepper Potts', '10880 Malibu Point', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'TonyStark@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1),
|
||||
(105, 'Max Eisenhardt', '251628698', 'Magneto', 'Rogue', 'Unknown Whereabouts', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'MaxEisenhardt@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 8, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 1, 1, NULL, 0, 0, 18, 0, 1),
|
||||
(106, 'DavidCharlesHaller', '53136686Q', 'Legion', 'Charles Xavier', 'Evil hideout', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'DavidCharlesHaller@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 0, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 1, 0, NULL, 0, 0, 19, 0, 1),
|
||||
(107, 'Hank Pym', '09854837G', 'Ant man', 'Hawk', 'Anthill', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'HankPym@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 0, 0, NULL, 0, 0, 19, 0, 1),
|
||||
(108, 'Charles Xavier', '22641921P', 'Professor X', 'Beast', '3800 Victory Pkwy, Cincinnati, OH 45207, USA', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'CharlesXavier@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 1, 1, NULL, 0, 0, 19, 0, 1),
|
||||
(109, 'Bruce Banner', '16104829E', 'Hulk', 'Black widow', 'Somewhere in New York', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'BruceBanner@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 0, 0, NULL, 0, 0, 19, 0, 1),
|
||||
(110, 'Jessica Jones', '58282869H', 'Jessica Jones', 'Luke Cage', 'NYCC 2015 Poster', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, 'JessicaJones@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, NULL, 1, 1, 0, 0, NULL, 0, 0, NULL, 0, 1),
|
||||
(111, 'Missing', NULL, 'Missing man', 'Anton', 'The space', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, NULL, NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 4, NULL, 1, 0, 1, 0, NULL, 1, 0, NULL, 0, 1),
|
||||
(112, 'Trash', NULL, 'Garbage man', 'Unknown name', 'New York city', 'Silla', 46460, 1111111111, 222222222, 333333333, 1, NULL, NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 4, NULL, 1, 0, 1, 0, NULL, 1, 0, NULL, 0, 1);
|
||||
|
||||
INSERT INTO `vn`.`client`(`id`, `name`, `fi`, `socialName`, `contact`, `street`, `city`, `postcode`, `isRelevant`, `email`, `iban`,`dueDay`,`accountingAccount`, `isEqualizated`, `provinceFk`, `hasToInvoice`, `credit`, `countryFk`, `isActive`, `gestdocFk`, `quality`, `payMethodFk`,`created`, `isTaxDataChecked`)
|
||||
SELECT id, name, CONCAT(RPAD(CONCAT(id,9),8,id),'A'), CONCAT(name, 'Social'), CONCAT(name, 'Contact'), CONCAT(name, 'Street'), 'SILLA', 46460, 1, CONCAT(name,'@mydomain.com'), NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1,NULL, 10, 5, CURDATE(), 1
|
||||
|
@ -1128,13 +1127,26 @@ INSERT INTO `vn`.`entry`(`id`, `supplierFk`, `created`, `travelFk`, `companyFk`,
|
|||
(6, 2, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 6, 442, 'Movement 6', 'this is the note six', 'observation six'),
|
||||
(7, 2, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 7, 442, 'Movement 7', 'this is the note seven', 'observation seven');
|
||||
|
||||
INSERT INTO `bi`.`claims_ratio`(`id_Cliente`, `Consumo`, `Reclamaciones`, `Ratio`, `recobro`, `inflacion`)
|
||||
INSERT INTO `vn`.`claimRatio`(`clientFk`, `yearSale`, `claimAmount`, `claimingRate`, `priceIncreasing`, `packingRate`)
|
||||
VALUES
|
||||
(101, 500, NULL, 0.00, 0.00, 1.00),
|
||||
(102, 1000, 2.00, 0.01, 0.05, 1.00),
|
||||
(103, 2000, 0.00, 0.00, 0.02, 1.00),
|
||||
(104, 2500, 150.00, 0.02, 0.10, 1.00);
|
||||
|
||||
INSERT INTO `bs`.`waste`(`buyer`, `year`, `week`, `family`, `saleTotal`, `saleWaste`, `rate`)
|
||||
VALUES
|
||||
('CharlesXavier', YEAR(DATE_ADD(CURDATE(), INTERVAL -1 WEEK)), WEEK(DATE_ADD(CURDATE(), INTERVAL -1 WEEK), 1), 'Carnation', '1062', '51', '4.8'),
|
||||
('CharlesXavier', YEAR(DATE_ADD(CURDATE(), INTERVAL -1 WEEK)), WEEK(DATE_ADD(CURDATE(), INTERVAL -1 WEEK), 1), 'Carnation Colombia', '35074', '687', '2.0'),
|
||||
('CharlesXavier', YEAR(DATE_ADD(CURDATE(), INTERVAL -1 WEEK)), WEEK(DATE_ADD(CURDATE(), INTERVAL -1 WEEK), 1), 'Carnation Mini', '1777', '13', '0.7'),
|
||||
('CharlesXavier', YEAR(DATE_ADD(CURDATE(), INTERVAL -1 WEEK)), WEEK(DATE_ADD(CURDATE(), INTERVAL -1 WEEK), 1), 'Carnation Short', '9182', '59', '0.6'),
|
||||
('DavidCharlesHaller', YEAR(DATE_ADD(CURDATE(), INTERVAL -1 WEEK)), WEEK(DATE_ADD(CURDATE(), INTERVAL -1 WEEK), 1), 'Containers', '-74', '0', '0.0'),
|
||||
('DavidCharlesHaller', YEAR(DATE_ADD(CURDATE(), INTERVAL -1 WEEK)), WEEK(DATE_ADD(CURDATE(), INTERVAL -1 WEEK), 1), 'Packagings', '-7', '0', '0.0'),
|
||||
('DavidCharlesHaller', YEAR(DATE_ADD(CURDATE(), INTERVAL -1 WEEK)), WEEK(DATE_ADD(CURDATE(), INTERVAL -1 WEEK), 1), 'Freight', '1100', '0', '0.0'),
|
||||
('HankPym', YEAR(DATE_ADD(CURDATE(), INTERVAL -1 WEEK)), WEEK(DATE_ADD(CURDATE(), INTERVAL -1 WEEK), 1), 'Funeral Accessories', '848', '-187', '-22.1'),
|
||||
('HankPym', YEAR(DATE_ADD(CURDATE(), INTERVAL -1 WEEK)), WEEK(DATE_ADD(CURDATE(), INTERVAL -1 WEEK), 1), 'Miscellaneous Accessories', '186', '0', '0.0'),
|
||||
('HankPym', YEAR(DATE_ADD(CURDATE(), INTERVAL -1 WEEK)), WEEK(DATE_ADD(CURDATE(), INTERVAL -1 WEEK), 1), 'Adhesives', '277', '0', '0.0');
|
||||
|
||||
INSERT INTO `vn`.`buy`(`id`,`entryFk`,`itemFk`,`buyingValue`,`quantity`,`packageFk`,`stickers`,`freightValue`,`packageValue`,`comissionValue`,`packing`,`grouping`,`groupingMode`,`location`,`price1`,`price2`,`price3`,`minPrice`,`producer`,`printedStickers`,`isChecked`,`isIgnored`, `created`)
|
||||
VALUES
|
||||
(1, 1, 1, 50, 5000, 4, 1, 1.500, 1.500, 0.000, 1, 1, 1, NULL, 0.00, 99.6, 99.4, 0.00, NULL, 0, 1, 0, DATE_ADD(CURDATE(), INTERVAL -2 MONTH)),
|
||||
|
@ -1928,73 +1940,6 @@ INSERT INTO `vn`.`queuePriority`(`id`, `priority`)
|
|||
(2, 'Normal'),
|
||||
(3, 'Baja');
|
||||
|
||||
INSERT INTO `vn`.`userPhoneType` (`code`, `description`)
|
||||
VALUES
|
||||
('businessPhone', 'Telefono de empresa del usuario'),
|
||||
('personalPhone', 'Telefono personal del usuario');
|
||||
|
||||
INSERT INTO `vn`.`userPhone`(`id`, `userFk`, `typeFk`, `phone`)
|
||||
VALUES
|
||||
(1, 101, 'personalPhone', 1111111111),
|
||||
(2, 102, 'personalPhone', 1111111111),
|
||||
(3, 103, 'personalPhone', 1111111111),
|
||||
(4, 104, 'personalPhone', 1111111111),
|
||||
(5, 105, 'personalPhone', 1111111111),
|
||||
(6, 106, 'personalPhone', 1111111111),
|
||||
(7, 107, 'personalPhone', 1111111111),
|
||||
(8, 108, 'personalPhone', 1111111111),
|
||||
(9, 109, 'personalPhone', 1111111111),
|
||||
(10, 110, 'personalPhone', 1111111111),
|
||||
(11, 111, 'personalPhone', 1111111111),
|
||||
(12, 112, 'personalPhone', 1111111111),
|
||||
(13, 1, 'personalPhone', 623111111),
|
||||
(14, 2, 'personalPhone', 623111111),
|
||||
(15, 3, 'personalPhone', 623111111),
|
||||
(16, 5, 'personalPhone', 623111111),
|
||||
(17, 6, 'personalPhone', 623111111),
|
||||
(18, 9, 'personalPhone', 623111111),
|
||||
(19, 13, 'personalPhone', 623111111),
|
||||
(20, 15, 'personalPhone', 623111111),
|
||||
(21, 16, 'personalPhone', 623111111),
|
||||
(22, 17, 'personalPhone', 623111111),
|
||||
(23, 18, 'personalPhone', 623111111),
|
||||
(24, 19, 'personalPhone', 623111111),
|
||||
(26, 21, 'personalPhone', 623111111),
|
||||
(27, 22, 'personalPhone', 623111111),
|
||||
(28, 30, 'personalPhone', 623111111),
|
||||
(29, 31, 'personalPhone', 623111111),
|
||||
(30, 32, 'personalPhone', 623111111),
|
||||
(31, 34, 'personalPhone', 623111111),
|
||||
(32, 35, 'personalPhone', 623111111),
|
||||
(33, 36, 'personalPhone', 623111111),
|
||||
(34, 37, 'personalPhone', 623111111),
|
||||
(35, 38, 'personalPhone', 623111111),
|
||||
(36, 39, 'personalPhone', 623111111),
|
||||
(37, 40, 'personalPhone', 623111111),
|
||||
(38, 41, 'personalPhone', 623111111),
|
||||
(39, 42, 'personalPhone', 623111111),
|
||||
(40, 43, 'personalPhone', 623111111),
|
||||
(41, 44, 'personalPhone', 623111111),
|
||||
(42, 45, 'personalPhone', 623111111),
|
||||
(43, 47, 'personalPhone', 623111111),
|
||||
(44, 48, 'personalPhone', 623111111),
|
||||
(45, 50, 'personalPhone', 623111111),
|
||||
(46, 51, 'personalPhone', 623111111),
|
||||
(47, 52, 'personalPhone', 623111111),
|
||||
(48, 54, 'personalPhone', 623111111),
|
||||
(49, 55, 'personalPhone', 623111111),
|
||||
(50, 56, 'personalPhone', 623111111),
|
||||
(51, 57, 'personalPhone', 623111111),
|
||||
(52, 58, 'personalPhone', 623111111),
|
||||
(53, 59, 'personalPhone', 623111111),
|
||||
(54, 60, 'personalPhone', 623111111),
|
||||
(55, 61, 'personalPhone', 623111111),
|
||||
(56, 65, 'personalPhone', 623111111),
|
||||
(57, 66, 'personalPhone', 623111111),
|
||||
(65, 107, 'businessPhone', 700987987),
|
||||
(67, 106, 'businessPhone', 1111111112),
|
||||
(68, 106, 'personalPhone', 1111111113);
|
||||
|
||||
INSERT INTO `vn`.`workerTimeControlParams` (`id`, `dayBreak`, `weekBreak`, `weekScope`, `dayWorkMax`, `dayStayMax`)
|
||||
VALUES
|
||||
(1, 43200, 129600, 734400, 43200, 50400);
|
||||
|
@ -2005,11 +1950,14 @@ INSERT INTO `vn`.`thermograph`(`id`, `model`)
|
|||
VALUES
|
||||
('TMM190901395', 'TEMPMATE'),
|
||||
('TL.BBA85422', 'TL30'),
|
||||
('TZ1905012010', 'DISPOSABLE');
|
||||
('TZ1905012010', 'DISPOSABLE'),
|
||||
('138350-0', 'DISPOSABLE');
|
||||
|
||||
INSERT INTO `vn`.`travelThermograph`(`thermographFk`, `created`, `warehouseFk`, `travelFk`, `temperature`, `result`, `dmsFk`)
|
||||
VALUES
|
||||
('TMM190901395', CURDATE(), 1, 1, 'WARM', 'Ok', NULL),
|
||||
('TL.BBA85422', DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 2, 2, 'COOL', 'Ok', NULL),
|
||||
('TL.BBA85422', CURDATE(), 2, 1, 'COOL', 'can not read the temperature', NULL),
|
||||
('TZ1905012010', CURDATE(), 1, 1, 'WARM', 'Temperature in range', 5);
|
||||
('TZ1905012010', CURDATE(), 1, 1, 'WARM', 'Temperature in range', 5),
|
||||
('138350-0', DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 1, 1, 'WARM', NULL, 5),
|
||||
('138350-0', CURDATE(), 1, NULL, 'COOL', NULL, NULL);
|
File diff suppressed because it is too large
Load Diff
|
@ -3,6 +3,7 @@
|
|||
SCHEMAS=(
|
||||
account
|
||||
bi
|
||||
bs
|
||||
cache
|
||||
edi
|
||||
hedera
|
||||
|
|
|
@ -35,7 +35,7 @@ describe('Ticket List sale path', () => {
|
|||
const value = await page
|
||||
.waitToGetProperty(selectors.ticketSales.firstSaleDiscount, 'innerText');
|
||||
|
||||
expect(value).toContain('0 %');
|
||||
expect(value).toContain('0.00%');
|
||||
});
|
||||
|
||||
it('should confirm the first sale contains the total import', async() => {
|
||||
|
|
|
@ -177,10 +177,10 @@ xdescribe('Ticket Edit sale path', () => {
|
|||
|
||||
it('should confirm the discount have been updated', async() => {
|
||||
const result = await nightmare
|
||||
.waitForTextInElement(`${selectors.ticketSales.firstSaleDiscount} > span`, '50 %')
|
||||
.waitForTextInElement(`${selectors.ticketSales.firstSaleDiscount} > span`, '50.00%')
|
||||
.waitToGetProperty(`${selectors.ticketSales.firstSaleDiscount} > span`, 'innerText');
|
||||
|
||||
expect(result).toContain('50 %');
|
||||
expect(result).toContain('50.00%');
|
||||
});
|
||||
|
||||
it('should confirm the total import for that item have been updated', async() => {
|
||||
|
|
|
@ -16,11 +16,21 @@ export default class Textarea extends Field {
|
|||
get rows() {
|
||||
return this.input.rows;
|
||||
}
|
||||
|
||||
set maxlength(value) {
|
||||
let length = typeof value == 'number' && value > 1 ? value : 50;
|
||||
this.input.setAttribute('maxlength', length);
|
||||
}
|
||||
|
||||
get maxlength() {
|
||||
return this.input.getAttribute('maxlength', length);
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.vnComponent('vnTextarea', {
|
||||
controller: Textarea,
|
||||
bindings: {
|
||||
rows: '<?'
|
||||
rows: '<?',
|
||||
maxlength: '<?'
|
||||
}
|
||||
});
|
||||
|
|
|
@ -34,4 +34,24 @@ describe('Component vnTextarea', () => {
|
|||
expect($ctrl.rows).toEqual(3);
|
||||
});
|
||||
});
|
||||
|
||||
describe('maxlength() setter', () => {
|
||||
it(`should set maxlength property of the element to the given value if it's a valid number`, () => {
|
||||
$ctrl.maxlength = 100;
|
||||
|
||||
expect($ctrl.maxlength).toEqual('100');
|
||||
});
|
||||
|
||||
it(`should set maxlength property of the element to 3 if the given value if it's null`, () => {
|
||||
$ctrl.maxlength = null;
|
||||
|
||||
expect($ctrl.maxlength).toEqual('50');
|
||||
});
|
||||
|
||||
it(`should set maxlength property of the element to 3 if the given value if it's not a valid number`, () => {
|
||||
$ctrl.maxlength = 'a';
|
||||
|
||||
expect($ctrl.maxlength).toEqual('50');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,15 +1,22 @@
|
|||
import ngModule from '../module';
|
||||
|
||||
/**
|
||||
* Formats a number multiplying by 100 and adding character %.
|
||||
*
|
||||
* @return {String} The formated number
|
||||
*/
|
||||
export default function percentage() {
|
||||
return function(input) {
|
||||
export default function percentage($translate) {
|
||||
function percentage(input, fractionSize = 2) {
|
||||
if (input == null || input === '')
|
||||
return null;
|
||||
return `${input} %`;
|
||||
};
|
||||
|
||||
return new Intl.NumberFormat($translate.use(), {
|
||||
style: 'percent',
|
||||
minimumFractionDigits: fractionSize,
|
||||
maximumFractionDigits: fractionSize
|
||||
}).format(parseFloat(input));
|
||||
}
|
||||
|
||||
percentage.$stateful = true;
|
||||
|
||||
return percentage;
|
||||
}
|
||||
|
||||
percentage.$inject = ['$translate'];
|
||||
|
||||
ngModule.filter('percentage', percentage);
|
||||
|
|
|
@ -23,6 +23,18 @@
|
|||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.icon-buyrequest:before {
|
||||
content: "\e914";
|
||||
}
|
||||
.icon-entry:before {
|
||||
content: "\e959";
|
||||
}
|
||||
.icon-thermometer:before {
|
||||
content: "\e95a";
|
||||
}
|
||||
.icon-deletedTicket:before {
|
||||
content: "\e958";
|
||||
}
|
||||
.icon-fruit:before {
|
||||
content: "\e957";
|
||||
}
|
||||
|
@ -134,9 +146,6 @@
|
|||
.icon-doc:before {
|
||||
content: "\e913";
|
||||
}
|
||||
.icon-entry:before {
|
||||
content: "\e914";
|
||||
}
|
||||
.icon-exit:before {
|
||||
content: "\e947";
|
||||
}
|
||||
|
@ -287,6 +296,3 @@
|
|||
.icon-worker:before {
|
||||
content: "\e943";
|
||||
}
|
||||
.icon-deletedTicket:before {
|
||||
content: "\e958";
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
<glyph unicode="" glyph-name="details" d="M908.823 844.777v-797.867h-793.6v797.867h793.6zM972.823 959.977h-921.6c-29.867 0-51.2-21.333-51.2-51.2v-921.6c0-21.333 21.333-51.2 51.2-51.2h921.6c21.333 0 51.2 29.867 51.2 51.2v921.6c0 29.867-29.867 51.2-51.2 51.2zM456.556 733.844h341.333v-115.2h-341.333v115.2zM456.556 503.444h341.333v-115.2h-341.333v115.2zM456.556 277.31h341.333v-115.2h-341.333v115.2zM226.156 733.844h115.2v-115.2h-115.2v115.2zM226.156 503.444h115.2v-115.2h-115.2v115.2zM226.156 277.31h115.2v-115.2h-115.2v115.2z" />
|
||||
<glyph unicode="" glyph-name="fiscal" d="M140.8 520.533v-341.333h149.333v341.333h-149.333zM439.467 520.533v-341.333h149.333v341.333h-149.333zM38.4-64h942.933v145.067h-942.933v-145.067zM733.867 520.533v-341.333h149.333v341.333h-149.333zM512 960l-473.6-243.2v-98.133h942.933v98.133l-469.333 243.2z" />
|
||||
<glyph unicode="" glyph-name="doc" d="M614.4 960h-409.6c-55.467 0-102.4-46.933-102.4-102.4v-819.2c0-55.467 46.933-102.4 102.4-102.4h614.4c55.467 0 102.4 46.933 102.4 102.4v614.4l-307.2 307.2zM716.8 140.8h-409.6v102.4h409.6v-102.4zM716.8 345.6h-409.6v102.4h409.6v-102.4zM563.2 601.6v281.6l281.6-281.6h-281.6z" />
|
||||
<glyph unicode="" glyph-name="entry" d="M0-64h1024v430.933h-264.533v-166.4l-247.467 247.467 247.467 247.467v-166.4h264.533v430.933h-1024v-1024z" />
|
||||
<glyph unicode="" glyph-name="buyrequest" d="M520.533 878.933c-34.133 0-55.467-25.6-55.467-55.467s25.6-55.467 55.467-55.467 55.467 25.6 55.467 55.467-21.333 55.467-55.467 55.467zM520.533 806.4c-12.8 0-17.067 8.533-17.067 17.067s8.533 17.067 17.067 17.067 17.067-8.533 17.067-17.067-4.267-17.067-17.067-17.067zM588.8 247.467l-4.267 12.8v4.267l-17.067 59.733h-273.067v-89.6h298.667zM294.4 686.933h452.267v-89.6h-452.267v89.6zM571.733 430.933c17.067 12.8 38.4 17.067 59.733 8.533l64-25.6h55.467v89.6h-456.533v-89.6h264.533c4.267 8.533 8.533 12.8 12.8 17.067zM643.985 256.128l95.27 85.478 202.299-225.473-95.27-85.478-202.299 225.473zM855.196 15.592l95.283 85.466 22.791-25.409-95.283-85.466-22.791 25.409zM1015.467 29.867l-34.133 38.4-93.867-85.333 34.133-38.4c4.267-4.267 12.8-8.533 17.067-8.533 8.533 0 12.8 0 17.067 8.533l59.733 51.2c8.533 8.533 12.8 25.6 0 34.133zM614.4 401.067c-4.267 0-8.533 0-12.8-4.267-4.267 0-4.267-8.533-4.267-12.8l34.133-119.467 93.867 85.333-110.933 51.2zM729.6 93.867h-524.8c-29.867 0-51.2 25.6-51.2 51.2v635.733c0 25.6 21.333 51.2 51.2 51.2h213.333l8.533 25.6c12.8 38.4 51.2 64 93.867 64s76.8-25.6 93.867-64l8.533-25.6h213.333c29.867 0 51.2-25.6 51.2-51.2v-541.867l38.4-42.667v584.533c0 46.933-42.667 89.6-89.6 89.6h-187.733c-17.067 51.2-68.267 89.6-128 89.6s-110.933-38.4-128-89.6h-187.733c-46.933 0-89.6-42.667-89.6-89.6v-635.733c0-46.933 42.667-89.6 89.6-89.6h554.667l-29.867 38.4z" />
|
||||
<glyph unicode="" glyph-name="eye" d="M512 797.867c-234.667 0-430.933-145.067-512-349.867 81.067-204.8 277.333-349.867 512-349.867s430.933 145.067 512 349.867c-81.067 204.8-277.333 349.867-512 349.867zM512 213.333c-128 0-234.667 102.4-234.667 234.667s106.667 234.667 234.667 234.667 234.667-106.667 234.667-234.667-106.667-234.667-234.667-234.667zM512 588.8c-76.8 0-140.8-64-140.8-140.8s64-140.8 140.8-140.8 140.8 64 140.8 140.8-64 140.8-140.8 140.8z" />
|
||||
<glyph unicode="" glyph-name="flower" d="M905.6 636.8c-9.6 3.2-19.2 19.2-16 25.6 6.4 89.6-25.6 163.2-99.2 214.4-76.8 51.2-156.8 54.4-236.8 9.6-19.2-9.6-28.8-9.6-48 0-76.8 48-153.6 54.4-233.6 12.8-80-44.8-118.4-112-121.6-201.6 0-19.2-6.4-28.8-25.6-38.4-83.2-41.6-124.8-108.8-128-201.6 0-80 32-150.4 102.4-192 22.4-16 38.4-28.8 28.8-57.6 3.2-89.6 38.4-160 115.2-201.6 76.8-44.8 156.8-38.4 233.6 3.2 6.4 3.2 22.4 0 32-3.2 38.4-12.8 73.6-38.4 112-38.4 140.8-9.6 243.2 89.6 246.4 233.6 0 9.6 9.6 19.2 16 25.6 28.8 25.6 70.4 48 92.8 80 86.4 112 48 259.2-70.4 329.6zM806.4 300.8c-16-3.2-28.8-3.2-48-6.4 6.4-16 9.6-32 12.8-44.8 25.6-70.4 0-140.8-64-176-64-32-134.4-12.8-179.2 51.2-6.4 12.8-16 22.4-22.4 32-22.4-22.4-41.6-44.8-64-60.8-51.2-38.4-118.4-35.2-166.4 3.2s-64 105.6-41.6 163.2c6.4 16 12.8 32 22.4 51.2-22.4 3.2-38.4 9.6-57.6 12.8-67.2 16-115.2 76.8-108.8 140.8 6.4 67.2 60.8 121.6 131.2 128 16 0 28.8 3.2 48 6.4-6.4 19.2-12.8 38.4-19.2 57.6-22.4 60.8 6.4 128 64 160s131.2 16 172.8-38.4c9.6-12.8 22.4-28.8 35.2-44.8 12.8 12.8 25.6 25.6 35.2 41.6 38.4 48 112 64 169.6 35.2s86.4-96 67.2-156.8c-6.4-22.4-16-44.8-28.8-70.4 16-3.2 32-6.4 48-9.6 73.6-12.8 118.4-67.2 118.4-140.8s-51.2-124.8-124.8-134.4zM512 624c-102.4 0-176-76.8-176-176 0-102.4 80-179.2 179.2-179.2 96 0 176 83.2 176 179.2s-80 176-179.2 176zM512 358.4c-48 0-89.6 38.4-86.4 89.6 0 48 41.6 86.4 86.4 86.4s86.4-41.6 86.4-89.6c0-48-38.4-86.4-86.4-86.4z" />
|
||||
<glyph unicode="" glyph-name="frozen" d="M1024 499.2h-213.333l166.4 166.4-72.533 72.533-238.933-238.933h-102.4v102.4l238.933 238.933-72.533 72.533-166.4-166.4v213.333h-102.4v-213.333l-166.4 166.4-72.533-72.533 238.933-238.933v-102.4h-102.4l-238.933 238.933-72.533-72.533 166.4-166.4h-213.333v-102.4h213.333l-166.4-166.4 72.533-72.533 238.933 238.933h102.4v-102.4l-238.933-238.933 72.533-72.533 166.4 166.4v-213.333h102.4v213.333l166.4-166.4 72.533 72.533-238.933 238.933v102.4h102.4l238.933-238.933 72.533 72.533-166.4 166.4h213.333v102.4z" />
|
||||
|
@ -96,4 +96,6 @@
|
|||
<glyph unicode="" glyph-name="deliveryprices" d="M789.333 264.533c-55.467 0-102.4-46.933-102.4-102.4s46.933-102.4 102.4-102.4 102.4 46.933 102.4 102.4c0 59.733-46.933 102.4-102.4 102.4zM789.333 110.933c-29.867 0-51.2 21.333-51.2 51.2s21.333 51.2 51.2 51.2 51.2-21.333 51.2-51.2c0-25.6-25.6-51.2-51.2-51.2zM251.733 264.533c-55.467 0-102.4-46.933-102.4-102.4s46.933-102.4 102.4-102.4 102.4 46.933 102.4 102.4c0 59.733-46.933 102.4-102.4 102.4zM251.733 110.933c-29.867 0-51.2 21.333-51.2 51.2s21.333 51.2 51.2 51.2 51.2-21.333 51.2-51.2c0-25.6-25.6-51.2-51.2-51.2zM1006.933 537.6l-196.267 192c-12.8 12.8-29.867 17.067-46.933 17.067h-98.133v38.4c0 25.6-21.333 51.2-51.2 51.2h-563.2c-29.867 0-51.2-21.333-51.2-51.2v-554.667c0-29.867 25.6-51.2 51.2-51.2h68.267c8.533 64 64 115.2 132.267 115.2 64 0 123.733-51.2 132.267-115.2h268.8c8.533 64 64 115.2 132.267 115.2s128-51.2 136.533-115.2h51.2c29.867 0 51.2 25.6 51.2 51.2v260.267c0 17.067-8.533 34.133-17.067 46.933zM392.533 605.867v-38.4h-170.667c0-8.533 0-12.8 0-17.067s0-12.8 0-17.067h170.667v-42.667h-157.867c12.8-25.6 25.6-42.667 51.2-59.733 21.333-12.8 46.933-21.333 76.8-21.333 42.667 0 76.8 17.067 102.4 46.933l46.933-42.667c-17.067-21.333-38.4-38.4-68.267-46.933-25.6-12.8-55.467-17.067-89.6-17.067s-64 4.267-89.6 17.067c-25.6 12.8-51.2 29.867-68.267 51.2s-29.867 42.667-38.4 72.533h-64v38.4h55.467c0 4.267 0 8.533 0 17.067s0 12.8 0 17.067h-55.467v42.667h64c8.533 29.867 21.333 51.2 38.4 76.8s42.667 38.4 68.267 51.2c29.867 8.533 59.733 12.8 93.867 12.8 29.867 0 59.733-4.267 89.6-17.067 25.6-8.533 46.933-25.6 64-46.933l-46.933-42.667c-29.867 29.867-64 46.933-102.4 46.933-29.867 0-55.467-8.533-76.8-21.333-25.6-17.067-42.667-34.133-51.2-59.733h157.867zM921.6 529.067h-187.733c-8.533 0-8.533 4.267-8.533 8.533v145.067c0 4.267 4.267 8.533 8.533 8.533h34.133c0 0 4.267 0 4.267-4.267l153.6-145.067c4.267 0 0-12.8-4.267-12.8z" />
|
||||
<glyph unicode="" glyph-name="fruit" d="M870.4 814.933c-204.8 196.267-529.067 192-725.333-8.533-196.267-204.8-192-529.067 8.533-725.333s524.8-192 725.333 12.8c196.267 200.533 192 524.8-8.533 721.067zM840.533 128c-174.933-179.2-465.067-183.467-644.267-8.533s-179.2 465.067-4.267 644.267 465.067 183.467 644.267 8.533c179.2-174.933 179.2-460.8 4.267-644.267zM145.067 366.933c-38.4 51.2-4.267 149.333 8.533 162.133 29.867 17.067 157.867-25.6 183.467-38.4s98.133-29.867 98.133-55.467c0-29.867-64-46.933-119.467-55.467-59.733-12.8-153.6-38.4-170.667-12.8zM256 170.667c-59.733 17.067-89.6 102.4-85.333 119.467 12.8 29.867 136.533 68.267 162.133 76.8 25.6 4.267 93.867 34.133 106.667 12.8 17.067-25.6-29.867-64-64-106.667-38.4-46.933-89.6-115.2-119.467-102.4zM405.333 622.933c-25.6 51.2-72.533 128-51.2 153.6 38.4 51.2 132.267 51.2 145.067 38.4 25.6-21.333 17.067-157.867 12.8-183.467s0-102.4-25.6-106.667c-29.867-8.533-55.467 46.933-81.067 98.133zM537.6 648.533c8.533 59.733 8.533 149.333 42.667 162.133 59.733 21.333 140.8-29.867 149.333-51.2 8.533-34.133-72.533-145.067-93.867-166.4s-59.733-85.333-85.333-76.8c-29.867 12.8-17.067 76.8-12.8 132.267zM494.933 217.6c-8.533-51.2-12.8-128-38.4-136.533-51.2-17.067-119.467 25.6-123.733 42.667-8.533 29.867 68.267 123.733 85.333 140.8s51.2 72.533 72.533 64c21.333-4.267 8.533-59.733 4.267-110.933zM320 516.267c-55.467 25.6-136.533 51.2-136.533 85.333 0 64 68.267 123.733 85.333 123.733 34.133 0 110.933-110.933 128-132.267 12.8-25.6 64-76.8 46.933-98.133-17.067-29.867-72.533 0-123.733 21.333zM887.467 482.133c38.4-51.2 8.533-149.333-17.067-162.133-29.867-17.067-145.067 38.4-170.667 46.933-25.6 12.8-98.133 29.867-98.133 55.467 0 29.867 64 38.4 123.733 51.2 55.467 8.533 140.8 34.133 162.133 8.533zM785.067 686.933c55.467-17.067 89.6-98.133 85.333-115.2-8.533-29.867-132.267-64-157.867-72.533-25.6-4.267-89.6-29.867-102.4-12.8-17.067 25.6 25.6 64 64 102.4 29.867 42.667 76.8 106.667 110.933 98.133zM725.333 328.533c51.2-17.067 102.4-46.933 102.4-76.8-4.267-51.2-64-115.2-98.133-115.2-29.867 0-89.6 106.667-102.4 132.267-12.8 21.333-51.2 76.8-34.133 98.133s76.8-17.067 132.267-38.4zM610.133 238.933c21.333-46.933 59.733-110.933 38.4-132.267-34.133-42.667-115.2-42.667-128-29.867-21.333 17.067-8.533 136.533-4.267 157.867 4.267 25.6 4.267 89.6 25.6 93.867 29.867 4.267 46.933-46.933 68.267-89.6z" />
|
||||
<glyph unicode="" glyph-name="deletedTicket" horiz-adv-x="900" d="M96.823 84.328h694.333v640.777c0 0-2.019 234.895-350.243 234.895s-344.090-234.895-344.090-234.895v-640.777zM227.684 652.223h171.244v152.494h102.496v-152.494h171.276v-102.496h-171.276v-357.519h-102.496v357.519h-171.244v102.496zM0 59.649v-123.649h900.415v123.649h-900.415z" />
|
||||
<glyph unicode="" glyph-name="entry" d="M0 328.882l392.882-392.882 265.404 265.404-100.31 100.31-102.4-100.31v303.020h303.020l-100.31-102.4 100.31-100.31 265.404 265.404-392.882 392.882z" />
|
||||
<glyph unicode="" glyph-name="thermometer" d="M641.567 326.792v35.527h64.784v25.078h-64.784v119.118h64.784v25.078h-64.784v119.118h64.784v25.078h-64.784v121.208h64.784v25.078h-64.784v8.359c0 71.053-58.514 129.567-129.567 129.567s-129.567-58.514-129.567-129.567v-503.641c-54.335-39.706-87.771-104.49-87.771-173.453 0-119.118 96.131-217.339 217.339-217.339 119.118 0 217.339 96.131 217.339 217.339 0 66.873-33.437 131.657-87.771 173.453zM512-28.473c-100.31 0-179.722 81.502-179.722 179.722 0 64.784 33.437 123.298 87.771 154.645v524.539c0 50.155 41.796 91.951 91.951 91.951s91.951-41.796 91.951-91.951v-522.449c54.335-31.347 87.771-89.861 87.771-154.645 0-100.31-79.412-181.812-179.722-181.812zM652.016 435.461v25.078h35.527v-25.078h-35.527zM652.016 579.657v25.078h35.527v-25.078h-35.527zM652.016 723.853v25.078h35.527v-25.078h-35.527zM568.424 284.996v543.347c0 0 0 0 0 0s0 0 0 0v0 0c0 31.347-25.078 56.424-56.424 56.424s-56.424-25.078-56.424-56.424v0-543.347c-52.245-20.898-87.771-73.143-87.771-131.657 0-79.412 64.784-144.196 144.196-144.196s144.196 64.784 144.196 144.196c0 58.514-35.527 108.669-87.771 131.657zM470.204 824.163v4.18c0 22.988 18.808 41.796 41.796 41.796s41.796-18.808 41.796-41.796v-219.429h-85.682v215.249z" />
|
||||
</font></defs></svg>
|
Before Width: | Height: | Size: 85 KiB After Width: | Height: | Size: 88 KiB |
Binary file not shown.
Binary file not shown.
|
@ -17,5 +17,6 @@ export default function moduleImport(moduleName) {
|
|||
case 'worker' : return import('worker/front');
|
||||
case 'invoiceOut' : return import('invoiceOut/front');
|
||||
case 'route' : return import('route/front');
|
||||
case 'entry' : return import('entry/front');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,8 +87,7 @@ vn-layout {
|
|||
& > * {
|
||||
display: block;
|
||||
padding: $spacing-md;
|
||||
box-sizing: border-box;
|
||||
height: 100%
|
||||
box-sizing: border-box
|
||||
}
|
||||
&.ng-enter {
|
||||
vn-side-menu {
|
||||
|
|
|
@ -2,4 +2,5 @@
|
|||
|
||||
.vn-module-card {
|
||||
padding: 0;
|
||||
height: 100%
|
||||
}
|
|
@ -2,4 +2,5 @@
|
|||
|
||||
.vn-module-main {
|
||||
padding: 0;
|
||||
height: 100%
|
||||
}
|
|
@ -43,6 +43,7 @@ Workers: Trabajadores
|
|||
Routes: Rutas
|
||||
Locator: Localizador
|
||||
Invoices out: Facturas emitidas
|
||||
Entries: Entradas
|
||||
|
||||
# Common
|
||||
|
||||
|
|
|
@ -219,7 +219,7 @@ module.exports = function(Self) {
|
|||
userFk: userFk,
|
||||
action: action,
|
||||
changedModel: ctx.Model.definition.name,
|
||||
changedModelId: changedModelId,
|
||||
changedModelId: changedModelId, // Model property with an different data type will throw a NaN error
|
||||
changedModelValue: where,
|
||||
oldInstance: oldInstance,
|
||||
newInstance: newInstance
|
||||
|
|
|
@ -155,10 +155,10 @@ module.exports = function(Self) {
|
|||
const result = await realMethod.call(this, data, options);
|
||||
|
||||
if (cb) cb(null, result);
|
||||
else return result;
|
||||
} catch (err) {
|
||||
let myErr = replaceErr(err, replaceErrFunc);
|
||||
if (cb)
|
||||
cb(myErr);
|
||||
if (cb) cb(myErr);
|
||||
else
|
||||
throw myErr;
|
||||
}
|
||||
|
|
|
@ -57,5 +57,9 @@
|
|||
"The postcode doesn't exists. Ensure you put the correct format": "The postcode doesn't exists. Ensure you put the correct format",
|
||||
"Can't create stowaway for this ticket": "Can't create stowaway for this ticket",
|
||||
"Has deleted the ticket id": "Has deleted the ticket id [#{{id}}]({{{url}}})",
|
||||
"Swift / BIC can't be empty": "Swift / BIC can't be empty"
|
||||
"Swift / BIC can't be empty": "Swift / BIC can't be empty",
|
||||
"MESSAGE_BOUGHT_UNITS": "Bought {{quantity}} units of {{concept}} (#{{itemId}}) for the ticket id [#{{ticketId}}]({{{url}}})",
|
||||
"MESSAGE_INSURANCE_CHANGE": "I have changed the insurence credit of client [{{clientName}} (#{{clientId}})]({{{url}}}) to *{{credit}} €*",
|
||||
"MESSAGE_CHANGED_PAYMETHOD": "I have changed the pay method for client [{{clientName}} (#{{clientId}})]({{{url}}})",
|
||||
"MESSAGE_CLAIM_ITEM_REGULARIZE": "I sent *{{quantity}}* units of [{{concept}} (#{{itemId}})]({{{itemUrl}}}) to {{nickname}} coming from ticket id [#{{ticketId}}]({{{ticketUrl}}})"
|
||||
}
|
|
@ -118,5 +118,9 @@
|
|||
"You should specify at least a start or end date": "Debes especificar al menos una fecha de inicio o de fín",
|
||||
"Start date should be lower than end date": "La fecha de inicio debe ser menor que la fecha de fín",
|
||||
"You should mark at least one week day": "Debes marcar al menos un día de la semana",
|
||||
"Swift / BIC can't be empty": "Swift / BIC no puede estar vacío"
|
||||
"Swift / BIC can't be empty": "Swift / BIC no puede estar vacío",
|
||||
"MESSAGE_BOUGHT_UNITS": "Se ha comprado {{quantity}} unidades de {{concept}} (#{{itemId}}) para el ticket id [#{{ticketId}}]({{{url}}})",
|
||||
"MESSAGE_INSURANCE_CHANGE": "He cambiado el crédito asegurado del cliente [{{clientName}} (#{{clientId}})]({{{url}}}) a *{{credit}} €*",
|
||||
"MESSAGE_CHANGED_PAYMETHOD": "He cambiado la forma de pago del cliente [{{clientName}} (#{{clientId}})]({{{url}}})",
|
||||
"MESSAGE_CLAIM_ITEM_REGULARIZE": "Envio *{{quantity}}* unidades de [{{concept}} (#{{itemId}})]({{{itemUrl}}}) a {{nickname}} provenientes del ticket id [#{{ticketId}}]({{{ticketUrl}}})"
|
||||
}
|
|
@ -19,6 +19,7 @@ module.exports = Self => {
|
|||
|
||||
Self.regularizeClaim = async(ctx, params) => {
|
||||
const models = Self.app.models;
|
||||
const $t = ctx.req.__; // $translate
|
||||
const resolvedState = 3;
|
||||
|
||||
let tx = await Self.beginTransaction({});
|
||||
|
@ -38,8 +39,7 @@ module.exports = Self => {
|
|||
const destination = claimEnd.claimDestination();
|
||||
const addressFk = destination && destination.addressFk;
|
||||
|
||||
if (!addressFk)
|
||||
continue;
|
||||
if (!addressFk) continue;
|
||||
|
||||
let sale = await getSale(claimEnd.saleFk, options);
|
||||
let ticketFk = await getTicketId({
|
||||
|
@ -70,15 +70,19 @@ module.exports = Self => {
|
|||
discount: 100
|
||||
}, options);
|
||||
|
||||
if (sale.ticket().client().salesPerson()) {
|
||||
await sendMessage(ctx, {
|
||||
itemFk: sale.itemFk,
|
||||
ticketFk: sale.ticketFk,
|
||||
recipientFk: sale.ticket().client().salesPerson().userFk,
|
||||
const salesPerson = sale.ticket().client().salesPerson();
|
||||
if (salesPerson) {
|
||||
const origin = ctx.req.headers.origin;
|
||||
const message = $t('MESSAGE_CLAIM_ITEM_REGULARIZE', {
|
||||
quantity: sale.quantity,
|
||||
concept: sale.concept,
|
||||
nickname: address.nickname
|
||||
}, options);
|
||||
itemId: sale.itemFk,
|
||||
ticketId: sale.ticketFk,
|
||||
nickname: address.nickname,
|
||||
ticketUrl: `${origin}/#!/ticket/${sale.ticketFk}/summary`,
|
||||
itemUrl: `${origin}/#!/item/${sale.itemFk}/summary`
|
||||
});
|
||||
await models.Chat.sendCheckingPresence(ctx, salesPerson.id, message);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -156,14 +160,4 @@ module.exports = Self => {
|
|||
|
||||
return ticket.id;
|
||||
}
|
||||
|
||||
async function sendMessage(ctx, params, options) {
|
||||
const message = `Envio ${params.quantity} unidades de "${params.concept}" (#${params.itemFk}) a `
|
||||
+ `"${params.nickname}" provenientes del ticket #${params.ticketFk}`;
|
||||
|
||||
await Self.app.models.Message.send(ctx, {
|
||||
recipientFk: params.recipientFk,
|
||||
message: message
|
||||
}, options);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -22,7 +22,13 @@ describe('regularizeClaim()', () => {
|
|||
});
|
||||
|
||||
it('should change claim state to resolved', async() => {
|
||||
let ctx = {req: {accessToken: {userId: 18}}};
|
||||
const ctx = {req: {
|
||||
accessToken: {userId: 18},
|
||||
headers: {origin: 'http://localhost'}}
|
||||
};
|
||||
ctx.req.__ = value => {
|
||||
return value;
|
||||
};
|
||||
let params = {claimFk: claimFk};
|
||||
|
||||
claimEnds = await app.models.ClaimEnd.importTicketSales(ctx, {
|
||||
|
|
|
@ -206,9 +206,9 @@ describe('claim', () => {
|
|||
return resolve({id: freightPickUpPrice});
|
||||
}));
|
||||
controller.onUpdateGreugeResponse('accept').then(res => {
|
||||
console.log('asdas');
|
||||
|
||||
}).catch(error => {
|
||||
console.log('errorrrr!!');
|
||||
|
||||
});
|
||||
|
||||
$httpBackend.flush();
|
||||
|
|
|
@ -10,4 +10,4 @@ import './descriptor';
|
|||
import './development';
|
||||
import './search-panel';
|
||||
import './summary';
|
||||
import './dms/index';
|
||||
import './photos';
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import ngModule from '../../module';
|
||||
import ngModule from '../module';
|
||||
import './style.scss';
|
||||
|
||||
class Controller {
|
||||
|
@ -108,7 +108,7 @@ class Controller {
|
|||
|
||||
Controller.$inject = ['$stateParams', '$scope', '$http', '$translate', 'vnToken', 'vnApp', 'vnConfig'];
|
||||
|
||||
ngModule.component('vnClaimDmsIndex', {
|
||||
ngModule.component('vnClaimPhotos', {
|
||||
template: require('./index.html'),
|
||||
controller: Controller,
|
||||
bindings: {
|
|
@ -2,7 +2,7 @@ import './index';
|
|||
import crudModel from 'core/mocks/crud-model';
|
||||
|
||||
describe('Claim', () => {
|
||||
describe('Component vnClaimDmsIndex', () => {
|
||||
describe('Component vnClaimPhotos', () => {
|
||||
let $componentController;
|
||||
let $scope;
|
||||
let $httpBackend;
|
||||
|
@ -16,7 +16,7 @@ describe('Claim', () => {
|
|||
$httpParamSerializer = _$httpParamSerializer_;
|
||||
$httpBackend = _$httpBackend_;
|
||||
$scope = $rootScope.$new();
|
||||
controller = $componentController('vnClaimDmsIndex', {$: $scope});
|
||||
controller = $componentController('vnClaimPhotos', {$: $scope});
|
||||
controller.$.model = crudModel;
|
||||
controller.claim = {
|
||||
id: 1,
|
|
@ -0,0 +1,32 @@
|
|||
@import "./variables";
|
||||
|
||||
vn-claim-photos {
|
||||
height: 100%;
|
||||
|
||||
.drop-zone {
|
||||
color: $color-font-secondary;
|
||||
box-sizing: border-box;
|
||||
border-radius: 0.5em;
|
||||
text-align: center;
|
||||
min-height: 100%;
|
||||
|
||||
.empty-rows {
|
||||
padding: 5em $spacing-md;
|
||||
font-size: 1.4em
|
||||
}
|
||||
|
||||
vn-icon {
|
||||
font-size: 3em
|
||||
}
|
||||
}
|
||||
|
||||
.photo-list {
|
||||
padding: $spacing-md;
|
||||
min-height: 100%;
|
||||
|
||||
.photo {
|
||||
width: 32em;
|
||||
height: 18em;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,7 +11,7 @@
|
|||
"card": [
|
||||
{"state": "claim.card.basicData", "icon": "settings"},
|
||||
{"state": "claim.card.detail", "icon": "icon-details"},
|
||||
{"state": "claim.card.dms.index", "icon": "image"},
|
||||
{"state": "claim.card.photos", "icon": "image"},
|
||||
{"state": "claim.card.development", "icon": "icon-traceability"},
|
||||
{"state": "claim.card.action", "icon": "icon-actions"}
|
||||
]
|
||||
|
@ -81,14 +81,9 @@
|
|||
},
|
||||
"acl": ["salesAssistant"]
|
||||
}, {
|
||||
"url": "/dms",
|
||||
"state": "claim.card.dms",
|
||||
"abstract": true,
|
||||
"component": "ui-view"
|
||||
}, {
|
||||
"url" : "/index",
|
||||
"state": "claim.card.dms.index",
|
||||
"component": "vn-claim-dms-index",
|
||||
"url": "/photos",
|
||||
"state": "claim.card.photos",
|
||||
"component": "vn-claim-photos",
|
||||
"description": "Photos",
|
||||
"params": {
|
||||
"claim": "$ctrl.claim"
|
||||
|
|
|
@ -60,8 +60,6 @@ module.exports = function(Self) {
|
|||
scope: {
|
||||
fields: ['id', 'name', 'active']
|
||||
}
|
||||
}, {
|
||||
relation: 'phones'
|
||||
}
|
||||
]
|
||||
});
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethodCtx('sendSms', {
|
||||
description: 'Log the message in clientLog and call the send method',
|
||||
accessType: 'WRITE',
|
||||
accepts: [{
|
||||
arg: 'id',
|
||||
type: 'Number',
|
||||
required: true,
|
||||
description: 'The ticket id',
|
||||
http: {source: 'path'}
|
||||
},
|
||||
{
|
||||
arg: 'destination',
|
||||
type: 'String',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
arg: 'message',
|
||||
type: 'String',
|
||||
required: true,
|
||||
}],
|
||||
returns: {
|
||||
type: 'Object',
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/:id/sendSms`,
|
||||
verb: 'POST'
|
||||
}
|
||||
});
|
||||
|
||||
Self.sendSms = async(ctx, id, destination, message) => {
|
||||
const userId = ctx.req.accessToken.userId;
|
||||
|
||||
let sms = await Self.app.models.Sms.send(ctx, id, destination, message);
|
||||
let logRecord = {
|
||||
originFk: id,
|
||||
userFk: userId,
|
||||
action: 'insert',
|
||||
changedModel: 'sms',
|
||||
newInstance: {
|
||||
destinationFk: id,
|
||||
destination: destination,
|
||||
message: message,
|
||||
statusCode: sms.statusCode,
|
||||
status: sms.status
|
||||
}
|
||||
};
|
||||
|
||||
const clientLog = await Self.app.models.ClientLog.create(logRecord);
|
||||
|
||||
sms.logId = clientLog.id;
|
||||
|
||||
return sms;
|
||||
};
|
||||
};
|
|
@ -7,7 +7,7 @@ describe('Client activeWorkersWithRole', () => {
|
|||
|
||||
let isSalesPerson = await app.models.Account.hasRole(result[0].id, 'salesPerson');
|
||||
|
||||
expect(result.length).toEqual(14);
|
||||
expect(result.length).toEqual(15);
|
||||
expect(isSalesPerson).toBeTruthy();
|
||||
});
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ describe('Client listWorkers', () => {
|
|||
.then(result => {
|
||||
let amountOfEmployees = Object.keys(result).length;
|
||||
|
||||
expect(amountOfEmployees).toEqual(49);
|
||||
expect(amountOfEmployees).toEqual(50);
|
||||
done();
|
||||
})
|
||||
.catch(done.fail);
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
|
||||
describe('client sendSms()', () => {
|
||||
let createdLog;
|
||||
|
||||
afterAll(async done => {
|
||||
await app.models.ClientLog.destroyById(createdLog.id);
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
it('should send a message and log it', async() => {
|
||||
let ctx = {req: {accessToken: {userId: 9}}};
|
||||
let id = 101;
|
||||
let destination = 222222222;
|
||||
let message = 'this is the message created in a test';
|
||||
|
||||
let sms = await app.models.Client.sendSms(ctx, id, destination, message);
|
||||
|
||||
logId = sms.logId;
|
||||
|
||||
createdLog = await app.models.ClientLog.findById(logId);
|
||||
let json = JSON.parse(JSON.stringify(createdLog.newInstance));
|
||||
|
||||
expect(json.message).toEqual(message);
|
||||
});
|
||||
});
|
|
@ -53,9 +53,6 @@ module.exports = Self => {
|
|||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
relation: 'phones'
|
||||
},
|
||||
{
|
||||
relation: 'country',
|
||||
scope: {
|
||||
|
|
|
@ -23,23 +23,25 @@ module.exports = Self => {
|
|||
});
|
||||
|
||||
Self.createWithInsurance = async(data, ctx) => {
|
||||
let tx = await Self.beginTransaction({});
|
||||
const tx = await Self.beginTransaction({});
|
||||
const models = Self.app.models;
|
||||
const $t = ctx.req.__; // $translate
|
||||
|
||||
try {
|
||||
let options = {transaction: tx};
|
||||
|
||||
let classificationSchema = {client: data.clientFk, started: data.started};
|
||||
let newClassification = await Self.create(classificationSchema, options);
|
||||
let CreditInsurance = Self.app.models.CreditInsurance;
|
||||
let insuranceSchema = {
|
||||
const newClassification = await Self.create({
|
||||
client: data.clientFk,
|
||||
started: data.started
|
||||
}, options);
|
||||
|
||||
await models.CreditInsurance.create({
|
||||
creditClassification: newClassification.id,
|
||||
credit: data.credit,
|
||||
grade: data.grade
|
||||
};
|
||||
}, options);
|
||||
|
||||
let newCreditInsurance = await CreditInsurance.create(insuranceSchema, options);
|
||||
await tx.commit();
|
||||
await CreditInsurance.messageSend(newCreditInsurance, ctx.req.accessToken);
|
||||
|
||||
return newClassification;
|
||||
} catch (e) {
|
||||
|
|
|
@ -1,7 +1,20 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
const LoopBackContext = require('loopback-context');
|
||||
|
||||
describe('Client createWithInsurance', () => {
|
||||
let classificationId;
|
||||
const activeCtx = {
|
||||
accessToken: {userId: 101},
|
||||
http: {
|
||||
req: {
|
||||
headers: {origin: 'http://localhost'}
|
||||
}
|
||||
}
|
||||
};
|
||||
const ctx = {req: activeCtx};
|
||||
activeCtx.http.req.__ = value => {
|
||||
return value;
|
||||
};
|
||||
|
||||
afterAll(async done => {
|
||||
await app.models.CreditClassification.destroyById(classificationId);
|
||||
|
@ -20,7 +33,9 @@ describe('Client createWithInsurance', () => {
|
|||
it('should not create the insurance if couldnt create the classification', async() => {
|
||||
let error;
|
||||
let data = {clientFk: null, started: Date.now(), credit: 999, grade: 255};
|
||||
let ctx = {req: {accessToken: {userId: 101}}};
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
|
||||
active: activeCtx
|
||||
});
|
||||
await app.models.CreditClassification.createWithInsurance(data, ctx)
|
||||
.catch(e => {
|
||||
error = e;
|
||||
|
@ -37,7 +52,9 @@ describe('Client createWithInsurance', () => {
|
|||
|
||||
it('should create a new client credit classification with insurance', async() => {
|
||||
let data = {clientFk: 101, started: Date.now(), credit: 999, grade: 255};
|
||||
let ctx = {req: {accessToken: {userId: 101}}};
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
|
||||
active: activeCtx
|
||||
});
|
||||
let result = await app.models.CreditClassification.createWithInsurance(data, ctx);
|
||||
|
||||
classificationId = result.id;
|
||||
|
|
|
@ -3,7 +3,7 @@ const xmlParser = require('xml2js').parseString;
|
|||
const UserError = require('vn-loopback/util/user-error');
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethodCtx('send', {
|
||||
Self.remoteMethod('send', {
|
||||
description: 'Sends SMS to a destination phone',
|
||||
accessType: 'WRITE',
|
||||
accepts: [{
|
||||
|
@ -83,7 +83,6 @@ module.exports = Self => {
|
|||
};
|
||||
|
||||
const sms = await Self.create(newSms);
|
||||
|
||||
if (statusCode != 200)
|
||||
throw new UserError(`We weren't able to send this SMS`);
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ module.exports = Self => {
|
|||
require('../methods/client/canBeInvoiced')(Self);
|
||||
require('../methods/client/uploadFile')(Self);
|
||||
require('../methods/client/lastActiveTickets')(Self);
|
||||
require('../methods/client/sendSms')(Self);
|
||||
|
||||
// Validations
|
||||
|
||||
|
@ -224,34 +225,38 @@ module.exports = Self => {
|
|||
const newInstance = hookState.newInstance;
|
||||
const oldInstance = hookState.oldInstance;
|
||||
const instance = ctx.instance;
|
||||
const models = Self.app.models;
|
||||
|
||||
const payMethodChanged = oldInstance.payMethodFk != newInstance.payMethodFk;
|
||||
const ibanChanged = oldInstance.iban != newInstance.iban;
|
||||
const dueDayChanged = oldInstance.dueDay != newInstance.dueDay;
|
||||
|
||||
if (payMethodChanged || ibanChanged || dueDayChanged) {
|
||||
const message = `La forma de pago del cliente con id ${instance.id} ha cambiado`;
|
||||
const salesPersonFk = instance.salesPersonFk;
|
||||
const loopBackContext = LoopBackContext.getCurrentContext();
|
||||
const httpCtx = {req: loopBackContext.active};
|
||||
const httpRequest = httpCtx.req.http.req;
|
||||
const $t = httpRequest.__;
|
||||
const origin = httpRequest.headers.origin;
|
||||
|
||||
if (salesPersonFk) {
|
||||
const salesPerson = await Self.app.models.Worker.findById(salesPersonFk);
|
||||
await Self.app.models.Message.send(ctx, {
|
||||
recipientFk: salesPerson.userFk,
|
||||
message: message
|
||||
const salesPersonId = instance.salesPersonFk;
|
||||
|
||||
if (salesPersonId) {
|
||||
const fullUrl = `${origin}/#!/client/${instance.id}/billing-data`;
|
||||
const message = $t('MESSAGE_CHANGED_PAYMETHOD', {
|
||||
clientId: instance.id,
|
||||
clientName: instance.name,
|
||||
url: fullUrl
|
||||
});
|
||||
await models.Chat.sendCheckingPresence(httpCtx, salesPersonId, message);
|
||||
}
|
||||
|
||||
// Send email to client
|
||||
|
||||
if (!instance.email) return;
|
||||
const loopBackContext = LoopBackContext.getCurrentContext();
|
||||
const headers = loopBackContext.active.http.req.headers;
|
||||
const params = {
|
||||
const serializedParams = httpParamSerializer({
|
||||
clientId: instance.id,
|
||||
recipient: instance.email
|
||||
};
|
||||
const serializedParams = httpParamSerializer(params);
|
||||
const query = `${headers.origin}/api/email/payment-update?${serializedParams}`;
|
||||
});
|
||||
const query = `${origin}/api/email/payment-update?${serializedParams}`;
|
||||
await request.get(query);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -200,11 +200,6 @@
|
|||
"type": "hasOne",
|
||||
"model": "ClaimRatio",
|
||||
"foreignKey": "clientFk"
|
||||
},
|
||||
"phones": {
|
||||
"type": "hasMany",
|
||||
"model": "UserPhone",
|
||||
"foreignKey": "userFk"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
const LoopBackContext = require('loopback-context');
|
||||
|
||||
module.exports = function(Self) {
|
||||
Self.validateCredit = function(credit) {
|
||||
return credit >= 0;
|
||||
|
@ -38,54 +40,31 @@ module.exports = function(Self) {
|
|||
message: 'The grade must be similar to the last one'
|
||||
});
|
||||
|
||||
Self.messageSend = async function(data, accessToken) {
|
||||
let filter = {
|
||||
include: {
|
||||
relation: 'classification',
|
||||
scope: {
|
||||
fields: ['client'],
|
||||
include: {
|
||||
relation: 'customer',
|
||||
scope: {
|
||||
fields: ['name', 'salesPersonFk'],
|
||||
include: {
|
||||
relation: 'salesPerson',
|
||||
scope: {
|
||||
fields: 'userFk',
|
||||
include: {
|
||||
relation: 'user',
|
||||
scope: {
|
||||
fields: ['name']
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let ctx = {req: {accessToken: accessToken}};
|
||||
let insurance = await Self.findById(data.id, filter);
|
||||
let customer = insurance.classification().customer();
|
||||
|
||||
if (!customer.salesPerson()) return;
|
||||
let salesPersonId = customer.salesPerson().user().id;
|
||||
let grade = data.grade ? `(Grado ${data.grade})` : '(Sin grado)';
|
||||
let params = {
|
||||
recipientFk: salesPersonId,
|
||||
message: `He cambiado el crédito asegurado del `
|
||||
+ `cliente "${customer.name}" a ${data.credit} € ${grade}`
|
||||
};
|
||||
|
||||
Self.app.models.Message.send(ctx, params);
|
||||
};
|
||||
|
||||
// Update from transaction misses ctx accessToken.
|
||||
// Fixed passing accessToken from method messageSend()
|
||||
Self.observe('after save', async function(ctx) {
|
||||
if (ctx.options.accessToken)
|
||||
await Self.messageSend(ctx.instance, ctx.options.accessToken);
|
||||
const loopBackContext = LoopBackContext.getCurrentContext();
|
||||
const httpCtx = {req: loopBackContext.active};
|
||||
const options = ctx.options ? ctx.options : null;
|
||||
const models = Self.app.models;
|
||||
|
||||
if (!ctx.isNewInstance) return;
|
||||
|
||||
const data = ctx.instance;
|
||||
const insurance = await Self.findById(data.id, null, options);
|
||||
const client = insurance.classification().customer();
|
||||
const salesPerson = client.salesPerson();
|
||||
|
||||
if (!salesPerson) return;
|
||||
|
||||
const httpRequest = httpCtx.req.http.req;
|
||||
const $t = httpRequest.__;
|
||||
const origin = httpRequest.headers.origin;
|
||||
const fullPath = `${origin}/#!/client/${client.id}`;
|
||||
const message = $t('MESSAGE_INSURANCE_CHANGE', {
|
||||
clientId: client.id,
|
||||
clientName: client.name,
|
||||
credit: data.credit,
|
||||
url: fullPath
|
||||
});
|
||||
await models.Chat.sendCheckingPresence(httpCtx, salesPerson.id, message);
|
||||
});
|
||||
};
|
||||
|
|
|
@ -32,5 +32,31 @@
|
|||
"model": "CreditClassification",
|
||||
"foreignKey": "creditClassification"
|
||||
}
|
||||
},
|
||||
"scope": {
|
||||
"include": {
|
||||
"relation": "classification",
|
||||
"scope": {
|
||||
"fields": ["client"],
|
||||
"include": {
|
||||
"relation": "customer",
|
||||
"scope": {
|
||||
"fields": ["name", "salesPersonFk"],
|
||||
"include": {
|
||||
"relation": "salesPerson",
|
||||
"scope": {
|
||||
"fields": "userFk",
|
||||
"include": {
|
||||
"relation": "user",
|
||||
"scope": {
|
||||
"fields": ["name"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,11 +1,7 @@
|
|||
{
|
||||
"name": "Sms",
|
||||
"description": "Sms sent to client",
|
||||
"base": "Loggable",
|
||||
"log": {
|
||||
"model":"ClientLog",
|
||||
"relation": "recipient"
|
||||
},
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "sms"
|
||||
|
@ -45,11 +41,6 @@
|
|||
"type": "belongsTo",
|
||||
"model": "Account",
|
||||
"foreignKey": "senderFk"
|
||||
},
|
||||
"recipient": {
|
||||
"type": "belongsTo",
|
||||
"model": "Client",
|
||||
"foreignKey": "destinationFk"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,20 @@
|
|||
info="You can save multiple emails">
|
||||
</vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-textfield
|
||||
vn-one
|
||||
label="Phone"
|
||||
ng-model="$ctrl.client.phone"
|
||||
rule>
|
||||
</vn-textfield>
|
||||
<vn-textfield
|
||||
vn-one
|
||||
label="Mobile"
|
||||
ng-model="$ctrl.client.mobile"
|
||||
rule>
|
||||
</vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-autocomplete
|
||||
vn-one
|
||||
|
|
|
@ -1,48 +1,45 @@
|
|||
<vn-crud-model
|
||||
url="UserPhoneTypes"
|
||||
data="phoneTypes"
|
||||
auto-load="true">
|
||||
</vn-crud-model>
|
||||
<vn-crud-model
|
||||
vn-id="model"
|
||||
url="UserPhones"
|
||||
data="$ctrl.phones">
|
||||
url="ClientContacts"
|
||||
fields="['id', 'name', 'phone', 'clientFk']"
|
||||
link="{clientFk: $ctrl.$stateParams.id}"
|
||||
data="contacts"
|
||||
auto-load="true">
|
||||
</vn-crud-model>
|
||||
<vn-watcher
|
||||
vn-id="watcher"
|
||||
data="$ctrl.phones">
|
||||
data="contacts"
|
||||
form="form">
|
||||
</vn-watcher>
|
||||
<form name="form" ng-submit="$ctrl.onSubmit()" class="vn-w-md">
|
||||
<vn-card class="vn-pa-lg">
|
||||
<vn-horizontal ng-repeat="clientPhone in $ctrl.phones">
|
||||
<vn-autocomplete
|
||||
<vn-horizontal ng-repeat="contact in contacts">
|
||||
<vn-textfield
|
||||
vn-one
|
||||
ng-model="clientPhone.typeFk"
|
||||
initial-data="clientPhone.typeFk"
|
||||
data ="phoneTypes"
|
||||
show-field="code"
|
||||
value-field="code"
|
||||
label="Type"
|
||||
vn-focus>
|
||||
</vn-autocomplete>
|
||||
label="Name"
|
||||
ng-model="contact.name"
|
||||
rule="ClientContact">
|
||||
</vn-textfield>
|
||||
<vn-textfield
|
||||
vn-one
|
||||
label="Phone"
|
||||
ng-model="clientPhone.phone">
|
||||
ng-model="contact.phone"
|
||||
rule="ClientContact"
|
||||
vn-focus>
|
||||
</vn-textfield>
|
||||
<vn-none>
|
||||
<vn-icon-button
|
||||
vn-tooltip="Remove phone"
|
||||
vn-tooltip="Remove contact"
|
||||
icon="delete"
|
||||
ng-click="model.remove($index)"
|
||||
tabindex="-1">
|
||||
tabindex="-1"
|
||||
ng-click="model.remove($index)">
|
||||
</vn-icon-button>
|
||||
</vn-none>
|
||||
</vn-horizontal>
|
||||
<vn-one>
|
||||
<vn-icon-button
|
||||
vn-bind="+"
|
||||
vn-tooltip="Add phone"
|
||||
vn-tooltip="Add contact"
|
||||
icon="add_circle"
|
||||
ng-click="$ctrl.add()">
|
||||
</vn-icon-button>
|
|
@ -0,0 +1,35 @@
|
|||
import ngModule from '../module';
|
||||
|
||||
class Controller {
|
||||
constructor($scope, $stateParams, $translate) {
|
||||
this.$scope = $scope;
|
||||
this.$stateParams = $stateParams;
|
||||
this.$translate = $translate;
|
||||
}
|
||||
|
||||
add() {
|
||||
this.$scope.model.insert({
|
||||
clientFk: this.client.id,
|
||||
name: this.$translate.instant('Phone'),
|
||||
phone: null
|
||||
});
|
||||
}
|
||||
|
||||
onSubmit() {
|
||||
this.$scope.watcher.check();
|
||||
this.$scope.model.save().then(() => {
|
||||
this.$scope.watcher.notifySaved();
|
||||
this.$scope.model.refresh();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Controller.$inject = ['$scope', '$stateParams', '$translate'];
|
||||
|
||||
ngModule.component('vnClientContact', {
|
||||
template: require('./index.html'),
|
||||
controller: Controller,
|
||||
bindings: {
|
||||
client: '<'
|
||||
}
|
||||
});
|
|
@ -30,7 +30,7 @@ import './credit-insurance/index';
|
|||
import './credit-insurance/create';
|
||||
import './credit-insurance/insurance/index';
|
||||
import './credit-insurance/insurance/create';
|
||||
import './phones';
|
||||
import './contact';
|
||||
import './sample/index';
|
||||
import './sample/create';
|
||||
import './web-payment';
|
||||
|
|
|
@ -24,6 +24,10 @@
|
|||
<vn-label-value
|
||||
label="Id"
|
||||
value="{{::client.id}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value
|
||||
label="Phone"
|
||||
value="{{::client.phone | phone}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value
|
||||
label="Town/City"
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
import ngModule from '../module';
|
||||
import Section from 'salix/components/section';
|
||||
|
||||
class Controller extends Section {
|
||||
get client() {
|
||||
return this._client;
|
||||
}
|
||||
|
||||
set client(value) {
|
||||
this._client = value;
|
||||
if (value)
|
||||
this.setLink(value);
|
||||
}
|
||||
|
||||
setLink(value) {
|
||||
this.$.$applyAsync(()=> {
|
||||
this.$.model.link = {userFk: value.id};
|
||||
this.$.model.refresh();
|
||||
});
|
||||
}
|
||||
|
||||
onSubmit() {
|
||||
this.$.watcher.check();
|
||||
return this.$.model.save().then(() => {
|
||||
this.$.watcher.updateOriginalData();
|
||||
this.$.watcher.notifySaved();
|
||||
this.card.reload();
|
||||
});
|
||||
}
|
||||
|
||||
add() {
|
||||
this.$.model.insert();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ngModule.component('vnClientPhones', {
|
||||
template: require('./index.html'),
|
||||
controller: Controller,
|
||||
require: {card: '^vnClientCard'},
|
||||
bindings: {
|
||||
client: '<'
|
||||
}
|
||||
});
|
|
@ -1,50 +0,0 @@
|
|||
import './index';
|
||||
import watcher from 'core/mocks/watcher';
|
||||
|
||||
describe('Component vnClientPhones', () => {
|
||||
let controller;
|
||||
let $element;
|
||||
let $scope;
|
||||
|
||||
beforeEach(ngModule('client'));
|
||||
|
||||
beforeEach(angular.mock.inject(($componentController, $rootScope) => {
|
||||
$scope = $rootScope.$new();
|
||||
$element = angular.element('<div></div>');
|
||||
$scope.watcher = watcher;
|
||||
$scope.model = {
|
||||
link: 1,
|
||||
save: () => {}
|
||||
};
|
||||
controller = $componentController('vnClientPhones', {$element, $scope});
|
||||
controller.card = {reload: () => {}};
|
||||
}));
|
||||
|
||||
describe('setLink()', () => {
|
||||
it('set the link in the model and refreshes it', () => {
|
||||
spyOn(controller.$, '$applyAsync');
|
||||
let value = {id: 106};
|
||||
controller.setLink(value);
|
||||
|
||||
expect(controller.$.$applyAsync).toHaveBeenCalledWith(jasmine.any(Function));
|
||||
});
|
||||
});
|
||||
|
||||
describe('onSubmit()', () => {
|
||||
it('should call watcher functions, reload the card and save the model', done => {
|
||||
spyOn(controller.$.watcher, 'check');
|
||||
spyOn(controller.$.model, 'save').and.returnValue(Promise.resolve());
|
||||
|
||||
spyOn(controller.$.watcher, 'updateOriginalData');
|
||||
spyOn(controller.$.watcher, 'notifySaved');
|
||||
spyOn(controller.card, 'reload');
|
||||
controller.onSubmit();
|
||||
controller.onSubmit().then(() => {
|
||||
expect(controller.$.watcher.updateOriginalData).toHaveBeenCalledWith();
|
||||
expect(controller.$.watcher.notifySaved).toHaveBeenCalledWith();
|
||||
expect(controller.card.reload).toHaveBeenCalledWith();
|
||||
done();
|
||||
}).catch(done.fail);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -26,7 +26,7 @@
|
|||
{"state": "client.card.webAccess", "icon": "cloud"},
|
||||
{"state": "client.card.mandate", "icon": "pan_tool"},
|
||||
{"state": "client.card.creditInsurance.index", "icon": "icon-solunion"},
|
||||
{"state": "client.card.phones", "icon": "contact_phone"},
|
||||
{"state": "client.card.contact", "icon": "contact_phone"},
|
||||
{"state": "client.card.sample.index", "icon": "mail"},
|
||||
{"state": "client.card.webPayment", "icon": "icon-onlinepayment"},
|
||||
{"state": "client.card.dms.index", "icon": "cloud_upload"}
|
||||
|
@ -282,10 +282,10 @@
|
|||
"client": "$ctrl.client"
|
||||
}
|
||||
}, {
|
||||
"url": "/phones",
|
||||
"state": "client.card.phones",
|
||||
"component": "vn-client-phones",
|
||||
"description": "Client phones",
|
||||
"url": "/contact",
|
||||
"state": "client.card.contact",
|
||||
"component": "vn-client-contact",
|
||||
"description": "Contacts",
|
||||
"params": {
|
||||
"client": "$ctrl.client"
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
vn-id="SMSDialog"
|
||||
on-response="$ctrl.onResponse($response)">
|
||||
<tpl-body>
|
||||
<section class="SMSDialog">
|
||||
<h5 class="vn-py-sm" translate>Send SMS</h5>
|
||||
<vn-horizontal>
|
||||
<vn-textfield
|
||||
|
@ -11,13 +12,21 @@
|
|||
</vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal >
|
||||
<vn-textarea
|
||||
vn-one
|
||||
<vn-textarea vn-one
|
||||
vn-id="message"
|
||||
label="Message"
|
||||
ng-model="$ctrl.sms.message"
|
||||
rows="5"
|
||||
maxlength="160"
|
||||
rule>
|
||||
</vn-textarea>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<span>
|
||||
{{'Characters remaining' | translate}}: {{$ctrl.charactersRemaining()}}
|
||||
</span>
|
||||
</vn-horizontal>
|
||||
</section>
|
||||
</tpl-body>
|
||||
<tpl-buttons>
|
||||
<input type="button" response="cancel" translate-attr="{value: 'Cancel'}"/>
|
||||
|
|
|
@ -16,9 +16,19 @@ class Controller extends Component {
|
|||
this.$scope.SMSDialog.show();
|
||||
}
|
||||
|
||||
charactersRemaining() {
|
||||
let elementMaxLength;
|
||||
let textAreaLength;
|
||||
const element = this.$scope.message;
|
||||
|
||||
textAreaLength = element.input.textLength;
|
||||
elementMaxLength = element.maxlength;
|
||||
return elementMaxLength - textAreaLength;
|
||||
}
|
||||
|
||||
onResponse(response) {
|
||||
if (response === 'accept') {
|
||||
this.$http.post(`Sms/send`, this.sms).then(res => {
|
||||
this.$http.post(`Clients/${this.$params.id}/sendSms`, this.sms).then(res => {
|
||||
this.vnApp.showMessage(this.$translate.instant('SMS sent!'));
|
||||
|
||||
if (res.data) this.emit('send', {response: res.data});
|
||||
|
|
|
@ -8,11 +8,13 @@ describe('Client', () => {
|
|||
|
||||
beforeEach(ngModule('client'));
|
||||
|
||||
beforeEach(angular.mock.inject(($componentController, _$httpBackend_) => {
|
||||
beforeEach(angular.mock.inject(($componentController, $rootScope, _$httpBackend_) => {
|
||||
$httpBackend = _$httpBackend_;
|
||||
let $scope = $rootScope.$new();
|
||||
$element = angular.element('<vn-dialog></vn-dialog>');
|
||||
controller = $componentController('vnClientSms', {$element});
|
||||
controller = $componentController('vnClientSms', {$element, $scope});
|
||||
controller.client = {id: 101};
|
||||
controller.$params = {id: 101};
|
||||
}));
|
||||
|
||||
describe('onResponse()', () => {
|
||||
|
@ -21,8 +23,7 @@ describe('Client', () => {
|
|||
controller.sms = {destinationFk: 101, destination: 111111111, message: 'My SMS'};
|
||||
|
||||
spyOn(controller.vnApp, 'showMessage');
|
||||
$httpBackend.when('POST', `Sms/send`, params).respond(200, params);
|
||||
$httpBackend.expect('POST', `Sms/send`, params).respond(params);
|
||||
$httpBackend.expect('POST', `Clients/101/sendSms`, params).respond(200, params);
|
||||
|
||||
controller.onResponse('accept');
|
||||
$httpBackend.flush();
|
||||
|
@ -30,5 +31,20 @@ describe('Client', () => {
|
|||
expect(controller.vnApp.showMessage).toHaveBeenCalledWith('SMS sent!');
|
||||
});
|
||||
});
|
||||
|
||||
describe('charactersRemaining()', () => {
|
||||
it('should return the characters remaining in a element', () => {
|
||||
controller.$scope.message = {
|
||||
input: {
|
||||
textLength: 50
|
||||
},
|
||||
maxlength: 150
|
||||
};
|
||||
|
||||
let result = controller.charactersRemaining();
|
||||
|
||||
expect(result).toEqual(100);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -2,3 +2,4 @@ Send SMS: Enviar SMS
|
|||
Destination: Destinatario
|
||||
Message: Mensaje
|
||||
SMS sent!: ¡SMS enviado!
|
||||
Characters remaining: Carácteres restantes
|
|
@ -1,7 +1,5 @@
|
|||
@import "variables";
|
||||
|
||||
vn-client-sms {
|
||||
textarea {
|
||||
height: 8em
|
||||
}
|
||||
.SMSDialog {
|
||||
min-width: 25em
|
||||
}
|
|
@ -12,10 +12,11 @@
|
|||
<vn-label-value label="Contact"
|
||||
value="{{$ctrl.summary.contact}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value ng-repeat = "phone in $ctrl.summary.phones"
|
||||
label="Phone"
|
||||
value="{{phone.phone}}">
|
||||
<vn-label-value label="Phone"
|
||||
value="{{$ctrl.summary.phone}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value label="Mobile"
|
||||
value="{{$ctrl.summary.mobile}}">
|
||||
<vn-label-value label="Email" ellipsize="false"
|
||||
value="{{$ctrl.summary.email}}">
|
||||
</vn-label-value>
|
||||
|
|
|
@ -0,0 +1,149 @@
|
|||
|
||||
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
|
||||
const buildFilter = require('vn-loopback/util/filter').buildFilter;
|
||||
const mergeFilters = require('vn-loopback/util/filter').mergeFilters;
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethodCtx('filter', {
|
||||
description: 'Find all instances of the model matched by filter from the data source.',
|
||||
accessType: 'READ',
|
||||
accepts: [
|
||||
{
|
||||
arg: 'filter',
|
||||
type: 'Object',
|
||||
description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string',
|
||||
http: {source: 'query'}
|
||||
}, {
|
||||
arg: 'search',
|
||||
type: 'String',
|
||||
description: 'Searchs the entry by id',
|
||||
http: {source: 'query'}
|
||||
}, {
|
||||
arg: 'id',
|
||||
type: 'Integer',
|
||||
description: 'The entry id',
|
||||
http: {source: 'query'}
|
||||
}, {
|
||||
arg: 'created',
|
||||
type: 'Date',
|
||||
description: 'The created date to filter',
|
||||
http: {source: 'query'}
|
||||
}, {
|
||||
arg: 'travelFk',
|
||||
type: 'Number',
|
||||
description: 'The travel id to filter',
|
||||
http: {source: 'query'}
|
||||
}, {
|
||||
arg: 'companyFk',
|
||||
type: 'Number',
|
||||
description: 'The company to filter',
|
||||
http: {source: 'query'}
|
||||
}, {
|
||||
arg: 'isBooked',
|
||||
type: 'Boolean',
|
||||
description: 'The isBokked filter',
|
||||
http: {source: 'query'}
|
||||
}, {
|
||||
arg: 'isConfirmed',
|
||||
type: 'Boolean',
|
||||
description: 'The isConfirmed filter',
|
||||
http: {source: 'query'}
|
||||
}, {
|
||||
arg: 'isOrdered',
|
||||
type: 'Boolean',
|
||||
description: 'The isOrdered filter',
|
||||
http: {source: 'query'}
|
||||
}, {
|
||||
arg: 'ref',
|
||||
type: 'String',
|
||||
description: 'The ref filter',
|
||||
http: {source: 'query'}
|
||||
}, {
|
||||
arg: 'supplierFk',
|
||||
type: 'Number',
|
||||
description: 'The supplier id to filter',
|
||||
http: {source: 'query'}
|
||||
}, {
|
||||
arg: 'currencyFk',
|
||||
type: 'Number',
|
||||
description: 'The currency id to filter',
|
||||
http: {source: 'query'}
|
||||
}
|
||||
],
|
||||
returns: {
|
||||
type: ['Object'],
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/filter`,
|
||||
verb: 'GET'
|
||||
}
|
||||
});
|
||||
|
||||
Self.filter = async(ctx, filter) => {
|
||||
let conn = Self.dataSource.connector;
|
||||
let where = buildFilter(ctx.args, (param, value) => {
|
||||
switch (param) {
|
||||
case 'search':
|
||||
return {'e.id': value};
|
||||
case 'ref':
|
||||
param = `e.${param}`;
|
||||
return {[param]: {like: `%${value}%`}};
|
||||
case 'created':
|
||||
return {'e.created': {gte: value}};
|
||||
case 'id':
|
||||
case 'isBooked':
|
||||
case 'isConfirmed':
|
||||
case 'isOrdered':
|
||||
case 'companyFk':
|
||||
case 'travelFk':
|
||||
case 'currencyFk':
|
||||
case 'supplierFk':
|
||||
param = `e.${param}`;
|
||||
return {[param]: value};
|
||||
}
|
||||
});
|
||||
filter = mergeFilters(ctx.args.filter, {where});
|
||||
|
||||
let stmts = [];
|
||||
let stmt;
|
||||
stmt = new ParameterizedSQL(
|
||||
`SELECT
|
||||
e.id,
|
||||
e.supplierFk,
|
||||
e.dated,
|
||||
e.ref,
|
||||
e.isBooked,
|
||||
e.isInventory,
|
||||
e.notes,
|
||||
e.isConfirmed,
|
||||
e.isOrdered,
|
||||
e.isRaid,
|
||||
e.commission,
|
||||
e.created,
|
||||
e.evaNotes,
|
||||
e.travelFk,
|
||||
e.currencyFk,
|
||||
e.companyFk,
|
||||
e.gestDocFk,
|
||||
e.invoiceInFk,
|
||||
s.name AS supplierName,
|
||||
co.code AS companyCode,
|
||||
cu.code AS currencyCode
|
||||
FROM vn.entry e
|
||||
JOIN vn.supplier s ON s.id = e.supplierFk
|
||||
JOIN vn.travel t ON t.id = e.travelFk
|
||||
JOIN vn.company co ON co.id = e.companyFk
|
||||
JOIN vn.currency cu ON cu.id = e.currencyFk`
|
||||
);
|
||||
|
||||
|
||||
stmt.merge(conn.makeSuffix(filter));
|
||||
let itemsIndex = stmts.push(stmt) - 1;
|
||||
|
||||
let sql = ParameterizedSQL.join(stmts, ';');
|
||||
let result = await conn.executeStmt(sql);
|
||||
return itemsIndex === 0 ? result : result[itemsIndex];
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
|
||||
describe('Entry filter()', () => {
|
||||
it('should return the entry matching "search"', async() => {
|
||||
let ctx = {
|
||||
args: {
|
||||
search: 1
|
||||
}
|
||||
};
|
||||
|
||||
let result = await app.models.Entry.filter(ctx);
|
||||
|
||||
expect(result.length).toEqual(1);
|
||||
expect(result[0].id).toEqual(1);
|
||||
});
|
||||
|
||||
it('should return the entry matching the currency', async() => {
|
||||
let ctx = {
|
||||
args: {
|
||||
currencyFk: 1
|
||||
}
|
||||
};
|
||||
|
||||
let result = await app.models.Entry.filter(ctx);
|
||||
|
||||
expect(result.length).toEqual(7);
|
||||
});
|
||||
|
||||
it('should return the entry matching the supplier', async() => {
|
||||
let ctx = {
|
||||
args: {
|
||||
supplierFk: 2
|
||||
}
|
||||
};
|
||||
|
||||
let result = await app.models.Entry.filter(ctx);
|
||||
|
||||
expect(result.length).toEqual(5);
|
||||
});
|
||||
|
||||
it('should return the entry matching the company', async() => {
|
||||
let ctx = {
|
||||
args: {
|
||||
companyFk: 442
|
||||
}
|
||||
};
|
||||
|
||||
let result = await app.models.Entry.filter(ctx);
|
||||
|
||||
expect(result.length).toEqual(6);
|
||||
});
|
||||
|
||||
it('should return the entries matching isBooked', async() => {
|
||||
let ctx = {
|
||||
args: {
|
||||
isBooked: true,
|
||||
}
|
||||
};
|
||||
|
||||
let result = await app.models.Entry.filter(ctx);
|
||||
|
||||
expect(result.length).toEqual(0);
|
||||
});
|
||||
|
||||
it('should return the routes matching the reference and travel', async() => {
|
||||
let ctx = {
|
||||
args: {
|
||||
reference: 'movement',
|
||||
travelFk: '2'
|
||||
}
|
||||
};
|
||||
|
||||
let result = await app.models.Entry.filter(ctx);
|
||||
|
||||
expect(result.length).toEqual(2);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"Entry": {
|
||||
"dataSource": "vn"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
|
||||
module.exports = Self => {
|
||||
require('../methods/entry/filter')(Self);
|
||||
};
|
|
@ -0,0 +1,5 @@
|
|||
<vn-portal slot="menu">
|
||||
<vn-entry-descriptor entry="$ctrl.entry"></vn-entry-descriptor>
|
||||
<vn-left-menu source="card"></vn-left-menu>
|
||||
</vn-portal>
|
||||
<ui-view></ui-view>
|
|
@ -0,0 +1,33 @@
|
|||
import ngModule from '../module';
|
||||
import ModuleCard from 'salix/components/module-card';
|
||||
|
||||
class Controller extends ModuleCard {
|
||||
reload() {
|
||||
let filter = {
|
||||
include: [
|
||||
{
|
||||
relation: 'company',
|
||||
scope: {
|
||||
fields: ['id', 'code']
|
||||
}
|
||||
}, {
|
||||
relation: 'travel'
|
||||
}, {
|
||||
relation: 'supplier',
|
||||
scope: {
|
||||
fields: ['id', 'name']
|
||||
}
|
||||
}, {
|
||||
relation: 'currency'
|
||||
}
|
||||
]
|
||||
};
|
||||
this.$http.get(`Entries/${this.$params.id}`, {filter})
|
||||
.then(response => this.entry = response.data);
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.component('vnEntry Card', {
|
||||
template: require('./index.html'),
|
||||
controller: Controller
|
||||
});
|
|
@ -0,0 +1,21 @@
|
|||
<div class="vn-descriptor">
|
||||
<div class="header">
|
||||
<a translate-attr="{title: 'Return to module index'}" ui-sref="entry.index">
|
||||
<vn-icon icon="chevron_left"></vn-icon>
|
||||
</a>
|
||||
<a translate-attr="{title: 'Preview'}" ui-sref="entry.card.summary({id: $ctrl.entry.id})">
|
||||
<vn-icon icon="desktop_windows"></vn-icon>
|
||||
</a>
|
||||
<span></span>
|
||||
</div>
|
||||
<div class="body">
|
||||
<div class="attributes">
|
||||
<vn-label-value label="Id"
|
||||
value="{{$ctrl.entry.id}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value label="Reference"
|
||||
value="{{$ctrl.entry.ref}}">
|
||||
</vn-label-value>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,20 @@
|
|||
import ngModule from '../module';
|
||||
|
||||
class Controller {
|
||||
constructor($scope) {
|
||||
this.$ = $scope;
|
||||
}
|
||||
}
|
||||
|
||||
Controller.$inject = ['$scope'];
|
||||
|
||||
ngModule.component('vnEntryDescriptor', {
|
||||
template: require('./index.html'),
|
||||
bindings: {
|
||||
entry: '<'
|
||||
},
|
||||
require: {
|
||||
card: '^?vnEntryCard'
|
||||
},
|
||||
controller: Controller
|
||||
});
|
|
@ -0,0 +1 @@
|
|||
Reference: Referencia
|
|
@ -0,0 +1,11 @@
|
|||
export * from './module';
|
||||
|
||||
import './main';
|
||||
import './index/';
|
||||
import './search-panel';
|
||||
import './descriptor';
|
||||
import './card';
|
||||
// import './summary';
|
||||
// import './basic-data';
|
||||
// import './log';
|
||||
// import './create';
|
|
@ -0,0 +1,63 @@
|
|||
<vn-crud-model
|
||||
vn-id="model"
|
||||
url="Entries/filter"
|
||||
limit="20"
|
||||
params="::$ctrl.params"
|
||||
data="entries"
|
||||
auto-load="true">
|
||||
</vn-crud-model>
|
||||
<vn-auto-search
|
||||
on-search="$ctrl.onSearch($params)">
|
||||
</vn-auto-search>
|
||||
<vn-data-viewer
|
||||
model="model"
|
||||
class="vn-mb-xl vn-w-xl">
|
||||
<vn-card>
|
||||
<vn-table model="model">
|
||||
<vn-thead>
|
||||
<vn-tr>
|
||||
<vn-th field="id" number>Id</vn-th>
|
||||
<vn-th field="created" center>Created</vn-th>
|
||||
<vn-th field="travelFk">Travel</vn-th>
|
||||
<vn-th>Notes</vn-th>
|
||||
<vn-th>Reference</vn-th>
|
||||
<vn-th field="isBooked" center>Booked</vn-th>
|
||||
<vn-th field="isInventory" center>Is inventory</vn-th>
|
||||
<vn-th field="isConfirmed" center>Confirmed</vn-th>
|
||||
<vn-th field="isOrdered" center>Ordered</vn-th>
|
||||
<vn-th field="isRaid" center>Is raid</vn-th>
|
||||
<vn-th center>Commission</vn-th>
|
||||
<vn-th field="supplierFk">Supplier</vn-th>
|
||||
<vn-th field="currencyFk" center>Currency</vn-th>
|
||||
<vn-th field="companyFk" center>Company</vn-th>
|
||||
</vn-tr>
|
||||
</vn-thead>
|
||||
<vn-tbody>
|
||||
<a ng-repeat="entry in entries"
|
||||
class="clickable vn-tr search-result"
|
||||
ui-sref="entry.card.summary({id: {{::entry.id}}})">
|
||||
<vn-td number>{{::entry.id}}</vn-td>
|
||||
<vn-td center>{{::entry.created | date:'dd/MM/yyyy'}}</vn-td>
|
||||
<vn-td center expand>{{::entry.travelFk}}</vn-td>
|
||||
<vn-td expand>{{::entry.notes}}</vn-td>
|
||||
<vn-td expand>{{::entry.ref}}</vn-td>
|
||||
<vn-td center><vn-check ng-model="entry.isBooked" disabled="true"></vn-check></vn-td>
|
||||
<vn-td center><vn-check ng-model="entry.isInventory" disabled="true"></vn-check></vn-td>
|
||||
<vn-td center><vn-check ng-model="entry.isConfirmed" disabled="true"></vn-check></vn-td>
|
||||
<vn-td center><vn-check ng-model="entry.isOrdered" disabled="true"></vn-check></vn-td>
|
||||
<vn-td center><vn-check ng-model="entry.isRaid" disabled="true"></vn-check></vn-td>
|
||||
<vn-td center expand>{{::entry.commission}}</vn-td>
|
||||
<vn-td expand>{{::entry.supplierName}}</vn-td>
|
||||
<vn-td center expand>{{::entry.currencyCode}}</vn-td>
|
||||
<vn-td center expand>{{::entry.companyCode}}</vn-td>
|
||||
</a>
|
||||
</vn-tbody>
|
||||
</vn-table>
|
||||
</vn-data-viewer>
|
||||
</vn-card>
|
||||
<vn-popup vn-id="summary">
|
||||
<vn-entry-summary
|
||||
entry="$ctrl.entrySelected">
|
||||
</vn-entry-summary>
|
||||
</vn-popup>
|
||||
<vn-scroll-up></vn-scroll-up>
|
|
@ -0,0 +1,21 @@
|
|||
import ngModule from '../module';
|
||||
|
||||
export default class Controller {
|
||||
constructor($scope) {
|
||||
this.$ = $scope;
|
||||
}
|
||||
|
||||
onSearch(params) {
|
||||
if (params)
|
||||
this.$.model.applyFilter(null, params);
|
||||
else
|
||||
this.$.model.clear();
|
||||
}
|
||||
}
|
||||
|
||||
Controller.$inject = ['$scope'];
|
||||
|
||||
ngModule.component('vnEntryIndex', {
|
||||
template: require('./index.html'),
|
||||
controller: Controller
|
||||
});
|
|
@ -0,0 +1,15 @@
|
|||
#Ordenar alfabeticamente
|
||||
Reference: Referencia
|
||||
Created: Creado
|
||||
Booked: Facturado
|
||||
Is inventory: Inventario
|
||||
Notes: Notas
|
||||
Travel: Envío
|
||||
Supplier: Proveedor
|
||||
Currency: Moneda
|
||||
Company: Empresa
|
||||
Confirmed: Confirmada
|
||||
Ordered: Pedida
|
||||
Is raid: Redada
|
||||
Commission: Comisión
|
||||
# Sections
|
|
@ -0,0 +1,11 @@
|
|||
<vn-portal slot="topbar">
|
||||
<vn-searchbar
|
||||
search-state="entry.index"
|
||||
panel="vn-entry-search-panel"
|
||||
info="Search entrys by id">
|
||||
</vn-searchbar>
|
||||
</vn-portal>
|
||||
<vn-portal slot="menu">
|
||||
<vn-left-menu></vn-left-menu>
|
||||
</vn-portal>
|
||||
<ui-view></ui-view>
|
|
@ -0,0 +1,9 @@
|
|||
import ngModule from '../module';
|
||||
import ModuleMain from 'salix/components/module-main';
|
||||
|
||||
export default class Entry extends ModuleMain {}
|
||||
|
||||
ngModule.vnComponent('vnEntry', {
|
||||
controller: Entry,
|
||||
template: require('./index.html')
|
||||
});
|
|
@ -0,0 +1,3 @@
|
|||
import {ng} from 'core/vendor';
|
||||
|
||||
export default ng.module('entry', ['vnCore']);
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue