Merge branch 'dev' into 6802-Clientes-gestionados-por-equipos

This commit is contained in:
Javi Gallego 2025-02-24 14:14:06 +01:00
commit 7f6c116658
31 changed files with 555 additions and 341 deletions

View File

@ -1,4 +1,5 @@
[mysqld]
bind-address = 0.0.0.0
log-bin = bin.log
max_binlog_size = 1GB
binlog_row_image = noblob

View File

@ -195,7 +195,7 @@ INSERT INTO `vn`.`sectorType` (`id`, `code`)
INSERT INTO `vn`.`sector`(`id`, `description`, `warehouseFk`, `code`, `typeFk`)
VALUES
(1, 'First sector', 1, 'FIRST', 1),
(2, 'Second sector', 2, 'SECOND',1);
(2, 'Second sector', 6, 'SECOND',1);
INSERT INTO `vn`.`printer` (`id`, `name`, `path`, `isLabeler`, `sectorFk`, `ipAddress`)
VALUES
@ -730,7 +730,8 @@ INSERT INTO `vn`.`zoneWarehouse` (`id`, `zoneFk`, `warehouseFk`)
(10, 10, 3),
(11, 11, 5),
(12, 12, 4),
(13, 13, 5);
(13, 13, 5),
(14, 7, 4);
INSERT INTO `vn`.`zoneClosure` (`zoneFk`, `dated`, `hour`)
VALUES
@ -1302,9 +1303,10 @@ INSERT INTO `vn`.`train`(`id`, `name`)
INSERT INTO `vn`.`operator` (`workerFk`, `numberOfWagons`, `trainFk`, `itemPackingTypeFk`, `warehouseFk`, `sectorFk`, `labelerFk`)
VALUES
('1106', '1', '1', 'H', '1', '1', '1'),
('9', '2', '1', 'H', '1', '1', '1'),
('1107', '1', '1', 'V', '1', '1', '1');
(1106, '1', '1', 'H', '1', '1', '1'),
(9, '2', '1', 'H', '1', '1', '1'),
(1107, '1', '1', 'V', '1', '1', '1'),
(72, '1', '1', 'V', '1', '1', '1');
INSERT INTO `vn`.`collection`(`id`, `workerFk`, `stateFk`, `created`, `trainFk`)
VALUES
@ -1615,6 +1617,7 @@ INSERT INTO `bs`.`waste`(`buyerFk`, `year`, `week`, `itemFk`, `itemTypeFk`, `sal
(19, 100, 1, 50, 100, 4, 1, 1.500, 1.500, 0.000, 1, 1, 'grouping', NULL, 0.00, 99.6, 99.4, 0, 1, 0, NULL, 1, util.VN_CURDATE()),
(20, 100, 2, 5, 450, 3, 2, 1.000, 1.000, 0.000, 10, 10, NULL, NULL, 0.00, 7.30, 7.00, 0, 1, 0, NULL, 2.5, util.VN_CURDATE()),
(21, 100,72, 55, 500, 5, 3, 1.000, 1.000, 0.000, 1, 1, 'packing', NULL, 0.00, 78.3, 75.6, 0, 1, 0, 1, 3, util.VN_CURDATE()),
(22, 100, 4, 55, 0, 5, 0, 0, 0, 0.000, 1, 1, 'packing', NULL, 0.00, 78.3, 75.6, 0, 1, 0, 1, 3, util.VN_CURDATE()),
(10000002, 12,88, 50.0000, 5000, 4, 1, 1.500, 1.500, 0.000, 1, 1, 'grouping', NULL, 0.00, 99.60, 99.40, 0, 1, 0, 1.00, 1,util.VN_CURDATE() - INTERVAL 2 MONTH);
INSERT INTO `hedera`.`order`(`id`, `date_send`, `customer_id`, `delivery_method_id`, `agency_id`, `address_id`, `company_id`, `note`, `source_app`, `confirmed`,`total`, `date_make`, `first_row_stamp`, `confirm_date`)
@ -1951,11 +1954,11 @@ INSERT INTO `vn`.`claimBeginning`(`id`, `claimFk`, `saleFk`, `quantity`)
INSERT INTO `vn`.`claimDestination`(`id`, `description`, `addressFk`)
VALUES
(1, 'Bueno', NULL),
(2, 'Basura/Perd.', 12),
(1, 'Bueno', 11),
(2, 'Basura/Perd.', NULL),
(3, 'Confeccion', NULL),
(4, 'Reclam.PRAG', 12),
(5, 'Corregido', 11);
(4, 'Reclam.PRAG', NULL),
(5, 'Corregido', NULL);
INSERT INTO `vn`.`claimDevelopment`(`id`, `claimFk`, `claimResponsibleFk`, `workerFk`, `claimReasonFk`, `claimResultFk`, `claimRedeliveryFk`, `claimDestinationFk`)
VALUES
@ -1970,9 +1973,9 @@ INSERT INTO `vn`.`claimEnd`(`id`, `saleFk`, `claimFk`, `workerFk`, `claimDestina
(1, 31, 4, 21, 2),
(2, 32, 3, 21, 3);
INSERT INTO `vn`.`claimConfig`(`id`, `maxResponsibility`, `monthsToRefund`, `minShipped`,`daysToClaim`)
INSERT INTO `vn`.`claimConfig`(`id`, `maxResponsibility`, `monthsToRefund`, `minShipped`,`daysToClaim`, `pickupDeliveryFk`, `warehouseFk`)
VALUES
(1, 5, 4, '2016-10-01', 7);
(1, 5, 4, '2016-10-01', 7, 8, 4);
INSERT INTO `vn`.`claimRatio`(`clientFk`, `yearSale`, `claimAmount`, `claimingRate`, `priceIncreasing`, `packingRate`)
VALUES
@ -3042,9 +3045,10 @@ INSERT INTO `salix`.`url` (`appName`, `environment`, `url`)
('salix', 'development', 'http://localhost:5000/#!/'),
('docuware', 'development', 'http://docuware');
INSERT INTO `vn`.`report` (`id`, `name`, `paperSizeFk`, `method`)
INSERT INTO `vn`.`report` (`name`, `method`)
VALUES
(3, 'invoice', NULL, 'InvoiceOuts/{refFk}/invoice-out-pdf');
('invoice', 'InvoiceOuts/{refFk}/invoice-out-pdf'),
('LabelBuy', 'Entries/{id}/{labelType}/buy-label');
INSERT INTO `vn`.`payDemDetail` (`id`, `detail`)
VALUES
@ -4116,3 +4120,6 @@ INSERT IGNORE INTO vn.vehicleType (id, name)
(2, 'furgoneta'),
(3, 'cabeza tractora'),
(4, 'remolque');
INSERT INTO vn.addressWaste (addressFk, type)
VALUES (11, 'fault');

View File

@ -1,5 +1,5 @@
DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` FUNCTION util.mockTime()
CREATE OR REPLACE DEFINER=`vn`@`localhost` FUNCTION util.mockTime()
RETURNS DATETIME
DETERMINISTIC
BEGIN
@ -8,7 +8,7 @@ END$$
DELIMITER ;
DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` FUNCTION util.mockUtcTime()
CREATE OR REPLACE DEFINER=`vn`@`localhost` FUNCTION util.mockUtcTime()
RETURNS DATETIME
DETERMINISTIC
BEGIN

View File

@ -5,7 +5,7 @@ CREATE OR REPLACE DEFINER=`vn`@`localhost` FUNCTION `util`.`mockTime`()
BEGIN
/**
* Returns current dateTime
*
*
* @return current datetime
*/
RETURN NOW();

View File

@ -1,26 +0,0 @@
DELIMITER $$
CREATE OR REPLACE DEFINER=`vn`@`localhost` FUNCTION `util`.`mockTimeBase`(vIsUtc BOOL)
RETURNS datetime
DETERMINISTIC
BEGIN
/**
* Returns the date formatted to utc if vIsUtc or config.mocTz if not
*
* @param vIsUtc If date must be returned as UTC format
* @return The formatted mock time
*/
DECLARE vMockUtcTime DATETIME;
DECLARE vMockTz VARCHAR(255);
SELECT mockUtcTime, mockTz
INTO vMockUtcTime, vMockTz
FROM config
LIMIT 1;
IF vIsUtc OR vMockTz IS NULL THEN
RETURN vMockUtcTime;
ELSE
RETURN CONVERT_TZ(vMockUtcTime, '+00:00', vMockTz);
END IF;
END$$
DELIMITER ;

View File

@ -4,22 +4,10 @@ CREATE OR REPLACE DEFINER=`vn`@`localhost` FUNCTION `util`.`mockUtcTime`()
DETERMINISTIC
BEGIN
/**
* Returns the UTC datetime in mockTime format or timeStamp depending on config table
* Returns current UTC dateTime
*
* @return The UTC datetime format
*/
-- FIXME: #5041 Commented because there is slowness when querying a table
/*
DECLARE vMockEnabled BOOL;
SELECT mockEnabled INTO vMockEnabled FROM config LIMIT 1;
IF vMockEnabled THEN
RETURN mockTimeBase(TRUE);
ELSE
RETURN UTC_TIMESTAMP();
END IF;
*/
RETURN UTC_TIMESTAMP();
END$$
DELIMITER ;

View File

@ -1,83 +1,86 @@
DELIMITER $$
CREATE OR REPLACE DEFINER=`vn`@`localhost` PROCEDURE `vn`.`report_print`(
vReportName VARCHAR(100),
vPrinterFk INT,
vUserFk INT,
vParams JSON,
vPriorityName VARCHAR(100)
)
vReportName VARCHAR(100),
vPrinterFk INT,
vUserFk INT,
vParams JSON,
vPriorityName VARCHAR(100)
)
BEGIN
/**
* Inserts in the print queue the report to be printed and the necessary parameters for this
* one taking into account the paper size of both the printer and the report.
*
* @param vReportName the report to be printed.
* @param vPrinterFk the printer selected.
* @param vUserFk user id.
* @param vParams JSON with report parameters.
* @param vPriorityName the printing priority.
*/
DECLARE vI INT DEFAULT 0;
DECLARE vKeys TEXT DEFAULT JSON_KEYS(vParams);
DECLARE vLength INT DEFAULT JSON_LENGTH(vKeys);
DECLARE vKey VARCHAR(255);
DECLARE vVal VARCHAR(255);
DECLARE vPrintQueueFk INT;
DECLARE vReportSize VARCHAR(255);
DECLARE vIsThePrinterReal INT;
DECLARE vPrinteSize VARCHAR(255);
DECLARE vPriorityFk INT;
DECLARE vReportFk INT;
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
RESIGNAL;
END;
/**
* Inserts in the print queue the report to be printed and the necessary parameters for this
* one taking into account the paper size of both the printer and the report.
*
* @param vReportName the report to be printed.
* @param vPrinterFk the printer selected.
* @param vUserFk user id.
* @param vParams JSON with report parameters.
* @param vPriorityName the printing priority.
*/
DECLARE vI INT DEFAULT 0;
DECLARE vKeys TEXT DEFAULT JSON_KEYS(vParams);
DECLARE vLength INT DEFAULT JSON_LENGTH(vKeys);
DECLARE vKey VARCHAR(255);
DECLARE vVal VARCHAR(255);
DECLARE vPrintQueueFk INT;
DECLARE vReportSize VARCHAR(255);
DECLARE vIsThePrinterReal INT;
DECLARE vPrinterSize VARCHAR(255);
DECLARE vPriorityFk INT;
DECLARE vReportFk INT;
DECLARE vTx BOOLEAN DEFAULT NOT @@in_transaction;
SELECT id, paperSizeFk INTO vReportFk, vReportSize
FROM report
WHERE name = vReportName;
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
CALL util.tx_rollback(vTx);
RESIGNAL;
END;
SELECT id, paperSizeFk INTO vIsThePrinterReal, vPrinteSize
FROM printer
WHERE id = vPrinterFk;
SELECT id INTO vPriorityFk
FROM queuePriority
WHERE code = vPriorityName;
SELECT id, paperSizeFk INTO vReportFk, vReportSize
FROM report
WHERE name = vReportName;
IF vIsThePrinterReal IS NULL THEN
CALL util.throw('printerNotExists');
END IF;
SELECT id, paperSizeFk INTO vIsThePrinterReal, vPrinterSize
FROM printer
WHERE id = vPrinterFk;
IF vReportFk IS NULL THEN
CALL util.throw('reportNotExists');
END IF;
SELECT id INTO vPriorityFk
FROM queuePriority
WHERE code = vPriorityName;
IF vReportSize <> vPrinteSize THEN
CALL util.throw('incorrectSize');
END IF;
IF vIsThePrinterReal IS NULL THEN
CALL util.throw('printerNotExists');
END IF;
START TRANSACTION;
INSERT INTO printQueue
SET printerFk = vPrinterFk,
priorityFk = vPriorityFk,
reportFk = vReportFk,
workerFk = vUserFk;
SET vPrintQueueFk = LAST_INSERT_ID();
IF vReportFk IS NULL THEN
CALL util.throw('reportNotExists');
END IF;
WHILE vI < vLength DO
SET vKey = JSON_VALUE(vKeys, CONCAT('$[', vI ,']'));
SET vVal = JSON_VALUE(vParams, CONCAT('$.', vKey));
IF vReportSize <> vPrinterSize THEN
CALL util.throw('incorrectSize');
END IF;
CALL util.tx_start(vTx);
INSERT INTO printQueue
SET printerFk = vPrinterFk,
priorityFk = vPriorityFk,
reportFk = vReportFk,
workerFk = vUserFk;
INSERT INTO printQueueArgs
SET printQueueFk = vPrintQueueFk,
name = vKey,
value = vVal;
SET vPrintQueueFk = LAST_INSERT_ID();
SET vI = vI + 1;
END WHILE;
COMMIT;
WHILE vI < vLength DO
SET vKey = JSON_VALUE(vKeys, CONCAT('$[', vI ,']'));
SET vVal = JSON_VALUE(vParams, CONCAT('$.', vKey));
INSERT INTO printQueueArgs
SET printQueueFk = vPrintQueueFk,
name = vKey,
value = vVal;
SET vI = vI + 1;
END WHILE;
CALL util.tx_commit(vTx);
END$$
DELIMITER ;

