salix/modules/client/back/models/client.js

320 lines
10 KiB
JavaScript
Raw Normal View History

2019-02-28 13:30:29 +00:00
let request = require('request-promise-native');
2018-12-27 11:54:16 +00:00
let UserError = require('vn-loopback/util/user-error');
let getFinalState = require('vn-loopback/util/hook').getFinalState;
let isMultiple = require('vn-loopback/util/hook').isMultiple;
const httpParamSerializer = require('vn-loopback/util/http').httpParamSerializer;
const LoopBackContext = require('loopback-context');
module.exports = Self => {
// Methods
require('../methods/client/activeWorkersWithRole')(Self);
require('../methods/client/getCard')(Self);
require('../methods/client/createWithUser')(Self);
require('../methods/client/listWorkers')(Self);
require('../methods/client/hasCustomerRole')(Self);
require('../methods/client/isValidClient')(Self);
require('../methods/client/addressesPropagateRe')(Self);
require('../methods/client/getDebt')(Self);
2018-03-27 13:06:22 +00:00
require('../methods/client/getMana')(Self);
require('../methods/client/getAverageInvoiced')(Self);
require('../methods/client/summary')(Self);
2018-07-13 10:37:58 +00:00
require('../methods/client/updateFiscalData')(Self);
2018-09-28 13:00:12 +00:00
require('../methods/client/getTransactions')(Self);
require('../methods/client/confirmTransaction')(Self);
2019-04-05 10:24:39 +00:00
require('../methods/client/canBeInvoiced')(Self);
require('../methods/client/uploadFile')(Self);
2019-08-09 06:04:44 +00:00
require('../methods/client/lastActiveTickets')(Self);
2020-01-15 12:27:14 +00:00
require('../methods/client/sendSms')(Self);
// Validations
Self.validatesPresenceOf('street', {
message: 'Street cannot be empty'
});
Self.validatesPresenceOf('city', {
message: 'City cannot be empty'
});
Self.validatesUniquenessOf('fi', {
2018-04-05 11:08:10 +00:00
message: 'TIN must be unique'
});
Self.validatesUniquenessOf('socialName', {
2018-04-05 11:20:27 +00:00
message: 'The company name must be unique'
});
Self.validatesFormatOf('email', {
2018-04-05 11:20:27 +00:00
message: 'Invalid email',
allowNull: true,
allowBlank: true,
with: /^[\w|.|-]+@[\w|-]+(\.[\w|-]+)*(,[\w|.|-]+@[\w|-]+(\.[\w|-]+)*)*$/
});
Self.validatesLengthOf('postcode', {
allowNull: true,
allowBlank: true,
min: 3, max: 10
});
Self.validateAsync('iban', ibanNeedsValidation, {
message: 'The IBAN does not have the correct format'
});
let validateIban = require('../validations/validateIban');
async function ibanNeedsValidation(err, done) {
let filter = {
fields: ['code'],
where: {id: this.countryFk}
};
let country = await Self.app.models.Country.findOne(filter);
let code = country ? country.code.toLowerCase() : null;
if (code != 'es')
return done();
if (!validateIban(this.iban))
err();
done();
}
2018-03-21 11:57:23 +00:00
Self.validateAsync('fi', tinIsValid, {
2018-04-05 11:08:10 +00:00
message: 'Invalid TIN'
});
2019-03-13 07:35:25 +00:00
2018-03-21 11:57:23 +00:00
let validateTin = require('../validations/validateTin');
async function tinIsValid(err, done) {
if (!this.isTaxDataChecked)
return done();
2018-03-12 13:13:36 +00:00
let filter = {
fields: ['code'],
where: {id: this.countryFk}
};
let country = await Self.app.models.Country.findOne(filter);
let code = country ? country.code.toLowerCase() : null;
2019-03-13 07:35:25 +00:00
if (!this.fi || !validateTin(this.fi, code))
2018-03-12 13:13:36 +00:00
err();
done();
}
Self.validate('payMethod', hasSalesMan, {
2018-04-05 11:20:27 +00:00
message: 'Cannot change the payment method if no salesperson'
});
2018-10-16 11:06:58 +00:00
function hasSalesMan(err) {
if (this.payMethod && !this.salesPerson)
err();
}
Self.validate('isEqualizated', cannotHaveET, {
message: 'Cannot check Equalization Tax in this NIF/CIF'
});
function cannotHaveET(err) {
2019-09-19 06:58:42 +00:00
if (!this.fi) return;
let tin = this.fi.toUpperCase();
let cannotHaveET = /^[A-B]/.test(tin);
if (cannotHaveET && this.isEqualizated)
err();
}
Self.validateAsync('payMethodFk', hasIban, {
message: 'That payment method requires an IBAN'
});
function hasIban(err, done) {
Self.app.models.PayMethod.findById(this.payMethodFk, (_, instance) => {
if (instance && instance.ibanRequired && !this.iban)
err();
done();
});
}
Self.validateAsync('bankEntityFk', hasBic, {
message: 'That payment method requires a BIC'
});
function hasBic(err, done) {
2018-11-22 14:17:35 +00:00
if (this.iban && !this.bankEntityFk)
err();
done();
}
Self.validateAsync('defaultAddressFk', isActive,
{message: 'Unable to default a disabled consignee'}
);
async function isActive(err, done) {
if (!this.defaultAddressFk)
return done();
const address = await Self.app.models.Address.findById(this.defaultAddressFk);
if (address && !address.isActive) err();
done();
}
Self.validateAsync('postCode', hasValidPostcode, {
message: `The postcode doesn't exists. Ensure you put the correct format`
});
async function hasValidPostcode(err, done) {
if (!this.postcode)
return done();
const models = Self.app.models;
const postcode = await models.Postcode.findById(this.postcode);
if (!postcode) err();
done();
}
function isAlpha(value) {
2019-10-01 13:12:02 +00:00
const regexp = new RegExp(/^[ñça-zA-Z0-9\s]*$/i);
return regexp.test(value);
}
Self.observe('before save', async function(ctx) {
let changes = ctx.data || ctx.instance;
let orgData = ctx.currentInstance;
let finalState = getFinalState(ctx);
let payMethodWithIban = 4;
// Validate socialName format
const socialNameChanged = orgData && changes
&& orgData.socialName != changes.socialName;
if (socialNameChanged && !isAlpha(changes.socialName))
throw new UserError('The socialName has an invalid format');
if (changes.salesPerson === null) {
changes.credit = 0;
changes.discount = 0;
changes.payMethodFk = 5; // Credit card
}
let payMethodFk = changes.payMethodFk || (orgData && orgData.payMethodFk);
let dueDay = changes.dueDay || (orgData && orgData.dueDay);
if (payMethodFk == payMethodWithIban && dueDay == 0)
changes.dueDay = 5;
if (isMultiple(ctx)) return;
if (changes.credit !== undefined) {
await validateCreditChange(ctx, finalState);
let filter = {fields: ['id'], where: {userFk: ctx.options.accessToken.userId}};
let worker = await Self.app.models.Worker.findOne(filter);
let newCredit = {
amount: changes.credit,
clientFk: finalState.id,
workerFk: worker ? worker.id : null
};
await Self.app.models.ClientCredit.create(newCredit);
}
});
2019-02-28 13:30:29 +00:00
Self.observe('after save', async ctx => {
if (ctx.isNewInstance) return;
const hookState = ctx.hookState;
const newInstance = hookState.newInstance;
const oldInstance = hookState.oldInstance;
const instance = ctx.instance;
const payMethodChanged = oldInstance.payMethodFk != newInstance.payMethodFk;
const ibanChanged = oldInstance.iban != newInstance.iban;
const dueDayChanged = oldInstance.dueDay != newInstance.dueDay;
if (payMethodChanged || ibanChanged || dueDayChanged) {
2019-03-01 10:09:20 +00:00
const message = `La forma de pago del cliente con id ${instance.id} ha cambiado`;
2019-02-28 13:30:29 +00:00
const salesPersonFk = instance.salesPersonFk;
2019-09-10 12:12:03 +00:00
if (salesPersonFk) {
const salesPerson = await Self.app.models.Worker.findById(salesPersonFk);
2019-02-28 13:30:29 +00:00
await Self.app.models.Message.send(ctx, {
recipientFk: salesPerson.userFk,
2019-02-28 13:30:29 +00:00
message: message
});
}
// Send email to client
if (!instance.email) return;
const loopBackContext = LoopBackContext.getCurrentContext();
const headers = loopBackContext.active.http.req.headers;
const params = {
clientId: instance.id,
recipient: instance.email
2019-02-28 13:30:29 +00:00
};
const serializedParams = httpParamSerializer(params);
const query = `${headers.origin}/api/email/payment-update?${serializedParams}`;
await request.get(query);
2019-02-28 13:30:29 +00:00
}
});
async function validateCreditChange(ctx, finalState) {
let models = Self.app.models;
let userId = ctx.options.accessToken.userId;
2018-05-17 11:18:16 +00:00
let currentUserIsManager = await models.Account.hasRole(userId, 'manager');
if (currentUserIsManager)
return;
let filter = {
fields: ['roleFk'],
where: {
maxAmount: {gt: ctx.data.credit}
}
};
let limits = await models.ClientCreditLimit.find(filter);
if (limits.length == 0)
throw new UserError('Credit limits not found');
// Si el usuario no tiene alguno de los roles no continua
let requiredRoles = [];
for (limit of limits)
requiredRoles.push(limit.roleFk);
let where = {
roleId: {inq: requiredRoles},
principalType: 'USER',
principalId: userId
};
let count = await models.RoleMapping.count(where);
if (count <= 0)
throw new UserError('The role cannot set this credit amount');
// Si se puso a 0 por gerencia, solo gerencia puede aumentarlo
let query = 'SELECT * FROM clientCredit WHERE clientFk = ? ORDER BY created DESC LIMIT 1';
let instances = await Self.rawSql(query, [finalState.id]);
2018-05-17 11:18:16 +00:00
if (instances.length !== 1 || instances[0].amount > 0)
return;
2018-05-17 11:18:16 +00:00
query = `
SELECT COUNT(*) AS hasRoleManager
FROM worker em
JOIN account.user ac ON ac.id = em.userFk
JOIN salix.RoleMapping rm ON rm.principalId = ac.id
JOIN account.role r on r.id = rm.roleId
WHERE em.id = ?
AND rm.principalType = 'USER'
AND r.name = 'manager'`;
let instance = await Self.rawSql(query, [instances[0].workerFk]);
2018-05-17 11:18:16 +00:00
if (instance[0].hasRoleManager)
throw new UserError('Only manager can change the credit');
}
};