Merge branch 'dev' into 6706-optimizeHooks
gitea/salix/pipeline/pr-dev This commit looks good Details

This commit is contained in:
Juan Ferrer 2024-02-05 10:27:53 +00:00
commit 43c245b45b
32 changed files with 103 additions and 324 deletions

View File

@ -1,16 +1,15 @@
CREATE OR REPLACE DEFINER=`root`@`localhost` CREATE OR REPLACE DEFINER=`root`@`localhost`
SQL SECURITY DEFINER SQL SECURITY DEFINER
VIEW `vn`.`ticketStateToday` VIEW `vn`.`ticketStateToday`
AS SELECT `ts`.`ticketFk` AS `ticket`, AS SELECT
`ts`.`ticketFk` AS `ticketFk`,
`ts`.`state` AS `state`, `ts`.`state` AS `state`,
`ts`.`productionOrder` AS `productionOrder`, `ts`.`productionOrder` AS `productionOrder`,
`ts`.`alertLevel` AS `alertLevel`, `ts`.`alertLevel` AS `alertLevel`,
`ts`.`userFk` AS `worker`, `ts`.`userFk` AS `userFk`,
`ts`.`code` AS `code`, `ts`.`code` AS `code`,
`ts`.`updated` AS `updated`, `ts`.`updated` AS `updated`,
`ts`.`isPicked` AS `isPicked` `ts`.`isPicked` AS `isPicked`
FROM ( FROM `ticketState` `ts`
`vn`.`ticketState` `ts` JOIN `ticket` `t` ON `t`.`id` = `ts`.`ticketFk`
JOIN `vn`.`ticket` `t` ON(`t`.`id` = `ts`.`ticketFk`) WHERE `t`.`shipped` BETWEEN `util`.`VN_CURDATE`() AND `MIDNIGHT`(`util`.`VN_CURDATE`());
)
WHERE `t`.`shipped` BETWEEN `util`.`VN_CURDATE`() AND `MIDNIGHT`(`util`.`VN_CURDATE`())

View File

@ -9,7 +9,7 @@ CREATE OR REPLACE DEFINER=`root`@`localhost`
lhp.m3, lhp.m3,
dl.minSpeed dl.minSpeed
FROM ticket t FROM ticket t
JOIN ticketStateToday tst ON tst.ticket = t.id JOIN ticketStateToday tst ON tst.ticketFk = t.id
JOIN state s ON s.id = tst.state JOIN state s ON s.id = tst.state
JOIN saleVolume sv ON sv.ticketFk = t.id JOIN saleVolume sv ON sv.ticketFk = t.id
LEFT JOIN lastHourProduction lhp ON lhp.warehouseFk = t.warehouseFk LEFT JOIN lastHourProduction lhp ON lhp.warehouseFk = t.warehouseFk

View File

@ -1,8 +0,0 @@
CREATE OR REPLACE DEFINER=`root`@`localhost`
SQL SECURITY DEFINER
VIEW `vn2008`.`Equipos`
AS SELECT `h`.`code` AS `alias`,
`h`.`description` AS `descripcion`,
`h`.`workerFk` AS `trabajador_id`,
`h`.`windowsSerial` AS `windowsSerial`
FROM `vn`.`host` `h`

View File

@ -1,6 +0,0 @@
CREATE OR REPLACE DEFINER=`root`@`localhost`
SQL SECURITY DEFINER
VIEW `vn2008`.`Prioridades`
AS SELECT `qp`.`id` AS `Id_Prioridad`,
`qp`.`priority` AS `Prioridad`
FROM `vn`.`queuePriority` `qp`

View File

@ -1,7 +0,0 @@
CREATE OR REPLACE DEFINER=`root`@`localhost`
SQL SECURITY DEFINER
VIEW `vn2008`.`deliveryPoint`
AS SELECT `dp`.`id` AS `id`,
`dp`.`name` AS `name`,
`dp`.`ubication` AS `ubication`
FROM `vn`.`deliveryPoint` `dp`

View File

@ -1,6 +0,0 @@
CREATE OR REPLACE DEFINER=`root`@`localhost`
SQL SECURITY DEFINER
VIEW `vn2008`.`device_user`
AS SELECT `dpu`.`deviceProductionFk` AS `device_id`,
`dpu`.`userFk` AS `user_id`
FROM `vn`.`deviceProductionUser` `dpu`

View File

