feat: refs #5483 unify DB #1955
|
@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
|
||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [2406.01] - 2024-02-08
|
||||||
|
|
||||||
|
### Added
|
||||||
|
### Changed
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
|
||||||
## [2404.01] - 2024-01-25
|
## [2404.01] - 2024-01-25
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
|
@ -95,10 +95,7 @@ describe('image upload()', () => {
|
||||||
spyOn(containerModel, 'upload');
|
spyOn(containerModel, 'upload');
|
||||||
|
|
||||||
const ctx = {req: {accessToken: {userId: hhrrId}},
|
const ctx = {req: {accessToken: {userId: hhrrId}},
|
||||||
args: {
|
args: {id: itemId, collection: 'user'}
|
||||||
id: itemId,
|
|
||||||
collection: 'user'
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -109,7 +106,7 @@ describe('image upload()', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should try to upload a file for the collection "catalog" and throw a privilege error', async() => {
|
it('should try to upload a file for the collection "catalog" and throw a privilege error', async() => {
|
||||||
const ctx = {req: {accessToken: {userId: hhrrId}},
|
const ctx = {req: {accessToken: {userId: 1}},
|
||||||
args: {
|
args: {
|
||||||
id: workerId,
|
id: workerId,
|
||||||
collection: 'catalog'
|
collection: 'catalog'
|
||||||
|
|
|
@ -35,10 +35,17 @@ module.exports = Self => {
|
||||||
let html = `<strong>Motivo</strong>:<br/>${reason}<br/>`;
|
let html = `<strong>Motivo</strong>:<br/>${reason}<br/>`;
|
||||||
html += `<strong>Usuario</strong>:<br/>${ctx.req.accessToken.userId} ${emailUser.email}<br/>`;
|
html += `<strong>Usuario</strong>:<br/>${ctx.req.accessToken.userId} ${emailUser.email}<br/>`;
|
||||||
|
|
||||||
|
delete additionalData.backError.config.headers.Authorization;
|
||||||
|
const httpRequest = JSON.parse(additionalData?.httpRequest);
|
||||||
|
|
||||||
|
if (httpRequest)
|
||||||
|
delete httpRequest.config.headers.Authorization;
|
||||||
|
additionalData.httpRequest = httpRequest;
|
||||||
|
|
||||||
for (const data in additionalData)
|
for (const data in additionalData)
|
||||||
html += `<strong>${data}</strong>:<br/>${tryParse(additionalData[data])}<br/>`;
|
html += `<strong>${data}</strong>:<br/>${tryParse(additionalData[data])}<br/>`;
|
||||||
|
|
||||||
const subjectReason = JSON.parse(additionalData?.httpRequest)?.data?.error;
|
const subjectReason = httpRequest?.data?.error;
|
||||||
smtp.send({
|
smtp.send({
|
||||||
to: `${config.app.reportEmail}, ${emailUser.email}`,
|
to: `${config.app.reportEmail}, ${emailUser.email}`,
|
||||||
subject:
|
subject:
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
const {ParameterizedSQL} = require('loopback-connector');
|
||||||
|
const {buildFilter} = require('vn-loopback/util/filter');
|
||||||
|
|
||||||
|
module.exports = Self => {
|
||||||
|
Self.remoteMethod('filter', {
|
||||||
|
description:
|
||||||
|
'Find all postcodes of the model matched by postcode, town, province or country.',
|
||||||
|
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: 'Value to filter',
|
||||||
|
http: {source: 'query'}
|
||||||
|
},
|
||||||
|
],
|
||||||
|
returns: {
|
||||||
|
type: ['object'],
|
||||||
|
root: true,
|
||||||
|
},
|
||||||
|
http: {
|
||||||
|
path: `/filter`,
|
||||||
|
verb: 'GET',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
Self.filter = async(ctx, filter, options) => {
|
||||||
|
const myOptions = {};
|
||||||
|
if (typeof options == 'object')
|
||||||
|
Object.assign(myOptions, options);
|
||||||
|
|
||||||
|
filter = ctx?.filter ?? {};
|
||||||
|
|
||||||
|
const conn = Self.dataSource.connector;
|
||||||
|
const where = buildFilter(filter?.where, (param, value) => {
|
||||||
|
switch (param) {
|
||||||
|
case 'search':
|
||||||
|
return {
|
||||||
|
or: [
|
||||||
|
{'pc.code': {like: `%${value}%`}},
|
||||||
|
{'t.name': {like: `%${value}%`}},
|
||||||
|
{'p.name': {like: `%${value}%`}},
|
||||||
|
{'c.country': {like: `%${value}%`}}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}) ?? {};
|
||||||
|
delete ctx.filter.where;
|
||||||
|
|
||||||
|
const stmts = [];
|
||||||
|
let stmt;
|
||||||
|
stmt = new ParameterizedSQL(`
|
||||||
|
SELECT
|
||||||
|
pc.townFk,
|
||||||
|
t.provinceFk,
|
||||||
|
p.countryFk,
|
||||||
|
pc.code,
|
||||||
|
t.name as town,
|
||||||
|
p.name as province,
|
||||||
|
c.country
|
||||||
|
FROM
|
||||||
|
postCode pc
|
||||||
|
JOIN town t on t.id = pc.townFk
|
||||||
|
JOIN province p on p.id = t.provinceFk
|
||||||
|
JOIN country c on c.id = p.countryFk
|
||||||
|
`);
|
||||||
|
|
||||||
|
stmt.merge(conn.makeSuffix({where, ...ctx}));
|
||||||
|
const itemsIndex = stmts.push(stmt) - 1;
|
||||||
|
|
||||||
|
const sql = ParameterizedSQL.join(stmts, ';');
|
||||||
|
const result = await conn.executeStmt(sql, myOptions);
|
||||||
|
return itemsIndex === 0 ? result : result[itemsIndex];
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,111 @@
|
||||||
|
const {models} = require('vn-loopback/server/server');
|
||||||
|
|
||||||
|
describe('Postcode filter()', () => {
|
||||||
|
it('should retrieve with no filter', async() => {
|
||||||
|
const tx = await models.Postcode.beginTransaction({});
|
||||||
|
const options = {transaction: tx};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const ctx = {
|
||||||
|
filter: {
|
||||||
|
},
|
||||||
|
limit: 1
|
||||||
|
};
|
||||||
|
const results = await models.Postcode.filter(ctx, options);
|
||||||
|
|
||||||
|
expect(results.length).toEqual(1);
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should retrieve with filter as postcode', async() => {
|
||||||
|
const tx = await models.Postcode.beginTransaction({});
|
||||||
|
const options = {transaction: tx};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const ctx = {
|
||||||
|
filter: {
|
||||||
|
where: {
|
||||||
|
search: 46,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const results = await models.Postcode.filter(ctx, options);
|
||||||
|
|
||||||
|
expect(results.length).toEqual(4);
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should retrieve with filter as city', async() => {
|
||||||
|
const tx = await models.Postcode.beginTransaction({});
|
||||||
|
const options = {transaction: tx};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const ctx = {
|
||||||
|
filter: {
|
||||||
|
where: {
|
||||||
|
search: 'Alz',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const results = await models.Postcode.filter(ctx, options);
|
||||||
|
|
||||||
|
expect(results.length).toEqual(1);
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should retrieve with filter as province', async() => {
|
||||||
|
const tx = await models.Postcode.beginTransaction({});
|
||||||
|
const options = {transaction: tx};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const ctx = {
|
||||||
|
filter: {
|
||||||
|
where: {
|
||||||
|
search: 'one',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const results = await models.Postcode.filter(ctx, options);
|
||||||
|
|
||||||
|
expect(results.length).toEqual(4);
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should retrieve with filter as country', async() => {
|
||||||
|
const tx = await models.Postcode.beginTransaction({});
|
||||||
|
const options = {transaction: tx};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const ctx = {
|
||||||
|
filter: {
|
||||||
|
where: {
|
||||||
|
search: 'Ec',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const results = await models.Postcode.filter(ctx, options);
|
||||||
|
|
||||||
|
expect(results.length).toEqual(1);
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
|
@ -20,7 +20,7 @@ module.exports = Self => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Self.internationalExpedition = async expeditionFk => {
|
Self.internationalExpedition = async (expeditionFk) => {
|
||||||
const models = Self.app.models;
|
const models = Self.app.models;
|
||||||
|
|
||||||
const viaexpressConfig = await models.ViaexpressConfig.findOne({
|
const viaexpressConfig = await models.ViaexpressConfig.findOne({
|
||||||
|
|
|
@ -20,11 +20,11 @@ module.exports = Self => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Self.renderer = async expeditionFk => {
|
Self.renderer = async (expeditionFk) => {
|
||||||
const models = Self.app.models;
|
const models = Self.app.models;
|
||||||
|
|
||||||
const viaexpressConfig = await models.ViaexpressConfig.findOne({
|
const viaexpressConfig = await models.ViaexpressConfig.findOne({
|
||||||
fields: ['client', 'user', 'password', 'defaultWeight', 'deliveryType']
|
fields: ['client', 'user', 'password', 'defaultWeight', 'deliveryType', 'agencyModeFk']
|
||||||
});
|
});
|
||||||
|
|
||||||
const expedition = await models.Expedition.findOne({
|
const expedition = await models.Expedition.findOne({
|
||||||
|
@ -34,7 +34,7 @@ module.exports = Self => {
|
||||||
{
|
{
|
||||||
relation: 'ticket',
|
relation: 'ticket',
|
||||||
scope: {
|
scope: {
|
||||||
fields: ['shipped', 'addressFk', 'clientFk', 'companyFk'],
|
fields: ['shipped', 'addressFk', 'clientFk', 'companyFk', 'agencyModeFk'],
|
||||||
include: [
|
include: [
|
||||||
{
|
{
|
||||||
relation: 'client',
|
relation: 'client',
|
||||||
|
@ -102,7 +102,6 @@ module.exports = Self => {
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
@ -110,13 +109,15 @@ module.exports = Self => {
|
||||||
const ticket = expedition.ticket();
|
const ticket = expedition.ticket();
|
||||||
const sender = ticket.company().client();
|
const sender = ticket.company().client();
|
||||||
const shipped = ticket.shipped.toISOString();
|
const shipped = ticket.shipped.toISOString();
|
||||||
|
const isInterdia = (ticket.agencyModeFk === viaexpressConfig.agencyModeFk)
|
||||||
const data = {
|
const data = {
|
||||||
viaexpressConfig,
|
viaexpressConfig,
|
||||||
sender,
|
sender,
|
||||||
senderAddress: sender.defaultAddress(),
|
senderAddress: sender.defaultAddress(),
|
||||||
client: ticket.client(),
|
client: ticket.client(),
|
||||||
address: ticket.address(),
|
address: ticket.address(),
|
||||||
shipped
|
shipped,
|
||||||
|
isInterdia
|
||||||
};
|
};
|
||||||
|
|
||||||
const template = fs.readFileSync(__dirname + '/template.ejs', 'utf-8');
|
const template = fs.readFileSync(__dirname + '/template.ejs', 'utf-8');
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
<Asegurado>0</Asegurado>
|
<Asegurado>0</Asegurado>
|
||||||
<Imprimir>0</Imprimir>
|
<Imprimir>0</Imprimir>
|
||||||
<ConDevolucionAlbaran>0</ConDevolucionAlbaran>
|
<ConDevolucionAlbaran>0</ConDevolucionAlbaran>
|
||||||
<Intradia>0</Intradia>
|
<Intradia><%= isInterdia %></Intradia>
|
||||||
<Observaciones></Observaciones>
|
<Observaciones></Observaciones>
|
||||||
<AlbaranRemitente></AlbaranRemitente>
|
<AlbaranRemitente></AlbaranRemitente>
|
||||||
<Modo>0</Modo>
|
<Modo>0</Modo>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
let UserError = require('vn-loopback/util/user-error');
|
let UserError = require('vn-loopback/util/user-error');
|
||||||
|
|
||||||
module.exports = Self => {
|
module.exports = Self => {
|
||||||
|
require('../methods/postcode/filter.js')(Self);
|
||||||
Self.rewriteDbError(function(err) {
|
Self.rewriteDbError(function(err) {
|
||||||
if (err.code === 'ER_DUP_ENTRY')
|
if (err.code === 'ER_DUP_ENTRY')
|
||||||
return new UserError(`This postcode already exists`);
|
return new UserError(`This postcode already exists`);
|
||||||
|
|
|
@ -29,6 +29,9 @@
|
||||||
},
|
},
|
||||||
"deliveryType": {
|
"deliveryType": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
},
|
||||||
|
"agencyModeFk": {
|
||||||
|
"type": "number"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,10 +79,10 @@ module.exports = function(Self) {
|
||||||
Self.getRoles = async(userId, options) => {
|
Self.getRoles = async(userId, options) => {
|
||||||
const result = await Self.rawSql(
|
const result = await Self.rawSql(
|
||||||
`SELECT r.name
|
`SELECT r.name
|
||||||
FROM account.user u
|
FROM account.user u
|
||||||
JOIN account.roleRole rr ON rr.role = u.role
|
JOIN account.roleRole rr ON rr.role = u.role
|
||||||
JOIN account.role r ON r.id = rr.inheritsFrom
|
JOIN account.role r ON r.id = rr.inheritsFrom
|
||||||
WHERE u.id = ?`, [userId], options);
|
WHERE u.id = ?`, [userId], options);
|
||||||
|
|
||||||
const roles = [];
|
const roles = [];
|
||||||
for (const role of result)
|
for (const role of result)
|
||||||
|
@ -142,7 +142,7 @@ module.exports = function(Self) {
|
||||||
ip: ctx.req.ip,
|
ip: ctx.req.ip,
|
||||||
owner: isOwner
|
owner: isOwner
|
||||||
});
|
});
|
||||||
throw new UserError('Try again');
|
throw new UserError('Try again');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
ALTER TABLE `vn`.`viaexpressConfig` ADD agencyModeFk int DEFAULT NULL NULL COMMENT 'Indica el agencyMode que es interdia';
|
||||||
|
ALTER TABLE `vn`.`viaexpressConfig` ADD CONSTRAINT viaexpressConfig_agencyMode_Fk FOREIGN KEY (agencyModeFK) REFERENCES vn.agencyMode(id) ON DELETE RESTRICT ON UPDATE RESTRICT;
|
|
@ -0,0 +1,4 @@
|
||||||
|
REVOKE UPDATE ON TABLE `vn`.`item` FROM `employee`;
|
||||||
|
|
||||||
|
|
||||||
|
GRANT UPDATE(id, equivalent, stems, minPrice, isToPrint, family, box, category, doPhoto, image, inkFk, intrastatFk, hasMinPrice, created, comment, typeFk, generic, producerFk, description, density, relevancy, expenseFk, isActive, subName, tag5, value5, tag6, value6, tag7, value7, tag8, value8, tag9, value9, tag10, value10, minimum, upToDown, supplyResponseFk, hasKgPrice, isFloramondo, isFragile, numberOfItemsPerCask, embalageCode, quality, stemMultiplier, itemPackingTypeFk, packingOut, genericFk, packingShelve, isLaid, lastUsed, weightByPiece, weightByPiece, editorFk, recycledPlastic, nonRecycledPlastic, minQuantity) ON TABLE `vn`.`item` TO `employee`;
|
|
@ -0,0 +1,12 @@
|
||||||
|
ALTER TABLE `vn`.`company` MODIFY COLUMN `supplierAccountFk` mediumint(8) unsigned DEFAULT NULL NULL COMMENT 'Cuenta por defecto para ingresos desde este pais';
|
||||||
|
|
||||||
|
|
||||||
|
ALTER TABLE `vn`.`supplierAccount`
|
||||||
|
ADD COLUMN `countryFk` mediumint(8) unsigned DEFAULT NULL,
|
||||||
|
ADD CONSTRAINT `fk_supplierAccount_country`
|
||||||
|
FOREIGN KEY (`countryFk`) REFERENCES `country` (`id`) ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
ALTER TABLE `vn`.`supplierAccount`
|
||||||
|
ADD UNIQUE KEY `uk_supplier_country` (`supplierFk`, `countryFk`);
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
INSERT INTO salix.ACL (model,property,accessType,permission,principalType,principalId) VALUES
|
INSERT INTO `salix`.`ACL` (model,property,accessType,permission,principalType,principalId) VALUES
|
||||||
('VnRole','*','READ','ALLOW','ROLE','employee'),
|
('VnRole','*','READ','ALLOW','ROLE','employee'),
|
||||||
('VnRole','*','WRITE','ALLOW','ROLE','it');
|
('VnRole','*','WRITE','ALLOW','ROLE','it');
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
ALTER TABLE vn.productionConfig ADD itemPreviousDefaultSize int NULL COMMENT 'Altura por defecto para los artículos de previa';
|
ALTER TABLE `vn`.`productionConfig` ADD itemPreviousDefaultSize int NULL COMMENT 'Altura por defecto para los artículos de previa';
|
||||||
UPDATE IGNORE vn.productionConfig SET itemPreviousDefaultSize = 40 WHERE id = 1;
|
UPDATE IGNORE `vn`.`productionConfig` SET itemPreviousDefaultSize = 40 WHERE id = 1;
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
UPDATE `vn`.`supplierAccount` sa
|
||||||
|
JOIN `vn`.`country` c ON sa.countryFk = c.id AND c.code = 'FR'
|
||||||
|
SET countryFk = c.id
|
||||||
|
WHERE iban = 'FR7630003012690002801121597';
|
||||||
|
|
||||||
|
UPDATE `vn`.`supplierAccount` sa
|
||||||
|
JOIN `vn`.`country` c ON sa.countryFk = c.id AND c.code = 'PT'
|
||||||
|
SET countryFk = c.id
|
||||||
|
WHERE iban = 'PT50001000005813059150168';
|
|
@ -0,0 +1,2 @@
|
||||||
|
ALTER TABLE `vn`.`invoiceOutConfig`
|
||||||
|
ADD IF NOT EXISTS refLen TINYINT UNSIGNED DEFAULT 5 NOT NULL COMMENT 'Invoice reference identifier length';
|
|
@ -4,17 +4,20 @@ CREATE OR REPLACE DEFINER=`root`@`localhost` TRIGGER `vn`.`invoiceOut_beforeInse
|
||||||
FOR EACH ROW
|
FOR EACH ROW
|
||||||
BEGIN
|
BEGIN
|
||||||
/**
|
/**
|
||||||
|
* Generates the next reference for the invoice serial. There cannot be gaps
|
||||||
|
* between identifiers of the same serial!
|
||||||
|
*
|
||||||
* Reference format:
|
* Reference format:
|
||||||
* - 0: Serial [A-Z]
|
* {0} Invoice serial
|
||||||
* - 1: Sage company id
|
* {1} The company code
|
||||||
* - 2-3: Last two digits of issued year
|
* {2-3} Last two digits of issue year
|
||||||
* - 4-8: Autoincrement identifier
|
* {4-$} Autoincrement identifier
|
||||||
**/
|
*/
|
||||||
DECLARE vNewRef INT DEFAULT 0;
|
DECLARE vRef INT DEFAULT 0;
|
||||||
DECLARE vCompanyCode INT;
|
DECLARE vRefLen INT;
|
||||||
|
DECLARE vRefPrefix VARCHAR(255);
|
||||||
DECLARE vLastRef VARCHAR(255);
|
DECLARE vLastRef VARCHAR(255);
|
||||||
DECLARE vRefStr VARCHAR(255);
|
DECLARE vCompanyCode INT;
|
||||||
DECLARE vRefLen INT DEFAULT 5;
|
|
||||||
DECLARE vYearLen INT DEFAULT 2;
|
DECLARE vYearLen INT DEFAULT 2;
|
||||||
DECLARE vPrefixLen INT;
|
DECLARE vPrefixLen INT;
|
||||||
|
|
||||||
|
@ -23,36 +26,34 @@ BEGIN
|
||||||
WHERE id = NEW.companyFk;
|
WHERE id = NEW.companyFk;
|
||||||
|
|
||||||
IF vCompanyCode IS NULL THEN
|
IF vCompanyCode IS NULL THEN
|
||||||
CALL util.throw('sageCompanyNotDefined');
|
CALL util.throw('companyCodeNotDefined');
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
SELECT MAX(i.ref) INTO vLastRef
|
SELECT MAX(i.ref) INTO vLastRef
|
||||||
FROM invoiceOut i
|
FROM invoiceOut i
|
||||||
WHERE i.serial = NEW.serial
|
WHERE i.serial = NEW.serial
|
||||||
AND i.issued BETWEEN util.firstDayOfYear(NEW.issued) AND util.dayEnd(util.lastDayOfYear(NEW.issued))
|
AND i.issued BETWEEN util.firstDayOfYear(NEW.issued) AND util.lastDayOfYear(NEW.issued)
|
||||||
AND i.companyFk = NEW.companyFk;
|
AND i.companyFk = NEW.companyFk;
|
||||||
|
|
||||||
IF vLastRef IS NOT NULL THEN
|
IF vLastRef IS NOT NULL THEN
|
||||||
SET vPrefixLen = LENGTH(NEW.serial) + LENGTH(vCompanyCode) + vYearLen;
|
SET vPrefixLen = LENGTH(NEW.serial) + LENGTH(vCompanyCode) + vYearLen;
|
||||||
SET vRefLen = LENGTH(vLastRef) - vPrefixLen;
|
SET vRefLen = LENGTH(vLastRef) - vPrefixLen;
|
||||||
SET vRefStr = SUBSTRING(vLastRef, vPrefixLen + 1);
|
SET vRefPrefix = LEFT(vLastRef, vPrefixLen);
|
||||||
SET vNewRef = vRefStr + 1;
|
SET vRef = RIGHT(vLastRef, vRefLen);
|
||||||
|
|
||||||
IF LENGTH(vNewRef) > vRefLen THEN
|
|
||||||
CALL util.throw('refLenExceeded');
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
SET NEW.ref = CONCAT(
|
|
||||||
SUBSTRING(vLastRef, 1, vPrefixLen),
|
|
||||||
LPAD(vNewRef, LENGTH(vRefStr), '0')
|
|
||||||
);
|
|
||||||
ELSE
|
ELSE
|
||||||
SET NEW.ref = CONCAT(
|
SELECT refLen INTO vRefLen FROM invoiceOutConfig;
|
||||||
|
SET vRefPrefix = CONCAT(
|
||||||
NEW.serial,
|
NEW.serial,
|
||||||
vCompanyCode,
|
vCompanyCode,
|
||||||
RIGHT(YEAR(NEW.issued), vYearLen),
|
RIGHT(YEAR(NEW.issued), vYearLen)
|
||||||
LPAD(1, vRefLen, '0')
|
|
||||||
);
|
);
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
|
SET vRef = vRef + 1;
|
||||||
|
IF LENGTH(vRef) > vRefLen THEN
|
||||||
|
CALL util.throw('refIdLenExceeded');
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
SET NEW.ref = CONCAT(vRefPrefix, LPAD(vRef, vRefLen, '0'));
|
||||||
END$$
|
END$$
|
||||||
DELIMITER ;
|
DELIMITER ;
|
|
@ -0,0 +1,589 @@
|
||||||
|
DELIMITER $$
|
||||||
|
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`sale_calculateComponent`(vSelf INT, vOption VARCHAR(25))
|
||||||
|
proc: BEGIN
|
||||||
|
/**
|
||||||
|
* Crea tabla temporal para vn.sale_recalcComponent() para recalcular los componentes
|
||||||
|
*
|
||||||
|
* @param vSelf Id de la venta
|
||||||
|
* @param vOption indica en que componente pone el descuadre, NULL en casos habituales
|
||||||
|
*/
|
||||||
|
CREATE OR REPLACE TEMPORARY TABLE tmp.recalculateSales
|
||||||
|
SELECT s.id
|
||||||
|
FROM sale s
|
||||||
|
WHERE s.id = vSelf;
|
||||||
|
|
||||||
|
CALL sale_recalcComponent(vOption);
|
||||||
|
|
||||||
|
DROP TEMPORARY TABLE tmp.recalculateSales;
|
||||||
|
END$$
|
||||||
|
DELIMITER ;
|
||||||
|
|
||||||
|
DELIMITER $$
|
||||||
|
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`sale_checkNoComponents`(vCreatedFrom DATETIME, vCreatedTo DATETIME)
|
||||||
|
BEGIN
|
||||||
|
/**
|
||||||
|
* Comprueba que las ventas creadas entre un rango de fechas tienen componentes
|
||||||
|
*
|
||||||
|
* @param vCreatedFrom inicio del rango
|
||||||
|
* @param vCreatedTo fin del rango
|
||||||
|
*/
|
||||||
|
DECLARE v_done BOOL DEFAULT FALSE;
|
||||||
|
DECLARE vSaleFk INTEGER;
|
||||||
|
DECLARE vTicketFk INTEGER;
|
||||||
|
DECLARE vConcept VARCHAR(50);
|
||||||
|
DECLARE vCur CURSOR FOR
|
||||||
|
SELECT s.id
|
||||||
|
FROM sale s
|
||||||
|
JOIN ticket t ON t.id = s.ticketFk
|
||||||
|
JOIN item i ON i.id = s.itemFk
|
||||||
|
JOIN itemType tp ON tp.id = i.typeFk
|
||||||
|
JOIN itemCategory ic ON ic.id = tp.categoryFk
|
||||||
|
LEFT JOIN tmp.coste c ON c.id = s.id
|
||||||
|
WHERE s.created >= vCreatedFrom AND s.created <= vCreatedTo
|
||||||
|
AND c.id IS NULL
|
||||||
|
AND t.agencyModeFk IS NOT NULL
|
||||||
|
AND t.isDeleted IS FALSE
|
||||||
|
AND t.warehouseFk = 60
|
||||||
|
AND ic.merchandise != FALSE
|
||||||
|
GROUP BY s.id;
|
||||||
|
|
||||||
|
DECLARE CONTINUE HANDLER FOR NOT FOUND
|
||||||
|
SET v_done = TRUE;
|
||||||
|
|
||||||
|
DROP TEMPORARY TABLE IF EXISTS tmp.coste;
|
||||||
|
|
||||||
|
DROP TEMPORARY TABLE IF EXISTS tmp.coste;
|
||||||
|
CREATE TEMPORARY TABLE tmp.coste
|
||||||
|
(PRIMARY KEY (id)) ENGINE = MEMORY
|
||||||
|
SELECT s.id
|
||||||
|
FROM sale s
|
||||||
|
JOIN item i ON i.id = s.itemFk
|
||||||
|
JOIN itemType tp ON tp.id = i.typeFk
|
||||||
|
JOIN itemCategory ic ON ic.id = tp.categoryFk
|
||||||
|
JOIN saleComponent sc ON sc.saleFk = s.id
|
||||||
|
JOIN component c ON c.id = sc.componentFk
|
||||||
|
JOIN componentType ct ON ct.id = c.typeFk AND ct.id = 6
|
||||||
|
WHERE s.created >= vCreatedFrom
|
||||||
|
AND ic.merchandise != FALSE;
|
||||||
|
|
||||||
|
OPEN vCur;
|
||||||
|
|
||||||
|
l: LOOP
|
||||||
|
SET v_done = FALSE;
|
||||||
|
FETCH vCur INTO vSaleFk;
|
||||||
|
|
||||||
|
IF v_done THEN
|
||||||
|
LEAVE l;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
SELECT ticketFk, concept
|
||||||
|
INTO vTicketFk, vConcept
|
||||||
|
FROM sale
|
||||||
|
WHERE id = vSaleFk;
|
||||||
|
|
||||||
|
CALL sale_calculateComponent(vSaleFk, 'renewPrices');
|
||||||
|
END LOOP;
|
||||||
|
|
||||||
|
CLOSE vCur;
|
||||||
|
DROP TEMPORARY TABLE tmp.coste;
|
||||||
|
END$$
|
||||||
|
DELIMITER ;
|
||||||
|
|
||||||
|
DELIMITER $$
|
||||||
|
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`sale_recalcComponent`(vOption VARCHAR(25))
|
||||||
|
proc: BEGIN
|
||||||
|
/**
|
||||||
|
* Este procedimiento recalcula los componentes de un conjunto de sales,
|
||||||
|
* eliminando los componentes existentes e insertandolos de nuevo
|
||||||
|
*
|
||||||
|
* @param vOption si no se quiere forzar llamar con NULL
|
||||||
|
* @table tmp.recalculateSales (id)
|
||||||
|
*/
|
||||||
|
DECLARE vShipped DATE;
|
||||||
|
DECLARE vWarehouseFk SMALLINT;
|
||||||
|
DECLARE vAgencyModeFk INT;
|
||||||
|
DECLARE vAddressFk INT;
|
||||||
|
DECLARE vTicketFk INT;
|
||||||
|
DECLARE vLanded DATE;
|
||||||
|
DECLARE vIsEditable BOOLEAN;
|
||||||
|
DECLARE vZoneFk INTEGER;
|
||||||
|
DECLARE vDone BOOL DEFAULT FALSE;
|
||||||
|
|
||||||
|
DECLARE vCur CURSOR FOR
|
||||||
|
SELECT DISTINCT s.ticketFk
|
||||||
|
FROM tmp.recalculateSales rs
|
||||||
|
JOIN vn.sale s ON s.id = rs.id;
|
||||||
|
|
||||||
|
DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = TRUE;
|
||||||
|
|
||||||
|
OPEN vCur;
|
||||||
|
|
||||||
|
l: LOOP
|
||||||
|
SET vDone = FALSE;
|
||||||
|
FETCH vCur INTO vTicketFk;
|
||||||
|
|
||||||
|
IF vDone THEN
|
||||||
|
LEAVE l;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
SELECT (hasToRecalcPrice OR ts.alertLevel IS NULL) AND t.refFk IS NULL,
|
||||||
|
t.zoneFk,
|
||||||
|
t.warehouseFk,
|
||||||
|
t.shipped,
|
||||||
|
t.addressFk,
|
||||||
|
t.agencyModeFk,
|
||||||
|
t.landed
|
||||||
|
INTO vIsEditable,
|
||||||
|
vZoneFk,
|
||||||
|
vWarehouseFk,
|
||||||
|
vShipped,
|
||||||
|
vAddressFk,
|
||||||
|
vAgencyModeFk,
|
||||||
|
vLanded
|
||||||
|
FROM ticket t
|
||||||
|
LEFT JOIN ticketState ts ON t.id = ts.ticketFk
|
||||||
|
LEFT JOIN alertLevel al ON al.id = ts.alertLevel
|
||||||
|
WHERE t.id = vTicketFk;
|
||||||
|
|
||||||
|
CALL zone_getLanded(vShipped, vAddressFk, vAgencyModeFk, vWarehouseFk, TRUE);
|
||||||
|
|
||||||
|
IF NOT EXISTS (SELECT TRUE FROM tmp.zoneGetLanded LIMIT 1) THEN
|
||||||
|
CALL util.throw(CONCAT('There is no zone for these parameters ', vTicketFk));
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
IF vLanded IS NULL OR vZoneFk IS NULL THEN
|
||||||
|
|
||||||
|
UPDATE ticket t
|
||||||
|
SET t.landed = (SELECT landed FROM tmp.zoneGetLanded LIMIT 1)
|
||||||
|
WHERE t.id = vTicketFk AND t.landed IS NULL;
|
||||||
|
|
||||||
|
IF vZoneFk IS NULL THEN
|
||||||
|
SELECT zoneFk INTO vZoneFk FROM tmp.zoneGetLanded LIMIT 1;
|
||||||
|
UPDATE ticket t
|
||||||
|
SET t.zoneFk = vZoneFk
|
||||||
|
WHERE t.id = vTicketFk AND t.zoneFk IS NULL;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
DROP TEMPORARY TABLE tmp.zoneGetLanded;
|
||||||
|
|
||||||
|
-- rellena la tabla buyUltimate con la ultima compra
|
||||||
|
CALL buyUltimate (vWarehouseFk, vShipped);
|
||||||
|
|
||||||
|
CREATE OR REPLACE TEMPORARY TABLE tmp.sale
|
||||||
|
(PRIMARY KEY (saleFk)) ENGINE = MEMORY
|
||||||
|
SELECT s.id saleFk, vWarehouseFk warehouseFk
|
||||||
|
FROM sale s
|
||||||
|
JOIN tmp.recalculateSales rs ON s.id = rs.id
|
||||||
|
WHERE s.ticketFk = vTicketFk;
|
||||||
|
|
||||||
|
CREATE OR REPLACE TEMPORARY TABLE tmp.ticketLot
|
||||||
|
SELECT vWarehouseFk warehouseFk, NULL available, s.itemFk, bu.buyFk, vZoneFk zoneFk
|
||||||
|
FROM sale s
|
||||||
|
JOIN tmp.recalculateSales rs ON s.id = rs.id
|
||||||
|
LEFT JOIN tmp.buyUltimate bu ON bu.itemFk = s.itemFk
|
||||||
|
WHERE s.ticketFk = vTicketFk
|
||||||
|
GROUP BY s.itemFk;
|
||||||
|
|
||||||
|
CALL catalog_componentPrepare();
|
||||||
|
CALL catalog_componentCalculate(vZoneFk, vAddressFk, vShipped, vWarehouseFk);
|
||||||
|
|
||||||
|
IF vOption IS NULL THEN
|
||||||
|
SET vOption = IF(vIsEditable, 'renewPrices', 'imbalance');
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
CALL ticketComponentUpdateSale(vOption);
|
||||||
|
CALL catalog_componentPurge();
|
||||||
|
|
||||||
|
DROP TEMPORARY TABLE tmp.buyUltimate;
|
||||||
|
DROP TEMPORARY TABLE tmp.sale;
|
||||||
|
|
||||||
|
END LOOP;
|
||||||
|
CLOSE vCur;
|
||||||
|
|
||||||
|
END$$
|
||||||
|
DELIMITER ;
|
||||||
|
|
||||||
|
DELIMITER $$
|
||||||
|
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`ticketCalculateClon`(IN vTicketNew INT, vTicketOld INT)
|
||||||
|
BEGIN
|
||||||
|
/*
|
||||||
|
* Recalcula los componentes un ticket clonado,
|
||||||
|
* las lineas a precio cero fuerza para que tengan precio, el resto lo respeta
|
||||||
|
* @param vTicketNew nuevo ticket clonado
|
||||||
|
* @param vTicketOld icket original, a partir del qual se clonara el nuevo
|
||||||
|
*/
|
||||||
|
|
||||||
|
REPLACE INTO orderTicket(orderFk,ticketFk)
|
||||||
|
SELECT orderFk, vTicketNew
|
||||||
|
FROM orderTicket
|
||||||
|
WHERE ticketFk = vTicketOld;
|
||||||
|
|
||||||
|
-- Bionizamos lineas con Preu = 0
|
||||||
|
CREATE OR REPLACE TEMPORARY TABLE tmp.recalculateSales
|
||||||
|
(PRIMARY KEY (id)) ENGINE = MEMORY
|
||||||
|
SELECT id
|
||||||
|
FROM sale
|
||||||
|
WHERE ticketFk = vTicketNew AND price = 0;
|
||||||
|
|
||||||
|
CALL sale_recalcComponent('renewPrices');
|
||||||
|
|
||||||
|
-- Bionizamos lineas con Preu > 0
|
||||||
|
CREATE OR REPLACE TEMPORARY TABLE tmp.recalculateSales
|
||||||
|
(PRIMARY KEY (id)) ENGINE = MEMORY
|
||||||
|
SELECT id
|
||||||
|
FROM sale
|
||||||
|
WHERE ticketFk = vTicketNew AND price > 0;
|
||||||
|
|
||||||
|
CALL sale_recalcComponent('imbalance');
|
||||||
|
|
||||||
|
DROP TEMPORARY TABLE IF EXISTS tmp.recalculateSales;
|
||||||
|
|
||||||
|
END$$
|
||||||
|
DELIMITER ;
|
||||||
|
|
||||||
|
DELIMITER $$
|
||||||
|
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`ticketComponentUpdate`(
|
||||||
|
vTicketFk INT,
|
||||||
|
vClientFk INT,
|
||||||
|
vAgencyModeFk INT,
|
||||||
|
vAddressFk INT,
|
||||||
|
vWarehouseFk TINYINT,
|
||||||
|
vCompanyFk SMALLINT,
|
||||||
|
vShipped DATETIME,
|
||||||
|
vLanded DATE,
|
||||||
|
vIsDeleted BOOLEAN,
|
||||||
|
vHasToBeUnrouted BOOLEAN,
|
||||||
|
vOption VARCHAR(25))
|
||||||
|
BEGIN
|
||||||
|
|
||||||
|
DECLARE EXIT HANDLER FOR SQLEXCEPTION
|
||||||
|
BEGIN
|
||||||
|
ROLLBACK;
|
||||||
|
RESIGNAL;
|
||||||
|
END;
|
||||||
|
|
||||||
|
START TRANSACTION;
|
||||||
|
|
||||||
|
IF (SELECT addressFk FROM ticket WHERE id = vTicketFk) <> vAddressFk THEN
|
||||||
|
|
||||||
|
UPDATE ticket t
|
||||||
|
JOIN address a ON a.id = vAddressFk
|
||||||
|
SET t.nickname = a.nickname
|
||||||
|
WHERE t.id = vTicketFk;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
UPDATE ticket t
|
||||||
|
SET
|
||||||
|
t.clientFk = vClientFk,
|
||||||
|
t.agencyModeFk = vAgencyModeFk,
|
||||||
|
t.addressFk = vAddressFk,
|
||||||
|
t.warehouseFk = vWarehouseFk,
|
||||||
|
t.companyFk = vCompanyFk,
|
||||||
|
t.landed = vLanded,
|
||||||
|
t.shipped = vShipped,
|
||||||
|
t.isDeleted = vIsDeleted
|
||||||
|
WHERE
|
||||||
|
t.id = vTicketFk;
|
||||||
|
|
||||||
|
IF vHasToBeUnrouted THEN
|
||||||
|
UPDATE ticket t SET t.routeFk = NULL
|
||||||
|
WHERE t.id = vTicketFk;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
DROP TEMPORARY TABLE IF EXISTS tmp.sale;
|
||||||
|
CREATE TEMPORARY TABLE tmp.sale
|
||||||
|
(PRIMARY KEY (saleFk))
|
||||||
|
ENGINE = MEMORY
|
||||||
|
SELECT id AS saleFk, vWarehouseFk warehouseFk
|
||||||
|
FROM sale s WHERE s.ticketFk = vTicketFk;
|
||||||
|
|
||||||
|
CALL ticketComponentUpdateSale (vOption);
|
||||||
|
|
||||||
|
DROP TEMPORARY TABLE tmp.sale;
|
||||||
|
COMMIT;
|
||||||
|
END$$
|
||||||
|
DELIMITER ;
|
||||||
|
|
||||||
|
DELIMITER $$
|
||||||
|
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`ticketComponentUpdateSale`(vCode VARCHAR(25))
|
||||||
|
BEGIN
|
||||||
|
/**
|
||||||
|
* A partir de la tabla tmp.sale, crea los Movimientos_componentes
|
||||||
|
* y modifica el campo Preu de la tabla Movimientos
|
||||||
|
*
|
||||||
|
* @param i_option integer tipo de actualizacion
|
||||||
|
* @param table tmp.sale tabla memory con el campo saleFk, warehouseFk
|
||||||
|
**/
|
||||||
|
DECLARE vComponentFk INT;
|
||||||
|
|
||||||
|
IF vCode <> 'renewPrices' THEN
|
||||||
|
SELECT id INTO vComponentFk FROM component WHERE `code` = vCode;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
DELETE sc.*
|
||||||
|
FROM tmp.sale tmps
|
||||||
|
JOIN saleComponent sc ON sc.saleFk = tmps.saleFk
|
||||||
|
JOIN `component` c ON c.id = sc.componentFk
|
||||||
|
WHERE c.isRenewable;
|
||||||
|
|
||||||
|
REPLACE INTO saleComponent(saleFk, componentFk, value)
|
||||||
|
SELECT s.id, tc.componentFk, tc.cost
|
||||||
|
FROM sale s
|
||||||
|
JOIN tmp.sale tmps ON tmps.saleFk = s.id
|
||||||
|
JOIN tmp.ticketComponent tc ON tc.itemFk = s.itemFk AND tc.warehouseFk = tmps.warehouseFk
|
||||||
|
LEFT JOIN saleComponent sc ON sc.saleFk = s.id
|
||||||
|
AND sc.componentFk = tc.componentFk
|
||||||
|
LEFT JOIN `component` c ON c.id = tc.componentFk
|
||||||
|
WHERE IF(sc.componentFk IS NULL AND NOT c.isRenewable, FALSE, TRUE);
|
||||||
|
|
||||||
|
-- Añadir componente venta por paquete
|
||||||
|
REPLACE INTO saleComponent(saleFk, componentFk, value)
|
||||||
|
SELECT t.id, t.componentFk, t.cost
|
||||||
|
FROM (
|
||||||
|
SELECT s.id, tc.componentFk, tc.cost, MOD(s.quantity, b.packing) as resto
|
||||||
|
FROM vn.sale s
|
||||||
|
JOIN tmp.sale tmps ON tmps.saleFk = s.id
|
||||||
|
JOIN cache.last_buy lb ON lb.item_id = s.itemFk AND tmps.warehouseFk = lb.warehouse_id
|
||||||
|
JOIN vn.buy b ON b.id = buy_id
|
||||||
|
JOIN tmp.ticketComponent tc ON tc.itemFk = s.itemFk AND tc.warehouseFk = tmps.warehouseFk
|
||||||
|
JOIN `component` c ON c.id = tc.componentFk AND c.code = 'salePerPackage'
|
||||||
|
LEFT JOIN (
|
||||||
|
SELECT s.id
|
||||||
|
FROM vn.sale s
|
||||||
|
JOIN tmp.sale tmps ON tmps.saleFk = s.id
|
||||||
|
JOIN tmp.ticketComponent tc ON tc.itemFk = s.itemFk AND tc.warehouseFk = tmps.warehouseFk
|
||||||
|
JOIN saleComponent sc ON sc.saleFk = s.id AND sc.componentFk = tc.componentFk
|
||||||
|
JOIN `component` c ON c.id = sc.componentFk AND c.code = 'lastUnitsDiscount'
|
||||||
|
) tp ON tp.id = s.id
|
||||||
|
WHERE tp.id IS NULL
|
||||||
|
HAVING resto <> 0) t;
|
||||||
|
|
||||||
|
IF vCode <> 'renewPrices' THEN
|
||||||
|
REPLACE INTO saleComponent(saleFk, componentFk, value)
|
||||||
|
SELECT s.id, vComponentFk, ROUND((s.price * (100 - s.discount) / 100) - SUM(sc.value), 3) dif
|
||||||
|
FROM sale s
|
||||||
|
JOIN tmp.sale tmps ON tmps.saleFk = s.id
|
||||||
|
LEFT JOIN saleComponent sc ON sc.saleFk = s.id
|
||||||
|
WHERE sc.saleFk <> vComponentFk
|
||||||
|
GROUP BY s.id
|
||||||
|
HAVING dif <> 0;
|
||||||
|
ELSE
|
||||||
|
UPDATE sale s
|
||||||
|
JOIN item i on i.id = s.itemFk
|
||||||
|
JOIN itemType it on it.id = i.typeFk
|
||||||
|
JOIN (SELECT SUM(sc.value) sumValue, sc.saleFk
|
||||||
|
FROM saleComponent sc
|
||||||
|
JOIN tmp.sale tmps ON tmps.saleFk = sc.saleFk
|
||||||
|
GROUP BY sc.saleFk) sc ON sc.saleFk = s.id
|
||||||
|
SET s.price = sumValue / ((100 - s.discount) / 100)
|
||||||
|
WHERE it.code != 'PRT' ;
|
||||||
|
|
||||||
|
REPLACE INTO saleComponent(saleFk, componentFk, value)
|
||||||
|
SELECT s.id, 21, ROUND((s.price * (100 - s.discount) / 100) - SUM(value), 3) saleValue
|
||||||
|
FROM sale s
|
||||||
|
JOIN tmp.sale tmps ON tmps.saleFk = s.id
|
||||||
|
LEFT JOIN saleComponent sc ON sc.saleFk = s.id
|
||||||
|
WHERE sc.componentFk != 21
|
||||||
|
GROUP BY s.id
|
||||||
|
HAVING ROUND(saleValue, 4) <> 0;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
UPDATE sale s
|
||||||
|
JOIN (
|
||||||
|
SELECT SUM(sc.value) sumValue, sc.saleFk
|
||||||
|
FROM saleComponent sc
|
||||||
|
JOIN tmp.sale tmps ON tmps.saleFk = sc.saleFk
|
||||||
|
JOIN `component` c ON c.id = sc.componentFk
|
||||||
|
JOIN componentType ct on ct.id = c.typeFk AND ct.isBase
|
||||||
|
GROUP BY sc.saleFk) sc ON sc.saleFk = s.id
|
||||||
|
SET s.priceFixed = sumValue, s.isPriceFixed = 1;
|
||||||
|
|
||||||
|
DELETE sc.*
|
||||||
|
FROM saleComponent sc
|
||||||
|
JOIN tmp.sale tmps ON tmps.saleFk = sc.saleFk
|
||||||
|
JOIN sale s on s.id = sc.saleFk
|
||||||
|
JOIN item i ON i.id = s.itemFk
|
||||||
|
JOIN itemType it ON it.id = i.typeFk
|
||||||
|
WHERE it.code = 'PRT';
|
||||||
|
|
||||||
|
INSERT INTO saleComponent(saleFk, componentFk, value)
|
||||||
|
SELECT s.id, 15, s.price
|
||||||
|
FROM sale s
|
||||||
|
JOIN tmp.sale tmps ON tmps.saleFk = s.id
|
||||||
|
JOIN item i ON i.id = s.itemFK
|
||||||
|
JOIN itemType it ON it.id = i.typeFk
|
||||||
|
WHERE it.code = 'PRT' AND s.price > 0;
|
||||||
|
END$$
|
||||||
|
DELIMITER ;
|
||||||
|
|
||||||
|
DELIMITER $$
|
||||||
|
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`ticket_checkNoComponents`(vShippedFrom DATETIME, vShippedTo DATETIME)
|
||||||
|
BEGIN
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Comprueba que los tickets entre un rango de fechas tienen componentes
|
||||||
|
* y recalcula sus componentes
|
||||||
|
*
|
||||||
|
* @param vShippedFrom rango inicial de fecha
|
||||||
|
* @param vShippedTo rango final de fecha
|
||||||
|
*/
|
||||||
|
|
||||||
|
CREATE OR REPLACE TEMPORARY TABLE tmp.coste
|
||||||
|
(primary key (id)) ENGINE = MEMORY
|
||||||
|
SELECT s.id
|
||||||
|
FROM ticket t
|
||||||
|
JOIN sale s ON s.ticketFk = t.id
|
||||||
|
JOIN item i ON i.id = s.itemFk
|
||||||
|
JOIN itemType tp ON tp.id = i.typeFk
|
||||||
|
JOIN itemCategory ic ON ic.id = tp.categoryFk
|
||||||
|
JOIN saleComponent sc ON sc.saleFk = s.id
|
||||||
|
JOIN component c ON c.id = sc.componentFk
|
||||||
|
JOIN componentType ct ON ct.id = c.typeFk AND ct.id = 1
|
||||||
|
WHERE t.shipped BETWEEN vShippedFrom AND vShippedTo
|
||||||
|
AND ic.merchandise;
|
||||||
|
|
||||||
|
CREATE OR REPLACE TEMPORARY TABLE tmp.recalculateSales
|
||||||
|
(primary key (id)) ENGINE = MEMORY
|
||||||
|
SELECT DISTINCT s.id
|
||||||
|
FROM ticket t
|
||||||
|
JOIN sale s ON s.ticketFk = t.id
|
||||||
|
JOIN item i ON i.id = s.itemFk
|
||||||
|
JOIN itemType tp ON tp.id = i.typeFk
|
||||||
|
JOIN itemCategory ic ON ic.id = tp.categoryFk
|
||||||
|
LEFT JOIN tmp.coste c ON c.id = s.id
|
||||||
|
WHERE t.shipped >= vShippedFrom AND t.shipped <= vShippedTo
|
||||||
|
AND c.id IS NULL
|
||||||
|
AND ic.merchandise;
|
||||||
|
|
||||||
|
CALL sale_recalcComponent('renewPrices');
|
||||||
|
|
||||||
|
DROP TEMPORARY TABLE tmp.recalculateSales;
|
||||||
|
DROP TEMPORARY TABLE tmp.coste;
|
||||||
|
END$$
|
||||||
|
DELIMITER ;
|
||||||
|
|
||||||
|
DELIMITER $$
|
||||||
|
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`ticket_componentMakeUpdate`(
|
||||||
|
vTicketFk INT,
|
||||||
|
vClientFk INT,
|
||||||
|
vNickname VARCHAR(50),
|
||||||
|
vAgencyModeFk INT,
|
||||||
|
vAddressFk INT,
|
||||||
|
vZoneFk INT,
|
||||||
|
vWarehouseFk INT,
|
||||||
|
vCompanyFk INT,
|
||||||
|
vShipped DATETIME,
|
||||||
|
vLanded DATE,
|
||||||
|
vIsDeleted BOOLEAN,
|
||||||
|
vHasToBeUnrouted BOOLEAN,
|
||||||
|
vOption VARCHAR(25))
|
||||||
|
BEGIN
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modifica en el ticket los campos que se le pasan por parámetro
|
||||||
|
* y cambia sus componentes
|
||||||
|
*
|
||||||
|
* @param vTicketFk Id del ticket a modificar
|
||||||
|
* @param vClientFk nuevo cliente
|
||||||
|
* @param vNickname nuevo alias
|
||||||
|
* @param vAgencyModeFk nueva agencia
|
||||||
|
* @param vAddressFk nuevo consignatario
|
||||||
|
* @param vZoneFk nueva zona
|
||||||
|
* @param vWarehouseFk nuevo almacen
|
||||||
|
* @param vCompanyFk nueva empresa
|
||||||
|
* @param vShipped nueva fecha del envio de mercancia
|
||||||
|
* @param vLanded nueva fecha de recepcion de mercancia
|
||||||
|
* @param vIsDeleted si se borra el ticket
|
||||||
|
* @param vHasToBeUnrouted si se le elimina la ruta al ticket
|
||||||
|
* @param vOption opcion para el case del proc ticketComponentUpdateSale
|
||||||
|
*/
|
||||||
|
|
||||||
|
DECLARE vPrice DECIMAL(10,2);
|
||||||
|
DECLARE vBonus DECIMAL(10,2);
|
||||||
|
|
||||||
|
CALL ticket_componentPreview (vTicketFk, vLanded, vAddressFk, vZoneFk, vWarehouseFk);
|
||||||
|
|
||||||
|
IF (SELECT addressFk FROM ticket WHERE id = vTicketFk) <> vAddressFk THEN
|
||||||
|
|
||||||
|
UPDATE ticket t
|
||||||
|
JOIN address a ON a.id = vAddressFk
|
||||||
|
SET t.nickname = a.nickname
|
||||||
|
WHERE t.id = vTicketFk;
|
||||||
|
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
CALL zone_getShipped(vLanded, vAddressFk, vAgencyModeFk, TRUE);
|
||||||
|
|
||||||
|
SELECT zoneFk, price, bonus INTO vZoneFk, vPrice, vBonus
|
||||||
|
FROM tmp.zoneGetShipped
|
||||||
|
WHERE shipped BETWEEN DATE(vShipped) AND util.dayEnd(vShipped) AND warehouseFk = vWarehouseFk LIMIT 1;
|
||||||
|
|
||||||
|
UPDATE ticket t
|
||||||
|
SET
|
||||||
|
t.clientFk = vClientFk,
|
||||||
|
t.nickname = vNickname,
|
||||||
|
t.agencyModeFk = vAgencyModeFk,
|
||||||
|
t.addressFk = vAddressFk,
|
||||||
|
t.zoneFk = vZoneFk,
|
||||||
|
t.zonePrice = vPrice,
|
||||||
|
t.zoneBonus = vBonus,
|
||||||
|
t.warehouseFk = vWarehouseFk,
|
||||||
|
t.companyFk = vCompanyFk,
|
||||||
|
t.landed = vLanded,
|
||||||
|
t.shipped = vShipped,
|
||||||
|
t.isDeleted = vIsDeleted
|
||||||
|
WHERE
|
||||||
|
t.id = vTicketFk;
|
||||||
|
|
||||||
|
IF vHasToBeUnrouted THEN
|
||||||
|
UPDATE ticket t SET t.routeFk = NULL
|
||||||
|
WHERE t.id = vTicketFk;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
DROP TEMPORARY TABLE IF EXISTS tmp.sale;
|
||||||
|
CREATE TEMPORARY TABLE tmp.sale
|
||||||
|
(PRIMARY KEY (saleFk))
|
||||||
|
ENGINE = MEMORY
|
||||||
|
SELECT id AS saleFk, vWarehouseFk warehouseFk
|
||||||
|
FROM sale s WHERE s.ticketFk = vTicketFk;
|
||||||
|
|
||||||
|
DROP TEMPORARY TABLE IF EXISTS tmp.ticketComponent;
|
||||||
|
CREATE TEMPORARY TABLE tmp.ticketComponent
|
||||||
|
SELECT * FROM tmp.ticketComponentPreview;
|
||||||
|
|
||||||
|
CALL ticketComponentUpdateSale (vOption);
|
||||||
|
|
||||||
|
DROP TEMPORARY TABLE tmp.sale;
|
||||||
|
DROP TEMPORARY TABLE IF EXISTS tmp.ticketComponent;
|
||||||
|
|
||||||
|
DROP TEMPORARY TABLE tmp.zoneGetShipped, tmp.ticketComponentPreview;
|
||||||
|
END$$
|
||||||
|
DELIMITER ;
|
||||||
|
|
||||||
|
DELIMITER $$
|
||||||
|
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`ticket_recalcComponents`(vSelf INT, vOption VARCHAR(25))
|
||||||
|
proc: BEGIN
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crea tabla temporal para sale_recalcComponent() para recalcular los componentes
|
||||||
|
*
|
||||||
|
* @param vSelf Id del ticket
|
||||||
|
* @param vOption si no se quiere forzar llamar con NULL
|
||||||
|
*/
|
||||||
|
|
||||||
|
CREATE OR REPLACE TEMPORARY TABLE tmp.recalculateSales
|
||||||
|
SELECT s.id
|
||||||
|
FROM sale s
|
||||||
|
WHERE s.ticketFk = vSelf;
|
||||||
|
|
||||||
|
CALL sale_recalcComponent(vOption);
|
||||||
|
|
||||||
|
DROP TEMPORARY TABLE tmp.recalculateSales;
|
||||||
|
END$$
|
||||||
|
DELIMITER ;
|
||||||
|
|
||||||
|
TRUNCATE TABLE `vn`.`ticketUpdateAction`;
|
||||||
|
INSERT INTO `vn`.`ticketUpdateAction` (id, description, code) VALUES(1, 'Cambiar los precios en el ticket', 'renewPrices');
|
||||||
|
INSERT INTO `vn`.`ticketUpdateAction` (id, description, code) VALUES(2, 'Convertir en maná', 'mana');
|
|
@ -0,0 +1,3 @@
|
||||||
|
GRANT EXECUTE ON PROCEDURE util.tx_commit TO guest;
|
||||||
|
GRANT EXECUTE ON PROCEDURE util.tx_rollback TO guest;
|
||||||
|
GRANT EXECUTE ON PROCEDURE util.tx_start TO guest;
|
|
@ -0,0 +1,85 @@
|
||||||
|
DROP PROCEDURE IF EXISTS vn.travel_cloneWithEntries;
|
||||||
|
|
||||||
|
DELIMITER $$
|
||||||
|
$$
|
||||||
|
CREATE DEFINER=`root`@`localhost` PROCEDURE `vn`.`travel_cloneWithEntries`(
|
||||||
|
IN vTravelFk INT,
|
||||||
|
IN vDateStart DATE,
|
||||||
|
IN vDateEnd DATE,
|
||||||
|
IN vWarehouseOutFk INT,
|
||||||
|
IN vWarehouseInFk INT,
|
||||||
|
IN vRef VARCHAR(255),
|
||||||
|
IN vAgencyModeFk INT,
|
||||||
|
OUT vNewTravelFk INT)
|
||||||
|
BEGIN
|
||||||
|
/**
|
||||||
|
* Clona un travel junto con sus entradas y compras
|
||||||
|
* @param vTravelFk travel plantilla a clonar
|
||||||
|
* @param vDateStart fecha del shipment del nuevo travel
|
||||||
|
* @param vDateEnd fecha del landing del nuevo travel
|
||||||
|
* @param vWarehouseOutFk warehouse del salida del nuevo travel
|
||||||
|
* @param vWarehouseInFk warehouse de landing del nuevo travel
|
||||||
|
* @param vRef referencia del nuevo travel
|
||||||
|
* @param vAgencyModeFk del nuevo travel
|
||||||
|
* @param vNewTravelFk id del nuevo travel
|
||||||
|
*/
|
||||||
|
DECLARE vNewEntryFk INT;
|
||||||
|
DECLARE vEvaNotes VARCHAR(255);
|
||||||
|
DECLARE vDone BOOL;
|
||||||
|
DECLARE vAuxEntryFk INT;
|
||||||
|
DECLARE vTx BOOLEAN DEFAULT !@@in_transaction;
|
||||||
|
DECLARE vRsEntry CURSOR FOR
|
||||||
|
SELECT e.id
|
||||||
|
FROM entry e
|
||||||
|
JOIN travel t ON t.id = e.travelFk
|
||||||
|
WHERE e.travelFk = vTravelFk;
|
||||||
|
|
||||||
|
DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = TRUE;
|
||||||
|
|
||||||
|
DECLARE EXIT HANDLER FOR SQLEXCEPTION
|
||||||
|
BEGIN
|
||||||
|
CALL util.tx_rollback(vTx);
|
||||||
|
RESIGNAL;
|
||||||
|
END;
|
||||||
|
|
||||||
|
CALL util.tx_start(vTx);
|
||||||
|
|
||||||
|
INSERT INTO travel (shipped, landed, warehouseInFk, warehouseOutFk, agencyModeFk, `ref`, isDelivered, isReceived, m3, cargoSupplierFk, kg,clonedFrom)
|
||||||
|
SELECT vDateStart, vDateEnd, vWarehouseInFk, vWarehouseOutFk, vAgencyModeFk, vRef, isDelivered, isReceived, m3,cargoSupplierFk, kg,vTravelFk
|
||||||
|
FROM travel
|
||||||
|
WHERE id = vTravelFk;
|
||||||
|
|
||||||
|
SET vNewTravelFk = LAST_INSERT_ID();
|
||||||
|
|
||||||
|
SET vDone = FALSE;
|
||||||
|
SET @isModeInventory = TRUE;
|
||||||
|
|
||||||
|
OPEN vRsEntry;
|
||||||
|
|
||||||
|
l: LOOP
|
||||||
|
SET vDone = FALSE;
|
||||||
|
FETCH vRsEntry INTO vAuxEntryFk;
|
||||||
|
|
||||||
|
IF vDone THEN
|
||||||
|
LEAVE l;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
CALL entry_cloneHeader(vAuxEntryFk, vNewEntryFk, vNewTravelFk);
|
||||||
|
CALL entry_copyBuys(vAuxEntryFk, vNewEntryFk);
|
||||||
|
|
||||||
|
SELECT evaNotes INTO vEvaNotes
|
||||||
|
FROM entry
|
||||||
|
WHERE id = vAuxEntryFk;
|
||||||
|
|
||||||
|
UPDATE entry
|
||||||
|
SET evaNotes = vEvaNotes
|
||||||
|
WHERE id = vNewEntryFk;
|
||||||
|
|
||||||
|
END LOOP;
|
||||||
|
|
||||||
|
SET @isModeInventory = FALSE;
|
||||||
|
CLOSE vRsEntry;
|
||||||
|
|
||||||
|
CALL util.tx_commit(vTx);
|
||||||
|
END$$
|
||||||
|
DELIMITER ;
|
|
@ -0,0 +1,15 @@
|
||||||
|
DELIMITER $$
|
||||||
|
$$
|
||||||
|
|
||||||
|
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `util`.`tx_commit`(IN tx BOOL)
|
||||||
|
BEGIN
|
||||||
|
/**
|
||||||
|
* Procedimiento para confirmar los cambios asociados a una transacción
|
||||||
|
*
|
||||||
|
* @param tx BOOL es true si existe transacción asociada
|
||||||
|
*/
|
||||||
|
IF tx THEN
|
||||||
|
COMMIT;
|
||||||
|
END IF;
|
||||||
|
END$$
|
||||||
|
DELIMITER ;
|
|
@ -0,0 +1,15 @@
|
||||||
|
DELIMITER $$
|
||||||
|
$$
|
||||||
|
|
||||||
|
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `util`.`tx_rollback`(tx BOOL)
|
||||||
|
BEGIN
|
||||||
|
/**
|
||||||
|
* Procedimiento para deshacer los cambios asociados a una transacción
|
||||||
|
*
|
||||||
|
* @param tx BOOL es true si existe transacción asociada
|
||||||
|
*/
|
||||||
|
IF tx THEN
|
||||||
|
ROLLBACK;
|
||||||
|
END IF;
|
||||||
|
END$$
|
||||||
|
DELIMITER ;
|
|
@ -0,0 +1,17 @@
|
||||||
|
|
||||||
|
|
||||||
|
DELIMITER $$
|
||||||
|
$$
|
||||||
|
|
||||||
|
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `util`.`tx_start`(tx BOOL)
|
||||||
|
BEGIN
|
||||||
|
/**
|
||||||
|
* Procedimiento para iniciar una transacción
|
||||||
|
*
|
||||||
|
* @param tx BOOL es true si existe transacción asociada
|
||||||
|
*/
|
||||||
|
IF tx THEN
|
||||||
|
START TRANSACTION;
|
||||||
|
END IF;
|
||||||
|
END$$
|
||||||
|
DELIMITER ;
|
File diff suppressed because it is too large
Load Diff
|
@ -180,11 +180,13 @@ INSERT INTO `vn`.`warehouse`(`id`, `name`, `code`, `isComparative`, `isInventory
|
||||||
(13, 'Inventory', 'inv', 1, 1, 1, 0, 0, 0, 2, 1, 0),
|
(13, 'Inventory', 'inv', 1, 1, 1, 0, 0, 0, 2, 1, 0),
|
||||||
(60, 'Algemesi', NULL, 1, 1, 1, 0, 0, 0, 2, 1, 0);
|
(60, 'Algemesi', NULL, 1, 1, 1, 0, 0, 0, 2, 1, 0);
|
||||||
|
|
||||||
|
INSERT INTO `vn`.`sectorType` (id,description)
|
||||||
|
VALUES (1,'First type');
|
||||||
|
|
||||||
INSERT INTO `vn`.`sector`(`id`, `description`, `warehouseFk`, `isPreviousPreparedByPacking`, `code`)
|
INSERT INTO `vn`.`sector`(`id`, `description`, `warehouseFk`, `code`, `typeFk`)
|
||||||
VALUES
|
VALUES
|
||||||
(1, 'First sector', 1, 1, 'FIRST'),
|
(1, 'First sector', 1, 'FIRST', 1),
|
||||||
(2, 'Second sector', 2, 0, 'SECOND');
|
(2, 'Second sector', 2, 'SECOND',1);
|
||||||
|
|
||||||
INSERT INTO `vn`.`printer` (`id`, `name`, `path`, `isLabeler`, `sectorFk`, `ipAddress`)
|
INSERT INTO `vn`.`printer` (`id`, `name`, `path`, `isLabeler`, `sectorFk`, `ipAddress`)
|
||||||
VALUES
|
VALUES
|
||||||
|
@ -194,6 +196,7 @@ INSERT INTO `vn`.`printer` (`id`, `name`, `path`, `isLabeler`, `sectorFk`, `ipAd
|
||||||
|
|
||||||
UPDATE `vn`.`sector` SET mainPrinterFk = 1 WHERE id = 1;
|
UPDATE `vn`.`sector` SET mainPrinterFk = 1 WHERE id = 1;
|
||||||
|
|
||||||
|
|
||||||
INSERT INTO `vn`.`worker`(`id`, `code`, `firstName`, `lastName`,`bossFk`, `phone`)
|
INSERT INTO `vn`.`worker`(`id`, `code`, `firstName`, `lastName`,`bossFk`, `phone`)
|
||||||
VALUES
|
VALUES
|
||||||
(1106, 'LGN', 'David Charles', 'Haller', 19, 432978106),
|
(1106, 'LGN', 'David Charles', 'Haller', 19, 432978106),
|
||||||
|
@ -600,6 +603,9 @@ INSERT INTO `vn`.`taxArea` (`code`, `claveOperacionFactura`, `CodigoTransaccion`
|
||||||
('NATIONAL', 0, 1),
|
('NATIONAL', 0, 1),
|
||||||
('WORLD', 2, 15);
|
('WORLD', 2, 15);
|
||||||
|
|
||||||
|
INSERT INTO vn.invoiceOutConfig
|
||||||
|
SET parallelism = 8;
|
||||||
|
|
||||||
INSERT INTO `vn`.`invoiceOutSerial` (`code`, `description`, `isTaxed`, `taxAreaFk`, `isCEE`, `type`)
|
INSERT INTO `vn`.`invoiceOutSerial` (`code`, `description`, `isTaxed`, `taxAreaFk`, `isCEE`, `type`)
|
||||||
VALUES
|
VALUES
|
||||||
('A', 'Global nacional', 1, 'NATIONAL', 0, 'global'),
|
('A', 'Global nacional', 1, 'NATIONAL', 0, 'global'),
|
||||||
|
@ -623,9 +629,6 @@ UPDATE `vn`.`invoiceOut` SET ref = 'T3333333' WHERE id = 3;
|
||||||
UPDATE `vn`.`invoiceOut` SET ref = 'T4444444' WHERE id = 4;
|
UPDATE `vn`.`invoiceOut` SET ref = 'T4444444' WHERE id = 4;
|
||||||
UPDATE `vn`.`invoiceOut` SET ref = 'A1111111' WHERE id = 5;
|
UPDATE `vn`.`invoiceOut` SET ref = 'A1111111' WHERE id = 5;
|
||||||
|
|
||||||
INSERT INTO vn.invoiceOutConfig
|
|
||||||
SET parallelism = 8;
|
|
||||||
|
|
||||||
INSERT INTO `vn`.`invoiceOutTax` (`invoiceOutFk`, `taxableBase`, `vat`, `pgcFk`)
|
INSERT INTO `vn`.`invoiceOutTax` (`invoiceOutFk`, `taxableBase`, `vat`, `pgcFk`)
|
||||||
VALUES
|
VALUES
|
||||||
(1, 895.76, 89.58, 4722000010),
|
(1, 895.76, 89.58, 4722000010),
|
||||||
|
@ -659,19 +662,20 @@ INSERT INTO `vn`.`invoiceOutExpense`(`id`, `invoiceOutFk`, `amount`, `expenseFk`
|
||||||
|
|
||||||
INSERT INTO `vn`.`zone` (`id`, `name`, `hour`, `agencyModeFk`, `travelingDays`, `price`, `bonus`, `itemMaxSize`)
|
INSERT INTO `vn`.`zone` (`id`, `name`, `hour`, `agencyModeFk`, `travelingDays`, `price`, `bonus`, `itemMaxSize`)
|
||||||
VALUES
|
VALUES
|
||||||
(1, 'Zone pickup A', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 1, 0, 0, 0, 100),
|
(1, 'Zone pickup A', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 1, 0, 1, 0, 100),
|
||||||
(2, 'Zone pickup B', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 1, 0, 0, 0, 100),
|
(2, 'Zone pickup B', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 1, 0, 1, 0, 100),
|
||||||
(3, 'Zone 247 A', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 7, 1, 2, 0, 100),
|
(3, 'Zone 247 A', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 7, 1, 2, 0, 100),
|
||||||
(4, 'Zone 247 B', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 7, 1, 2, 0, 100),
|
(4, 'Zone 247 B', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 7, 1, 2, 0, 100),
|
||||||
(5, 'Zone expensive A', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 8, 1, 1000, 0, 100),
|
(5, 'Zone expensive A', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 8, 1, 1000, 0, 100),
|
||||||
(6, 'Zone expensive B', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 8, 1, 1000, 0, 100),
|
(6, 'Zone expensive B', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 8, 1, 1000, 0, 100),
|
||||||
(7, 'Zone refund', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 23, 0, 0, 0, 100),
|
(7, 'Zone refund', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 23, 0, 1, 0, 100),
|
||||||
(8, 'Zone others', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 10, 0, 0, 0, 100),
|
(8, 'Zone others', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 10, 0, 1, 0, 100),
|
||||||
(9, 'Zone superMan', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 2, 0, 0, 0, 100),
|
(9, 'Zone superMan', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 2, 0, 1, 0, 100),
|
||||||
(10, 'Zone teleportation', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 3, 0, 0, 0, 100),
|
(10, 'Zone teleportation', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 3, 0, 1, 0, 100),
|
||||||
(11, 'Zone pickup C', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 1, 0, 0, 0, 100),
|
(11, 'Zone pickup C', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 1, 0, 1, 0, 100),
|
||||||
(12, 'Zone entanglement', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 4, 0, 0, 0, 100),
|
(12, 'Zone entanglement', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 4, 0, 1, 0, 100),
|
||||||
(13, 'Zone quantum break', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 5, 0, 0, 0, 100);
|
(13, 'Zone quantum break', CONCAT(util.VN_CURDATE(), ' ', TIME('23:59')), 5, 0, 1, 0, 100);
|
||||||
|
|
||||||
|
|
||||||
INSERT INTO `vn`.`zoneWarehouse` (`id`, `zoneFk`, `warehouseFk`)
|
INSERT INTO `vn`.`zoneWarehouse` (`id`, `zoneFk`, `warehouseFk`)
|
||||||
VALUES
|
VALUES
|
||||||
|
@ -1426,16 +1430,29 @@ INSERT INTO `vn`.`ticketWeekly`(`ticketFk`, `weekDay`)
|
||||||
(5, 6),
|
(5, 6),
|
||||||
(15, 6);
|
(15, 6);
|
||||||
|
|
||||||
INSERT INTO `vn`.`travel`(`id`,`shipped`, `landed`, `warehouseInFk`, `warehouseOutFk`, `agencyModeFk`, `m3`, `kg`,`ref`, `totalEntries`, `cargoSupplierFk`)
|
INSERT INTO `vn`.`awb` (id, code, package, weight, created, amount, transitoryFk, taxFk)
|
||||||
VALUES
|
VALUES
|
||||||
(1, DATE_ADD(util.VN_CURDATE(), INTERVAL -2 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -2 MONTH), 1, 2, 1, 100.00, 1000, 'first travel', 1, 1),
|
(1, '07546501420', 67, 671, util.VN_CURDATE(), 1761, 1, 1),
|
||||||
(2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 1, 2, 1, 150, 2000, 'second travel', 2, 2),
|
(2, '07546491421', 252, 2769, util.VN_CURDATE(), 5231, 1, 1),
|
||||||
(3, util.VN_CURDATE(), util.VN_CURDATE(), 1, 2, 1, 0.00, 0.00, 'third travel', 1, 1),
|
(3, '07546500823', 102, 1495, util.VN_CURDATE(), 3221, 1, 1),
|
||||||
(4, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 1, 3, 1, 50.00, 500, 'fourth travel', 0, 2),
|
(4, '99610288821', 252, 2777, util.VN_CURDATE(), 3641, 1, 1),
|
||||||
(5, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 3, 3, 1, 50.00, 500, 'fifth travel', 1, 1),
|
(5, '07546500834', 229, 3292, util.VN_CURDATE(), 6601, 2, 1),
|
||||||
(6, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 4, 4, 1, 50.00, 500, 'sixth travel', 1, 2),
|
(6, '22101929561', 37, 458, util.VN_CURDATE(), 441, 2, 1),
|
||||||
(7, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 5, 4, 1, 50.00, 500, 'seventh travel', 2, 1),
|
(7, '07546491432', 258, 3034, util.VN_CURDATE(), 6441, 2, 1),
|
||||||
(8, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 5, 1, 1, 50.00, 500, 'eight travel', 1, 2);
|
(8, '99610288644', 476, 4461, util.VN_CURDATE(), 5751, 442, 1),
|
||||||
|
(9, '99610289193', 302, 2972, util.VN_CURDATE(), 3871, 442, 1),
|
||||||
|
(10, '07546500856', 185, 2364, util.VN_CURDATE(), 5321, 442, 1);
|
||||||
|
|
||||||
|
INSERT INTO `vn`.`travel`(`id`,`shipped`, `landed`, `warehouseInFk`, `warehouseOutFk`, `agencyModeFk`, `m3`, `kg`,`ref`, `totalEntries`, `cargoSupplierFk`, `awbFK`)
|
||||||
|
VALUES
|
||||||
|
(1, DATE_ADD(util.VN_CURDATE(), INTERVAL -2 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -2 MONTH), 1, 2, 1, 100.00, 1000, 'first travel', 1, 1, 1),
|
||||||
|
(2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 1, 2, 1, 150, 2000, 'second travel', 2, 2, 2),
|
||||||
|
(3, util.VN_CURDATE(), util.VN_CURDATE(), 1, 2, 1, 0.00, 0.00, 'third travel', 1, 1, 3),
|
||||||
|
(4, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 1, 3, 1, 50.00, 500, 'fourth travel', 0, 2, 4),
|
||||||
|
(5, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 3, 3, 1, 50.00, 500, 'fifth travel', 1, 1, 5),
|
||||||
|
(6, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 4, 4, 1, 50.00, 500, 'sixth travel', 1, 2, 6),
|
||||||
|
(7, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 5, 4, 1, 50.00, 500, 'seventh travel', 2, 1, 7),
|
||||||
|
(8, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 5, 1, 1, 50.00, 500, 'eight travel', 1, 2, 10);
|
||||||
|
|
||||||
INSERT INTO `vn`.`entry`(`id`, `supplierFk`, `created`, `travelFk`, `isConfirmed`, `companyFk`, `invoiceNumber`, `reference`, `isExcludedFromAvailable`, `isRaid`, `evaNotes`)
|
INSERT INTO `vn`.`entry`(`id`, `supplierFk`, `created`, `travelFk`, `isConfirmed`, `companyFk`, `invoiceNumber`, `reference`, `isExcludedFromAvailable`, `isRaid`, `evaNotes`)
|
||||||
VALUES
|
VALUES
|
||||||
|
@ -2499,20 +2516,7 @@ INSERT INTO `vn`.`rate`(`dated`, `warehouseFk`, `rate0`, `rate1`, `rate2`, `rate
|
||||||
(DATE_ADD(util.VN_CURDATE(), INTERVAL -1 YEAR), 1, 10, 15, 20, 25),
|
(DATE_ADD(util.VN_CURDATE(), INTERVAL -1 YEAR), 1, 10, 15, 20, 25),
|
||||||
(util.VN_CURDATE(), 1, 12, 17, 22, 27);
|
(util.VN_CURDATE(), 1, 12, 17, 22, 27);
|
||||||
|
|
||||||
INSERT INTO `vn`.`awb` (id, code, package, weight, created, amount, transitoryFk, taxFk)
|
INSERT INTO `vn`.`dua` (id, code, awbFk__, issued, operated, booked, bookEntried, gestdocFk, customsValue, companyFk)
|
||||||
VALUES
|
|
||||||
(1, '07546501420', 67, 671, util.VN_CURDATE(), 1761, 1, 1),
|
|
||||||
(2, '07546491421', 252, 2769, util.VN_CURDATE(), 5231, 1, 1),
|
|
||||||
(3, '07546500823', 102, 1495, util.VN_CURDATE(), 3221, 1, 1),
|
|
||||||
(4, '99610288821', 252, 2777, util.VN_CURDATE(), 3641, 1, 1),
|
|
||||||
(5, '07546500834', 229, 3292, util.VN_CURDATE(), 6601, 2, 1),
|
|
||||||
(6, '22101929561', 37, 458, util.VN_CURDATE(), 441, 2, 1),
|
|
||||||
(7, '07546491432', 258, 3034, util.VN_CURDATE(), 6441, 2, 1),
|
|
||||||
(8, '99610288644', 476, 4461, util.VN_CURDATE(), 5751, 442, 1),
|
|
||||||
(9, '99610289193', 302, 2972, util.VN_CURDATE(), 3871, 442, 1),
|
|
||||||
(10, '07546500856', 185, 2364, util.VN_CURDATE(), 5321, 442, 1);
|
|
||||||
|
|
||||||
INSERT INTO `vn`.`dua` (id, code, awbFk, issued, operated, booked, bookEntried, gestdocFk, customsValue, companyFk)
|
|
||||||
VALUES
|
VALUES
|
||||||
(1, '19ES0028013A481523', 1, util.VN_CURDATE(), util.VN_CURDATE(), util.VN_CURDATE(), util.VN_CURDATE(), 1, 11276.95, 442),
|
(1, '19ES0028013A481523', 1, util.VN_CURDATE(), util.VN_CURDATE(), util.VN_CURDATE(), util.VN_CURDATE(), 1, 11276.95, 442),
|
||||||
(2, '21ES00280136115760', 2, util.VN_CURDATE(), util.VN_CURDATE(), util.VN_CURDATE(), util.VN_CURDATE(), 2, 1376.20, 442),
|
(2, '21ES00280136115760', 2, util.VN_CURDATE(), util.VN_CURDATE(), util.VN_CURDATE(), util.VN_CURDATE(), 2, 1376.20, 442),
|
||||||
|
@ -2525,6 +2529,17 @@ INSERT INTO `vn`.`dua` (id, code, awbFk, issued, operated, booked, bookEntried,
|
||||||
(9, '19ES00280132025491', 9, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), util.VN_CURDATE(), util.VN_CURDATE(), util.VN_CURDATE(), 2, 7126.23, 442),
|
(9, '19ES00280132025491', 9, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), util.VN_CURDATE(), util.VN_CURDATE(), util.VN_CURDATE(), 2, 7126.23, 442),
|
||||||
(10, '19ES00280132025492', 10, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), util.VN_CURDATE(), util.VN_CURDATE(), util.VN_CURDATE(), 2, 4631.45, 442);
|
(10, '19ES00280132025492', 10, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), util.VN_CURDATE(), util.VN_CURDATE(), util.VN_CURDATE(), 2, 4631.45, 442);
|
||||||
|
|
||||||
|
INSERT INTO `vn`.`duaEntry` (`duaFk`, `entryFk`, `value`, `customsValue`, `euroValue`)
|
||||||
|
VALUES
|
||||||
|
(1, 1, 1.00, 1.00, 1.00),
|
||||||
|
(2, 2, 1.00, 1.00, 1.00),
|
||||||
|
(3, 3, 1.00, 1.00, 1.00),
|
||||||
|
(4, 4, 1.00, 1.00, 1.00),
|
||||||
|
(5, 5, 1.00, 1.00, 1.00),
|
||||||
|
(6, 6, 1.00, 1.00, 1.00),
|
||||||
|
(7, 7, 1.00, 1.00, 1.00),
|
||||||
|
(8, 8, 1.00, 1.00, 1.00);
|
||||||
|
|
||||||
REPLACE INTO `vn`.`invoiceIn`(`id`, `serialNumber`,`serial`, `supplierFk`, `issued`, `created`, `supplierRef`, `isBooked`, `companyFk`, `docFk`)
|
REPLACE INTO `vn`.`invoiceIn`(`id`, `serialNumber`,`serial`, `supplierFk`, `issued`, `created`, `supplierRef`, `isBooked`, `companyFk`, `docFk`)
|
||||||
VALUES
|
VALUES
|
||||||
(1, 1001, 'R', 1, util.VN_CURDATE(), util.VN_CURDATE(), 1234, 0, 442, 1),
|
(1, 1001, 'R', 1, util.VN_CURDATE(), util.VN_CURDATE(), 1234, 0, 442, 1),
|
||||||
|
@ -2911,7 +2926,7 @@ INSERT INTO `vn`.`workerConfig` (`id`, `businessUpdated`, `roleFk`, `payMethodFk
|
||||||
|
|
||||||
INSERT INTO `vn`.`ticketRefund`(`refundTicketFk`, `originalTicketFk`)
|
INSERT INTO `vn`.`ticketRefund`(`refundTicketFk`, `originalTicketFk`)
|
||||||
VALUES
|
VALUES
|
||||||
(24, 7);
|
(24, 8);
|
||||||
|
|
||||||
INSERT INTO `vn`.`deviceProductionModels` (`code`)
|
INSERT INTO `vn`.`deviceProductionModels` (`code`)
|
||||||
VALUES
|
VALUES
|
||||||
|
|
|
@ -49,6 +49,20 @@ async function test() {
|
||||||
random: false,
|
random: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const SpecReporter = require('jasmine-spec-reporter').SpecReporter;
|
||||||
|
jasmine.addReporter(new SpecReporter({
|
||||||
|
spec: {
|
||||||
|
displaySuccessful: false,
|
||||||
|
displayPending: false,
|
||||||
|
displayDuration: false,
|
||||||
|
displayFailed: true,
|
||||||
|
displayErrorMessages: true,
|
||||||
|
},
|
||||||
|
summary: {
|
||||||
|
displayPending: false,
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
await backendStatus();
|
await backendStatus();
|
||||||
|
|
||||||
jasmine.jasmine.DEFAULT_TIMEOUT_INTERVAL = 30000;
|
jasmine.jasmine.DEFAULT_TIMEOUT_INTERVAL = 30000;
|
||||||
|
|
|
@ -27,11 +27,8 @@ describe('Item Edit basic data path', () => {
|
||||||
|
|
||||||
it(`should edit the item basic data and confirm the item data was edited`, async() => {
|
it(`should edit the item basic data and confirm the item data was edited`, async() => {
|
||||||
const values = {
|
const values = {
|
||||||
name: 'Rose of Purity',
|
|
||||||
longName: 'RS Rose of Purity',
|
|
||||||
type: 'Anthurium',
|
type: 'Anthurium',
|
||||||
intrastat: 'Coral y materiales similares',
|
intrastat: 'Coral y materiales similares',
|
||||||
origin: 'Spain',
|
|
||||||
relevancy: 1,
|
relevancy: 1,
|
||||||
generic: 'Pallet',
|
generic: 'Pallet',
|
||||||
isActive: false,
|
isActive: false,
|
||||||
|
|
|
@ -225,7 +225,8 @@ describe('Ticket Edit sale path', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should show error trying to delete a ticket with a refund', async() => {
|
it('should show error trying to delete a ticket with a refund', async() => {
|
||||||
await page.accessToSearchResult('6');
|
await page.loginAndModule('production', 'ticket');
|
||||||
|
await page.accessToSearchResult('8');
|
||||||
await page.waitToClick(selectors.ticketDescriptor.moreMenu);
|
await page.waitToClick(selectors.ticketDescriptor.moreMenu);
|
||||||
await page.waitToClick(selectors.ticketDescriptor.moreMenuDeleteTicket);
|
await page.waitToClick(selectors.ticketDescriptor.moreMenuDeleteTicket);
|
||||||
await page.waitToClick(selectors.globalItems.acceptButton);
|
await page.waitToClick(selectors.globalItems.acceptButton);
|
||||||
|
|
|
@ -22,17 +22,6 @@ describe('Travel basic data path', () => {
|
||||||
await page.waitForState('travel.card.basicData');
|
await page.waitForState('travel.card.basicData');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw error if try move a travel with entries', async() => {
|
|
||||||
const lastMonth = Date.vnNew();
|
|
||||||
lastMonth.setMonth(lastMonth.getMonth() - 1);
|
|
||||||
|
|
||||||
await page.pickDate(selectors.travelBasicData.deliveryDate, lastMonth);
|
|
||||||
await page.waitToClick(selectors.travelBasicData.save);
|
|
||||||
const message = await page.waitForSnackbar();
|
|
||||||
|
|
||||||
expect(message.text).toContain('Cannot past travels with entries');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should set a wrong delivery date then receive an error on submit', async() => {
|
it('should set a wrong delivery date then receive an error on submit', async() => {
|
||||||
await page.loginAndModule('buyer', 'travel');
|
await page.loginAndModule('buyer', 'travel');
|
||||||
await page.write(selectors.travelIndex.generalSearchFilter, '4');
|
await page.write(selectors.travelIndex.generalSearchFilter, '4');
|
||||||
|
|
|
@ -270,8 +270,8 @@ class VnMySQL extends MySQL {
|
||||||
|
|
||||||
isLoggable(model) {
|
isLoggable(model) {
|
||||||
const Model = this.getModelDefinition(model).model;
|
const Model = this.getModelDefinition(model).model;
|
||||||
const settings = Model.definition.settings;
|
const {settings} = Model.definition;
|
||||||
return settings.base && settings.base === 'Loggable';
|
return settings.mixins?.Loggable;
|
||||||
}
|
}
|
||||||
|
|
||||||
invokeMethod(method, args, model, ctx, opts, cb) {
|
invokeMethod(method, args, model, ctx, opts, cb) {
|
||||||
|
@ -291,7 +291,7 @@ class VnMySQL extends MySQL {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const userId = opts.httpCtx && opts.httpCtx.active.accessToken.userId;
|
const userId = opts.httpCtx && opts.httpCtx.active?.accessToken?.userId;
|
||||||
if (userId) {
|
if (userId) {
|
||||||
const user = await Model.app.models.VnUser.findById(userId, {fields: ['name']}, opts);
|
const user = await Model.app.models.VnUser.findById(userId, {fields: ['name']}, opts);
|
||||||
await this.executeP(`CALL account.myUser_loginWithName(?)`, [user.name], opts);
|
await this.executeP(`CALL account.myUser_loginWithName(?)`, [user.name], opts);
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
|
const SalixError = require('../../util/salixError');
|
||||||
const UserError = require('../../util/user-error');
|
const UserError = require('../../util/user-error');
|
||||||
const logToConsole = require('strong-error-handler/lib/logger');
|
const logToConsole = require('strong-error-handler/lib/logger');
|
||||||
|
|
||||||
module.exports = function() {
|
module.exports = function() {
|
||||||
return function(err, req, res, next) {
|
return function(err, req, res, next) {
|
||||||
// Thrown user errors
|
// Thrown user errors
|
||||||
if (err instanceof UserError) {
|
if (err instanceof SalixError) {
|
||||||
err.message = req.__(err.message, ...err.translateArgs);
|
err.message = req.__(err.message, ...err.translateArgs);
|
||||||
return next(err);
|
return next(err);
|
||||||
}
|
}
|
||||||
|
@ -13,7 +14,7 @@ module.exports = function() {
|
||||||
if (err.statusCode == 422) {
|
if (err.statusCode == 422) {
|
||||||
try {
|
try {
|
||||||
let code;
|
let code;
|
||||||
let messages = err.details.messages;
|
let {messages} = err.details;
|
||||||
for (code in messages) break;
|
for (code in messages) break;
|
||||||
err.message = req.__(messages[code][0]);
|
err.message = req.__(messages[code][0]);
|
||||||
return next(err);
|
return next(err);
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
module.exports = class ForbiddenError extends Error {
|
const SalixError = require('./salixError');
|
||||||
|
module.exports = class ForbiddenError extends SalixError {
|
||||||
constructor(message, code, ...translateArgs) {
|
constructor(message, code, ...translateArgs) {
|
||||||
super(message);
|
super(message);
|
||||||
this.name = 'ForbiddenError';
|
this.name = ForbiddenError.name;
|
||||||
this.statusCode = 403;
|
this.statusCode = 403;
|
||||||
this.code = code;
|
this.code = code;
|
||||||
this.translateArgs = translateArgs;
|
this.translateArgs = translateArgs;
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
module.exports = class SalixError extends Error {
|
||||||
|
constructor(message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
};
|
|
@ -4,10 +4,11 @@
|
||||||
* the final user, so they cannot contain sensitive data and must
|
* the final user, so they cannot contain sensitive data and must
|
||||||
* be understandable by people who do not have a technical profile.
|
* be understandable by people who do not have a technical profile.
|
||||||
*/
|
*/
|
||||||
module.exports = class UserError extends Error {
|
const SalixError = require('./salixError');
|
||||||
|
module.exports = class UserError extends SalixError {
|
||||||
constructor(message, code, ...translateArgs) {
|
constructor(message, code, ...translateArgs) {
|
||||||
super(message);
|
super(message);
|
||||||
this.name = 'UserError';
|
this.name = UserError.name;
|
||||||
this.statusCode = 400;
|
this.statusCode = 400;
|
||||||
this.code = code;
|
this.code = code;
|
||||||
this.translateArgs = translateArgs;
|
this.translateArgs = translateArgs;
|
||||||
|
|
|
@ -42,14 +42,15 @@
|
||||||
translate-attr="{title: 'Set as default'}">
|
translate-attr="{title: 'Set as default'}">
|
||||||
</vn-icon-button>
|
</vn-icon-button>
|
||||||
</vn-none>
|
</vn-none>
|
||||||
<vn-one
|
<vn-one
|
||||||
style="overflow: hidden; min-width: 14em;">
|
style="overflow: hidden; min-width: 14em;">
|
||||||
<div class="ellipsize"><b>{{::address.nickname}} - #{{::address.id}}</b></div>
|
<div class="ellipsize"><b>{{::address.nickname}} - #{{::address.id}}</b></div>
|
||||||
<div class="ellipsize" name="street">{{::address.street}}</div>
|
<div class="ellipsize" name="street">{{::address.street}}</div>
|
||||||
<div class="ellipsize">
|
<div class="ellipsize">
|
||||||
<span ng-show="::address.postalCode">{{::address.postalCode}} -</span>
|
<span ng-show="::address.postalCode">{{::address.postalCode}} -</span>
|
||||||
<span ng-show="::address.city">{{::address.city}},</span>
|
<span ng-show="::address.city">{{::address.city}},</span>
|
||||||
{{::address.province.name}}
|
<span ng-show="::address.province.name">{{::address.province.name}},</span>
|
||||||
|
{{::address.province.country.country}}
|
||||||
</div>
|
</div>
|
||||||
<div class="ellipsize">
|
<div class="ellipsize">
|
||||||
{{::address.phone}}<span ng-if="::address.mobile">, </span>
|
{{::address.phone}}<span ng-if="::address.mobile">, </span>
|
||||||
|
@ -72,7 +73,7 @@
|
||||||
class="vn-hide-narrow vn-px-md border-solid-left"
|
class="vn-hide-narrow vn-px-md border-solid-left"
|
||||||
style="height: 6em; overflow: auto;">
|
style="height: 6em; overflow: auto;">
|
||||||
<vn-one ng-repeat="observation in address.observations track by $index" ng-class="{'vn-pt-sm': $index}">
|
<vn-one ng-repeat="observation in address.observations track by $index" ng-class="{'vn-pt-sm': $index}">
|
||||||
<b>{{::observation.observationType.description}}:</b>
|
<b>{{::observation.observationType.description}}:</b>
|
||||||
<span>{{::observation.description}}</span>
|
<span>{{::observation.description}}</span>
|
||||||
</vn-one>
|
</vn-one>
|
||||||
</vn-vertical>
|
</vn-vertical>
|
||||||
|
|
|
@ -33,7 +33,13 @@ class Controller extends Section {
|
||||||
}, {
|
}, {
|
||||||
relation: 'province',
|
relation: 'province',
|
||||||
scope: {
|
scope: {
|
||||||
fields: ['id', 'name']
|
fields: ['id', 'name', 'countryFk'],
|
||||||
|
include: {
|
||||||
|
relation: 'country',
|
||||||
|
scope: {
|
||||||
|
fields: ['id', 'country']
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -127,7 +127,7 @@ module.exports = Self => {
|
||||||
case 'isBooked':
|
case 'isBooked':
|
||||||
return {[`ii.${param}`]: value};
|
return {[`ii.${param}`]: value};
|
||||||
case 'awbCode':
|
case 'awbCode':
|
||||||
return {'awb.code': value};
|
return {'sub.code': value};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -143,20 +143,27 @@ module.exports = Self => {
|
||||||
ii.issued,
|
ii.issued,
|
||||||
ii.isBooked,
|
ii.isBooked,
|
||||||
ii.supplierRef,
|
ii.supplierRef,
|
||||||
ii.docFk AS dmsFk,
|
ii.docFk dmsFk,
|
||||||
dm.file,
|
dm.file,
|
||||||
ii.supplierFk,
|
ii.supplierFk,
|
||||||
ii.expenseFkDeductible deductibleExpenseFk,
|
ii.expenseFkDeductible deductibleExpenseFk,
|
||||||
s.name AS supplierName,
|
s.name supplierName,
|
||||||
s.account,
|
s.account,
|
||||||
SUM(iid.amount) AS amount,
|
SUM(iid.amount) amount,
|
||||||
awb.code AS awbCode
|
sub.code awbCode
|
||||||
FROM invoiceIn ii
|
FROM invoiceIn ii
|
||||||
JOIN supplier s ON s.id = ii.supplierFk
|
JOIN supplier s ON s.id = ii.supplierFk
|
||||||
LEFT JOIN invoiceInDueDay iid ON iid.invoiceInFk = ii.id
|
LEFT JOIN invoiceInDueDay iid ON iid.invoiceInFk = ii.id
|
||||||
LEFT JOIN duaInvoiceIn dii ON dii.invoiceInFk = ii.id
|
LEFT JOIN duaInvoiceIn dii ON dii.invoiceInFk = ii.id
|
||||||
LEFT JOIN dua d ON d.id = dii.duaFk
|
LEFT JOIN dua d ON d.id = dii.duaFk
|
||||||
LEFT JOIN awb ON awb.id = d.awbFk
|
LEFT JOIN (
|
||||||
|
SELECT awb.code, de.duaFk
|
||||||
|
FROM duaEntry de
|
||||||
|
JOIN entry e ON e.id = de.entryFk
|
||||||
|
JOIN travel t ON t.id = e.travelFk
|
||||||
|
JOIN awb ON awb.id = t.awbFk
|
||||||
|
GROUP BY de.duaFk
|
||||||
|
) sub ON sub.duaFk = d.id
|
||||||
LEFT JOIN company co ON co.id = ii.companyFk
|
LEFT JOIN company co ON co.id = ii.companyFk
|
||||||
LEFT JOIN dms dm ON dm.id = ii.docFk`
|
LEFT JOIN dms dm ON dm.id = ii.docFk`
|
||||||
);
|
);
|
||||||
|
|
|
@ -98,9 +98,10 @@ describe('InvoiceIn filter()', () => {
|
||||||
const options = {transaction: tx};
|
const options = {transaction: tx};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
const awbExpected = '07546501420';
|
||||||
const ctx = {
|
const ctx = {
|
||||||
args: {
|
args: {
|
||||||
awbCode: '07546500856',
|
awbCode: awbExpected,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -108,8 +109,8 @@ describe('InvoiceIn filter()', () => {
|
||||||
const firstRow = result[0];
|
const firstRow = result[0];
|
||||||
|
|
||||||
expect(result.length).toEqual(1);
|
expect(result.length).toEqual(1);
|
||||||
expect(firstRow.id).toEqual(10);
|
expect(firstRow.id).toEqual(1);
|
||||||
expect(firstRow.awbCode).toEqual('07546500856');
|
expect(firstRow.awbCode).toEqual(awbExpected);
|
||||||
|
|
||||||
await tx.rollback();
|
await tx.rollback();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
@ -18,22 +18,6 @@
|
||||||
</vn-crud-model>
|
</vn-crud-model>
|
||||||
<form name="form" ng-submit="watcher.submit()" ng-cloak class="vn-w-md">
|
<form name="form" ng-submit="watcher.submit()" ng-cloak class="vn-w-md">
|
||||||
<vn-card class="vn-pa-lg">
|
<vn-card class="vn-pa-lg">
|
||||||
<vn-horizontal>
|
|
||||||
<vn-textfield
|
|
||||||
label="Name"
|
|
||||||
ng-model="$ctrl.item.name"
|
|
||||||
vn-name="name"
|
|
||||||
rule
|
|
||||||
vn-focus>
|
|
||||||
</vn-textfield>
|
|
||||||
<vn-textfield
|
|
||||||
label="Full name"
|
|
||||||
ng-model="$ctrl.item.longName"
|
|
||||||
vn-name="longName"
|
|
||||||
rule
|
|
||||||
info="Full name calculates based on tags 1-3. Is not recommended to change it manually">
|
|
||||||
</vn-textfield>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal>
|
<vn-horizontal>
|
||||||
<vn-autocomplete
|
<vn-autocomplete
|
||||||
url="ItemTypes"
|
url="ItemTypes"
|
||||||
|
@ -52,6 +36,34 @@
|
||||||
</div>
|
</div>
|
||||||
</tpl-item>
|
</tpl-item>
|
||||||
</vn-autocomplete>
|
</vn-autocomplete>
|
||||||
|
<vn-textfield
|
||||||
|
label="Reference"
|
||||||
|
ng-model="$ctrl.item.comment"
|
||||||
|
vn-name="comment"
|
||||||
|
rule>
|
||||||
|
</vn-textfield>
|
||||||
|
<vn-input-number
|
||||||
|
min="0"
|
||||||
|
label="Relevancy"
|
||||||
|
ng-model="$ctrl.item.relevancy"
|
||||||
|
vn-name="relevancy"
|
||||||
|
rule>
|
||||||
|
</vn-input-number>
|
||||||
|
</vn-horizontal>
|
||||||
|
<vn-horizontal>
|
||||||
|
<vn-input-number
|
||||||
|
min="0"
|
||||||
|
label="stems"
|
||||||
|
ng-model="$ctrl.item.stems"
|
||||||
|
vn-name="stems"
|
||||||
|
rule>
|
||||||
|
</vn-input-number>
|
||||||
|
<vn-input-number
|
||||||
|
min="0"
|
||||||
|
label="Multiplier"
|
||||||
|
ng-model="$ctrl.item.stemMultiplier"
|
||||||
|
vn-name="stemMultiplier">
|
||||||
|
</vn-input-number>
|
||||||
<vn-autocomplete
|
<vn-autocomplete
|
||||||
label="Generic"
|
label="Generic"
|
||||||
url="Items/withName"
|
url="Items/withName"
|
||||||
|
@ -109,59 +121,6 @@
|
||||||
initial-data="$ctrl.item.expense">
|
initial-data="$ctrl.item.expense">
|
||||||
</vn-autocomplete>
|
</vn-autocomplete>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
<vn-horizontal>
|
|
||||||
<vn-autocomplete
|
|
||||||
data="originsData"
|
|
||||||
label="Origin"
|
|
||||||
show-field="name"
|
|
||||||
value-field="id"
|
|
||||||
ng-model="$ctrl.item.originFk"
|
|
||||||
vn-name="origin"
|
|
||||||
initial-data="$ctrl.item.origin">
|
|
||||||
</vn-autocomplete>
|
|
||||||
<vn-input-number
|
|
||||||
min="0"
|
|
||||||
label="Size"
|
|
||||||
ng-model="$ctrl.item.size"
|
|
||||||
vn-name="size"
|
|
||||||
rule>
|
|
||||||
</vn-input-number>
|
|
||||||
<vn-textfield
|
|
||||||
label="Reference"
|
|
||||||
ng-model="$ctrl.item.comment"
|
|
||||||
vn-name="comment"
|
|
||||||
rule>
|
|
||||||
</vn-textfield>
|
|
||||||
<vn-input-number
|
|
||||||
min="0"
|
|
||||||
label="Relevancy"
|
|
||||||
ng-model="$ctrl.item.relevancy"
|
|
||||||
vn-name="relevancy"
|
|
||||||
rule>
|
|
||||||
</vn-input-number>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-input-number
|
|
||||||
min="0"
|
|
||||||
label="stems"
|
|
||||||
ng-model="$ctrl.item.stems"
|
|
||||||
vn-name="stems"
|
|
||||||
rule>
|
|
||||||
</vn-input-number>
|
|
||||||
<vn-input-number
|
|
||||||
min="0"
|
|
||||||
label="Multiplier"
|
|
||||||
ng-model="$ctrl.item.stemMultiplier"
|
|
||||||
vn-name="stemMultiplier">
|
|
||||||
</vn-input-number>
|
|
||||||
<vn-input-number
|
|
||||||
min="1"
|
|
||||||
label="Minimum sales quantity"
|
|
||||||
ng-model="$ctrl.item.minQuantity"
|
|
||||||
vn-name="minQuantity"
|
|
||||||
rule>
|
|
||||||
</vn-input-number>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal>
|
<vn-horizontal>
|
||||||
<vn-input-number
|
<vn-input-number
|
||||||
min="0"
|
min="0"
|
||||||
|
@ -192,14 +151,6 @@
|
||||||
rule>
|
rule>
|
||||||
</vn-input-number>
|
</vn-input-number>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
<vn-horizontal>
|
|
||||||
<vn-textarea
|
|
||||||
label="Description"
|
|
||||||
ng-model="$ctrl.item.description"
|
|
||||||
vn-name="description"
|
|
||||||
rule>
|
|
||||||
</vn-textarea>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal>
|
<vn-horizontal>
|
||||||
<vn-check
|
<vn-check
|
||||||
label="Active"
|
label="Active"
|
||||||
|
@ -224,6 +175,14 @@
|
||||||
info="This item does need a photo">
|
info="This item does need a photo">
|
||||||
</vn-check>
|
</vn-check>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
|
<vn-horizontal>
|
||||||
|
<vn-textarea
|
||||||
|
label="Description"
|
||||||
|
ng-model="$ctrl.item.description"
|
||||||
|
vn-name="description"
|
||||||
|
rule>
|
||||||
|
</vn-textarea>
|
||||||
|
</vn-horizontal>
|
||||||
</vn-card>
|
</vn-card>
|
||||||
<vn-button-bar>
|
<vn-button-bar>
|
||||||
<vn-submit
|
<vn-submit
|
||||||
|
|
|
@ -40,7 +40,7 @@ module.exports = Self => {
|
||||||
currentDate.setHours(0, 0, 0, 0);
|
currentDate.setHours(0, 0, 0, 0);
|
||||||
const nextDay = Date.vnNew();
|
const nextDay = Date.vnNew();
|
||||||
nextDay.setDate(currentDate.getDate() + 1);
|
nextDay.setDate(currentDate.getDate() + 1);
|
||||||
|
nextDay.setHours(0, 0, 0, 0);
|
||||||
const filter = {
|
const filter = {
|
||||||
where: {
|
where: {
|
||||||
and: [
|
and: [
|
||||||
|
|
|
@ -20,6 +20,9 @@
|
||||||
},
|
},
|
||||||
"beneficiary": {
|
"beneficiary": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
},
|
||||||
|
"supplierFk": {
|
||||||
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"relations": {
|
"relations": {
|
||||||
|
|
|
@ -14,17 +14,30 @@ module.exports = Self => {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const salesFilter = {
|
let sales;
|
||||||
where: {id: {inq: salesIds}},
|
let services;
|
||||||
include: {
|
|
||||||
relation: 'components',
|
if (salesIds && salesIds.length) {
|
||||||
scope: {
|
sales = await models.Sale.find({
|
||||||
fields: ['saleFk', 'componentFk', 'value']
|
where: {id: {inq: salesIds}},
|
||||||
|
include: {
|
||||||
|
relation: 'components',
|
||||||
|
scope: {
|
||||||
|
fields: ['saleFk', 'componentFk', 'value']
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}, myOptions);
|
||||||
};
|
}
|
||||||
const sales = await models.Sale.find(salesFilter, myOptions);
|
|
||||||
let ticketsIds = [...new Set(sales.map(sale => sale.ticketFk))];
|
if (servicesIds && servicesIds.length) {
|
||||||
|
services = await models.TicketService.find({
|
||||||
|
where: {id: {inq: servicesIds}}
|
||||||
|
}, myOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
let ticketsIds = sales ?
|
||||||
|
[...new Set(sales.map(sale => sale.ticketFk))] :
|
||||||
|
[...new Set(services.map(service => service.ticketFk))];
|
||||||
|
|
||||||
const mappedTickets = new Map();
|
const mappedTickets = new Map();
|
||||||
|
|
||||||
|
@ -39,32 +52,28 @@ module.exports = Self => {
|
||||||
newTickets.push(newTicket);
|
newTickets.push(newTicket);
|
||||||
mappedTickets.set(ticketId, newTicket.id);
|
mappedTickets.set(ticketId, newTicket.id);
|
||||||
}
|
}
|
||||||
|
if (sales) {
|
||||||
|
for (const sale of sales) {
|
||||||
|
const newTicketId = mappedTickets.get(sale.ticketFk);
|
||||||
|
|
||||||
for (const sale of sales) {
|
const createdSale = await models.Sale.create({
|
||||||
const newTicketId = mappedTickets.get(sale.ticketFk);
|
ticketFk: newTicketId,
|
||||||
|
itemFk: sale.itemFk,
|
||||||
|
quantity: negative ? - sale.quantity : sale.quantity,
|
||||||
|
concept: sale.concept,
|
||||||
|
price: sale.price,
|
||||||
|
discount: sale.discount,
|
||||||
|
}, myOptions);
|
||||||
|
|
||||||
const createdSale = await models.Sale.create({
|
const components = sale.components();
|
||||||
ticketFk: newTicketId,
|
for (const component of components)
|
||||||
itemFk: sale.itemFk,
|
component.saleFk = createdSale.id;
|
||||||
quantity: negative ? - sale.quantity : sale.quantity,
|
|
||||||
concept: sale.concept,
|
|
||||||
price: sale.price,
|
|
||||||
discount: sale.discount,
|
|
||||||
}, myOptions);
|
|
||||||
|
|
||||||
const components = sale.components();
|
await models.SaleComponent.create(components, myOptions);
|
||||||
for (const component of components)
|
}
|
||||||
component.saleFk = createdSale.id;
|
|
||||||
|
|
||||||
await models.SaleComponent.create(components, myOptions);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (servicesIds && servicesIds.length) {
|
if (services) {
|
||||||
const servicesFilter = {
|
|
||||||
where: {id: {inq: servicesIds}}
|
|
||||||
};
|
|
||||||
const services = await models.TicketService.find(servicesFilter, myOptions);
|
|
||||||
|
|
||||||
for (const service of services) {
|
for (const service of services) {
|
||||||
const newTicketId = mappedTickets.get(service.ticketFk);
|
const newTicketId = mappedTickets.get(service.ticketFk);
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@ module.exports = Self => {
|
||||||
{
|
{
|
||||||
arg: 'salesIds',
|
arg: 'salesIds',
|
||||||
type: ['number'],
|
type: ['number'],
|
||||||
required: true
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
arg: 'servicesIds',
|
arg: 'servicesIds',
|
||||||
|
|
|
@ -44,24 +44,7 @@ describe('Sale refund()', () => {
|
||||||
|
|
||||||
const tickets = await models.Sale.refund(ctx, salesIds, servicesIds, withWarehouse, options);
|
const tickets = await models.Sale.refund(ctx, salesIds, servicesIds, withWarehouse, options);
|
||||||
|
|
||||||
const refundedTicket = await models.Ticket.findOne({
|
const refundedTicket = await getTicketRefund(tickets[0].id, options);
|
||||||
where: {
|
|
||||||
id: tickets[0].id
|
|
||||||
},
|
|
||||||
include: [
|
|
||||||
{
|
|
||||||
relation: 'ticketSales',
|
|
||||||
scope: {
|
|
||||||
include: {
|
|
||||||
relation: 'components'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
relation: 'ticketServices',
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}, options);
|
|
||||||
const ticketsAfter = await models.Ticket.find({}, options);
|
const ticketsAfter = await models.Ticket.find({}, options);
|
||||||
const salesLength = refundedTicket.ticketSales().length;
|
const salesLength = refundedTicket.ticketSales().length;
|
||||||
const componentsLength = refundedTicket.ticketSales()[0].components().length;
|
const componentsLength = refundedTicket.ticketSales()[0].components().length;
|
||||||
|
@ -77,4 +60,42 @@ describe('Sale refund()', () => {
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should create a ticket without sales', async() => {
|
||||||
|
const servicesIds = [4];
|
||||||
|
const tx = await models.Sale.beginTransaction({});
|
||||||
|
const options = {transaction: tx};
|
||||||
|
try {
|
||||||
|
const tickets = await models.Sale.refund(ctx, null, servicesIds, withWarehouse, options);
|
||||||
|
const refundedTicket = await getTicketRefund(tickets[0].id, options);
|
||||||
|
|
||||||
|
expect(refundedTicket).toBeDefined();
|
||||||
|
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
async function getTicketRefund(id, options) {
|
||||||
|
return models.Ticket.findOne({
|
||||||
|
where: {
|
||||||
|
id
|
||||||
|
},
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
relation: 'ticketSales',
|
||||||
|
scope: {
|
||||||
|
include: {
|
||||||
|
relation: 'components'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
relation: 'ticketServices',
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}, options);
|
||||||
|
}
|
||||||
|
|
|
@ -74,8 +74,8 @@ module.exports = Self => {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
arg: 'option',
|
arg: 'option',
|
||||||
type: 'number',
|
type: 'string',
|
||||||
description: 'Action id'
|
description: 'Action code'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
arg: 'isWithoutNegatives',
|
arg: 'isWithoutNegatives',
|
||||||
|
|
|
@ -60,7 +60,7 @@ describe('ticket componentUpdate()', () => {
|
||||||
shipped: today,
|
shipped: today,
|
||||||
landed: tomorrow,
|
landed: tomorrow,
|
||||||
isDeleted: false,
|
isDeleted: false,
|
||||||
option: 1,
|
option: 'renewPrices',
|
||||||
isWithoutNegatives: false
|
isWithoutNegatives: false
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -74,7 +74,6 @@ describe('ticket componentUpdate()', () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
await models.Ticket.componentUpdate(ctx, options);
|
await models.Ticket.componentUpdate(ctx, options);
|
||||||
|
|
||||||
[componentValue] = await models.SaleComponent.rawSql(componentOfSaleSeven, null, options);
|
[componentValue] = await models.SaleComponent.rawSql(componentOfSaleSeven, null, options);
|
||||||
|
@ -110,7 +109,7 @@ describe('ticket componentUpdate()', () => {
|
||||||
shipped: today,
|
shipped: today,
|
||||||
landed: tomorrow,
|
landed: tomorrow,
|
||||||
isDeleted: false,
|
isDeleted: false,
|
||||||
option: 1,
|
option: 'renewPrices',
|
||||||
isWithoutNegatives: false
|
isWithoutNegatives: false
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -176,7 +175,7 @@ describe('ticket componentUpdate()', () => {
|
||||||
shipped: newDate,
|
shipped: newDate,
|
||||||
landed: tomorrow,
|
landed: tomorrow,
|
||||||
isDeleted: false,
|
isDeleted: false,
|
||||||
option: 1,
|
option: 'renewPrices',
|
||||||
isWithoutNegatives: true
|
isWithoutNegatives: true
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -235,7 +234,7 @@ describe('ticket componentUpdate()', () => {
|
||||||
shipped: newDate,
|
shipped: newDate,
|
||||||
landed: tomorrow,
|
landed: tomorrow,
|
||||||
isDeleted: false,
|
isDeleted: false,
|
||||||
option: 1,
|
option: 'renewPrices',
|
||||||
isWithoutNegatives: false,
|
isWithoutNegatives: false,
|
||||||
keepPrice: true
|
keepPrice: true
|
||||||
};
|
};
|
||||||
|
@ -288,7 +287,7 @@ describe('ticket componentUpdate()', () => {
|
||||||
shipped: newDate,
|
shipped: newDate,
|
||||||
landed: tomorrow,
|
landed: tomorrow,
|
||||||
isDeleted: false,
|
isDeleted: false,
|
||||||
option: 1,
|
option: 'renewPrices',
|
||||||
isWithoutNegatives: false,
|
isWithoutNegatives: false,
|
||||||
keepPrice: false
|
keepPrice: false
|
||||||
};
|
};
|
||||||
|
|
|
@ -117,7 +117,7 @@ describe('ticket setDeleted()', () => {
|
||||||
return value;
|
return value;
|
||||||
};
|
};
|
||||||
|
|
||||||
const ticketId = 7;
|
const ticketId = 8;
|
||||||
await models.Ticket.setDeleted(ctx, ticketId, options);
|
await models.Ticket.setDeleted(ctx, ticketId, options);
|
||||||
|
|
||||||
await tx.rollback();
|
await tx.rollback();
|
||||||
|
|
|
@ -28,7 +28,6 @@ module.exports = Self => {
|
||||||
|
|
||||||
const loopBackContext = LoopBackContext.getCurrentContext();
|
const loopBackContext = LoopBackContext.getCurrentContext();
|
||||||
ctx.req = loopBackContext.active;
|
ctx.req = loopBackContext.active;
|
||||||
if (await models.ACL.checkAccessAcl(ctx, 'Sale', 'canForceQuantity', 'WRITE')) return;
|
|
||||||
|
|
||||||
const ticketId = changes?.ticketFk || instance?.ticketFk;
|
const ticketId = changes?.ticketFk || instance?.ticketFk;
|
||||||
const itemId = changes?.itemFk || instance?.itemFk;
|
const itemId = changes?.itemFk || instance?.itemFk;
|
||||||
|
|
|
@ -76,7 +76,7 @@
|
||||||
<vn-radio
|
<vn-radio
|
||||||
ng-model="$ctrl.ticket.option"
|
ng-model="$ctrl.ticket.option"
|
||||||
label="{{::action.description}}"
|
label="{{::action.description}}"
|
||||||
val={{::action.id}}>
|
val={{::action.code}}>
|
||||||
</vn-radio>
|
</vn-radio>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -25,12 +25,7 @@ class Controller extends Component {
|
||||||
|
|
||||||
loadDefaultTicketAction() {
|
loadDefaultTicketAction() {
|
||||||
const isSalesAssistant = this.aclService.hasAny(['salesAssistant']);
|
const isSalesAssistant = this.aclService.hasAny(['salesAssistant']);
|
||||||
const defaultOption = isSalesAssistant ? 'turnInMana' : 'changePrice';
|
this.ticket.option = isSalesAssistant ? 'mana' : 'renewPrices';
|
||||||
const filter = {where: {code: defaultOption}};
|
|
||||||
|
|
||||||
this.$http.get(`TicketUpdateActions`, {filter}).then(response => {
|
|
||||||
return this.ticket.option = response.data[0].id;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onStepChange() {
|
onStepChange() {
|
||||||
|
@ -112,7 +107,7 @@ class Controller extends Component {
|
||||||
shipped: this.ticket.shipped,
|
shipped: this.ticket.shipped,
|
||||||
landed: this.ticket.landed,
|
landed: this.ticket.landed,
|
||||||
isDeleted: this.ticket.isDeleted,
|
isDeleted: this.ticket.isDeleted,
|
||||||
option: parseInt(this.ticket.option),
|
option: this.ticket.option,
|
||||||
isWithoutNegatives: this.ticket.withoutNegatives,
|
isWithoutNegatives: this.ticket.withoutNegatives,
|
||||||
withWarningAccept: this.ticket.withWarningAccept,
|
withWarningAccept: this.ticket.withWarningAccept,
|
||||||
keepPrice: false
|
keepPrice: false
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
|
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
|
||||||
const UserError = require('vn-loopback/util/user-error');
|
const UserError = require('vn-loopback/util/user-error');
|
||||||
const loggable = require('vn-loopback/util/log');
|
|
||||||
|
|
||||||
module.exports = Self => {
|
module.exports = Self => {
|
||||||
Self.remoteMethodCtx('cloneWithEntries', {
|
Self.remoteMethodCtx('cloneWithEntries', {
|
||||||
|
@ -11,8 +10,9 @@ module.exports = Self => {
|
||||||
type: 'number',
|
type: 'number',
|
||||||
required: true,
|
required: true,
|
||||||
description: 'The original travel id',
|
description: 'The original travel id',
|
||||||
http: {source: 'path'}
|
http: {source: 'path'},
|
||||||
}],
|
},
|
||||||
|
],
|
||||||
returns: {
|
returns: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
description: 'The new cloned travel id',
|
description: 'The new cloned travel id',
|
||||||
|
@ -24,61 +24,75 @@ module.exports = Self => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Self.cloneWithEntries = async(ctx, id) => {
|
Self.cloneWithEntries = async(ctx, id, options) => {
|
||||||
const conn = Self.dataSource.connector;
|
const conn = Self.dataSource.connector;
|
||||||
const travel = await Self.findById(id, {
|
const myOptions = {};
|
||||||
fields: [
|
let tx = options?.transaction;
|
||||||
'id',
|
|
||||||
'shipped',
|
|
||||||
'landed',
|
|
||||||
'warehouseInFk',
|
|
||||||
'warehouseOutFk',
|
|
||||||
'agencyModeFk',
|
|
||||||
'ref'
|
|
||||||
]
|
|
||||||
});
|
|
||||||
const started = Date.vnNew();
|
|
||||||
const ended = Date.vnNew();
|
|
||||||
|
|
||||||
if (!travel)
|
try {
|
||||||
throw new UserError('Travel not found');
|
if (typeof options == 'object')
|
||||||
|
Object.assign(myOptions, options);
|
||||||
|
|
||||||
let stmts = [];
|
if (!myOptions.transaction) {
|
||||||
let stmt;
|
tx = await Self.beginTransaction({});
|
||||||
|
myOptions.transaction = tx;
|
||||||
|
}
|
||||||
|
|
||||||
stmt = new ParameterizedSQL(
|
const travel = await Self.findById(id, {
|
||||||
`CALL travel_cloneWithEntries(?, ?, ?, ?, ?, ?, ?, @vTravelFk)`, [
|
fields: [
|
||||||
id,
|
'id',
|
||||||
started,
|
'shipped',
|
||||||
ended,
|
'landed',
|
||||||
travel.warehouseOutFk,
|
'warehouseInFk',
|
||||||
travel.warehouseInFk,
|
'warehouseOutFk',
|
||||||
travel.ref,
|
'agencyModeFk',
|
||||||
travel.agencyModeFk
|
'ref'
|
||||||
]
|
]
|
||||||
);
|
});
|
||||||
stmts.push(stmt);
|
const started = Date.vnNew();
|
||||||
const newTravelIndex = stmts.push('SELECT @vTravelFk AS id') - 1;
|
const ended = Date.vnNew();
|
||||||
|
|
||||||
const sql = ParameterizedSQL.join(stmts, ';');
|
if (!travel)
|
||||||
const result = await conn.executeStmt(sql);
|
throw new UserError('Travel not found');
|
||||||
const [lastInsert] = result[newTravelIndex];
|
|
||||||
|
|
||||||
if (!lastInsert.id)
|
let stmts = [];
|
||||||
throw new UserError('Unable to clone this travel');
|
let stmt;
|
||||||
|
stmt = new ParameterizedSQL(
|
||||||
|
`CALL travel_cloneWithEntries(?, ?, ?, ?, ?, ?, ?, @vTravelFk)`, [
|
||||||
|
id,
|
||||||
|
started,
|
||||||
|
ended,
|
||||||
|
travel.warehouseOutFk,
|
||||||
|
travel.warehouseInFk,
|
||||||
|
travel.ref,
|
||||||
|
travel.agencyModeFk
|
||||||
|
]
|
||||||
|
);
|
||||||
|
stmts.push(stmt);
|
||||||
|
const newTravelIndex = stmts.push('SELECT @vTravelFk AS id') - 1;
|
||||||
|
|
||||||
const newTravel = await Self.findById(lastInsert.id, {
|
const sql = ParameterizedSQL.join(stmts, ';');
|
||||||
fields: [
|
const result = await conn.executeStmt(sql, myOptions);
|
||||||
'id',
|
const [lastInsert] = result[newTravelIndex];
|
||||||
'shipped',
|
|
||||||
'landed',
|
|
||||||
'warehouseInFk',
|
|
||||||
'warehouseOutFk',
|
|
||||||
'agencyModeFk',
|
|
||||||
'ref'
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
return newTravel.id;
|
if (!lastInsert.id)
|
||||||
|
throw new UserError('Unable to clone this travel');
|
||||||
|
|
||||||
|
const newTravel = await Self.findById(lastInsert.id, {
|
||||||
|
fields: [
|
||||||
|
'id',
|
||||||
|
'shipped',
|
||||||
|
'landed',
|
||||||
|
'warehouseInFk',
|
||||||
|
'warehouseOutFk',
|
||||||
|
'agencyModeFk',
|
||||||
|
'ref'
|
||||||
|
]
|
||||||
|
}, myOptions);
|
||||||
|
return newTravel.id;
|
||||||
|
} catch (e) {
|
||||||
|
if (tx) await tx.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,73 +5,36 @@ describe('Travel cloneWithEntries()', () => {
|
||||||
const travelId = 5;
|
const travelId = 5;
|
||||||
const currentUserId = 1102;
|
const currentUserId = 1102;
|
||||||
const ctx = {req: {accessToken: {userId: currentUserId}}};
|
const ctx = {req: {accessToken: {userId: currentUserId}}};
|
||||||
let travelBefore;
|
|
||||||
let newTravelId;
|
let newTravelId;
|
||||||
|
|
||||||
// afterAll(async() => {
|
|
||||||
// try {
|
|
||||||
// const entries = await models.Entry.find({
|
|
||||||
// where: {
|
|
||||||
// travelFk: newTravelId
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// const entriesId = entries.map(entry => entry.id);
|
|
||||||
|
|
||||||
// // Destroy all entries buys
|
|
||||||
// await models.Buy.destroyAll({
|
|
||||||
// where: {
|
|
||||||
// entryFk: {inq: entriesId}
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
|
|
||||||
// // Destroy travel entries
|
|
||||||
// await models.Entry.destroyAll({
|
|
||||||
// where: {
|
|
||||||
// travelFk: newTravelId
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
|
|
||||||
// // Destroy new travel
|
|
||||||
// await models.Travel.destroyById(newTravelId);
|
|
||||||
|
|
||||||
// // Restore original travel shipped & landed
|
|
||||||
// const travel = await models.Travel.findById(travelId);
|
|
||||||
// await travel.updateAttributes({
|
|
||||||
// shipped: travelBefore.shipped,
|
|
||||||
// landed: travelBefore.landed
|
|
||||||
// });
|
|
||||||
// } catch (error) {
|
|
||||||
// console.error(error);
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
|
|
||||||
it(`should clone the travel and the containing entries`, async() => {
|
it(`should clone the travel and the containing entries`, async() => {
|
||||||
pending('#2687 - Cannot make a data rollback because of the triggers');
|
const tx = await models.Travel.beginTransaction({
|
||||||
|
});
|
||||||
const warehouseThree = 3;
|
const warehouseThree = 3;
|
||||||
const agencyModeOne = 1;
|
const agencyModeOne = 1;
|
||||||
const yesterday = Date.vnNew();
|
try {
|
||||||
yesterday.setDate(yesterday.getDate() - 1);
|
const options = {transaction: tx};
|
||||||
|
newTravelId = await models.Travel.cloneWithEntries(ctx, travelId, options);
|
||||||
|
const travelEntries = await models.Entry.find({
|
||||||
|
where: {
|
||||||
|
travelFk: newTravelId
|
||||||
|
}
|
||||||
|
}, options);
|
||||||
|
const newTravel = await models.Travel.findById(travelId);
|
||||||
|
|
||||||
travelBefore = await models.Travel.findById(travelId);
|
expect(newTravelId).not.toEqual(travelId);
|
||||||
await travelBefore.updateAttributes({
|
expect(newTravel.ref).toEqual('fifth travel');
|
||||||
shipped: yesterday,
|
expect(newTravel.warehouseInFk).toEqual(warehouseThree);
|
||||||
landed: yesterday
|
expect(newTravel.warehouseOutFk).toEqual(warehouseThree);
|
||||||
});
|
expect(newTravel.agencyModeFk).toEqual(agencyModeOne);
|
||||||
|
expect(travelEntries.length).toBeGreaterThan(0);
|
||||||
|
|
||||||
newTravelId = await models.Travel.cloneWithEntries(ctx, travelId);
|
await tx.rollback();
|
||||||
const travelEntries = await models.Entry.find({
|
const travelRemoved = await models.Travel.findById(newTravelId, options);
|
||||||
where: {
|
|
||||||
travelFk: newTravelId
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const newTravel = await models.Travel.findById(travelId);
|
expect(travelRemoved).toBeNull();
|
||||||
|
} catch (e) {
|
||||||
expect(newTravelId).not.toEqual(travelId);
|
if (tx) await tx.rollback();
|
||||||
expect(newTravel.ref).toEqual('fifth travel');
|
throw e;
|
||||||
expect(newTravel.warehouseInFk).toEqual(warehouseThree);
|
}
|
||||||
expect(newTravel.warehouseOutFk).toEqual(warehouseThree);
|
|
||||||
expect(newTravel.agencyModeFk).toEqual(agencyModeOne);
|
|
||||||
expect(travelEntries.length).toBeGreaterThan(0);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -247,6 +247,7 @@ describe('workerTimeControl add/delete timeEntry()', () => {
|
||||||
|
|
||||||
const start = new Date(dated - 1);
|
const start = new Date(dated - 1);
|
||||||
start.setHours(0, 0, 0);
|
start.setHours(0, 0, 0);
|
||||||
|
|
||||||
await models.WorkerTimeControl.rawSql('CALL vn.timeControl_calculateByUser(?, ?, ?)', [
|
await models.WorkerTimeControl.rawSql('CALL vn.timeControl_calculateByUser(?, ?, ?)', [
|
||||||
hankPymId,
|
hankPymId,
|
||||||
start,
|
start,
|
||||||
|
@ -255,7 +256,7 @@ describe('workerTimeControl add/delete timeEntry()', () => {
|
||||||
|
|
||||||
let [timeControlCalculateTable] = await models.WorkerTimeControl.rawSql('SELECT * FROM tmp.timeControlCalculate', null, options);
|
let [timeControlCalculateTable] = await models.WorkerTimeControl.rawSql('SELECT * FROM tmp.timeControlCalculate', null, options);
|
||||||
|
|
||||||
expect(timeControlCalculateTable.timeWorkSeconds).toEqual(26400);
|
expect(timeControlCalculateTable.timeWorkSeconds).toEqual(25200);
|
||||||
await tx.rollback();
|
await tx.rollback();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
await tx.rollback();
|
await tx.rollback();
|
||||||
|
|
|
@ -3,7 +3,7 @@ const UserError = require('vn-loopback/util/user-error');
|
||||||
module.exports = Self => {
|
module.exports = Self => {
|
||||||
Self.remoteMethodCtx('updateTimeEntry', {
|
Self.remoteMethodCtx('updateTimeEntry', {
|
||||||
description: 'Updates a time entry for a worker if the user role is above the worker',
|
description: 'Updates a time entry for a worker if the user role is above the worker',
|
||||||
accessType: 'READ',
|
accessType: 'WRITE',
|
||||||
accepts: [{
|
accepts: [{
|
||||||
arg: 'id',
|
arg: 'id',
|
||||||
type: 'number',
|
type: 'number',
|
||||||
|
|
|
@ -41,15 +41,16 @@ module.exports = Self => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const stmt = new ParameterizedSQL(`
|
const stmt = new ParameterizedSQL(`
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM(
|
FROM(
|
||||||
SELECT DISTINCT w.id, w.code, u.name, u.nickname, u.active, b.departmentFk
|
SELECT w.id, w.code, u.name, u.nickname, u.active, wd.departmentFk
|
||||||
FROM worker w
|
FROM worker w
|
||||||
JOIN account.user u ON u.id = w.id
|
JOIN account.user u ON u.id = w.id
|
||||||
LEFT JOIN business b ON b.workerFk = w.id
|
LEFT JOIN workerDepartment wd ON wd.workerFk = w.id
|
||||||
) w`);
|
) w`);
|
||||||
|
|
||||||
stmt.merge(conn.makeSuffix(filter));
|
stmt.merge(conn.makeSuffix(filter));
|
||||||
|
|
||||||
return conn.executeStmt(stmt);
|
return conn.executeStmt(stmt);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
{
|
{
|
||||||
"name": "salix-back",
|
"name": "salix-back",
|
||||||
"version": "24.04.01",
|
"version": "24.06.01",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "salix-back",
|
"name": "salix-back",
|
||||||
"version": "24.04.01",
|
"version": "24.06.01",
|
||||||
"license": "GPL-3.0",
|
"license": "GPL-3.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^1.2.2",
|
"axios": "^1.2.2",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "salix-back",
|
"name": "salix-back",
|
||||||
"version": "24.04.01",
|
"version": "24.06.01",
|
||||||
"author": "Verdnatura Levante SL",
|
"author": "Verdnatura Levante SL",
|
||||||
"description": "Salix backend",
|
"description": "Salix backend",
|
||||||
"license": "GPL-3.0",
|
"license": "GPL-3.0",
|
||||||
|
|
|
@ -45,4 +45,4 @@
|
||||||
</attachment>
|
</attachment>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</email-body>
|
</email-body>
|
||||||
|
|
|
@ -1,14 +1,33 @@
|
||||||
const Component = require(`vn-print/core/component`);
|
const Component = require(`vn-print/core/component`);
|
||||||
const emailBody = new Component('email-body');
|
const emailBody = new Component('email-body');
|
||||||
const attachment = new Component('attachment');
|
const attachment = new Component('attachment');
|
||||||
|
const db = require('../../../core/database');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
name: 'letter-debtor-nd',
|
name: 'letter-debtor-nd',
|
||||||
async serverPrefetch() {
|
async serverPrefetch() {
|
||||||
this.debtor = await this.fetchDebtor(this.id, this.companyId);
|
this.debtor = await db.findOne(`
|
||||||
|
SELECT sa.id,
|
||||||
if (!this.debtor)
|
sa.iban,
|
||||||
throw new Error('Something went wrong');
|
be.name bankName,
|
||||||
|
sa.countryFk,
|
||||||
|
c.countryFk
|
||||||
|
FROM supplierAccount sa
|
||||||
|
JOIN bankEntity be ON sa.bankEntityFk = be.id
|
||||||
|
LEFT JOIN company co ON co.supplierAccountFk = sa.id
|
||||||
|
JOIN client c ON c.countryFk = sa.countryFk
|
||||||
|
WHERE c.id = ?;
|
||||||
|
`, [this.id]);
|
||||||
|
if (!this.debtor) {
|
||||||
|
this.debtor = await db.findOne(`
|
||||||
|
SELECT sa.iban,
|
||||||
|
be.name bankName
|
||||||
|
FROM supplierAccount sa
|
||||||
|
JOIN bankEntity be ON sa.bankEntityFk = be.id
|
||||||
|
JOIN company co ON co.supplierAccountFk = sa.id
|
||||||
|
WHERE co.id = ?;
|
||||||
|
`, [this.companyId]);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
subject: Reminder of Outstanding Balance Notice
|
||||||
|
title: Reminder Notice
|
||||||
|
sections:
|
||||||
|
introduction:
|
||||||
|
title: Dear Customer
|
||||||
|
description: We are writing to you once again to inform you that your debt with our company remains unpaid, as you can verify in the attached statement.
|
||||||
|
terms: Since the agreed payment deadlines have significantly passed, there should be no further delay in settling the outstanding amount.
|
||||||
|
payMethod:
|
||||||
|
description: To do so, you have the following payment options
|
||||||
|
options:
|
||||||
|
- Online payment through our website.
|
||||||
|
- Deposit or transfer to the account number provided at the bottom of this letter, indicating your customer number.
|
||||||
|
legalAction:
|
||||||
|
description: If this payment reminder is not heeded, we will be compelled to initiate the necessary legal actions, which may include
|
||||||
|
options:
|
||||||
|
- Inclusion in negative credit and financial solvency records.
|
||||||
|
- Legal proceedings.
|
||||||
|
- Debt assignment to a debt collection agency.
|
||||||
|
contactPhone: For inquiries, you can reach us at <strong>96 324 21 00</strong>.
|
||||||
|
conclusion: We look forward to hearing from you. <br/> Thank you for your attention.
|
||||||
|
transferAccount: Bank Transfer Details
|
|
@ -0,0 +1,26 @@
|
||||||
|
subject: Réitération de l'avis de solde débiteur
|
||||||
|
title: Avis réitéré
|
||||||
|
sections:
|
||||||
|
introduction:
|
||||||
|
title: Cher client
|
||||||
|
description: Nous vous écrivons à nouveau pour vous informer qu'il est toujours en attente
|
||||||
|
votre dette envers notre société, comme vous pouvez le voir dans le relevé ci-joint.
|
||||||
|
terms: Étant donné que les délais de paiement convenus sont largement dépassés, il n'est pas approprié
|
||||||
|
retard plus important dans le règlement du montant dû.
|
||||||
|
payMethod:
|
||||||
|
description: Pour cela, vous disposez des modes de paiement suivants
|
||||||
|
options:
|
||||||
|
- Paiement en ligne depuis notre site internet.
|
||||||
|
- Revenu ou virement sur le numéro de compte que nous détaillons en bas de ce courrier,
|
||||||
|
indiquant le numéro de client.
|
||||||
|
legalAction:
|
||||||
|
description: Si cette obligation de paiement n'est pas remplie, nous serons contraints de
|
||||||
|
d'engager les actions judiciaires qui se déroulent, parmi lesquelles
|
||||||
|
options:
|
||||||
|
- Inclusion dans les dossiers négatifs sur la solvabilité financière et le crédit.
|
||||||
|
- Réclamation judiciaire.
|
||||||
|
- Cession de créance à une société de gestion de recouvrement.
|
||||||
|
contactPhone: Pour toute demande, vous pouvez nous contacter au <strong>96
|
||||||
|
324 21 00</strong>.
|
||||||
|
conclusion: En attente de vos nouvelles. <br/> Merci pour ton attention.
|
||||||
|
transferAccount: Données pour virement bancaire
|
|
@ -0,0 +1,26 @@
|
||||||
|
subject: Reiteração de aviso de saldo devedor
|
||||||
|
title: Aviso reiterado
|
||||||
|
sections:
|
||||||
|
introduction:
|
||||||
|
title: Estimado cliente
|
||||||
|
description: Estamos escrevendo para você novamente para informar que ainda está pendente
|
||||||
|
sua dívida para com nossa empresa, conforme demonstrativo anexo.
|
||||||
|
terms: Dado que os prazos de pagamento acordados são largamente excedidos, não é adequado
|
||||||
|
maior atraso na liquidação do valor devido.
|
||||||
|
payMethod:
|
||||||
|
description: Para isso você tem as seguintes formas de pagamento
|
||||||
|
options:
|
||||||
|
- Pagamento online em nosso site.
|
||||||
|
- Renda ou transferência para o número da conta que detalhamos no final desta carta,
|
||||||
|
indicando o número do cliente.
|
||||||
|
legalAction:
|
||||||
|
description: Se esta obrigação de pagamento não for cumprida, seremos obrigados a
|
||||||
|
para iniciar as ações legais que procedem, entre as quais estão
|
||||||
|
options:
|
||||||
|
- Inclusão em processos negativos de solvência financeira e de crédito.
|
||||||
|
- Reivindicação judicial.
|
||||||
|
- Cessão de dívida a uma empresa de gestão de cobranças.
|
||||||
|
contactPhone: Para consultas, você pode entrar em contato conosco em <strong>96
|
||||||
|
324 21 00</strong>.
|
||||||
|
conclusion: Aguardando suas notícias. <br/> Agradecimentos para sua atenção.
|
||||||
|
transferAccount: Dados para transferência bancária
|
|
@ -1,10 +1,9 @@
|
||||||
SELECT
|
SELECT c.dueDay,
|
||||||
c.dueDay,
|
sa.iban,
|
||||||
c.iban,
|
be.name bankName
|
||||||
sa.iban,
|
FROM client c
|
||||||
be.name AS bankName
|
JOIN supplierAccount sa ON sa.id = cny.supplierAccountFk
|
||||||
FROM client c
|
JOIN bankEntity be ON be.id = sa.bankEntityFk
|
||||||
JOIN company AS cny
|
JOIN company cny
|
||||||
JOIN supplierAccount AS sa ON sa.id = cny.supplierAccountFk
|
WHERE c.id = ?
|
||||||
JOIN bankEntity be ON be.id = sa.bankEntityFk
|
AND cny.id = ?
|
||||||
WHERE c.id = ? AND cny.id = ?
|
|
||||||
|
|
|
@ -28,4 +28,4 @@
|
||||||
</attachment>
|
</attachment>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</email-body>
|
</email-body>
|
||||||
|
|
|
@ -1,14 +1,33 @@
|
||||||
const Component = require(`vn-print/core/component`);
|
const Component = require(`vn-print/core/component`);
|
||||||
const emailBody = new Component('email-body');
|
const emailBody = new Component('email-body');
|
||||||
const attachment = new Component('attachment');
|
const attachment = new Component('attachment');
|
||||||
|
const db = require('../../../core/database');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
name: 'letter-debtor-st',
|
name: 'letter-debtor-st',
|
||||||
async serverPrefetch() {
|
async serverPrefetch() {
|
||||||
this.debtor = await this.fetchDebtor(this.id, this.companyId);
|
this.debtor = await db.findOne(`
|
||||||
|
SELECT sa.id,
|
||||||
if (!this.debtor)
|
sa.iban,
|
||||||
throw new Error('Something went wrong');
|
be.name bankName,
|
||||||
|
sa.countryFk,
|
||||||
|
c.countryFk
|
||||||
|
FROM supplierAccount sa
|
||||||
|
JOIN bankEntity be ON sa.bankEntityFk = be.id
|
||||||
|
LEFT JOIN company co ON co.supplierAccountFk = sa.id
|
||||||
|
JOIN client c ON c.countryFk = sa.countryFk
|
||||||
|
WHERE c.id = ?;
|
||||||
|
`, [this.id]);
|
||||||
|
if (!this.debtor) {
|
||||||
|
this.debtor = await db.findOne(`
|
||||||
|
SELECT sa.iban,
|
||||||
|
be.name bankName
|
||||||
|
FROM supplierAccount sa
|
||||||
|
JOIN bankEntity be ON sa.bankEntityFk = be.id
|
||||||
|
JOIN company co ON co.supplierAccountFk = sa.id
|
||||||
|
WHERE co.id = ?;
|
||||||
|
`, [this.companyId]);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
subject: Initial Notice for Outstanding Balance
|
||||||
|
title: Initial Notice for Outstanding Balance
|
||||||
|
sections:
|
||||||
|
introduction:
|
||||||
|
title: Dear Customer
|
||||||
|
description: Through this letter, we would like to inform you that, according to our accounting records, your account has an outstanding balance that needs to be settled.
|
||||||
|
checkExtract: We kindly request you to verify that the attached statement corresponds to the information you have. Our administration department will be happy to clarify any questions you may have and provide any documents you may request.
|
||||||
|
checkValidData: If, upon reviewing the provided information, everything appears to be accurate, we kindly ask you to proceed with rectifying your situation.
|
||||||
|
payMethod: If you prefer not to visit our offices in person, you can make the payment through a bank transfer to the account listed at the bottom of this communication, indicating your customer number. Alternatively, you can make the payment online through our website.
|
||||||
|
conclusion: We sincerely appreciate your kind cooperation.
|
||||||
|
transferAccount: Bank Transfer Details
|
|
@ -1,10 +1,9 @@
|
||||||
SELECT
|
SELECT c.dueDay,
|
||||||
c.dueDay,
|
sa.iban,
|
||||||
c.iban,
|
be.name bankName
|
||||||
sa.iban,
|
FROM client c
|
||||||
be.name AS bankName
|
JOIN supplierAccount sa ON sa.id = cny.supplierAccountFk
|
||||||
FROM client c
|
JOIN bankEntity be ON be.id = sa.bankEntityFk
|
||||||
JOIN company AS cny
|
JOIN company cny
|
||||||
JOIN supplierAccount AS sa ON sa.id = cny.supplierAccountFk
|
WHERE c.id = ?
|
||||||
JOIN bankEntity be ON be.id = sa.bankEntityFk
|
AND cny.id = ?
|
||||||
WHERE c.id = ? AND cny.id = ?
|
|
||||||
|
|
|
@ -45,4 +45,4 @@ instructions:
|
||||||
title: Instrucciones
|
title: Instrucciones
|
||||||
accountFields: Rellenar los campos relativos a la cuenta bancaria
|
accountFields: Rellenar los campos relativos a la cuenta bancaria
|
||||||
signDocument: Firmar y sellar el documento. Para que tenga validez, en el sello debe aparecer el CIF/NIF. De no ser así, deberá acompañarse la solicitud de un certificado de titularidad de la cuenta.
|
signDocument: Firmar y sellar el documento. Para que tenga validez, en el sello debe aparecer el CIF/NIF. De no ser así, deberá acompañarse la solicitud de un certificado de titularidad de la cuenta.
|
||||||
thanks: ¡Gracias por su colaboración!
|
thanks: ¡Gracias por su colaboración!
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
reportName: direct-debit
|
reportName: direct-debit
|
||||||
title: Direct Debit
|
title: Direct Debit
|
||||||
description: En signant ce formulaire de mandat, vous autorisez VERDNATURA LEVANTE SL
|
description: En signant ce formulaire de mandat, vous autorisez VERDNATURA LEVANTE SL
|
||||||
à envoyer des instructions à votre banque pour débiter votre compte, et (B) votre banque
|
à envoyer des instructions à votre banque pour débiter votre compte, et (B) votre banque
|
||||||
à débiter votre compte conformément aux instructions de VERDNATURA LEVANTE SL.
|
à débiter votre compte conformément aux instructions de VERDNATURA LEVANTE SL.
|
||||||
Vous bénéficiez d’un droit au remboursement par votre banque selon les conditions décrites
|
Vous bénéficiez d’un droit au remboursement par votre banque selon les conditions décrites
|
||||||
dans la convention que vous avez passée avec elle. Toute demande de remboursement doit être
|
dans la convention que vous avez passée avec elle. Toute demande de remboursement doit être
|
||||||
présentée dans les 8 semaines suivant la date de débit de votre compte.
|
présentée dans les 8 semaines suivant la date de débit de votre compte.
|
||||||
Votre banque peut vous renseigner au sujet de vos droits relatifs à ce mandat.
|
Votre banque peut vous renseigner au sujet de vos droits relatifs à ce mandat.
|
||||||
documentCopy: Veuillez dater, signer et retourner ce document à votre banque.
|
documentCopy: Veuillez dater, signer et retourner ce document à votre banque.
|
||||||
mandatoryFields: TOUS LES CHAMPS DOIVENT ÊTRE REINSEGNÉS IMPÉRATIVEMENT.
|
mandatoryFields: TOUS LES CHAMPS DOIVENT ÊTRE REINSEGNÉS IMPÉRATIVEMENT.
|
||||||
|
@ -42,4 +42,4 @@ instructions:
|
||||||
title: instructions
|
title: instructions
|
||||||
accountFields: Remplissez les champs relatifs au compte bancaire
|
accountFields: Remplissez les champs relatifs au compte bancaire
|
||||||
signDocument: Signez et scellez le document. Pour être valide, le CIF / NIF doit apparaître sur le cachet. Sinon, la demande de certificat de propriété du compte doit être jointe.
|
signDocument: Signez et scellez le document. Pour être valide, le CIF / NIF doit apparaître sur le cachet. Sinon, la demande de certificat de propriété du compte doit être jointe.
|
||||||
thanks: Merci de votre collaboration!
|
thanks: Merci de votre collaboration!
|
||||||
|
|
|
@ -27,8 +27,8 @@
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{$t('supplier.identifier')}}</td>
|
<td>{{$t('supplier.identifier')}}</td>
|
||||||
<th>
|
<th>
|
||||||
<div>ES89000B97367486</div>
|
<div>{{supplier.iban}}</div>
|
||||||
<div>B97367486-000</div>
|
<div>{{supplier.nif}}</div>
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
const vnReport = require('../../../core/mixins/vn-report.js');
|
const vnReport = require('../../../core/mixins/vn-report.js');
|
||||||
|
const db = require('../../../core/database');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
name: 'sepa-core',
|
name: 'sepa-core',
|
||||||
|
@ -18,5 +19,16 @@ module.exports = {
|
||||||
type: Number,
|
type: Number,
|
||||||
required: true
|
required: true
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getSupplierCif() {
|
||||||
|
return db.findOne(`
|
||||||
|
SELECT sa.iban, s.nif
|
||||||
|
FROM supplierAccount sa
|
||||||
|
JOIN company co ON co.supplierAccountFk = sa.id
|
||||||
|
JOIN supplier s ON sa.supplierFk = s.id
|
||||||
|
WHERE co.id = ?`) [this.companyId];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,17 +1,27 @@
|
||||||
SELECT
|
SELECT
|
||||||
m.code mandateCode,
|
m.code mandateCode,
|
||||||
s.name,
|
s.name,
|
||||||
s.street,
|
s.street,
|
||||||
sc.country,
|
sc.country,
|
||||||
s.postCode,
|
s.postCode,
|
||||||
s.city,
|
s.city,
|
||||||
sp.name province
|
sp.name province,
|
||||||
FROM client c
|
s.nif,
|
||||||
LEFT JOIN mandate m ON m.clientFk = c.id
|
sa.iban,
|
||||||
AND m.companyFk = ? AND m.finished IS NULL
|
sa.supplierFk,
|
||||||
|
be.name bankName
|
||||||
|
FROM
|
||||||
|
client c
|
||||||
|
LEFT JOIN mandate m ON m.clientFk = c.id AND m.companyFk = ? AND m.finished IS NULL
|
||||||
LEFT JOIN supplier s ON s.id = m.companyFk
|
LEFT JOIN supplier s ON s.id = m.companyFk
|
||||||
LEFT JOIN country sc ON sc.id = s.countryFk
|
LEFT JOIN country sc ON sc.id = s.countryFk
|
||||||
LEFT JOIN province sp ON sp.id = s.provinceFk
|
LEFT JOIN province sp ON sp.id = s.provinceFk
|
||||||
LEFT JOIN province p ON p.id = c.provinceFk
|
LEFT JOIN province p ON p.id = c.provinceFk
|
||||||
WHERE (m.companyFk = ? OR m.companyFk IS NULL) AND c.id = ?
|
LEFT JOIN supplierAccount sa ON sa.supplierFk = s.id
|
||||||
ORDER BY m.created DESC LIMIT 1
|
LEFT JOIN bankEntity be ON sa.bankEntityFk = be.id
|
||||||
|
WHERE
|
||||||
|
(m.companyFk = ? OR m.companyFk IS NULL)
|
||||||
|
AND (c.id = ? OR (c.id IS NULL AND c.countryFk = sa.countryFk))
|
||||||
|
ORDER BY
|
||||||
|
m.created DESC
|
||||||
|
LIMIT 1;
|
||||||
|
|
Loading…
Reference in New Issue