3002-backend_transactions #679

Merged
joan merged 3 commits from 3002-backend_transactions into dev 2021-06-29 11:01:21 +00:00
14 changed files with 459 additions and 251 deletions

View File

@ -54,7 +54,8 @@ module.exports = Self => {
arg: 'from',
type: 'date',
description: `The from date filter`
}, {
},
{
arg: 'to',
type: 'date',
description: `The to date filter`
@ -90,16 +91,21 @@ module.exports = Self => {
}
});
Self.filter = async(ctx, filter) => {
Self.filter = async(ctx, filter, options) => {
const conn = Self.dataSource.connector;
const args = ctx.args;
let myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
if (args && args.to) {
const dateTo = args.to;
dateTo.setHours(23, 59, 0, 0);
}
let where = buildFilter(ctx.args, (param, value) => {
const where = buildFilter(ctx.args, (param, value) => {
switch (param) {
case 'search':
return /^\d+$/.test(value)
@ -127,10 +133,9 @@ module.exports = Self => {
filter = mergeFilters(filter, {where});
let stmts = [];
let stmt;
const stmts = [];
stmt = new ParameterizedSQL(
const stmt = new ParameterizedSQL(
`SELECT
ii.id,
ii.serialNumber,
@ -169,10 +174,11 @@ module.exports = Self => {
stmt.merge(conn.makePagination(filter));
let itemsIndex = stmts.push(stmt) - 1;
const itemsIndex = stmts.push(stmt) - 1;
const sql = ParameterizedSQL.join(stmts, ';');
const result = await conn.executeStmt(sql, myOptions);
let sql = ParameterizedSQL.join(stmts, ';');
let result = await conn.executeStmt(sql);
return itemsIndex === 0 ? result : result[itemsIndex];
};
};

View File

@ -2,86 +2,150 @@ const app = require('vn-loopback/server/server');
describe('InvoiceIn filter()', () => {
it('should return the invoice in matching supplier name', async() => {
let ctx = {
const tx = await app.models.Entry.beginTransaction({});
const options = {transaction: tx};
try {
const ctx = {
args: {
search: 'Plants SL',
}
};
let result = await app.models.InvoiceIn.filter(ctx);
const result = await app.models.InvoiceIn.filter(ctx, {}, options);
expect(result.length).toEqual(5);
expect(result[0].supplierName).toEqual('Plants SL');
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should return the invoice in matching supplier reference', async() => {
let ctx = {
const tx = await app.models.Entry.beginTransaction({});
const options = {transaction: tx};
try {
const ctx = {
args: {
supplierRef: '1241',
}
};
let result = await app.models.InvoiceIn.filter(ctx);
const result = await app.models.InvoiceIn.filter(ctx, {}, options);
expect(result.length).toEqual(1);
expect(result[0].supplierRef).toEqual('1241');
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should return the invoice in matching the serial number', async() => {
let ctx = {
const tx = await app.models.Entry.beginTransaction({});
const options = {transaction: tx};
try {
const ctx = {
args: {
serialNumber: '1002',
}
};
let result = await app.models.InvoiceIn.filter(ctx);
const result = await app.models.InvoiceIn.filter(ctx, {}, options);
expect(result.length).toEqual(1);
expect(result[0].serialNumber).toEqual(1002);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should return the invoice in matching the account', async() => {
let ctx = {
const tx = await app.models.Entry.beginTransaction({});
const options = {transaction: tx};
try {
const ctx = {
args: {
account: '4000020002',
}
};
let result = await app.models.InvoiceIn.filter(ctx);
const result = await app.models.InvoiceIn.filter(ctx, {}, options);
expect(result.length).toEqual(5);
expect(result[0].account).toEqual('4000020002');
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should return the invoice in matching the awb code', async() => {
let ctx = {
const tx = await app.models.Entry.beginTransaction({});
const options = {transaction: tx};
try {
const ctx = {
args: {
awbCode: '07546491432',
}
};
let result = await app.models.InvoiceIn.filter(ctx);
const result = await app.models.InvoiceIn.filter(ctx, {}, options);
const firstRow = result[0];
expect(result.length).toEqual(1);
expect(firstRow.id).toEqual(7);
expect(firstRow.awbCode).toEqual('07546491432');
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should return the invoice in matching the amount', async() => {
let ctx = {
const tx = await app.models.Entry.beginTransaction({});
const options = {transaction: tx};
try {
const ctx = {
args: {
amount: '64.23',
}
};
let result = await app.models.InvoiceIn.filter(ctx);
const result = await app.models.InvoiceIn.filter(ctx, {}, options);
expect(result.length).toEqual(1);
expect(result[0].amount).toEqual(64.23);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should return the invoice in matching "from" and "to"', async() => {
const tx = await app.models.Entry.beginTransaction({});
const options = {transaction: tx};
try {
const from = new Date();
const to = new Date();
from.setHours(0, 0, 0, 0);
@ -91,21 +155,37 @@ describe('InvoiceIn filter()', () => {
args: {from, to}
};
const result = await app.models.InvoiceIn.filter(ctx);
const result = await app.models.InvoiceIn.filter(ctx, {}, options);
expect(result.length).toEqual(6);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should return the booked invoice in', async() => {
let ctx = {
const tx = await app.models.Entry.beginTransaction({});
const options = {transaction: tx};
try {
const ctx = {
args: {
isBooked: true,
}
};
let result = await app.models.InvoiceIn.filter(ctx);
const result = await app.models.InvoiceIn.filter(ctx, {}, options);
expect(result.length).toEqual(6);
expect(result[0].isBooked).toBeTruthy();
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});

View File

@ -2,8 +2,18 @@ const app = require('vn-loopback/server/server');
describe('invoiceIn summary()', () => {
it('should return a summary object containing data from one invoiceIn', async() => {
const summary = await app.models.InvoiceIn.summary(1);
const tx = await app.models.Entry.beginTransaction({});
const options = {transaction: tx};
try {
const summary = await app.models.InvoiceIn.summary(1, options);
expect(summary.supplierRef).toEqual('1234');
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});

View File

@ -19,7 +19,12 @@ module.exports = Self => {
}
});
Self.summary = async id => {
Self.summary = async(id, options) => {
let myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
const filter = {
include: [
{
@ -55,6 +60,6 @@ module.exports = Self => {
]
};
return Self.app.models.InvoiceIn.findById(id, filter);
return Self.app.models.InvoiceIn.findById(id, filter, myOptions);
};
};

View File

@ -20,21 +20,45 @@ module.exports = Self => {
}
});
Self.book = async ref => {
Self.book = async(ref, options) => {
const models = Self.app.models;
let tx;
let myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
try {
const ticketAddress = await models.Ticket.findOne({
where: {invoiceOut: ref}
});
}, myOptions);
const invoiceCompany = await models.InvoiceOut.findOne({
where: {ref: ref}
});
}, myOptions);
let query = 'SELECT vn.addressTaxArea(?, ?) AS code';
const [taxArea] = await Self.rawSql(query, [
ticketAddress.address,
invoiceCompany.company
]);
], myOptions);
query = 'CALL vn.invoiceOutAgain(?, ?)';
return Self.rawSql(query, [ref, taxArea.code]);
const result = Self.rawSql(query, [ref, taxArea.code], myOptions);
if (tx) await tx.commit();
return result;
} catch (e) {
if (tx) await tx.rollback();
throw e;
}
};
};

View File

@ -34,22 +34,22 @@ module.exports = Self => {
throw new UserError(`Action not allowed on the test environment`);
let tx;
let newOptions = {};
let myOptions = {};
if (typeof options == 'object')
Object.assign(newOptions, options);
Object.assign(myOptions, options);
if (!newOptions.transaction) {
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
newOptions.transaction = tx;
myOptions.transaction = tx;
}
let fileSrc;
try {
const invoiceOut = await Self.findById(id, null, newOptions);
const invoiceOut = await Self.findById(id, null, myOptions);
await invoiceOut.updateAttributes({
hasPdf: true
}, newOptions);
}, myOptions);
const response = got.stream(`${origin}/api/report/invoice`, {
query: {

View File

@ -20,25 +20,37 @@ module.exports = Self => {
}
});
Self.delete = async id => {
const transaction = await Self.beginTransaction({});
try {
let options = {transaction: transaction};
Self.delete = async(id, options) => {
let tx;
let myOptions = {};
let invoiceOut = await Self.findById(id);
let tickets = await Self.app.models.Ticket.find({where: {refFk: invoiceOut.ref}});
if (typeof options == 'object')
Object.assign(myOptions, options);
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
try {
const invoiceOut = await Self.findById(id, {}, myOptions);
const tickets = await Self.app.models.Ticket.find({where: {refFk: invoiceOut.ref}}, myOptions);
const promises = [];
tickets.forEach(ticket => {
promises.push(ticket.updateAttribute('refFk', null, options));
promises.push(ticket.updateAttribute('refFk', null, myOptions));
});
await Promise.all(promises);
await invoiceOut.destroy(options);
await transaction.commit();
await Promise.all(promises, myOptions);
await invoiceOut.destroy(myOptions);
if (tx) await tx.commit();
return tickets;
} catch (e) {
await transaction.rollback();
if (tx) await tx.rollback();
throw e;
}
};

View File

@ -85,10 +85,14 @@ module.exports = Self => {
}
});
Self.filter = async(ctx, filter) => {
let conn = Self.dataSource.connector;
Self.filter = async(ctx, filter, options) => {
const conn = Self.dataSource.connector;
let myOptions = {};
let where = buildFilter(ctx.args, (param, value) => {
if (typeof options == 'object')
Object.assign(myOptions, options);
const where = buildFilter(ctx.args, (param, value) => {
switch (param) {
case 'search':
return {'i.ref': {like: `%${value}%`}};
@ -115,10 +119,9 @@ module.exports = Self => {
filter = mergeFilters(filter, {where});
let stmts = [];
let stmt;
const stmts = [];
stmt = new ParameterizedSQL(
const stmt = new ParameterizedSQL(
`SELECT
i.id,
i.ref,
@ -136,10 +139,12 @@ module.exports = Self => {
);
stmt.merge(conn.makeSuffix(filter));
let itemsIndex = stmts.push(stmt) - 1;
let sql = ParameterizedSQL.join(stmts, ';');
let result = await conn.executeStmt(sql);
const itemsIndex = stmts.push(stmt) - 1;
const sql = ParameterizedSQL.join(stmts, ';');
const result = await conn.executeStmt(sql, myOptions);
return itemsIndex === 0 ? result : result[itemsIndex];
};
};

View File

@ -3,30 +3,26 @@ const app = require('vn-loopback/server/server');
describe('invoiceOut book()', () => {
const invoiceOutId = 5;
it('should check that invoice out booked is untainted', async() => {
const invoiceOut = await app.models.InvoiceOut.findById(invoiceOutId);
expect(invoiceOut.booked).toBeDefined();
expect(invoiceOut.hasPdf).toBeTruthy();
});
it('should update the booked property', async() => {
const originalInvoiceOut = await app.models.InvoiceOut.findById(invoiceOutId);
const tx = await app.models.InvoiceOut.beginTransaction({});
const options = {transaction: tx};
try {
const originalInvoiceOut = await app.models.InvoiceOut.findById(invoiceOutId, {}, options);
const bookedDate = originalInvoiceOut.booked;
const invoiceOutRef = originalInvoiceOut.ref;
await app.models.InvoiceOut.book(invoiceOutRef);
await app.models.InvoiceOut.book(invoiceOutRef, options);
const updatedInvoiceOut = await app.models.InvoiceOut.findById(invoiceOutId);
const updatedInvoiceOut = await app.models.InvoiceOut.findById(invoiceOutId, {}, options);
expect(updatedInvoiceOut.booked).not.toEqual(bookedDate);
expect(updatedInvoiceOut.hasPdf).toBeFalsy();
// restores
await updatedInvoiceOut.updateAttributes({
booked: originalInvoiceOut.booked,
hasPdf: originalInvoiceOut.hasPdf,
amount: originalInvoiceOut.amount
});
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});

View File

@ -3,36 +3,51 @@ const LoopBackContext = require('loopback-context');
describe('invoiceOut delete()', () => {
const invoiceOutId = 2;
let originalInvoiceOut;
let originalTicket;
const userId = 1106;
const activeCtx = {
accessToken: {userId: userId},
};
it('should check that there is one ticket in the target invoiceOut', async() => {
const invoiceOut = await app.models.InvoiceOut.findById(invoiceOutId);
const tickets = await app.models.Ticket.find({where: {refFk: invoiceOut.ref}});
const tx = await app.models.InvoiceOut.beginTransaction({});
const options = {transaction: tx};
try {
const invoiceOut = await app.models.InvoiceOut.findById(invoiceOutId, {}, options);
const tickets = await app.models.Ticket.find({where: {refFk: invoiceOut.ref}}, options);
expect(tickets.length).toEqual(1);
expect(tickets[0].id).toEqual(3);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it(`should delete the target invoiceOut then check the ticket doesn't have a refFk anymore`, async() => {
const tx = await app.models.InvoiceOut.beginTransaction({});
const options = {transaction: tx};
try {
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: activeCtx
});
originalInvoiceOut = await app.models.InvoiceOut.findById(invoiceOutId);
await app.models.InvoiceOut.delete(invoiceOutId);
originalTicket = await app.models.Ticket.findById(3);
const deletedInvoiceOut = await app.models.InvoiceOut.findById(invoiceOutId);
await app.models.InvoiceOut.delete(invoiceOutId, options);
const originalTicket = await app.models.Ticket.findById(3, {}, options);
const deletedInvoiceOut = await app.models.InvoiceOut.findById(invoiceOutId, {}, options);
expect(deletedInvoiceOut).toBeNull();
expect(originalTicket.refFk).toBeNull();
// restores
const restoredInvoiceOut = await app.models.InvoiceOut.create(originalInvoiceOut);
await restoredInvoiceOut.updateAttribute('ref', originalInvoiceOut.ref);
await originalTicket.updateAttribute('refFk', restoredInvoiceOut.ref);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});

View File

@ -5,57 +5,101 @@ describe('InvoiceOut filter()', () => {
today.setHours(2, 0, 0, 0);
it('should return the invoice out matching ref', async() => {
let ctx = {
const tx = await app.models.InvoiceOut.beginTransaction({});
const options = {transaction: tx};
try {
const ctx = {
args: {
search: 'T4444444',
}
};
let result = await app.models.InvoiceOut.filter(ctx);
const result = await app.models.InvoiceOut.filter(ctx, {}, options);
expect(result.length).toEqual(1);
expect(result[0].ref).toEqual('T4444444');
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should return the invoice out matching clientFk', async() => {
let ctx = {
const tx = await app.models.InvoiceOut.beginTransaction({});
const options = {transaction: tx};
try {
const ctx = {
args: {
clientFk: 1102,
}
};
let result = await app.models.InvoiceOut.filter(ctx);
const result = await app.models.InvoiceOut.filter(ctx, {}, options);
expect(result.length).toEqual(1);
expect(result[0].ref).toEqual('T2222222');
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should return the invoice out matching hasPdf', async() => {
let ctx = {
const tx = await app.models.InvoiceOut.beginTransaction({});
const options = {transaction: tx};
try {
const ctx = {
args: {
hasPdf: true,
}
};
let result = await app.models.InvoiceOut.filter(ctx);
const result = await app.models.InvoiceOut.filter(ctx, {}, options);
expect(result.length).toEqual(5);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should return the invoice out matching amount', async() => {
let ctx = {
const tx = await app.models.InvoiceOut.beginTransaction({});
const options = {transaction: tx};
try {
const ctx = {
args: {
amount: 121.36,
}
};
let result = await app.models.InvoiceOut.filter(ctx);
const result = await app.models.InvoiceOut.filter(ctx, {}, options);
expect(result.length).toEqual(1);
expect(result[0].ref).toEqual('T2222222');
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should return the invoice out matching min and max', async() => {
const tx = await app.models.InvoiceOut.beginTransaction({});
const options = {transaction: tx};
try {
let ctx = {
args: {
min: 0,
@ -63,47 +107,14 @@ describe('InvoiceOut filter()', () => {
}
};
let result = await app.models.InvoiceOut.filter(ctx);
let result = await app.models.InvoiceOut.filter(ctx, {}, options);
expect(result.length).toEqual(3);
});
// #1428 cuadrar formato de horas
xit('should return the invoice out matching issued', async() => {
let ctx = {
args: {
issued: today,
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
};
let result = await app.models.InvoiceOut.filter(ctx);
expect(result.length).toEqual(1);
});
// #1428 cuadrar formato de horas
xit('should return the invoice out matching created', async() => {
let ctx = {
args: {
created: today,
}
};
let result = await app.models.InvoiceOut.filter(ctx);
expect(result.length).toEqual(5);
});
// #1428 cuadrar formato de horas
xit('should return the invoice out matching dued', async() => {
let ctx = {
args: {
dued: today
}
};
let result = await app.models.InvoiceOut.filter(ctx);
expect(result.length).toEqual(1);
});
});

View File

@ -3,8 +3,18 @@ const app = require('vn-loopback/server/server');
describe('entry getTickets()', () => {
const invoiceOutId = 4;
it('should get the ticket of an invoiceOut', async() => {
const result = await app.models.InvoiceOut.getTickets(invoiceOutId);
const tx = await app.models.InvoiceOut.beginTransaction({});
const options = {transaction: tx};
try {
const result = await app.models.InvoiceOut.getTickets(invoiceOutId, {}, options);
expect(result.length).toEqual(1);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});

View File

@ -2,24 +2,54 @@ const app = require('vn-loopback/server/server');
describe('invoiceOut summary()', () => {
it('should return a summary object containing data from one invoiceOut', async() => {
const result = await app.models.InvoiceOut.summary(1);
const tx = await app.models.InvoiceOut.beginTransaction({});
const options = {transaction: tx};
try {
const result = await app.models.InvoiceOut.summary(1, options);
expect(result.invoiceOut.id).toEqual(1);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it(`should return a summary object containing it's supplier country`, async() => {
const summary = await app.models.InvoiceOut.summary(1);
const tx = await app.models.InvoiceOut.beginTransaction({});
const options = {transaction: tx};
try {
const summary = await app.models.InvoiceOut.summary(1, options);
const supplier = summary.invoiceOut.supplier();
expect(summary.invoiceOut.ref).toEqual('T1111111');
expect(supplier.id).toEqual(442);
expect(supplier.countryFk).toEqual(1);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it(`should return a summary object containing idata from it's tax types`, async() => {
const summary = await app.models.InvoiceOut.summary(1);
const tx = await app.models.InvoiceOut.beginTransaction({});
const options = {transaction: tx};
try {
const summary = await app.models.InvoiceOut.summary(1, options);
expect(summary.invoiceOut.ref).toEqual('T1111111');
expect(summary.invoiceOut.taxesBreakdown.length).toEqual(2);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});

View File

@ -19,8 +19,12 @@ module.exports = Self => {
}
});
Self.summary = async id => {
Self.summary = async(id, options) => {
let summary = {};
let myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
const filter = {
fields: [
@ -58,14 +62,14 @@ module.exports = Self => {
]
};
summary.invoiceOut = await Self.app.models.InvoiceOut.findOne(filter);
summary.invoiceOut = await Self.app.models.InvoiceOut.findOne(filter, myOptions);
const invoiceOutTaxes = await Self.rawSql(`
SELECT iot.* , pgc.*, IF(pe.equFk IS NULL, taxableBase, 0) AS Base, pgc.rate / 100 as vatPercent
FROM vn.invoiceOutTax iot
JOIN vn.pgc ON pgc.code = iot.pgcFk
LEFT JOIN vn.pgcEqu pe ON pe.equFk = pgc.code
WHERE invoiceOutFk = ?`, [summary.invoiceOut.id]);
WHERE invoiceOutFk = ?`, [summary.invoiceOut.id], myOptions);
summary.invoiceOut.taxesBreakdown = invoiceOutTaxes;