@ -1,10 +0,0 @@
CREATE OR REPLACE DEFINER=`root`@`localhost`
SQL SECURITY DEFINER
VIEW `vn2008`.`edi_feature`
AS SELECT `edi`.`feature`.`item_id` AS `item_id`,
`edi`.`feature`.`feature_type_id` AS `feature_type_id`,
`edi`.`feature`.`feature_value` AS `feature_value`,
`edi`.`feature`.`entry_date` AS `entry_date`,
`edi`.`feature`.`expiry_date` AS `expiry_date`,
`edi`.`feature`.`change_date_time` AS `change_date_time`
FROM `edi`.`feature`

View File

@ -1,9 +0,0 @@
CREATE OR REPLACE DEFINER=`root`@`localhost`
SQL SECURITY DEFINER
VIEW `vn2008`.`edi_genus`
AS SELECT `edi`.`genus`.`genus_id` AS `genus_id`,
`edi`.`genus`.`latin_genus_name` AS `latin_genus_name`,
`edi`.`genus`.`entry_date` AS `entry_date`,
`edi`.`genus`.`expiry_date` AS `expiry_date`,
`edi`.`genus`.`change_date_time` AS `change_date_time`
FROM `edi`.`genus`

View File

@ -1,11 +0,0 @@
CREATE OR REPLACE DEFINER=`root`@`localhost`
SQL SECURITY DEFINER
VIEW `vn2008`.`edi_item_feature`
AS SELECT `edi`.`item_feature`.`item_id` AS `item_id`,
`edi`.`item_feature`.`presentation_order` AS `presentation_order`,
`edi`.`item_feature`.`feature` AS `feature`,
`edi`.`item_feature`.`regulation_type` AS `regulation_type`,
`edi`.`item_feature`.`entry_date` AS `entry_date`,
`edi`.`item_feature`.`expiry_date` AS `expiry_date`,
`edi`.`item_feature`.`change_date_time` AS `change_date_time`
FROM `edi`.`item_feature`

View File

@ -1,10 +0,0 @@
CREATE OR REPLACE DEFINER=`root`@`localhost`
SQL SECURITY DEFINER
VIEW `vn2008`.`edi_plant`
AS SELECT `edi`.`plant`.`plant_id` AS `plant_id`,
`edi`.`plant`.`genus_id` AS `genus_id`,
`edi`.`plant`.`specie_id` AS `specie_id`,
`edi`.`plant`.`entry_date` AS `entry_date`,
`edi`.`plant`.`expiry_date` AS `expiry_date`,
`edi`.`plant`.`change_date_time` AS `change_date_time`
FROM `edi`.`plant`

View File

@ -1,10 +0,0 @@
CREATE OR REPLACE DEFINER=`root`@`localhost`
SQL SECURITY DEFINER
VIEW `vn2008`.`edi_type`
AS SELECT `edi`.`type`.`type_id` AS `type_id`,
`edi`.`type`.`type_group_id` AS `type_group_id`,
`edi`.`type`.`description` AS `description`,
`edi`.`type`.`entry_date` AS `entry_date`,
`edi`.`type`.`expiry_date` AS `expiry_date`,
`edi`.`type`.`change_date_time` AS `change_date_time`
FROM `edi`.`type`

View File

@ -1,10 +0,0 @@
CREATE OR REPLACE DEFINER=`root`@`localhost`
SQL SECURITY DEFINER
VIEW `vn2008`.`edi_value`
AS SELECT `edi`.`value`.`type_id` AS `type_id`,
`edi`.`value`.`type_value` AS `type_value`,
`edi`.`value`.`type_description` AS `type_description`,
`edi`.`value`.`entry_date` AS `entry_date`,
`edi`.`value`.`expiry_date` AS `expiry_date`,
`edi`.`value`.`change_date_time` AS `change_date_time`
FROM `edi`.`value`

View File

@ -1,9 +0,0 @@
CREATE OR REPLACE DEFINER=`root`@`localhost`
SQL SECURITY DEFINER
VIEW `vn2008`.`escritos`
AS SELECT `s`.`id` AS `id`,
`s`.`code` AS `abrev`,
`s`.`description` AS `descripcion`,
`s`.`isVisible` AS `visible`,
`s`.`hasCompany` AS `hasCompany`
FROM `vn`.`sample` `s`

View File

@ -1,10 +0,0 @@
CREATE OR REPLACE DEFINER=`root`@`localhost`
SQL SECURITY DEFINER
VIEW `vn2008`.`person_user`
AS SELECT `u`.`id` AS `id`,
`u`.`role` AS `mysql_user_id`,
`u`.`name` AS `name`,
`u`.`password` AS `password`,
`u`.`active` AS `active`,
`u`.`lastPassChange` AS `last_pass_change`
FROM `account`.`user` `u`