View File

@ -0,0 +1,14 @@
ALTER TABLE `vn`.`claimConfig`
ADD COLUMN `pickupDeliveryFk` INT(11)
COMMENT 'Agencia utilizada para las recogidas mediante reparto',
ADD COLUMN `warehouseFk` smallint(6) unsigned
COMMENT 'Almacén usado para los tickets de reclamaciones',
ADD CONSTRAINT `fk_claimConfig_pickupdeliveryFk`
FOREIGN KEY (`pickupdeliveryFk`)
REFERENCES `agencyMode` (`id`),
ADD CONSTRAINT `fk_claimConfig_warehouseFk`
FOREIGN KEY (`warehouseFk`)
REFERENCES `warehouse` (`id`);

View File

@ -0,0 +1,2 @@
INSERT IGNORE INTO vn.state (name,`order`,alertLevel,code,isPreviousPreparable,isPicked)
VALUES ('Recogido',3,4,'PICKED_UP',0,1)

View File

@ -0,0 +1,5 @@
ALTER TABLE `vn`.`claimEnd`
ADD COLUMN `shelvingFk` INT(11) DEFAULT NULL AFTER `editorFk`,
ADD INDEX `claimEnd_fk_shelving` (`shelvingFk`),
ADD CONSTRAINT `claimEnd_fk_shelving` FOREIGN KEY (`shelvingFk`)
REFERENCES `shelving` (`id`) ON DELETE SET NULL ON UPDATE CASCADE;

