Merge pull request '8356-devToTest' (!3339) from 8356-devToTest into test
gitea/salix/pipeline/head This commit looks good Details

Reviewed-on: #3339
Reviewed-by: Carlos Satorres <carlossa@verdnatura.es>
This commit is contained in:
Alex Moreno 2025-01-07 08:37:56 +00:00
commit b83499c180
21 changed files with 180 additions and 102 deletions

View File

@ -19,7 +19,7 @@ module.exports = Self => {
if (acl.principalType == 'ROLE' && acl.permission == 'ALLOW') {
const staticAcl = {
model: model.name,
property: '*',
property: acl.property,
accessType: acl.accessType,
permission: acl.permission,
principalType: acl.principalType,

View File

@ -974,26 +974,30 @@ INSERT INTO `vn`.`itemFamily`(`code`, `description`)
('SER', 'Services'),
('VT', 'Sales');
INSERT INTO `vn`.`item`(`id`, `typeFk`, `stems`, `originFk`, `description`, `producerFk`, `intrastatFk`, `expenseFk`,
`comment`, `relevancy`, `image`, `subName`, `minPrice`, `family`, `isFloramondo`, `genericFk`, `itemPackingTypeFk`, `hasMinPrice`, `weightByPiece`)
INSERT INTO `vn`.`item`(
`id`, `typeFk`, `stems`, `originFk`, `description`, `producerFk`, `intrastatFk`, `expenseFk`,
`comment`, `relevancy`, `image`, `subName`, `minPrice`, `family`, `isFloramondo`, `genericFk`,
`itemPackingTypeFk`, `hasMinPrice`, `weightByPiece`, `isCustomInspectionRequired`
)
VALUES
(1, 2, 1, 1, NULL, 1, 06021010, 2000000000, NULL, 0, '1', NULL, 0, 'EMB', 0, NULL, 'V', 0, 3),
(2, 2, 1, 2, NULL, 1, 06021010, 2000000000, NULL, 0, '2', NULL, 0, 'VT', 0, NULL, 'H', 0, 2),
(3, 1, 1, 3, NULL, 1, 05080000, 4751000000, NULL, 0, '3', NULL, 0, 'VT', 0, NULL, NULL, 0, 5),
(4, 1, 1, 1, 'Increases block', 1, 05080000, 4751000000, NULL, 0, '4', NULL, 0, 'VT', 0, NULL, NULL, 0, NULL),
(5, 3, 1, 2, NULL, 2, 06021010, 4751000000, NULL, 0, '5', NULL, 0, 'VT', 0, NULL, NULL, 0, NULL),
(6, 5, 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '6', NULL, 0, 'VT', 0, NULL, NULL, 0, NULL),
(7, 5, 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '7', NULL, 0, 'VT', 0, NULL, NULL, 0, NULL),
(8, 2, 1, 1, NULL, 1, 06021010, 2000000000, NULL, 0, '8', NULL, 0, 'VT', 0, NULL, NULL, 0, NULL),
(9, 2, 1, 2, NULL, 1, 06021010, 2000000000, NULL, 0, '9', NULL, 0, 'VT', 1, NULL, NULL, 0, NULL),
(10, 1, 1, 3, NULL, 1, 05080000, 4751000000, NULL, 0, '10', NULL, 0, 'VT', 0, NULL, NULL, 0, NULL),
(11, 1, 1, 1, NULL, 1, 05080000, 4751000000, NULL, 0, '11', NULL, 0, 'VT', 0, NULL, NULL, 0, NULL),
(12, 3, 1, 2, NULL, 2, 06021010, 4751000000, NULL, 0, '12', NULL, 0, 'VT', 0, NULL, NULL, 0, NULL),
(13, 5, 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '13', NULL, 1, 'VT', 1, NULL, NULL, 1, NULL),
(14, 5, 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 'VT', 1, NULL, NULL, 0, NULL),
(15, 4, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 'EMB', 0, NULL, NULL, 0, NULL),
(16, 6, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 'EMB', 0, NULL, NULL, 0, NULL),
(71, 6, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 'VT', 0, NULL, NULL, 0, NULL);
(1, 2, 1, 1, NULL, 1, 06021010, 2000000000, NULL, 0, '1', NULL, 0, 'EMB', 0, NULL, 'V', 0, 3, 1),
(2, 2, 1, 2, NULL, 1, 06021010, 2000000000, NULL, 0, '2', NULL, 0, 'VT', 0, NULL, 'H', 0, 2, 1),
(3, 1, 1, 3, NULL, 1, 05080000, 4751000000, NULL, 0, '3', NULL, 0, 'VT', 0, NULL, NULL, 0, 5, 0),
(4, 1, 1, 1, 'Increases block', 1, 05080000, 4751000000, NULL, 0, '4', NULL, 0, 'VT', 0, NULL, NULL, 0, NULL, 0),
(5, 3, 1, 2, NULL, 2, 06021010, 4751000000, NULL, 0, '5', NULL, 0, 'VT', 0, NULL, NULL, 0, NULL, 0),
(6, 5, 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '6', NULL, 0, 'VT', 0, NULL, NULL, 0, NULL, 0),
(7, 5, 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '7', NULL, 0, 'VT', 0, NULL, NULL, 0, NULL, 0),
(8, 2, 1, 1, NULL, 1, 06021010, 2000000000, NULL, 0, '8', NULL, 0, 'VT', 0, NULL, NULL, 0, NULL, 0),
(9, 2, 1, 2, NULL, 1, 06021010, 2000000000, NULL, 0, '9', NULL, 0, 'VT', 1, NULL, NULL, 0, NULL, 0),
(10, 1, 1, 3, NULL, 1, 05080000, 4751000000, NULL, 0, '10', NULL, 0, 'VT', 0, NULL, NULL, 0, NULL, 0),
(11, 1, 1, 1, NULL, 1, 05080000, 4751000000, NULL, 0, '11', NULL, 0, 'VT', 0, NULL, NULL, 0, NULL, 0),
(12, 3, 1, 2, NULL, 2, 06021010, 4751000000, NULL, 0, '12', NULL, 0, 'VT', 0, NULL, NULL, 0, NULL, 0),
(13, 5, 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '13', NULL, 1, 'VT', 1, NULL, NULL, 1, NULL, 0),
(14, 5, 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 'VT', 1, NULL, NULL, 0, NULL, 0),
(15, 4, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 'EMB', 0, NULL, NULL, 0, NULL, 0),
(16, 6, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 'EMB', 0, NULL, NULL, 0, NULL, 0),
(71, 6, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 'VT', 0, NULL, NULL, 0, NULL, 0);
-- Update the taxClass after insert of the items
UPDATE `vn`.`itemTaxCountry` SET `taxClassFk` = 2
@ -3968,7 +3972,7 @@ VALUES(1, '');
INSERT INTO dipole.expedition_PrintOut (expeditionFk, ticketFk, addressFk, street, postalCode, city, shopName, isPrinted, created, printerFk, routeFk, parkingCode,
truckName, clientFk, phone, province, agency, m3, workerCode, itemFk, quantity, longName, shelvingFk, comments)
VALUES(1, 1, 0, ' ', ' ', ' ', ' ', 0, '2001-01-01 00:00:00', 1, 0, ' ', ' ', 0, NULL, '', NULL, 0.000, NULL, 10, NULL, NULL, 'NCC', NULL);
VALUES(1, 1, 0, ' ', ' ', ' ', ' ', 0, '2001-01-01 00:00:00', 1, 0, ' ', ' ', 0, NULL, '', NULL, 0.000, NULL, 10, NULL, 'Ranged Reinforced weapon sniper rifle 700mm' , 'NCC', NULL);
INSERT INTO vn.accountDetail
(id, value, accountDetailTypeFk, supplierAccountFk)

View File

@ -107,7 +107,7 @@ BEGIN
) INTO vHas0Amount;
IF vHas0Amount THEN
CALL util.throw('Hay líneas vacías. Por favor, elimínelas');
CALL util.throw('orderLinesWithZero');
END IF;
START TRANSACTION;

View File

@ -0,0 +1,11 @@
INSERT INTO hedera.message (code, description)
VALUES ('orderLinesWithZero','There are empty lines. Please delete them');
INSERT INTO hedera.messageI18n (code, lang, description)
VALUES ('orderLinesWithZero','es','Hay líneas vacías. Por favor, elimínelas');
INSERT INTO hedera.messageI18n (code, lang, description)
VALUES ('orderLinesWithZero','fr','Il y a des lignes vides. Veuillez les supprimer');
INSERT INTO hedera.messageI18n (code, lang, description)
VALUES ('orderLinesWithZero','pt','Existem linhas vazias. Por favor, apague-os');

View File

@ -0,0 +1,3 @@
ALTER TABLE vn.country
ADD CONSTRAINT country_unique_name UNIQUE KEY (name);

View File

@ -0,0 +1,2 @@
ALTER TABLE `vn`.`item`
ADD COLUMN `isCustomInspectionRequired` TINYINT(1) NOT NULL DEFAULT 0 COMMENT 'Indicates if the item requires physical inspection at customs';

View File

@ -249,5 +249,6 @@
"Sales already moved": "Sales already moved",
"Holidays to past days not available": "Holidays to past days not available",
"Price cannot be blank": "Price cannot be blank",
"There are tickets to be invoiced": "There are tickets to be invoiced"
"There are tickets to be invoiced": "There are tickets to be invoiced",
"The address of the customer must have information about Incoterms and Customs Agent": "The address of the customer must have information about Incoterms and Customs Agent"
}

View File

@ -36,7 +36,7 @@ module.exports = Self => {
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
};
}
try {
const user = await models.VnUser.findOne({

View File

@ -2,7 +2,7 @@ const UserError = require('vn-loopback/util/user-error');
module.exports = function(Self) {
Self.remoteMethod('canBeInvoiced', {
description: 'Change property isEqualizated in all client addresses',
description: 'Check if a client can be invoiced',
accessType: 'READ',
accepts: [
{
@ -38,7 +38,7 @@ module.exports = function(Self) {
Object.assign(myOptions, options);
const client = await models.Client.findById(id, {
fields: ['id', 'isTaxDataChecked', 'hasToInvoice', 'payMethodFk'],
fields: ['id', 'isTaxDataChecked', 'hasToInvoice', 'payMethodFk', 'isActive'],
include:
{
relation: 'payMethod',
@ -53,9 +53,6 @@ module.exports = function(Self) {
if (client.payMethod().code === 'wireTransfer' && !company.supplierAccountFk)
throw new UserError('The company has not informed the supplier account for bank transfers');
if (client.isTaxDataChecked && client.hasToInvoice)
return true;
return false;
return client.isTaxDataChecked && client.hasToInvoice && client.isActive;
};
};

View File

@ -8,6 +8,8 @@ describe('client canBeInvoiced()', () => {
const activeCtx = {
accessToken: {userId: userId}
};
let tx;
let options;
beforeAll(async() => {
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
@ -15,60 +17,45 @@ describe('client canBeInvoiced()', () => {
});
});
beforeEach(async() => {
tx = await models.Client.beginTransaction({});
options = {transaction: tx};
});
afterEach(async() => {
await tx.rollback();
});
it('should return falsy for a client without the data checked', async() => {
const tx = await models.Client.beginTransaction({});
try {
const options = {transaction: tx};
const client = await models.Client.findById(clientId, null, options);
await client.updateAttribute('isTaxDataChecked', false, options);
const canBeInvoiced = await models.Client.canBeInvoiced(clientId, companyId, options);
expect(canBeInvoiced).toEqual(false);
});
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
it('should return falsy for a client not active', async() => {
const client = await models.Client.findById(clientId, null, options);
await client.updateAttribute('isActive', false, options);
const canBeInvoiced = await models.Client.canBeInvoiced(clientId, companyId, options);
expect(canBeInvoiced).toEqual(false);
});
it('should return falsy for a client with invoicing disabled', async() => {
const tx = await models.Client.beginTransaction({});
try {
const options = {transaction: tx};
const client = await models.Client.findById(clientId, null, options);
await client.updateAttribute('hasToInvoice', false, options);
const canBeInvoiced = await models.Client.canBeInvoiced(clientId, companyId, options);
expect(canBeInvoiced).toEqual(false);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should return truthy for an invoiceable client', async() => {
const tx = await models.Client.beginTransaction({});
try {
const options = {transaction: tx};
const canBeInvoiced = await models.Client.canBeInvoiced(clientId, companyId, options);
expect(canBeInvoiced).toEqual(true);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});

View File

@ -84,6 +84,11 @@
"type": "belongsTo",
"model": "CustomsAgent",
"foreignKey": "customsAgentFk"
},
"postcode": {
"type": "belongsTo",
"model": "Postcode",
"foreignKey": "postalCode"
}
}
}

View File

@ -1,3 +1,5 @@
const UserError = require('vn-loopback/util/user-error');
module.exports = Self => {
Self.remoteMethodCtx('clientsToInvoice', {
description: 'Get the clients to make global invoicing',
@ -47,7 +49,12 @@ module.exports = Self => {
}
try {
// Packaging liquidation
const clientCanBeInvoiced =
await Self.app.models.Client.canBeInvoiced(clientId, companyFk, myOptions);
if (!clientCanBeInvoiced)
throw new UserError(`This client can't be invoiced`);
const vIsAllInvoiceable = false;
await Self.rawSql('CALL ticketPackaging_add(?, ?, ?, ?)', [
clientId,
@ -71,9 +78,6 @@ module.exports = Self => {
AND t.shipped BETWEEN ? AND util.dayEnd(?)
AND (t.clientFk = ? OR ? IS NULL )
AND t.companyFk = ?
AND c.hasToInvoice
AND c.isTaxDataChecked
AND c.isActive
AND NOT t.isDeleted
GROUP BY IF(c.hasToInvoiceByAddress, a.id, c.id)
HAVING SUM(t.totalWithVat) > 0;`;

View File

@ -7,7 +7,12 @@ module.exports = Self => {
arg: 'companyFk',
type: 'number',
required: true
}
},
{
arg: 'serialType',
type: 'string',
required: true
},
],
returns: {
type: ['object'],
@ -19,16 +24,16 @@ module.exports = Self => {
}
});
Self.getInvoiceDate = async companyFk => {
Self.getInvoiceDate = async(companyFk, serialType) => {
const models = Self.app.models;
const [invoiceDate] = await models.InvoiceOut.rawSql(
`SELECT MAX(io.issued) issued
FROM invoiceOut io
JOIN invoiceOutSerial ios ON ios.code = io.serial
WHERE ios.type = 'global'
WHERE ios.type = ?
AND io.issued
AND io.companyFk = ?`,
[companyFk]
[serialType, companyFk]
);
return invoiceDate;
};

View File

@ -4,11 +4,11 @@ describe('InvoiceOut clientsToInvoice()', () => {
const userId = 1;
const clientId = 1101;
const companyFk = 442;
const maxShipped = new Date();
const maxShipped = Date.vnNew();
maxShipped.setMonth(11);
maxShipped.setDate(31);
maxShipped.setHours(23, 59, 59, 999);
const invoiceDate = new Date();
const invoiceDate = Date.vnNew();
const activeCtx = {
getLocale: () => {
return 'en';

View File

@ -0,0 +1,39 @@
const models = require('vn-loopback/server/server').models;
const moment = require('moment');
describe('getInvoiceDate()', () => {
const companyFk = 442;
let tx;
let options;
beforeEach(async() => {
tx = await models.InvoiceOut.beginTransaction({});
options = {transaction: tx};
});
afterEach(async() => {
await tx.rollback();
});
it('should return a correct date for serialType "global"', async() => {
const serialType = 'global';
const result = await models.InvoiceOut.getInvoiceDate(companyFk, serialType, options);
expect(moment(result.issued).format('YYYY-MM-DD')).toEqual('2000-12-01');
});
it('should return null for serialType "multiple"', async() => {
const serialType = 'multiple';
const result = await models.InvoiceOut.getInvoiceDate(companyFk, serialType, options);
expect(result.issued).toBeNull();
});
it('should return correct date for serialType "quick"', async() => {
const serialType = 'quick';
const result = await models.InvoiceOut.getInvoiceDate(companyFk, serialType, options);
expect(moment(result.issued).format('YYYY-MM-DD')).toEqual('2001-01-01');
});
});

View File

@ -154,6 +154,9 @@
},
"photoMotivation": {
"type": "string"
},
"isCustomInspectionRequired": {
"type": "boolean"
}
},
"relations": {

View File

@ -50,7 +50,8 @@ module.exports = Self => {
su.name scannerUserName,
es.scanned,
est.description state,
de.longName
de.longName,
de.itemFk
FROM vn.expedition e
LEFT JOIN vn.expeditionStateType est ON est.id = e.stateTypeFk
INNER JOIN vn.item i1 ON i1.id = e.freightItemFk

View File

@ -77,6 +77,8 @@ describe('ticket makeInvoice()', () => {
await tx.rollback();
}
expect(error.message).toEqual(`The address of the customer must have information about Incoterms and Customs Agent`);
expect(error.message).toEqual(
`The address of the customer must have information about Incoterms and Customs Agent`
);
});
});

View File

@ -189,7 +189,8 @@ module.exports = Self => {
b.stickers *
IF(pkg.volume, pkg.volume, pkg.width * pkg.depth * pkg.height) / 1000000
) AS DECIMAL(10,0)
) as volumeKg
) as volumeKg,
MAX(i.isCustomInspectionRequired) isCustomInspectionRequired
FROM tmp.travel tr
JOIN entry e ON e.travelFk = tr.id
JOIN buy b ON b.entryFk = e.id

View File

@ -112,4 +112,17 @@ describe('Travel extraCommunityFilter()', () => {
expect(result.length).toEqual(2);
});
it('should return field isCustomInspectionRequired true', async() => {
const ctx = {
args: {
id: 2
}
};
const result = await app.models.Travel.extraCommunityFilter(ctx, filter);
expect(result[0].entries[0].isCustomInspectionRequired).toBeTruthy();
expect(result[0].entries[1].isCustomInspectionRequired).toBeFalsy();
});
});

View File

@ -1,6 +1,6 @@
{
"name": "salix-back",
"version": "24.52.0",
"version": "25.02.0",
"author": "Verdnatura Levante SL",
"description": "Salix backend",
"license": "GPL-3.0",