View File

@ -1,9 +0,0 @@
CREATE OR REPLACE DEFINER=`root`@`localhost`
SQL SECURITY DEFINER
VIEW `vn2008`.`person_user_idtrabajador`
AS SELECT `t`.`Id_Trabajador` AS `Id_Trabajador`
FROM (
`vn2008`.`person_user` `p`
JOIN `vn2008`.`Trabajadores` `t` ON(`p`.`id` = `t`.`user_id`)
)
WHERE `t`.`user_id` = `account`.`myUser_getId`()

View File

@ -1,7 +0,0 @@
CREATE OR REPLACE DEFINER=`root`@`localhost`
SQL SECURITY DEFINER
VIEW `vn2008`.`reference_min`
AS SELECT `rc`.`dated` AS `date`,
`rc`.`value` AS `rate`,
`rc`.`currencyFk` AS `moneda_id`
FROM `vn`.`referenceCurrent` `rc`

View File

@ -0,0 +1,4 @@
UPDATE salix.ACL
SET property='clone'
WHERE model = 'Sale'
AND property = 'refund'

View File

@ -0,0 +1 @@
REVOKE SELECT ON TABLE vn2008.reference_min FROM logistic;

View File

@ -203,5 +203,7 @@
"Cannot past travels with entries": "Cannot past travels with entries", "Cannot past travels with entries": "Cannot past travels with entries",
"It was not able to remove the next expeditions:": "It was not able to remove the next expeditions: {{expeditions}}", "It was not able to remove the next expeditions:": "It was not able to remove the next expeditions: {{expeditions}}",
"Incorrect pin": "Incorrect pin.", "Incorrect pin": "Incorrect pin.",
"The notification subscription of this worker cant be modified": "The notification subscription of this worker cant be modified" "The notification subscription of this worker cant be modified": "The notification subscription of this worker cant be modified",
"Fecha fuera de rango": "Fecha fuera de rango",
"There is no zone for these parameters 34": "There is no zone for these parameters 34"
} }

View File

@ -1,4 +1,32 @@
module.exports = Self => { module.exports = Self => {
Self.remoteMethodCtx('clone', {
description: 'Clone sales and services provided',
accessType: 'WRITE',
accepts: [
{
arg: 'salesIds',
type: ['number'],
}, {
arg: 'servicesIds',
type: ['number']
}, {
arg: 'withWarehouse',
type: 'boolean',
required: true
}, {
arg: 'negative',
type: 'boolean'
}
],
returns: {
type: ['object'],
root: true
},
http: {
path: `/clone`,
verb: 'POST'
}
});
Self.clone = async(ctx, salesIds, servicesIds, withWarehouse, negative, options) => { Self.clone = async(ctx, salesIds, servicesIds, withWarehouse, negative, options) => {
const models = Self.app.models; const models = Self.app.models;
const myOptions = {}; const myOptions = {};

View File

@ -1,61 +0,0 @@
module.exports = Self => {
Self.remoteMethodCtx('refund', {
description: 'Create refund tickets with sales and services if provided',
accessType: 'WRITE',
accepts: [
{
arg: 'salesIds',
type: ['number'],
},
{
arg: 'servicesIds',
type: ['number']
},
{
arg: 'withWarehouse',
type: 'boolean',
required: true
}
],
returns: {
type: ['object'],
root: true
},
http: {
path: `/refund`,
verb: 'post'
}
});
Self.refund = async(ctx, salesIds, servicesIds, withWarehouse, options) => {
const models = Self.app.models;
const myOptions = {userId: ctx.req.accessToken.userId};
let tx;
if (typeof options == 'object')
Object.assign(myOptions, options);
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
try {
const refundsTicket = await models.Sale.clone(
ctx,
salesIds,
servicesIds,
withWarehouse,
true,
myOptions
);
if (tx) await tx.commit();
return refundsTicket;
} catch (e) {
if (tx) await tx.rollback();
throw e;
}
};
};

View File

@ -67,4 +67,34 @@ describe('Ticket cloning - clone function', () => {
expect(services.length).toBeGreaterThan(0); expect(services.length).toBeGreaterThan(0);
} }
}); });
it('should create a ticket without sales', async() => {
const servicesIds = [4];
const tickets = await models.Sale.clone(ctx, null, servicesIds, false, false, options);
const refundedTicket = await getTicketRefund(tickets[0].id, options);
expect(refundedTicket).toBeDefined();
});
}); });
async function getTicketRefund(id, options) {
return models.Ticket.findOne({
where: {
id
},
include: [
{
relation: 'ticketSales',
scope: {
include: {
relation: 'components'
}
}
},
{
relation: 'ticketServices',
}
]
}, options);
}