View File

@ -0,0 +1,8 @@
UPDATE vn.claimDestination cd
SET cd.addressFk = NULL
WHERE code IN ('garbage/loss','manufacturing','supplierClaim','corrected');
UPDATE vn.claimDestination cd
JOIN vn.addressWaste aw ON aw.`type` = 'fault'
SET cd.addressFk = aw.addressFk
WHERE code IN ('good');

View File

@ -257,8 +257,7 @@
"Ticket has been delivered out of order": "The ticket {{ticket}} of route {{{fullUrl}}} has been delivered out of order.",
"clonedFromTicketWeekly": ", that is a cloned sale from ticket {{ ticketWeekly }}",
"negativeReplaced": "Replaced item [#{{oldItemId}}]({{{oldItemUrl}}}) {{oldItem}} with [#{{newItemId}}]({{{newItemUrl}}}) {{newItem}} from ticket [{{ticketId}}]({{{ticketUrl}}})",
"The tag and priority can't be repeated": "The tag and priority can't be repeated",
"duplicateWarehouse": "The introduced warehouse already exists",
"There is no zone for these parameters 1000001": "There is no zone for these parameters 1000001",
"null": "null"
}
"The tag and priority can't be repeated": "The tag and priority can't be repeated",
"The introduced warehouse already exists": "The introduced warehouse already exists",
"The code already exists": "The code already exists"
}

View File

@ -19,7 +19,7 @@
"That payment method requires a BIC": "El método de pago seleccionado requiere un BIC",
"State cannot be blank": "El estado no puede estar en blanco",
"Worker cannot be blank": "El trabajador no puede estar en blanco",
"Cannot change the payment method if no department": "No se puede cambiar la forma de pago si no hay departamento asignado",
"Cannot change the payment method if no salesperson": "No se puede cambiar la forma de pago si no hay comercial asignado",
"can't be blank": "El campo no puede estar vacío",
"Observation type must be unique": "El tipo de observación no puede repetirse",
"The credit must be an integer greater than or equal to zero": "The credit must be an integer greater than or equal to zero",
@ -399,6 +399,6 @@
"Price cannot be blank": "El precio no puede estar en blanco",
"clonedFromTicketWeekly": ", que es una linea clonada del ticket {{ticketWeekly}}",
"negativeReplaced": "Sustituido el articulo [#{{oldItemId}}]({{{oldItemUrl}}}) {{oldItem}} por [#{{newItemId}}]({{{newItemUrl}}}) {{newItem}} del ticket [{{ticketId}}]({{{ticketUrl}}})",
"duplicateWarehouse": "El almacén seleccionado ya existe en la zona",
"Future ticket date not allowed": "Future ticket date not allowed"
}
"The introduced warehouse already exists": "El almacén seleccionado ya existe en la zona",
"The code already exists": "El código ya existe"
}

View File