View File

@ -1,101 +0,0 @@
const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context');
describe('Sale refund()', () => {
const userId = 5;
const ctx = {req: {accessToken: userId}, args: {}};
const activeCtx = {
accessToken: {userId},
};
const servicesIds = [3];
const withWarehouse = true;
beforeEach(() => {
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: activeCtx
});
});
it('should create ticket with the selected lines', async() => {
const tx = await models.Sale.beginTransaction({});
const salesIds = [7, 8];
try {
const options = {transaction: tx};
const refundedTickets = await models.Sale.refund(ctx, salesIds, servicesIds, withWarehouse, options);
expect(refundedTickets).toBeDefined();
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should create one ticket for each unique ticketFk in the sales', async() => {
const tx = await models.Sale.beginTransaction({});
const salesIds = [6, 7];
try {
const options = {transaction: tx};
const ticketsBefore = await models.Ticket.find({}, options);
const tickets = await models.Sale.refund(ctx, salesIds, servicesIds, withWarehouse, options);
const refundedTicket = await getTicketRefund(tickets[0].id, options);
const ticketsAfter = await models.Ticket.find({}, options);
const salesLength = refundedTicket.ticketSales().length;
const componentsLength = refundedTicket.ticketSales()[0].components().length;
expect(refundedTicket).toBeDefined();
expect(salesLength).toEqual(1);
expect(ticketsBefore.length).toEqual(ticketsAfter.length - 2);
expect(componentsLength).toEqual(4);
await tx.rollback();
} catch (e) {
await tx.rollback();
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);
}

View File

@ -108,6 +108,23 @@ module.exports = function(Self) {
await Self.rawSql('CALL invoiceOutBooking(?)', [resultInvoice.id], myOptions); await Self.rawSql('CALL invoiceOutBooking(?)', [resultInvoice.id], myOptions);
const client = await models.Client.findById(clientId,
{fields: ['hasElectronicInvoice', 'name', 'email']}, myOptions);
if (client.hasElectronicInvoice) {
const url = await models.Url.getUrl();
await models.NotificationQueue.create({
notificationFk: 'invoice-electronic',
authorFk: client.id,
params: JSON.stringify(
{
'name': client.name,
'email': client.email,
'ticketId': ticketsIds.join(','),
'url': url + 'ticket/index?q=' + encodeURIComponent(JSON.stringify({clientFk: clientId}))
})
}, myOptions);
}
if (tx) await tx.commit(); if (tx) await tx.commit();
return resultInvoice.id; return resultInvoice.id;

View File

@ -20,7 +20,7 @@ module.exports = Self => {
}, },
http: { http: {
path: `/refund`, path: `/refund`,
verb: 'post' verb: 'POST'
} }
}); });
@ -45,7 +45,7 @@ module.exports = Self => {
const services = await models.TicketService.find(filter, myOptions); const services = await models.TicketService.find(filter, myOptions);
const servicesIds = services.map(service => service.id); const servicesIds = services.map(service => service.id);
const refundedTickets = await models.Sale.refund(ctx, salesIds, servicesIds, withWarehouse, myOptions); const refundedTickets = await models.Sale.clone(ctx, salesIds, servicesIds, withWarehouse, true, myOptions);
if (tx) await tx.commit(); if (tx) await tx.commit();

View File

@ -9,7 +9,6 @@ module.exports = Self => {
require('../methods/sale/updateQuantity')(Self); require('../methods/sale/updateQuantity')(Self);
require('../methods/sale/updateConcept')(Self); require('../methods/sale/updateConcept')(Self);
require('../methods/sale/recalculatePrice')(Self); require('../methods/sale/recalculatePrice')(Self);
require('../methods/sale/refund')(Self);
require('../methods/sale/canEdit')(Self); require('../methods/sale/canEdit')(Self);
require('../methods/sale/usesMana')(Self); require('../methods/sale/usesMana')(Self);
require('../methods/sale/clone')(Self); require('../methods/sale/clone')(Self);

View File

@ -248,23 +248,6 @@ class Controller extends Section {
if (this.ticket.address.incotermsFk && !this.ticket.weight && !force) if (this.ticket.address.incotermsFk && !this.ticket.weight && !force)
return this.$.withoutWeightConfirmation.show(); return this.$.withoutWeightConfirmation.show();
const client = this.ticket.client;
if (client.hasElectronicInvoice) {
this.$http.post(`NotificationQueues`, {
notificationFk: 'invoice-electronic',
authorFk: client.id,
params: JSON.stringify(
{
'name': client.name,
'email': client.email,
'ticketId': this.id,
'url': window.location.href
})
}).then(() => {
this.vnApp.showSuccess(this.$t('Invoice sent'));
});
}
return this.$http.post(`Tickets/invoiceTicketsAndPdf`, {ticketsIds: [this.id]}) return this.$http.post(`Tickets/invoiceTicketsAndPdf`, {ticketsIds: [this.id]})
.then(() => this.reload()) .then(() => this.reload())
.then(() => this.vnApp.showSuccess(this.$t('Ticket invoiced'))); .then(() => this.vnApp.showSuccess(this.$t('Ticket invoiced')));

View File

@ -523,8 +523,8 @@ class Controller extends Section {
if (!sales) return; if (!sales) return;
const salesIds = sales.map(sale => sale.id); const salesIds = sales.map(sale => sale.id);
const params = {salesIds: salesIds, withWarehouse: withWarehouse}; const params = {salesIds: salesIds, withWarehouse: withWarehouse, negative: true};
const query = 'Sales/refund'; const query = 'Sales/clone';
this.$http.post(query, params).then(res => { this.$http.post(query, params).then(res => {
const [refundTicket] = res.data; const [refundTicket] = res.data;
this.vnApp.showSuccess(this.$t('The following refund ticket have been created', { this.vnApp.showSuccess(this.$t('The following refund ticket have been created', {

View File

@ -727,9 +727,10 @@ describe('Ticket', () => {
jest.spyOn(controller.$state, 'go'); jest.spyOn(controller.$state, 'go');
const params = { const params = {
salesIds: [1, 4], salesIds: [1, 4],
negative: true
}; };
const refundTicket = {id: 99}; const refundTicket = {id: 99};
$httpBackend.expect('POST', 'Sales/refund', params).respond(200, [refundTicket]); $httpBackend.expect('POST', 'Sales/clone', params).respond(200, [refundTicket]);
controller.createRefund(); controller.createRefund();
$httpBackend.flush(); $httpBackend.flush();

View File

@ -55,10 +55,10 @@ class Controller extends Section {
createRefund() { createRefund() {
if (!this.checkeds.length) return; if (!this.checkeds.length) return;
const params = {servicesIds: this.checkeds, withWarehouse: false}; const params = {servicesIds: this.checkeds, withWarehouse: false, negative: true};
const query = 'Sales/refund'; const query = 'Sales/clone';
this.$http.post(query, params).then(res => { this.$http.post(query, params).then(res => {
const refundTicket = res.data; const [refundTicket] = res.data;
this.vnApp.showSuccess(this.$t('The following refund ticket have been created', { this.vnApp.showSuccess(this.$t('The following refund ticket have been created', {
ticketId: refundTicket.id ticketId: refundTicket.id
})); }));

View File

@ -30,13 +30,12 @@ module.exports = Self => {
if (typeof options == 'object') if (typeof options == 'object')
Object.assign(myOptions, options); Object.assign(myOptions, options);
stmts.push(new ParameterizedSQL('CALL vn.subordinateGetList(?)', [userId])); stmts.push(new ParameterizedSQL('CALL vn.worker_getHierarchy(?)', [userId]));
const queryIndex = stmts.push('SELECT * FROM tmp.subordinate') - 1; const queryIndex = stmts.push('SELECT * FROM tmp.workerHierarchyList') - 1;
stmts.push('DROP TEMPORARY TABLE tmp.subordinate'); stmts.push('DROP TEMPORARY TABLE tmp.workerHierarchyList');
const sql = ParameterizedSQL.join(stmts, ';'); const sql = ParameterizedSQL.join(stmts, ';');
const result = await conn.executeStmt(sql, myOptions); const result = await conn.executeStmt(sql, myOptions);
return result[queryIndex]; return result[queryIndex];
}; };
}; };

View File

@ -10,7 +10,7 @@ module.exports = {
required: true required: true
}, },
ticketId: { ticketId: {
type: [Number], type: [String],
required: true required: true
}, },
url: { url: {