@ -74,66 +74,77 @@ module.exports = Self => {
}
try {
const worker = await models.Worker.findOne({
where: {id: userId}
}, myOptions);
const obsevationType = await models.ObservationType.findOne({
where: {code: 'salesPerson'}
}, myOptions);
const agencyMode = await models.AgencyMode.findOne({
where: {code: 'refund'}
}, myOptions);
const state = await models.State.findOne({
where: {code: 'DELIVERED'}
}, myOptions);
const zone = await models.Zone.findOne({
where: {agencyModeFk: agencyMode.id}
}, myOptions);
const claim = await models.Claim.findOne(filter, myOptions);
const today = Date.vnNew();
let agencyModeFk;
let nickname;
let state;
let discountValue = null;
let packages = 0;
const claimConfig = await models.ClaimConfig.findOne();
const warehouseFk = claimConfig.warehouseFk;
if (claim.pickup === null || claim.pickup == 'agency') {
state = await models.State.findOne({
where: {code: 'DELIVERED'}
}, myOptions);
const agencyMode = await models.AgencyMode.findOne({
where: {code: 'refund'}
}, myOptions);
agencyModeFk = agencyMode.id;
nickname = `Abono del: ${claim.ticketFk}`;
} else {
discountValue = 100;
packages = 1;
state = await models.State.findOne({
where: {code: 'WAITING_FOR_PICKUP'}
}, myOptions);
nickname = `Recogida pendiente del: ${claim.ticketFk}`;
agencyModeFk = claimConfig.pickupDeliveryFk;
}
const nextShipped = await models.Agency.getShipped(
ctx, today, claim.ticket().addressFk, agencyModeFk, warehouseFk, myOptions
);
const newRefundTicket = await models.Ticket.create({
clientFk: claim.ticket().clientFk,
shipped: today,
landed: today,
nickname: `Abono del: ${claim.ticketFk}`,
warehouseFk: claim.ticket().warehouseFk,
shipped: nextShipped.shipped,
landed: null,
nickname,
warehouseFk,
companyFk: claim.ticket().companyFk,
addressFk: claim.ticket().addressFk,
agencyModeFk: agencyMode.id,
zoneFk: zone.id
agencyModeFk,
zoneFk: claim.ticket().zoneFk,
packages
}, myOptions);
if (claim.pickup == 'pickup') {
const observationDelivery =
await models.ObservationType.findOne({where: {code: 'delivery'}}, myOptions);
await saveObservation({
description: `recoger reclamación: ${claim.id}`,
ticketFk: newRefundTicket.id,
observationTypeFk: observationDelivery.id
}, myOptions);
}
await models.TicketRefund.create({
refundTicketFk: newRefundTicket.id,
originalTicketFk: claim.ticket().id
}, myOptions);
await saveObservation({
description: `Reclama ticket: ${claim.ticketFk}`,
ticketFk: newRefundTicket.id,
observationTypeFk: obsevationType.id
}, myOptions);
const salesToRefund = await models.ClaimBeginning.find(salesFilter, myOptions);
const createdSales = await addSalesToTicket(salesToRefund, newRefundTicket.id, discountValue, myOptions);
await insertIntoClaimEnd(createdSales, id, userId, myOptions);
await models.Ticket.state(ctx, {
ticketFk: newRefundTicket.id,
stateFk: state.id,
userFk: worker.id
userFk: userId
}, myOptions);
const salesToRefund = await models.ClaimBeginning.find(salesFilter, myOptions);
const createdSales = await addSalesToTicket(salesToRefund, newRefundTicket.id, myOptions);
await insertIntoClaimEnd(createdSales, id, worker.id, myOptions);
await Self.rawSql('CALL vn.ticketCalculateClon(?, ?)', [
newRefundTicket.id, claim.ticketFk
], myOptions);
if (tx) await tx.commit();
return newRefundTicket;
@ -143,23 +154,36 @@ module.exports = Self => {
}
};
async function addSalesToTicket(salesToRefund, ticketId, options) {
let formatedSales = [];
salesToRefund.forEach(sale => {
let formatedSale = {
itemFk: sale.sale().itemFk,
ticketFk: ticketId,
concept: sale.sale().concept,
quantity: -Math.abs(sale.quantity),
price: sale.sale().price,
discount: sale.sale().discount,
reserved: sale.sale().reserved,
isPicked: sale.sale().isPicked,
created: sale.sale().created
async function addSalesToTicket(salesToRefund, newTicketId, discountValue, options) {
const createdSales = [];
const models = Self.app.models;
for (const saleToRefund of salesToRefund) {
const oldSale = saleToRefund.sale();
const newSaleData = {
itemFk: oldSale.itemFk,
ticketFk: newTicketId,
concept: oldSale.concept,
quantity: -Math.abs(saleToRefund.quantity),
price: oldSale.price,
discount: discountValue ?? oldSale.discount,
reserved: oldSale.reserved,
isPicked: oldSale.isPicked,
created: oldSale.created
};
formatedSales.push(formatedSale);
});
return await Self.app.models.Sale.create(formatedSales, options);
const newSale = await models.Sale.create(newSaleData, options);
const oldSaleComponents = await models.SaleComponent.find({
where: {saleFk: oldSale.id}
}, options);
const newComponents = oldSaleComponents.map(component => {
const data = component.toJSON ? component.toJSON() : {...component};
delete data.id;
data.saleFk = newSale.id;
return data;
});
await models.SaleComponent.create(newComponents, options);
createdSales.push(newSale);
}
return createdSales;
}
async function insertIntoClaimEnd(createdSales, claimId, workerId, options) {

View File

@ -1,44 +0,0 @@
const app = require('vn-loopback/server/server');
const LoopBackContext = require('loopback-context');
const models = app.models;
describe('claimBeginning', () => {
const claimManagerId = 72;
const activeCtx = {
accessToken: {userId: claimManagerId},
__: value => value
};
const ctx = {req: activeCtx};
describe('importToNewRefundTicket()', () => {
it('should create a new ticket with negative sales and insert the negative sales into claimEnd', async() => {
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: activeCtx
});
let claimId = 1;
const tx = await models.Entry.beginTransaction({});
try {
const options = {transaction: tx};
const ticket = await models.ClaimBeginning.importToNewRefundTicket(ctx, claimId, options);
const refundTicketSales = await models.Sale.find({
where: {ticketFk: ticket.id}
}, options);
const salesInsertedInClaimEnd = await models.ClaimEnd.find({
where: {claimFk: claimId}
}, options);
expect(refundTicketSales.length).toEqual(1);
expect(refundTicketSales[0].quantity).toEqual(-5);
expect(salesInsertedInClaimEnd[0].saleFk).toEqual(refundTicketSales[0].id);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});
});

View File

@ -0,0 +1,99 @@
const app = require('vn-loopback/server/server');
const LoopBackContext = require('loopback-context');
const models = app.models;
describe('importToNewRefundTicket()', () => {
let tx;
const claimManagerId = 72;
const activeCtx = {
accessToken: {userId: claimManagerId},
};
let ctx = {req: activeCtx};
let options;
const claimId = 1;
const expectedDate = Date.vnNew();
beforeEach(async() => {
LoopBackContext.getCurrentContext = () => ({
active: activeCtx,
});
tx = await models.Entry.beginTransaction({});
options = {transaction: tx};
spyOn(models.Agency, 'getShipped').and.returnValue(Promise.resolve({shipped: expectedDate}));
});
afterEach(async() => {
await tx.rollback();
});
it('should create a new ticket with negative sales and insert the negative sales into claimEnd', async() => {
const ticket = await models.ClaimBeginning.importToNewRefundTicket(ctx, claimId, options);
const refundTicketSales = await models.Sale.find({
where: {ticketFk: ticket.id}
}, options);
const salesInsertedInClaimEnd = await models.ClaimEnd.find({
where: {claimFk: claimId}
}, options);
expect(refundTicketSales.length).toEqual(1);
expect(refundTicketSales[0].quantity).toEqual(-5);
expect(salesInsertedInClaimEnd[0].saleFk).toEqual(refundTicketSales[0].id);
});
it('should set DELIVERED state and refund agency mode', async() => {
const state = await models.State.findOne({
where: {code: 'DELIVERED'}
}, options);
const ticket = await models.ClaimBeginning.importToNewRefundTicket(ctx, claimId, options);
const ticketTracking = await models.TicketTracking.findOne({
where: {ticketFk: ticket.id},
order: 'id DESC'
}, options);
const newSales = await models.Sale.find({
where: {ticketFk: ticket.id}
}, options);
newSales.forEach(sale => {
expect(sale.discount).toEqual(0);
});
expect(ticketTracking.stateFk).toEqual(state.id);
});
it('should set WAITING_FOR_PICKUP state for delivery pickups', async() => {
const state = await models.State.findOne({
where: {code: 'WAITING_FOR_PICKUP'}
}, options);
await models.Claim.updateAll({id: claimId}, {pickup: 'delivery'}, options);
const ticket = await models.ClaimBeginning.importToNewRefundTicket(ctx, claimId, options);
const ticketTracking = await models.TicketTracking.findOne({
where: {ticketFk: ticket.id},
order: 'id DESC'
}, options);
const newSales = await models.Sale.find({
where: {ticketFk: ticket.id}
}, options);
newSales.forEach(sale => {
expect(sale.discount).toEqual(100);
});
expect(ticketTracking.stateFk).toEqual(state.id);
});
it('should set DELIVERED state for agency pickups', async() => {
const state = await models.State.findOne({
where: {code: 'DELIVERED'}
}, options);
await models.Claim.updateAll({id: claimId}, {pickup: 'agency'}, options);
const ticket = await models.ClaimBeginning.importToNewRefundTicket(ctx, claimId, options);
const ticketTracking = await models.TicketTracking.findOne({
where: {ticketFk: ticket.id},
order: 'id DESC'
}, options);
expect(ticketTracking.stateFk).toEqual(state.id);
});
});

View File

@ -40,21 +40,24 @@ module.exports = Self => {
const stmt = new ParameterizedSQL(
`SELECT *
FROM (
SELECT
SELECT
ce.id,
ce.claimFk,
s.itemFk,
s.ticketFk,
ce.claimDestinationFk,
t.landed,
s.quantity,
s.concept,
s.price,
s.itemFk,
s.ticketFk,
ce.claimDestinationFk,
t.landed,
s.quantity,
s.concept,
s.price,
s.discount,
s.quantity * s.price * ((100 - s.discount) / 100) total
s.quantity * s.price * ((100 - s.discount) / 100) total,
ce.shelvingFk,
sh.code shelvingCode
FROM vn.claimEnd ce
LEFT JOIN vn.sale s ON s.id = ce.saleFk
LEFT JOIN vn.sale s ON s.id = ce.saleFk
LEFT JOIN vn.ticket t ON t.id = s.ticketFk
LEFT JOIN vn.shelving sh ON sh.id = ce.shelvingFk
) ce`
);

View File

@ -3,12 +3,14 @@ module.exports = Self => {
description: `Imports lines from claimBeginning to a new ticket
with specific shipped, landed dates, agency and company`,
accessType: 'WRITE',
accepts: [{
arg: 'id',
type: 'number',
description: 'The claim id',
http: {source: 'path'}
}],
accepts: [
{
arg: 'id',
type: 'number',
description: 'The claim id',
http: {source: 'path'}
}
],
returns: {
type: ['Object'],
root: true
@ -22,8 +24,6 @@ module.exports = Self => {
Self.regularizeClaim = async(ctx, claimFk, options) => {
const models = Self.app.models;
const $t = ctx.req.__; // $translate
const resolvedState = 3;
let tx;
const myOptions = {};
@ -37,11 +37,29 @@ module.exports = Self => {
try {
const claimEnds = await models.ClaimEnd.find({
include: {
relation: 'claimDestination',
fields: ['addressFk']
},
where: {claimFk}
where: {claimFk: claimFk},
include: [
{
relation: 'claimDestination',
scope: {fields: ['addressFk']}
},
{
relation: 'shelving',
scope: {
fields: ['code', 'parkingFk'],
include: {
relation: 'parking',
scope: {
fields: ['sectorFk'],
include: {
relation: 'sector',
scope: {fields: ['warehouseFk']}
}
}
}
}
}
]
}, myOptions);
for (let claimEnd of claimEnds) {
@ -55,7 +73,7 @@ module.exports = Self => {
const department = sale.ticket().client().department();
if (department) {
const nickname = address?.nickname || destination.description;
const nickname = destination.description;
const url = await Self.app.models.Url.getUrl();
const message = $t('Sent units from ticket', {
quantity: sale.quantity,
@ -69,18 +87,21 @@ module.exports = Self => {
await models.Chat.send(ctx, `#${department.chatName}`, message);
}
if (!address) continue;
if (!addressId) continue;
const warehouseFk = claimEnd.shelving().parking().sector().warehouseFk;
const address = await models.Address.findById(addressId, null, myOptions);
let ticketFk = await getTicketId({
addressFk: addressId,
companyFk: sale.ticket().companyFk,
warehouseFk: sale.ticket().warehouseFk
warehouseFk: warehouseFk
}, myOptions);
if (!ticketFk) {
ctx.args = {
clientId: address.clientFk,
warehouseId: sale.ticket().warehouseFk,
warehouseId: warehouseFk,
companyId: sale.ticket().companyFk,
addressId: addressId
};
@ -90,15 +111,43 @@ module.exports = Self => {
ticketFk: ticketFk,
itemFk: sale.itemFk,
concept: sale.concept,
quantity: -sale.quantity,
quantity: sale.quantity,
price: sale.price,
discount: 100
}, myOptions);
const [buyFk] = await Self.rawSql('SELECT vn.buy_getLastWithoutInventory(?, ?) buyFk',
[sale.itemFk, warehouseFk], myOptions
);
await Self.rawSql('CALL vn.itemShelving_add(?, ?, ?, NULL, NULL, NULL, ?)',
[claimEnd.shelving().code, buyFk.buyFk, -sale.quantity, warehouseFk],
myOptions
);
const operator = await models.Operator.findById(
ctx.req.accessToken.userId, {fields: ['labelerFk']}, myOptions);
const params = JSON.stringify({
copies: 1,
id: buyFk.buyFk,
labelType: 'qr'
});
await Self.rawSql(`CALL vn.report_print( ?, ?, ?, ?, ?)`,
['LabelBuy',
operator?.labelerFk,
ctx.req.accessToken.userId,
params,
'normal'
],
myOptions);
}
const resolvedState = await models.ClaimState.findOne({
where: {code: 'resolved'}
}, myOptions);
let claim = await Self.findById(claimFk, null, myOptions);
claim = await claim.updateAttributes({
claimStateFk: resolvedState
claimStateFk: resolvedState.id
}, myOptions);
if (tx) await tx.commit();
@ -152,7 +201,7 @@ module.exports = Self => {
}
}, options);
return ticket && ticket.id;
return ticket?.id;
}
async function createTicket(ctx, options) {

View File

@ -1,11 +1,8 @@
const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context');
describe('claim regularizeClaim()', () => {
const userId = 18;
const ctx = beforeAll.mockLoopBackContext(userId);
ctx.req.__ = (value, params) => {
return params.nickname;
};
const userId = 72;
const chatModel = models.Chat;
const claimId = 1;
const ticketId = 1;
@ -13,9 +10,27 @@ describe('claim regularizeClaim()', () => {
const resolvedState = 3;
const trashDestination = 2;
const okDestination = 1;
const trashAddress = 12;
let claimEnds = [];
let trashTicket;
const activeCtx = {accessToken: {userId}};
let ctx = {req: activeCtx};
let tx;
let options;
beforeEach(async() => {
LoopBackContext.getCurrentContext = () => ({
active: activeCtx,
});
ctx.req.__ = (_value, params) => {
return params.nickname;
};
tx = await models.Claim.beginTransaction({});
options = {transaction: tx};
});
afterEach(async() => {
await tx.rollback();
});
async function importTicket(ticketId, claimId, userId, options) {
const ticketSales = await models.Sale.find({
@ -41,14 +56,14 @@ describe('claim regularizeClaim()', () => {
spyOn(chatModel, 'send').and.callThrough();
claimEnds = await importTicket(ticketId, claimId, userId, options);
claimEnds = await importTicket(ticketId, claimId, userId, options);
for (const claimEnd of claimEnds)
await claimEnd.updateAttributes({claimDestinationFk: trashDestination}, options);
for (const claimEnd of claimEnds)
await claimEnd.updateAttributes({claimDestinationFk: trashDestination}, options);
let claimBefore = await models.Claim.findById(claimId, null, options);
await models.Claim.regularizeClaim(ctx, claimId, options);
let claimAfter = await models.Claim.findById(claimId, null, options);
let claimBefore = await models.Claim.findById(claimId, null, options);
await models.Claim.regularizeClaim(ctx, claimId, options);
let claimAfter = await models.Claim.findById(claimId, null, options);
trashTicket = await models.Ticket.findOne({where: {addressFk: 12}}, options);
@ -73,12 +88,12 @@ describe('claim regularizeClaim()', () => {
spyOn(chatModel, 'send').and.callThrough();
claimEnds = await importTicket(ticketId, claimId, userId, options);
claimEnds = await importTicket(ticketId, claimId, userId, options);
for (let claimEnd of claimEnds)
await claimEnd.updateAttributes({claimDestinationFk: okDestination}, options);
await models.Claim.regularizeClaim(ctx, claimId, options);
await models.Claim.regularizeClaim(ctx, claimId, options);
expect(chatModel.send).toHaveBeenCalledWith(ctx, '#es_vip_equipo', 'Bueno');
expect(chatModel.send).toHaveBeenCalledTimes(4);

View File

@ -2,6 +2,9 @@
"Claim": {
"dataSource": "vn"
},
"ClaimConfig": {
"dataSource": "vn"
},
"ClaimContainer": {
"dataSource": "claimStorage"
},
@ -43,5 +46,5 @@
},
"ClaimObservation": {
"dataSource": "vn"
}
}
}

View File

@ -0,0 +1,42 @@
{
"name": "ClaimConfig",
"base": "VnModel",
"mixins": {
"Loggable": true
},
"options": {
"mysql": {
"table": "claimConfig"
}
},
"properties": {
"id": {
"type": "number",
"id": true,
"description": "Identifier"
},
"maxResponsibility": {
"type": "number"
},
"monthsToRefund": {
"type": "number"
},
"minShipped": {
"type": "date"
},
"pickupdeliveryFk": {
"type": "number"
},
"warehouseFk": {
"type": "number"
}
},
"relations": {
"pickupDelivery": {
"type": "belongsTo",
"model": "AgencyMode",
"foreignKey": "pickupdeliveryFk"
}
}
}

View File

@ -41,6 +41,11 @@
"type": "belongsTo",
"model": "ClaimDestination",
"foreignKey": "claimDestinationFk"
},
"shelving": {
"type": "belongsTo",
"model": "Shelving",
"foreignKey": "shelvingFk"
}
}
}

View File

@ -43,6 +43,17 @@ module.exports = function(Self) {
password: String(Math.random() * 100000000000000)
};
const supplier = await models.Supplier.findOne({
where: {nif: data.fi}
});
const role = supplier ? await models.VnRole.findOne({
where: {name: 'supplier'}
}) : null;
if (role)
user.roleFk = role.id;
try {
const province = await models.Province.findOne({
where: {id: data.provinceFk},

View File

@ -49,11 +49,11 @@ describe('Client Create', () => {
expect(error.message).toEqual('An email is necessary');
});
it('should create a new account with dailyInvoice', async() => {
it('should create a new account with dailyInvoice and role supplier', async() => {
const newAccount = {
userName: 'deadpool',
email: 'deadpool@marvel.com',
fi: '16195279J',
fi: '07972486L',
name: 'Wade',
socialName: 'DEADPOOL MARVEL',
street: 'WALL STREET',
@ -62,33 +62,30 @@ describe('Client Create', () => {
provinceFk: 1
};
try {
const province = await models.Province.findById(newAccount.provinceFk, {
fields: ['id', 'name', 'autonomyFk'],
include: {
relation: 'autonomy'
}
}, options);
const province = await models.Province.findById(newAccount.provinceFk, {
fields: ['id', 'name', 'autonomyFk'],
include: {
relation: 'autonomy'
}
}, options);
const client = await models.Client.createWithUser(newAccount, options);
const account = await models.VnUser.findOne({where: {name: newAccount.userName}}, options);
const client = await models.Client.createWithUser(newAccount, options);
const account = await models.VnUser.findOne({where: {name: newAccount.userName}}, options);
const supplierRole = await models.VnRole.findOne({where: {name: 'supplier'}}, options);
expect(province.autonomy().hasDailyInvoice).toBeTruthy();
expect(account.name).toEqual(newAccount.userName);
expect(client.id).toEqual(account.id);
expect(client.name).toEqual(newAccount.name);
expect(client.email).toEqual(newAccount.email);
expect(client.fi).toEqual(newAccount.fi);
expect(client.socialName).toEqual(newAccount.socialName);
expect(client.businessTypeFk).toEqual(newAccount.businessTypeFk);
expect(client.hasDailyInvoice).toBeTruthy();
} catch (e) {
await tx.rollback();
throw e;
}
expect(account.roleFk).toEqual(supplierRole.id);
expect(province.autonomy().hasDailyInvoice).toBeTruthy();
expect(account.name).toEqual(newAccount.userName);
expect(client.id).toEqual(account.id);
expect(client.name).toEqual(newAccount.name);
expect(client.email).toEqual(newAccount.email);
expect(client.fi).toEqual(newAccount.fi);
expect(client.socialName).toEqual(newAccount.socialName);
expect(client.businessTypeFk).toEqual(newAccount.businessTypeFk);
expect(client.hasDailyInvoice).toBeTruthy();
});
it('should create a new account without dailyInvoice', async() => {
it('should create a new account without dailyInvoice and role customer', async() => {
const newAccount = {
userName: 'deadpool',
email: 'deadpool@marvel.com',
@ -101,22 +98,20 @@ describe('Client Create', () => {
provinceFk: 3
};
try {
const province = await models.Province.findById(newAccount.provinceFk, {
fields: ['id', 'name', 'autonomyFk'],
include: {
relation: 'autonomy'
}
}, options);
const province = await models.Province.findById(newAccount.provinceFk, {
fields: ['id', 'name', 'autonomyFk'],
include: {
relation: 'autonomy'
}
}, options);
const client = await models.Client.createWithUser(newAccount, options);
const client = await models.Client.createWithUser(newAccount, options);
const vnUser = await models.VnUser.findOne({where: {name: newAccount.userName}}, options);
const customerRole = await models.VnRole.findOne({where: {name: 'customer'}}, options);
expect(province.autonomy.hasDailyInvoice).toBeFalsy();
expect(client.hasDailyInvoice).toBeFalsy();
} catch (e) {
await tx.rollback();
throw e;
}
expect(vnUser.roleFk).toEqual(customerRole.id);
expect(province.autonomy.hasDailyInvoice).toBeFalsy();
expect(client.hasDailyInvoice).toBeFalsy();
});
it('should not be able to create a user if exists', async() => {

View File

@ -46,29 +46,24 @@ module.exports = Self => {
}
try {
const itemDestination = await models.ClaimDestination.findOne({
include: {
relation: 'address',
scope: {
fields: ['clientFk']
}
},
where: {description: 'Corregido'}
const addressWaste = await models.AddressWaste.findOne({
where: {type: 'fault'},
include: 'address'
}, myOptions);
const item = await models.Item.findById(itemFk, null, myOptions);
let ticketId = await getTicketId({
clientFk: itemDestination.address.clientFk,
addressFk: itemDestination.addressFk,
clientFk: addressWaste.address().clientFk,
addressFk: addressWaste.addressFk,
warehouseFk: warehouseFk
}, myOptions);
if (!ticketId) {
ctx.args = {
clientId: itemDestination.address().clientFk,
clientId: addressWaste.address().clientFk,
warehouseId: warehouseFk,
addressId: itemDestination.addressFk
addressId: addressWaste.addressFk
};
ticketId = await createTicket(ctx, myOptions);
}
@ -121,7 +116,7 @@ module.exports = Self => {
}
}, options);
return ticket && ticket.id;
return ticket?.id;
}
};
};

View File

@ -0,0 +1,5 @@
module.exports = Self => {
Self.validatesUniquenessOf('code', {
message: `The code already exists`
});
};

View File

@ -1,4 +1,8 @@
module.exports = Self => {
require('../methods/shelving/getSummary')(Self);
require('../methods/shelving/addLog')(Self);
Self.validatesUniquenessOf('code', {
message: `The code already exists`
});
};

View File

@ -33,6 +33,11 @@ module.exports = Self => {
type: 'date',
description: `The to date filter`
},
{
arg: 'shipped',
type: 'date',
description: `The shipped date filter`
},
{
arg: 'nickname',
type: 'string',
@ -203,11 +208,13 @@ module.exports = Self => {
return {'t.refFk': null};
case 'pending':
return {'st.isNotValidated': value};
case 'myTeam':
if (value)
return {'c.departmentFk': departmentFk};
else
return {'c.departmentFk': {neq: departmentFk}};
case 'id':
case 'clientFk':
case 'agencyModeFk':
case 'warehouseFk':
case 'shipped':
param = `t.${param}`;
return {[param]: value};
}
});

View File

@ -3,7 +3,7 @@ let UserError = require('vn-loopback/util/user-error');
module.exports = Self => {
Self.rewriteDbError(function(err) {
if (err.code === 'ER_DUP_ENTRY')
return new UserError(`duplicateWarehouse`);
return new UserError(`The introduced warehouse already exists`);
return err;
});
};

View File

@ -60,7 +60,7 @@
"@babel/register": "^7.7.7",
"@commitlint/cli": "^19.2.1",
"@commitlint/config-conventional": "^19.1.0",
"@verdnatura/myt": "^1.6.12",
"@verdnatura/myt": "^1.6.13",
"angular-mocks": "^1.7.9",
"babel-jest": "^26.0.1",
"babel-loader": "^8.2.4",

View File

@ -143,8 +143,8 @@ devDependencies:
specifier: ^19.1.0
version: 19.1.0
'@verdnatura/myt':
specifier: ^1.6.12
version: 1.6.12
specifier: ^1.6.13
version: 1.6.13
angular-mocks:
specifier: ^1.7.9
version: 1.8.3
@ -2846,8 +2846,8 @@ packages:
dev: false
optional: true
/@verdnatura/myt@1.6.12:
resolution: {integrity: sha512-t/SiDuQW9KJkcjhwQ9AkrcoTwghxQ7IyQ56e+88eYdoMi24l6bQGF0wHzMaIPRfQAoR8hqgfMOief4OAqW4Iqw==}
/@verdnatura/myt@1.6.13:
resolution: {integrity: sha512-Qw5cfXa2FnjrMBbzP3InYc3vIjbNhyHhmle12Y7FaYFeYE+CXlerryuMqtcoe4+9PsCqwDCKlW37YKmipy2cnQ==}
hasBin: true
dependencies:
'@sqltools/formatter': 1.2.5