item module transactions
gitea/salix/pipeline/head This commit looks good Details

This commit is contained in:
Carlos Jimenez Ruiz 2021-07-12 12:54:59 +02:00
parent dd3473b93d
commit 21e34de1dd
37 changed files with 1012 additions and 621 deletions

View File

@ -80,12 +80,12 @@ module.exports = Self => {
}, },
{ {
arg: 'mine', arg: 'mine',
type: 'Boolean', type: 'boolean',
description: `Search requests attended by the current user` description: `Search requests attended by the current user`
} }
], ],
returns: { returns: {
type: ['Object'], type: ['object'],
root: true root: true
}, },
http: { http: {
@ -94,9 +94,13 @@ module.exports = Self => {
} }
}); });
Self.filter = async(ctx, filter) => { Self.filter = async(ctx, filter, options) => {
const conn = Self.dataSource.connector; const conn = Self.dataSource.connector;
let userId = ctx.req.accessToken.userId; const userId = ctx.req.accessToken.userId;
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
if (ctx.args.mine) if (ctx.args.mine)
ctx.args.buyerFk = userId; ctx.args.buyerFk = userId;
@ -128,36 +132,35 @@ module.exports = Self => {
filter = mergeFilters(filter, {where}); filter = mergeFilters(filter, {where});
const stmts = []; const stmts = [];
let stmt;
stmt = new ParameterizedSQL( const stmt = new ParameterizedSQL(`
`SELECT fp.id, SELECT fp.id,
fp.itemFk, fp.itemFk,
fp.warehouseFk, fp.warehouseFk,
fp.rate2, fp.rate2,
fp.rate3, fp.rate3,
fp.started, fp.started,
fp.ended, fp.ended,
i.minPrice, i.minPrice,
i.hasMinPrice, i.hasMinPrice,
i.name, i.name,
i.subName, i.subName,
i.tag5, i.tag5,
i.value5, i.value5,
i.tag6, i.tag6,
i.value6, i.value6,
i.tag7, i.tag7,
i.value7, i.value7,
i.tag8, i.tag8,
i.value8, i.value8,
i.tag9, i.tag9,
i.value9, i.value9,
i.tag10, i.tag10,
i.value10 i.value10
FROM priceFixed fp FROM priceFixed fp
JOIN item i ON i.id = fp.itemFk JOIN item i ON i.id = fp.itemFk
JOIN itemType it ON it.id = i.typeFk` JOIN itemType it ON it.id = i.typeFk
); `);
if (ctx.args.tags) { if (ctx.args.tags) {
let i = 1; let i = 1;
@ -186,7 +189,8 @@ module.exports = Self => {
const fixedPriceIndex = stmts.push(stmt) - 1; const fixedPriceIndex = stmts.push(stmt) - 1;
const sql = ParameterizedSQL.join(stmts, ';'); const sql = ParameterizedSQL.join(stmts, ';');
const result = await conn.executeStmt(sql); const result = await conn.executeStmt(sql, myOptions);
return fixedPriceIndex === 0 ? result : result[fixedPriceIndex]; return fixedPriceIndex === 0 ? result : result[fixedPriceIndex];
}; };
}; };

View File

@ -1,86 +1,136 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('fixed price filter()', () => { describe('fixed price filter()', () => {
it('should return 1 result filtering by item ID', async() => { it('should return 1 result filtering by item ID', async() => {
const itemID = 3; const tx = await models.FixedPrice.beginTransaction({});
const ctx = {
req: {accessToken: {userId: 1}},
args: {
search: itemID
}
};
const result = await app.models.FixedPrice.filter(ctx);
expect(result.length).toEqual(1); try {
expect(result[0].id).toEqual(2); const options = {transaction: tx};
expect(result[0].itemFk).toEqual(itemID); const itemID = 3;
const ctx = {
req: {accessToken: {userId: 1}},
args: {
search: itemID
}
};
const result = await models.FixedPrice.filter(ctx, null, options);
expect(result.length).toEqual(1);
expect(result[0].id).toEqual(2);
expect(result[0].itemFk).toEqual(itemID);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should return 1 result filtering by item type code', async() => { it('should return 1 result filtering by item type code', async() => {
const itemCode = 'CRI'; const tx = await models.FixedPrice.beginTransaction({});
const ctx = {
req: {accessToken: {userId: 1}},
args: {
search: itemCode
}
};
const itemType = await app.models.ItemType.findOne({
where: {code: itemCode},
fields: ['id']
});
const items = await app.models.Item.find({
where: {typeFk: itemType.id},
fields: ['id']
});
const IDs = items.map(item => {
return item.id;
});
const result = await app.models.FixedPrice.filter(ctx); try {
const firstResult = result[0]; const options = {transaction: tx};
const itemCode = 'CRI';
const ctx = {
req: {accessToken: {userId: 1}},
args: {
search: itemCode
}
};
const itemType = await models.ItemType.findOne({
where: {code: itemCode},
fields: ['id']
}, options);
const items = await models.Item.find({
where: {typeFk: itemType.id},
fields: ['id']
}, options);
const IDs = items.map(item => {
return item.id;
});
expect(result.length).toEqual(1); const result = await models.FixedPrice.filter(ctx, null, options);
expect(firstResult.id).toEqual(2); const firstResult = result[0];
expect(IDs).toContain(firstResult.itemFk);
expect(result.length).toEqual(1);
expect(firstResult.id).toEqual(2);
expect(IDs).toContain(firstResult.itemFk);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should return 2 results filtering by warehouse', async() => { it('should return 2 results filtering by warehouse', async() => {
const warehouseID = 1; const tx = await models.FixedPrice.beginTransaction({});
const ctx = {
req: {accessToken: {userId: 1}},
args: {
warehouseFk: warehouseID
}
};
const result = await app.models.FixedPrice.filter(ctx);
const length = result.length;
const anyResult = result[Math.floor(Math.random() * Math.floor(length))];
expect(result.length).toEqual(2); try {
expect(anyResult.warehouseFk).toEqual(warehouseID); const options = {transaction: tx};
const warehouseID = 1;
const ctx = {
req: {accessToken: {userId: 1}},
args: {
warehouseFk: warehouseID
}
};
const result = await models.FixedPrice.filter(ctx, null, options);
const length = result.length;
const anyResult = result[Math.floor(Math.random() * Math.floor(length))];
expect(result.length).toEqual(2);
expect(anyResult.warehouseFk).toEqual(warehouseID);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should return no results filtering by hasMinPrice', async() => { it('should return no results filtering by hasMinPrice', async() => {
const ctx = { const tx = await models.FixedPrice.beginTransaction({});
req: {accessToken: {userId: 1}},
args: {
hasMinPrice: true
}
};
const result = await app.models.FixedPrice.filter(ctx);
expect(result.length).toEqual(0); try {
const options = {transaction: tx};
const ctx = {
req: {accessToken: {userId: 1}},
args: {
hasMinPrice: true
}
};
const result = await models.FixedPrice.filter(ctx, null, options);
expect(result.length).toEqual(0);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should return no results filtering by typeFk', async() => { it('should return no results filtering by typeFk', async() => {
const ctx = { const tx = await models.FixedPrice.beginTransaction({});
req: {accessToken: {userId: 1}},
args: {
typeFk: 1
}
};
const result = await app.models.FixedPrice.filter(ctx);
expect(result.length).toEqual(1); try {
const options = {transaction: tx};
const ctx = {
req: {accessToken: {userId: 1}},
args: {
typeFk: 1
}
};
const result = await models.FixedPrice.filter(ctx, null, options);
expect(result.length).toEqual(1);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -1,62 +1,75 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('upsertFixedPrice()', () => { describe('upsertFixedPrice()', () => {
const now = new Date(); const now = new Date();
const fixedPriceId = 1; const fixedPriceId = 1;
let originalFixedPrice; let originalFixedPrice;
let originalItem;
beforeAll(async() => { beforeAll(async() => {
originalFixedPrice = await app.models.FixedPrice.findById(fixedPriceId); originalFixedPrice = await models.FixedPrice.findById(fixedPriceId);
originalItem = await app.models.Item.findById(originalFixedPrice.itemFk);
});
afterAll(async() => {
await originalFixedPrice.save();
await originalItem.save();
}); });
it(`should toggle the hasMinPrice boolean if there's a minPrice and update the rest of the data`, async() => { it(`should toggle the hasMinPrice boolean if there's a minPrice and update the rest of the data`, async() => {
const ctx = {args: { const tx = await models.FixedPrice.beginTransaction({});
id: fixedPriceId,
itemFk: originalFixedPrice.itemFk,
warehouseFk: 1,
rate2: 100,
rate3: 300,
started: now,
ended: now,
minPrice: 100,
hasMinPrice: false
}};
const result = await app.models.FixedPrice.upsertFixedPrice(ctx, ctx.args.id); try {
const options = {transaction: tx};
const ctx = {args: {
id: fixedPriceId,
itemFk: originalFixedPrice.itemFk,
warehouseFk: 1,
rate2: 100,
rate3: 300,
started: now,
ended: now,
minPrice: 100,
hasMinPrice: false
}};
delete ctx.args.started; const result = await models.FixedPrice.upsertFixedPrice(ctx, options);
delete ctx.args.ended;
ctx.args.hasMinPrice = true;
expect(result).toEqual(jasmine.objectContaining(ctx.args)); delete ctx.args.started;
delete ctx.args.ended;
ctx.args.hasMinPrice = true;
expect(result).toEqual(jasmine.objectContaining(ctx.args));
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it(`should toggle the hasMinPrice boolean if there's no minPrice and update the rest of the data`, async() => { it(`should toggle the hasMinPrice boolean if there's no minPrice and update the rest of the data`, async() => {
const ctx = {args: { const tx = await models.FixedPrice.beginTransaction({});
id: fixedPriceId,
itemFk: originalFixedPrice.itemFk,
warehouseFk: 1,
rate2: 2.5,
rate3: 2,
started: now,
ended: now,
minPrice: 0,
hasMinPrice: true
}};
const result = await app.models.FixedPrice.upsertFixedPrice(ctx, ctx.args.id); try {
const options = {transaction: tx};
const ctx = {args: {
id: fixedPriceId,
itemFk: originalFixedPrice.itemFk,
warehouseFk: 1,
rate2: 2.5,
rate3: 2,
started: now,
ended: now,
minPrice: 0,
hasMinPrice: true
}};
delete ctx.args.started; const result = await models.FixedPrice.upsertFixedPrice(ctx, options);
delete ctx.args.ended;
ctx.args.hasMinPrice = false;
expect(result).toEqual(jasmine.objectContaining(ctx.args)); delete ctx.args.started;
delete ctx.args.ended;
ctx.args.hasMinPrice = false;
expect(result).toEqual(jasmine.objectContaining(ctx.args));
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -2,48 +2,50 @@ module.exports = Self => {
Self.remoteMethod('upsertFixedPrice', { Self.remoteMethod('upsertFixedPrice', {
description: 'Inserts or updates a fixed price for an item', description: 'Inserts or updates a fixed price for an item',
accessType: 'WRITE', accessType: 'WRITE',
accepts: [{ accepts: [
arg: 'ctx', {
type: 'object', arg: 'ctx',
http: {source: 'context'} type: 'object',
}, http: {source: 'context'}
{ },
arg: 'id', {
type: 'number', arg: 'id',
description: 'The fixed price id' type: 'number',
}, description: 'The fixed price id'
{ },
arg: 'itemFk', {
type: 'number' arg: 'itemFk',
}, type: 'number'
{ },
arg: 'warehouseFk', {
type: 'number' arg: 'warehouseFk',
}, type: 'number'
{ },
arg: 'started', {
type: 'date' arg: 'started',
}, type: 'date'
{ },
arg: 'ended', {
type: 'date' arg: 'ended',
}, type: 'date'
{ },
arg: 'rate2', {
type: 'number' arg: 'rate2',
}, type: 'number'
{ },
arg: 'rate3', {
type: 'number' arg: 'rate3',
}, type: 'number'
{ },
arg: 'minPrice', {
type: 'number' arg: 'minPrice',
}, type: 'number'
{ },
arg: 'hasMinPrice', {
type: 'any' arg: 'hasMinPrice',
}], type: 'any'
}
],
returns: { returns: {
type: 'object', type: 'object',
root: true root: true
@ -54,21 +56,29 @@ module.exports = Self => {
} }
}); });
Self.upsertFixedPrice = async ctx => { Self.upsertFixedPrice = async(ctx, options) => {
const models = Self.app.models; const models = Self.app.models;
const args = ctx.args; const args = ctx.args;
const tx = await models.Address.beginTransaction({}); let tx;
try { const myOptions = {};
const options = {transaction: tx};
delete args.ctx; // removed unwanted data
if (typeof options == 'object')
Object.assign(myOptions, options);
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
try {
delete args.ctx; // removed unwanted data
const fixedPrice = await models.FixedPrice.upsert(args, options); const fixedPrice = await models.FixedPrice.upsert(args, options);
const targetItem = await models.Item.findById(args.itemFk, null, options); const targetItem = await models.Item.findById(args.itemFk, null, options);
await targetItem.updateAttributes({ await targetItem.updateAttributes({
minPrice: args.minPrice, minPrice: args.minPrice,
hasMinPrice: args.minPrice ? true : false hasMinPrice: args.minPrice ? true : false
}, options); }, myOptions);
const itemFields = [ const itemFields = [
'minPrice', 'minPrice',
@ -99,16 +109,17 @@ module.exports = Self => {
} }
}; };
const result = await models.FixedPrice.findById(fixedPrice.id, filter, options); const result = await models.FixedPrice.findById(fixedPrice.id, filter, myOptions);
const item = result.item(); const item = result.item();
for (let key of itemFields) for (let key of itemFields)
result[key] = item[key]; result[key] = item[key];
await tx.commit(); if (tx) await tx.commit();
return result; return result;
} catch (e) { } catch (e) {
await tx.rollback(); if (tx) await tx.rollback();
throw e; throw e;
} }
}; };

View File

@ -1,10 +1,20 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('item-barcode toItem()', () => { describe('item-barcode toItem()', () => {
it('should return the same number if there is a barcode and a item with the same ID', async() => { it('should return the same number if there is a barcode and a item with the same ID', async() => {
let barcode = 3; const tx = await models.Item.beginTransaction({});
let result = await app.models.ItemBarcode.toItem(barcode); const options = {transaction: tx};
expect(result).toBe(3); try {
const barcode = 3;
const result = await models.ItemBarcode.toItem(barcode, options);
expect(result).toBe(3);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -4,12 +4,12 @@ module.exports = Self => {
accessType: 'READ', accessType: 'READ',
accepts: [{ accepts: [{
arg: 'barcode', arg: 'barcode',
type: 'Number', type: 'number',
required: true, required: true,
description: 'barcode' description: 'barcode'
}], }],
returns: { returns: {
type: 'Number', type: 'number',
root: true root: true
}, },
http: { http: {
@ -18,11 +18,18 @@ module.exports = Self => {
} }
}); });
Self.toItem = async barcode => { Self.toItem = async(barcode, options) => {
let query = `SELECT vn.barcodeToItem(?)`; const myOptions = {};
let [item] = await Self.rawSql(query, [barcode]);
if (typeof options == 'object')
Object.assign(myOptions, options);
const query = `SELECT vn.barcodeToItem(?)`;
let [item] = await Self.rawSql(query, [barcode], myOptions);
if (item) if (item)
item = Object.values(item); item = Object.values(item)[0];
return item[0];
return item;
}; };
}; };

View File

@ -5,17 +5,19 @@ module.exports = Self => {
Self.remoteMethod('filterItemTags', { Self.remoteMethod('filterItemTags', {
description: 'Returns the distinct values of a tag property', description: 'Returns the distinct values of a tag property',
accessType: 'READ', accessType: 'READ',
accepts: [{ accepts: [
arg: 'tagFk', {
type: 'number', arg: 'tagFk',
required: true, type: 'number',
description: 'The foreign key from tag table', required: true,
http: {source: 'path'} description: 'The foreign key from tag table',
}, { http: {source: 'path'}
arg: 'filter', }, {
type: 'Object', arg: 'filter',
description: `Filter defining where, order, offset, and limit - must be a JSON-encoded string` type: 'object',
}], description: `Filter defining where, order, offset, and limit - must be a JSON-encoded string`
}
],
returns: { returns: {
root: true, root: true,
type: ['object'] type: ['object']
@ -26,16 +28,21 @@ module.exports = Self => {
} }
}); });
Self.filterItemTags = async(tagFk, filter) => { Self.filterItemTags = async(tagFk, filter, options) => {
let conn = Self.dataSource.connector; const conn = Self.dataSource.connector;
let where = {tagFk: tagFk}; const myOptions = {};
myFilter = mergeFilters(filter, {where});
if (typeof options == 'object')
Object.assign(myOptions, options);
const where = {tagFk: tagFk};
const myFilter = mergeFilters(filter, {where});
stmt = new ParameterizedSQL( stmt = new ParameterizedSQL(
`SELECT DISTINCT(value) `SELECT DISTINCT(value)
FROM itemTag`); FROM itemTag`);
stmt.merge(conn.makeSuffix(myFilter)); stmt.merge(conn.makeSuffix(myFilter));
return await conn.executeStmt(stmt); return conn.executeStmt(stmt, myOptions);
}; };
}; };

View File

@ -1,9 +1,19 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('item filterItemTags()', () => { describe('item filterItemTags()', () => {
it('should filter ItemTags table', async() => { it('should filter ItemTags table', async() => {
let [result] = await app.models.ItemTag.filterItemTags(1, {}); const tx = await models.Item.beginTransaction({});
const options = {transaction: tx};
expect(result.value).toEqual('Black'); try {
const [result] = await models.ItemTag.filterItemTags(1, null, options);
expect(result.value).toEqual('Black');
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -12,7 +12,7 @@ module.exports = Self => {
http: {source: 'path'} http: {source: 'path'}
}], }],
returns: { returns: {
type: 'Object', type: 'object',
description: 'new cloned itemId', description: 'new cloned itemId',
root: true, root: true,
}, },
@ -22,13 +22,21 @@ module.exports = Self => {
} }
}); });
Self.clone = async itemId => { Self.clone = async(itemId, options) => {
let tx = await Self.beginTransaction({}); let tx;
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
try { try {
let options = {transaction: tx}; const origin = await Self.findById(itemId, null, myOptions);
const origin = await Self.findById(itemId, null, options);
if (!origin) if (!origin)
throw new UserError(`This item doesn't exists`); throw new UserError(`This item doesn't exists`);
@ -38,16 +46,17 @@ module.exports = Self => {
origin.comment = undefined; origin.comment = undefined;
origin.size = undefined; origin.size = undefined;
const newItem = await Self.create(origin, options); const newItem = await Self.create(origin, myOptions);
await cloneTaxes(origin.id, newItem.id, options); await cloneTaxes(origin.id, newItem.id, myOptions);
await cloneBotanical(origin.id, newItem.id, options); await cloneBotanical(origin.id, newItem.id, myOptions);
await cloneTags(origin.id, newItem.id, options); await cloneTags(origin.id, newItem.id, myOptions);
if (tx) await tx.commit();
await tx.commit();
return newItem; return newItem;
} catch (e) { } catch (e) {
await tx.rollback(); if (tx) await tx.rollback();
throw e; throw e;
} }
}; };

View File

@ -2,23 +2,25 @@ module.exports = Self => {
Self.remoteMethod('createIntrastat', { Self.remoteMethod('createIntrastat', {
description: 'Creates a new item intrastat', description: 'Creates a new item intrastat',
accessType: 'WRITE', accessType: 'WRITE',
accepts: [{ accepts: [
arg: 'id', {
type: 'number', arg: 'id',
required: true, type: 'number',
description: 'The item id', required: true,
http: {source: 'path'} description: 'The item id',
}, http: {source: 'path'}
{ },
arg: 'intrastatId', {
type: 'number', arg: 'intrastatId',
required: true type: 'number',
}, required: true
{ },
arg: 'description', {
type: 'string', arg: 'description',
required: true type: 'string',
}], required: true
}
],
returns: { returns: {
type: 'boolean', type: 'boolean',
root: true root: true
@ -29,31 +31,52 @@ module.exports = Self => {
} }
}); });
Self.createIntrastat = async(id, intrastatId, description) => { Self.createIntrastat = async(id, intrastatId, description, options) => {
const models = Self.app.models; const models = Self.app.models;
const country = await models.Country.findOne({ const myOptions = {};
where: {code: 'ES'} let tx;
});
const itemTaxCountry = await models.ItemTaxCountry.findOne({ if (typeof options == 'object')
where: { Object.assign(myOptions, options);
itemFk: id,
countryFk: country.id
},
order: 'effectived DESC'
});
const taxClassCode = await models.TaxClassCode.findOne({
where: {
taxClassFk: itemTaxCountry.taxClassFk
},
order: 'effectived DESC'
});
return models.Intrastat.create({ if (!myOptions.transaction) {
id: intrastatId, tx = await Self.beginTransaction({});
description: description, myOptions.transaction = tx;
taxClassFk: itemTaxCountry.taxClassFk, }
taxCodeFk: taxClassCode.taxCodeFk
}); try {
const country = await models.Country.findOne({
where: {code: 'ES'}
}, myOptions);
const itemTaxCountry = await models.ItemTaxCountry.findOne({
where: {
itemFk: id,
countryFk: country.id
},
order: 'effectived DESC'
}, myOptions);
const taxClassCode = await models.TaxClassCode.findOne({
where: {
taxClassFk: itemTaxCountry.taxClassFk
},
order: 'effectived DESC'
}, myOptions);
const intrastat = await models.Intrastat.create({
id: intrastatId,
description: description,
taxClassFk: itemTaxCountry.taxClassFk,
taxCodeFk: taxClassCode.taxCodeFk
}, myOptions);
if (tx) await tx.commit();
return intrastat;
} catch (e) {
if (tx) await tx.rollback();
throw e;
}
}; };
}; };

View File

@ -71,7 +71,7 @@ module.exports = Self => {
Self.filter = async(ctx, filter, options) => { Self.filter = async(ctx, filter, options) => {
const conn = Self.dataSource.connector; const conn = Self.dataSource.connector;
let myOptions = {}; const myOptions = {};
if (typeof options == 'object') if (typeof options == 'object')
Object.assign(myOptions, options); Object.assign(myOptions, options);
@ -83,7 +83,9 @@ module.exports = Self => {
where: {code: ctx.args.search}, where: {code: ctx.args.search},
fields: ['itemFk'] fields: ['itemFk']
}, myOptions); }, myOptions);
const itemIds = []; const itemIds = [];
for (const item of items) for (const item of items)
itemIds.push(item.itemFk); itemIds.push(item.itemFk);
@ -116,12 +118,11 @@ module.exports = Self => {
return {'intr.description': value}; return {'intr.description': value};
} }
}); });
filter = mergeFilters(filter, {where}); filter = mergeFilters(filter, {where});
const stmts = []; const stmts = [];
let stmt; const stmt = new ParameterizedSQL(
stmt = new ParameterizedSQL(
`SELECT `SELECT
i.id, i.id,
i.image, i.image,

View File

@ -19,9 +19,15 @@ module.exports = Self => {
} }
}); });
Self.getBalance = async filter => { Self.getBalance = async(filter, options) => {
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
const where = filter.where; const where = filter.where;
let [diary] = await Self.rawSql(`CALL vn.item_getBalance(?, ?)`, [where.itemFk, where.warehouseFk]); const query = 'CALL vn.item_getBalance(?, ?)';
const [diary] = await Self.rawSql(query, [where.itemFk, where.warehouseFk], myOptions);
for (const entry of diary) for (const entry of diary)
if (entry.clientType === 'loses') entry.highlighted = true; if (entry.clientType === 'loses') entry.highlighted = true;

View File

@ -19,12 +19,13 @@ module.exports = Self => {
} }
}); });
Self.getCard = async id => { Self.getCard = async(id, options) => {
let item = {}; const myOptions = {};
// Item basic data if (typeof options == 'object')
let filter = { Object.assign(myOptions, options);
where: {id: id},
const filter = {
include: [ include: [
{ {
relation: 'itemType', relation: 'itemType',
@ -58,8 +59,8 @@ module.exports = Self => {
} }
] ]
}; };
[item] = await Self.app.models.Item.find(filter); const item = await Self.app.models.Item.findById(id, filter, myOptions);
return item; return item ? item : {};
}; };
}; };

View File

@ -19,14 +19,18 @@ module.exports = Self => {
} }
}); });
Self.getSummary = async(ctx, id) => { Self.getSummary = async(ctx, id, options) => {
let promises = [];
let summary = {};
const models = Self.app.models; const models = Self.app.models;
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
const promises = [];
const summary = {};
// Item basic data and taxes // Item basic data and taxes
let filter = { let filter = {
where: {id: id},
include: [ include: [
{relation: 'itemType', {relation: 'itemType',
scope: { scope: {
@ -67,7 +71,7 @@ module.exports = Self => {
} }
] ]
}; };
promises.push(models.Item.find(filter)); promises.push(models.Item.findById(id, filter, myOptions));
// Tags // Tags
filter = { filter = {
@ -79,35 +83,36 @@ module.exports = Self => {
relation: 'tag' relation: 'tag'
} }
}; };
promises.push(models.ItemTag.find(filter)); promises.push(models.ItemTag.find(filter, myOptions));
// Botanical // Botanical
filter = { filter = {
where: {itemFk: id}, where: {itemFk: id},
include: [{relation: 'genus'}, {relation: 'specie'}] include: [{relation: 'genus'}, {relation: 'specie'}]
}; };
promises.push(models.ItemBotanical.find(filter)); promises.push(models.ItemBotanical.find(filter, myOptions));
// Niches // Niches
filter = { filter = {
where: {itemFk: id}, where: {itemFk: id},
include: {relation: 'warehouse'} include: {relation: 'warehouse'}
}; };
promises.push(models.ItemNiche.find(filter)); promises.push(models.ItemNiche.find(filter, myOptions));
let res = await Promise.all(promises); let res = await Promise.all(promises);
[summary.item] = res[0]; summary.item = res[0];
summary.tags = res[1]; summary.tags = res[1];
[summary.botanical] = res[2]; [summary.botanical] = res[2];
summary.niches = res[3]; summary.niches = res[3];
const userConfig = await models.UserConfig.getUserConfig(ctx); const userConfig = await models.UserConfig.getUserConfig(ctx, myOptions);
res = await models.Item.getVisibleAvailable(summary.item.id, userConfig.warehouseFk); res = await models.Item.getVisibleAvailable(summary.item.id, userConfig.warehouseFk, null, myOptions);
summary.available = res.available; summary.available = res.available;
summary.visible = res.visible; summary.visible = res.visible;
return summary; return summary;
}; };
}; };

View File

@ -5,19 +5,20 @@ module.exports = Self => {
accepts: [ accepts: [
{ {
arg: 'id', arg: 'id',
type: 'Number', type: 'number',
required: true, required: true,
}, },
{ {
arg: 'warehouseFk', arg: 'warehouseFk',
type: 'Number', type: 'number',
required: true, required: true,
}, },
{ {
arg: 'dated', arg: 'dated',
type: 'Date', type: 'date',
required: false, required: false,
}], }
],
returns: { returns: {
type: ['object'], type: ['object'],
root: true root: true
@ -28,32 +29,43 @@ module.exports = Self => {
} }
}); });
Self.getVisibleAvailable = async(id, warehouseFk, dated = new Date()) => { Self.getVisibleAvailable = async(id, warehouseFk, dated = new Date(), options) => {
let stmts = []; const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
const stmts = [];
stmts.push(new ParameterizedSQL( stmts.push(new ParameterizedSQL(
'CALL cache.available_refresh(@availableCalc, FALSE, ?, ?)', [ 'CALL cache.available_refresh(@availableCalc, FALSE, ?, ?)',
[
warehouseFk, warehouseFk,
dated dated
] ],
myOptions
)); ));
stmts.push(new ParameterizedSQL( stmts.push(new ParameterizedSQL(
'CALL cache.visible_refresh(@visibleCalc, FALSE,?)', [ 'CALL cache.visible_refresh(@visibleCalc, FALSE,?)', [
warehouseFk warehouseFk
] ]
)); ));
const visibleIndex = stmts.push(new ParameterizedSQL( const visibleIndex = stmts.push(new ParameterizedSQL(
'SELECT visible FROM cache.visible WHERE calc_id = @visibleCalc AND item_id = ?', [ 'SELECT visible FROM cache.visible WHERE calc_id = @visibleCalc AND item_id = ?',
id [id],
] myOptions
)) - 1; )) - 1;
const availableIndex = stmts.push(new ParameterizedSQL( const availableIndex = stmts.push(new ParameterizedSQL(
'SELECT available FROM cache.available WHERE calc_id = @availableCalc AND item_id = ?', [ 'SELECT available FROM cache.available WHERE calc_id = @availableCalc AND item_id = ?',
id [id],
] myOptions
)) - 1; )) - 1;
const sql = ParameterizedSQL.join(stmts, ';'); const sql = ParameterizedSQL.join(stmts, ';');
let res = await Self.rawStmt(sql); const res = await Self.rawStmt(sql, myOptions);
return { return {
available: res[availableIndex][0] ? res[availableIndex][0].available : 0, available: res[availableIndex][0] ? res[availableIndex][0].available : 0,

View File

@ -17,7 +17,7 @@ module.exports = Self => {
} }
], ],
returns: { returns: {
type: ['Object'], type: ['object'],
root: true root: true
}, },
http: { http: {
@ -26,7 +26,12 @@ module.exports = Self => {
} }
}); });
Self.getWasteByItem = async(buyer, family) => { Self.getWasteByItem = async(buyer, family, options) => {
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
const wastes = await Self.rawSql(` const wastes = await Self.rawSql(`
SELECT *, 100 * dwindle / total AS percentage SELECT *, 100 * dwindle / total AS percentage
FROM ( FROM (
@ -41,7 +46,7 @@ module.exports = Self => {
AND week = WEEK(TIMESTAMPADD(WEEK,-1,CURDATE()), 1) AND week = WEEK(TIMESTAMPADD(WEEK,-1,CURDATE()), 1)
GROUP BY buyer, itemFk GROUP BY buyer, itemFk
) sub ) sub
ORDER BY family, percentage DESC`, [buyer, family]); ORDER BY family, percentage DESC`, [buyer, family], myOptions);
const details = []; const details = [];

View File

@ -4,7 +4,7 @@ module.exports = Self => {
accessType: 'READ', accessType: 'READ',
accepts: [], accepts: [],
returns: { returns: {
type: ['Object'], type: ['object'],
root: true root: true
}, },
http: { http: {
@ -13,7 +13,12 @@ module.exports = Self => {
} }
}); });
Self.getWasteByWorker = async() => { Self.getWasteByWorker = async options => {
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
const wastes = await Self.rawSql(` const wastes = await Self.rawSql(`
SELECT *, 100 * dwindle / total AS percentage SELECT *, 100 * dwindle / total AS percentage
FROM ( FROM (
@ -26,7 +31,7 @@ module.exports = Self => {
AND week = WEEK(TIMESTAMPADD(WEEK,-1,CURDATE()), 1) AND week = WEEK(TIMESTAMPADD(WEEK,-1,CURDATE()), 1)
GROUP BY buyer, family GROUP BY buyer, family
) sub ) sub
ORDER BY percentage DESC`); ORDER BY percentage DESC`, null, myOptions);
const details = []; const details = [];

View File

@ -21,8 +21,13 @@ module.exports = Self => {
} }
}); });
Self.lastEntriesFilter = async filter => { Self.lastEntriesFilter = async(filter, options) => {
const conn = Self.dataSource.connector; const conn = Self.dataSource.connector;
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
const stmt = new ParameterizedSQL( const stmt = new ParameterizedSQL(
`SELECT `SELECT
w.id AS warehouseFk, w.id AS warehouseFk,
@ -64,6 +69,6 @@ module.exports = Self => {
LEFT JOIN edi.ekt ek ON b.ektFk = ek.id`); LEFT JOIN edi.ekt ek ON b.ektFk = ek.id`);
stmt.merge(conn.makeSuffix(filter)); stmt.merge(conn.makeSuffix(filter));
return conn.executeStmt(stmt); return conn.executeStmt(stmt, myOptions);
}; };
}; };

View File

@ -2,7 +2,7 @@ let UserError = require('vn-loopback/util/user-error');
module.exports = Self => { module.exports = Self => {
Self.remoteMethod('new', { Self.remoteMethod('new', {
description: 'Create a new item and returns the new ID', description: 'returns the created item',
accessType: 'WRITE', accessType: 'WRITE',
accepts: [{ accepts: [{
arg: 'params', arg: 'params',
@ -19,8 +19,20 @@ module.exports = Self => {
} }
}); });
Self.new = async params => { Self.new = async(params, options) => {
let validUpdateParams = [ const models = Self.app.models;
const myOptions = {};
let tx;
if (typeof options == 'object')
Object.assign(myOptions, options);
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
const validUpdateParams = [
'provisionalName', 'provisionalName',
'typeFk', 'typeFk',
'intrastatFk', 'intrastatFk',
@ -33,20 +45,21 @@ module.exports = Self => {
throw new UserError(`You don't have enough privileges to do that`); throw new UserError(`You don't have enough privileges to do that`);
} }
let tx = await Self.beginTransaction({});
try { try {
let options = {transaction: tx}; const provisionalName = params.provisionalName;
let provisionalName = params.provisionalName;
delete params.provisionalName; delete params.provisionalName;
let item = await Self.app.models.Item.create(params, options); const item = await models.Item.create(params, myOptions);
const typeTags = await models.ItemTypeTag.find({
where: {itemTypeFk: item.typeFk}
}, myOptions);
let typeTags = await Self.app.models.ItemTypeTag.find({where: {itemTypeFk: item.typeFk}});
let query = `SET @isTriggerDisabled = TRUE`; let query = `SET @isTriggerDisabled = TRUE`;
await Self.rawSql(query, null, options);
let nameTag = await Self.app.models.Tag.findOne({where: {name: 'Nombre temporal'}}); await Self.rawSql(query, null, myOptions);
let nameTag = await models.Tag.findOne({where: {name: 'Nombre temporal'}});
let newTags = []; let newTags = [];
@ -55,17 +68,19 @@ module.exports = Self => {
newTags.push({itemFk: item.id, tagFk: typeTag.tagFk, value: '', priority: typeTag.priority}); newTags.push({itemFk: item.id, tagFk: typeTag.tagFk, value: '', priority: typeTag.priority});
}); });
await Self.app.models.ItemTag.create(newTags, options); await models.ItemTag.create(newTags, myOptions);
query = `SET @isTriggerDisabled = FALSE`; query = `SET @isTriggerDisabled = FALSE`;
await Self.rawSql(query, null, options); await Self.rawSql(query, null, myOptions);
query = `CALL vn.itemRefreshTags(?)`; query = `CALL vn.itemRefreshTags(?)`;
await Self.rawSql(query, [item.id], options); await Self.rawSql(query, [item.id], myOptions);
await tx.commit();
if (tx) await tx.commit();
return item; return item;
} catch (e) { } catch (e) {
await tx.rollback(); if (tx) await tx.rollback();
throw e; throw e;
} }
}; };

View File

@ -2,22 +2,26 @@ module.exports = Self => {
Self.remoteMethodCtx('regularize', { Self.remoteMethodCtx('regularize', {
description: 'Sends items to the trash', description: 'Sends items to the trash',
accessType: 'WRITE', accessType: 'WRITE',
accepts: [{ accepts: [
arg: 'itemFk', {
type: 'number', arg: 'itemFk',
required: true, type: 'number',
description: 'The item id', required: true,
}, { description: 'The item id',
arg: 'quantity', },
type: 'number', {
required: true, arg: 'quantity',
description: 'The visible quantity', type: 'number',
}, { required: true,
arg: 'warehouseFk', description: 'The visible quantity',
type: 'number', },
required: true, {
description: 'The id of the warehouse where the inventory happened', arg: 'warehouseFk',
}], type: 'number',
required: true,
description: 'The id of the warehouse where the inventory happened',
}
],
returns: { returns: {
type: 'boolean', type: 'boolean',
root: true root: true
@ -28,37 +32,44 @@ module.exports = Self => {
} }
}); });
Self.regularize = async(ctx, itemFk, quantity, warehouseFk) => { Self.regularize = async(ctx, itemFk, quantity, warehouseFk, options) => {
const models = Self.app.models; const models = Self.app.models;
const myOptions = {};
let tx;
const itemDestination = await models.ClaimDestination.findOne({ if (typeof options == 'object')
include: { Object.assign(myOptions, options);
relation: 'address',
scope: { if (!myOptions.transaction) {
fields: ['clientFk'] tx = await Self.beginTransaction({});
} myOptions.transaction = tx;
}, }
where: {description: 'Corregido'}
});
let tx = await Self.beginTransaction({});
try { try {
let options = {transaction: tx}; const itemDestination = await models.ClaimDestination.findOne({
include: {
relation: 'address',
scope: {
fields: ['clientFk']
}
},
where: {description: 'Corregido'}
}, myOptions);
let item = await models.Item.findById(itemFk); const item = await models.Item.findById(itemFk, null, myOptions);
let ticketFk = await getTicketId({ let ticketId = await getTicketId({
clientFk: itemDestination.address.clientFk, clientFk: itemDestination.address.clientFk,
addressFk: itemDestination.addressFk, addressFk: itemDestination.addressFk,
warehouseFk: warehouseFk warehouseFk: warehouseFk
}, options); }, myOptions);
if (!ticketFk) { if (!ticketId) {
ticketFk = await createTicket(ctx, { ticketId = await createTicket(ctx, {
clientId: itemDestination.address().clientFk, clientId: itemDestination.address().clientFk,
warehouseId: warehouseFk, warehouseId: warehouseFk,
addressId: itemDestination.addressFk addressId: itemDestination.addressFk
}, options); }, myOptions);
} }
res = await models.Item.getVisibleAvailable(itemFk, warehouseFk); res = await models.Item.getVisibleAvailable(itemFk, warehouseFk);
@ -66,17 +77,18 @@ module.exports = Self => {
let newQuantity = res.visible - quantity; let newQuantity = res.visible - quantity;
await models.Sale.create({ await models.Sale.create({
ticketFk: ticketFk, ticketFk: ticketId,
itemFk: itemFk, itemFk: itemFk,
concept: item.name, concept: item.name,
quantity: newQuantity, quantity: newQuantity,
discount: 100 discount: 100
}, options); }, myOptions);
await tx.commit(); if (tx) await tx.commit();
return ticketFk;
return ticketId;
} catch (e) { } catch (e) {
await tx.rollback(); if (tx) await tx.rollback();
throw e; throw e;
} }

View File

@ -1,4 +1,4 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('item clone()', () => { describe('item clone()', () => {
let nextItemId; let nextItemId;
@ -8,30 +8,47 @@ describe('item clone()', () => {
LEFT JOIN vn.item i2 ON i1.id + 1 = i2.id LEFT JOIN vn.item i2 ON i1.id + 1 = i2.id
WHERE i2.id IS NULL ORDER BY i1.id LIMIT 1`; WHERE i2.id IS NULL ORDER BY i1.id LIMIT 1`;
[nextAvailableId] = await app.models.Item.rawSql(query); [nextAvailableId] = await models.Item.rawSql(query);
nextItemId = nextAvailableId.id; nextItemId = nextAvailableId.id;
}); });
it('should clone the given item and it should have the expected id', async() => { it('should clone the given item and it should have the expected id', async() => {
let itemFk = 1; const tx = await models.FixedPrice.beginTransaction({});
let result = await app.models.Item.clone(itemFk);
expect(result.id).toEqual(nextItemId); try {
expect(result.image).toBeUndefined(); const options = {transaction: tx};
expect(result.itemTag).toBeUndefined(); const itemFk = 1;
expect(result.comment).toBeUndefined(); const result = await models.Item.clone(itemFk, options);
expect(result.description).toBeUndefined();
expect(result.id).toEqual(nextItemId);
expect(result.image).toBeUndefined();
expect(result.itemTag).toBeUndefined();
expect(result.comment).toBeUndefined();
expect(result.description).toBeUndefined();
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should attempt to clone the given item but give an error as it doesnt exist', async() => { it('should attempt to clone the given item but give an error as it doesnt exist', async() => {
let error; const tx = await models.FixedPrice.beginTransaction({});
let itemFk = 999;
await app.models.Item.clone(itemFk)
.catch(e => {
expect(e.message).toContain(`This item doesn't exists`);
error = e;
});
expect(error).toBeDefined(); let error;
try {
const options = {transaction: tx};
const itemFk = 999;
await models.Item.clone(itemFk, options);
await tx.rollback();
} catch (e) {
await tx.rollback();
error = e;
}
expect(error.message).toContain(`This item doesn't exists`);
}); });
}); });

View File

@ -1,22 +1,25 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('createIntrastat()', () => { describe('createIntrastat()', () => {
let newIntrastat;
afterAll(async done => {
await app.models.Intrastat.destroyById(newIntrastat.id);
done();
});
it('should create a new intrastat', async() => { it('should create a new intrastat', async() => {
const intrastatId = 588420239; const tx = await models.FixedPrice.beginTransaction({});
const description = 'Tropical Flowers';
const itemId = 9;
newIntrastat = await app.models.Item.createIntrastat(itemId, intrastatId, description);
expect(newIntrastat.description).toEqual(description); try {
expect(newIntrastat.taxClassFk).toEqual(1); const options = {transaction: tx};
expect(newIntrastat.taxCodeFk).toEqual(21); const intrastatId = 588420239;
const description = 'Tropical Flowers';
const itemId = 9;
const newIntrastat = await models.Item.createIntrastat(itemId, intrastatId, description, options);
expect(newIntrastat.description).toEqual(description);
expect(newIntrastat.taxClassFk).toEqual(1);
expect(newIntrastat.taxCodeFk).toEqual(21);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -1,14 +1,14 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('item filter()', () => { describe('item filter()', () => {
it('should return 1 result filtering by id', async() => { it('should return 1 result filtering by id', async() => {
const tx = await app.models.Item.beginTransaction({}); const tx = await models.Item.beginTransaction({});
const options = {transaction: tx}; const options = {transaction: tx};
try { try {
const filter = {}; const filter = {};
const ctx = {args: {filter: filter, search: 1}}; const ctx = {args: {filter: filter, search: 1}};
const result = await app.models.Item.filter(ctx, filter, options); const result = await models.Item.filter(ctx, filter, options);
expect(result.length).toEqual(1); expect(result.length).toEqual(1);
expect(result[0].id).toEqual(1); expect(result[0].id).toEqual(1);
@ -21,13 +21,13 @@ describe('item filter()', () => {
}); });
it('should return 1 result filtering by barcode', async() => { it('should return 1 result filtering by barcode', async() => {
const tx = await app.models.Item.beginTransaction({}); const tx = await models.Item.beginTransaction({});
const options = {transaction: tx}; const options = {transaction: tx};
try { try {
const filter = {}; const filter = {};
const ctx = {args: {filter: filter, search: 4444444444}}; const ctx = {args: {filter: filter, search: 4444444444}};
const result = await app.models.Item.filter(ctx, filter, options); const result = await models.Item.filter(ctx, filter, options);
expect(result.length).toEqual(1); expect(result.length).toEqual(1);
expect(result[0].id).toEqual(2); expect(result[0].id).toEqual(2);
@ -40,7 +40,7 @@ describe('item filter()', () => {
}); });
it('should return 2 results using filter and tags', async() => { it('should return 2 results using filter and tags', async() => {
const tx = await app.models.Item.beginTransaction({}); const tx = await models.Item.beginTransaction({});
const options = {transaction: tx}; const options = {transaction: tx};
try { try {
@ -50,7 +50,7 @@ describe('item filter()', () => {
}; };
const tags = [{value: 'medical box', tagFk: 58}]; const tags = [{value: 'medical box', tagFk: 58}];
const ctx = {args: {filter: filter, typeFk: 5, tags: tags}}; const ctx = {args: {filter: filter, typeFk: 5, tags: tags}};
const result = await app.models.Item.filter(ctx, filter, options); const result = await models.Item.filter(ctx, filter, options);
expect(result.length).toEqual(2); expect(result.length).toEqual(2);

View File

@ -1,33 +1,39 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context'); const LoopBackContext = require('loopback-context');
describe('item getBalance()', () => { describe('item getBalance()', () => {
it('should return the balance lines of a client type loses in which one has highlighted true', async() => { it('should return the balance lines of a client type loses in which one has highlighted true', async() => {
const activeCtx = { const tx = await models.Item.beginTransaction({});
accessToken: {userId: 9}, const options = {transaction: tx};
};
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: activeCtx
});
const losesClientId = 1111; try {
const ticket = await app.models.Ticket.findById(7); const activeCtx = {
const originalClientId = ticket.clientFk; accessToken: {userId: 9},
await ticket.updateAttribute('clientFk', losesClientId); };
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: activeCtx
});
const losesClientId = 1111;
const ticket = await models.Ticket.findById(7, null, options);
const filter = { await ticket.updateAttribute('clientFk', losesClientId, options);
where: {
itemFk: 1,
warehouseFk: 1
}
};
const results = await app.models.Item.getBalance(filter);
const result = results.find(element => element.clientType == 'loses'); const filter = {
where: {
itemFk: 1,
warehouseFk: 1
}
};
const results = await models.Item.getBalance(filter, options);
expect(result.highlighted).toBe(true); const result = results.find(element => element.clientType == 'loses');
// restores expect(result.highlighted).toBe(true);
await ticket.updateAttribute('clientFk', originalClientId);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -0,0 +1,23 @@
const models = require('vn-loopback/server/server').models;
describe('item getCard()', () => {
it('should return the item', async() => {
const tx = await models.Item.beginTransaction({});
const options = {transaction: tx};
try {
const itemId = 1;
const result = await models.Item.getCard(itemId, options);
expect(result.id).toEqual(itemId);
expect(result.itemType()).toEqual(jasmine.any(Object));
expect(result.tags()).toEqual(jasmine.any(Array));
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});

View File

@ -1,12 +0,0 @@
const app = require('vn-loopback/server/server');
describe('item getBalance()', () => {
it('should check the property balance of the 4 resultant entries', async() => {
let params = {where: {itemFk: 1, warehouseFk: 2}};
let result = await app.models.Item.getBalance(params);
expect(result.length).toBe(2);
expect(result[0].balance).toBe(-100);
expect(result[1].balance).toBe(-200);
});
});

View File

@ -1,16 +1,27 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('item getSummary()', () => { describe('item getSummary()', () => {
it('should return summary with item, tags, botanical, niches, available and visible defined ', async() => { it('should return summary with item, tags, botanical, niches, available and visible defined ', async() => {
const ctx = {req: {accessToken: {userId: 1}}}; const tx = await models.Item.beginTransaction({});
let result = await app.models.Item.getSummary(ctx, 1); const options = {transaction: tx};
let keys = Object.keys(result);
expect(keys).toContain('item'); try {
expect(keys).toContain('tags'); const ctx = {req: {accessToken: {userId: 1}}};
expect(keys).toContain('botanical');
expect(keys).toContain('niches'); const result = await models.Item.getSummary(ctx, 1, options);
expect(keys).toContain('available'); const keys = Object.keys(result);
expect(keys).toContain('visible');
expect(keys).toContain('item');
expect(keys).toContain('tags');
expect(keys).toContain('botanical');
expect(keys).toContain('niches');
expect(keys).toContain('available');
expect(keys).toContain('visible');
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -1,33 +1,46 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('item getVisibleAvailable()', () => { describe('item getVisibleAvailable()', () => {
it('should check available visible for today', async() => { it('should check available visible for today', async() => {
const itemFk = 1; const tx = await models.Item.beginTransaction({});
const warehouseFk = 1; const options = {transaction: tx};
const dated = new Date();
let result = await app.models.Item.getVisibleAvailable(itemFk, warehouseFk, dated);
expect(result.available).toEqual(187); try {
expect(result.visible).toEqual(92); const itemFk = 1;
}); const warehouseFk = 1;
const dated = new Date();
it('should check available visible for no dated', async() => { const result = await models.Item.getVisibleAvailable(itemFk, warehouseFk, dated, options);
const itemFk = 1;
const warehouseFk = 1;
let result = await app.models.Item.getVisibleAvailable(itemFk, warehouseFk);
expect(result.available).toEqual(187); expect(result.available).toEqual(187);
expect(result.visible).toEqual(92); expect(result.visible).toEqual(92);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should check available visible for yesterday', async() => { it('should check available visible for yesterday', async() => {
const itemFk = 1; const tx = await models.Item.beginTransaction({});
const warehouseFk = 1; const options = {transaction: tx};
let dated = new Date();
dated.setDate(dated.getDate() - 1);
let result = await app.models.Item.getVisibleAvailable(itemFk, warehouseFk, dated);
expect(result.available).toEqual(0); try {
expect(result.visible).toEqual(92); const itemFk = 1;
const warehouseFk = 1;
const dated = new Date();
dated.setDate(dated.getDate() - 1);
const result = await models.Item.getVisibleAvailable(itemFk, warehouseFk, dated, options);
expect(result.available).toEqual(0);
expect(result.visible).toEqual(92);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -1,14 +1,24 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('Item getWasteByItem()', () => { describe('Item getWasteByItem()', () => {
it('should check for the waste breakdown by worker and item', async() => { it('should check for the waste breakdown by worker and item', async() => {
const result = await app.models.Item.getWasteByItem('CharlesXavier', 'Cymbidium'); const tx = await models.Item.beginTransaction({});
const options = {transaction: tx};
const length = result.length; try {
const anyResult = result[Math.floor(Math.random() * Math.floor(length))]; const result = await models.Item.getWasteByItem('CharlesXavier', 'Cymbidium', options);
expect(anyResult.buyer).toEqual('CharlesXavier'); const length = result.length;
expect(anyResult.family).toEqual('Cymbidium'); const anyResult = result[Math.floor(Math.random() * Math.floor(length))];
expect(anyResult.lines.length).toBeGreaterThanOrEqual(2);
expect(anyResult.buyer).toEqual('CharlesXavier');
expect(anyResult.family).toEqual('Cymbidium');
expect(anyResult.lines.length).toBeGreaterThanOrEqual(2);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -1,13 +1,23 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('Item getWasteByWorker()', () => { describe('Item getWasteByWorker()', () => {
it('should check for the waste breakdown for every worker', async() => { it('should check for the waste breakdown for every worker', async() => {
const result = await app.models.Item.getWasteByWorker(); const tx = await models.Item.beginTransaction({});
const options = {transaction: tx};
const length = result.length; try {
const anyResult = result[Math.floor(Math.random() * Math.floor(length))]; const result = await models.Item.getWasteByWorker(options);
expect(anyResult.buyer).toMatch(/(CharlesXavier|HankPym|DavidCharlesHaller)/); const length = result.length;
expect(anyResult.lines.length).toBeGreaterThanOrEqual(3); const anyResult = result[Math.floor(Math.random() * Math.floor(length))];
expect(anyResult.buyer).toMatch(/(CharlesXavier|HankPym|DavidCharlesHaller)/);
expect(anyResult.lines.length).toBeGreaterThanOrEqual(3);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -1,4 +1,4 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('item lastEntriesFilter()', () => { describe('item lastEntriesFilter()', () => {
const minDate = new Date(value); const minDate = new Date(value);
@ -7,18 +7,38 @@ describe('item lastEntriesFilter()', () => {
maxHour.setHours(23, 59, 59, 59); maxHour.setHours(23, 59, 59, 59);
it('should return one entry for a given item', async() => { it('should return one entry for a given item', async() => {
const filter = {where: {itemFk: 1, landed: {between: [minDate, maxDate]}}}; const tx = await models.Item.beginTransaction({});
const result = await app.models.Item.lastEntriesFilter(filter); const options = {transaction: tx};
expect(result.length).toEqual(1); try {
const filter = {where: {itemFk: 1, landed: {between: [minDate, maxDate]}}};
const result = await models.Item.lastEntriesFilter(filter, options);
expect(result.length).toEqual(1);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should return five entries for a given item', async() => { it('should return five entries for a given item', async() => {
minDate.setMonth(minDate.getMonth() - 2, 1); const tx = await models.Item.beginTransaction({});
const options = {transaction: tx};
const filter = {where: {itemFk: 1, landed: {between: [minDate, maxDate]}}}; try {
const result = await app.models.Item.lastEntriesFilter(filter); minDate.setMonth(minDate.getMonth() - 2, 1);
expect(result.length).toEqual(5); const filter = {where: {itemFk: 1, landed: {between: [minDate, maxDate]}}};
const result = await models.Item.lastEntriesFilter(filter, options);
expect(result.length).toEqual(5);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -1,45 +1,41 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('item new()', () => { describe('item new()', () => {
let item;
afterAll(async done => {
try {
let sql = 'DELETE FROM vn.itemLog WHERE originFk = ?';
await app.models.Item.rawSql(sql, [item.id]);
sql = 'DELETE FROM vn.item WHERE id = ?';
await app.models.Item.rawSql(sql, [item.id]);
} catch (error) {
console.error(error);
}
done();
});
it('should create a new item, adding the name as a tag', async() => { it('should create a new item, adding the name as a tag', async() => {
let itemParams = { const tx = await models.Item.beginTransaction({});
intrastatFk: 5080000, const options = {transaction: tx};
originFk: 1,
provisionalName: 'planta',
typeFk: 2,
relevancy: 0
};
item = await app.models.Item.new(itemParams);
let temporalNameTag = await app.models.Tag.findOne({where: {name: 'Nombre temporal'}});
let temporalName = await app.models.ItemTag.findOne({ try {
where: { const itemParams = {
itemFk: item.id, intrastatFk: 5080000,
tagFk: temporalNameTag.id, originFk: 1,
} provisionalName: 'planta',
}); typeFk: 2,
item = await app.models.Item.findById(item.id); relevancy: 0
};
expect(item.intrastatFk).toEqual(5080000); let item = await models.Item.new(itemParams, options);
expect(item.originFk).toEqual(1); const temporalNameTag = await models.Tag.findOne({where: {name: 'Nombre temporal'}}, options);
expect(item.typeFk).toEqual(2);
expect(item.name).toEqual('planta'); const temporalName = await models.ItemTag.findOne({
expect(temporalName.value).toEqual('planta'); where: {
itemFk: item.id,
tagFk: temporalNameTag.id,
}
}, options);
item = await models.Item.findById(item.id, null, options);
expect(item.intrastatFk).toEqual(5080000);
expect(item.originFk).toEqual(1);
expect(item.typeFk).toEqual(2);
expect(item.name).toEqual('planta');
expect(temporalName.value).toEqual('planta');
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -1,29 +1,32 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('regularize()', () => { describe('regularize()', () => {
const itemFk = 1;
const warehouseFk = 1;
const trashAddress = 11;
let trashTicket;
afterAll(async done => {
await app.models.Ticket.destroyById(trashTicket.id);
done();
});
it('should create a new ticket and add a line', async() => { it('should create a new ticket and add a line', async() => {
let ctx = {req: {accessToken: {userId: 18}}}; const tx = await models.Item.beginTransaction({});
let res = await app.models.Item.getVisibleAvailable(itemFk, warehouseFk); const options = {transaction: tx};
let visible = res.visible;
let saleQuantity = visible - 11;
let ticketFk = await app.models.Item.regularize(ctx, itemFk, 11, warehouseFk); try {
let sale = await app.models.Sale.findOne({where: {ticketFk: ticketFk}}); const ctx = {req: {accessToken: {userId: 18}}};
trashTicket = await app.models.Ticket.findById(ticketFk); const itemId = 1;
const warehouseId = 1;
const quantity = 11;
const date = undefined;
expect(sale.quantity).toEqual(saleQuantity); const res = await models.Item.getVisibleAvailable(itemId, warehouseId, date, options);
expect(sale.discount).toEqual(100);
expect(trashTicket.addressFk).toEqual(trashAddress); const visible = res.visible;
const expectedQuantity = visible - quantity;
const ticketId = await models.Item.regularize(ctx, itemId, quantity, warehouseId, options);
const sale = await models.Sale.findOne({where: {ticketFk: ticketId}}, options);
expect(sale.quantity).toEqual(expectedQuantity);
expect(sale.discount).toEqual(100);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -1,34 +1,47 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('item updateTaxes()', () => { describe('item updateTaxes()', () => {
let taxesInFixtures = [{id: 3, taxClassFk: 1}];
it('should throw an error if the taxClassFk is blank', async() => { it('should throw an error if the taxClassFk is blank', async() => {
const tx = await models.Item.beginTransaction({});
const options = {transaction: tx};
let error; let error;
let taxes = [{id: 3, taxClassFk: undefined}];
await app.models.Item.updateTaxes(taxes) try {
.catch(err => { const taxes = [{id: 3, taxClassFk: undefined}];
expect(err.message).toEqual('Tax class cannot be blank');
error = err;
});
expect(error).toBeDefined(); await models.Item.updateTaxes(taxes, options);
await tx.rollback();
} catch (e) {
await tx.rollback();
error = e;
}
expect(error.message).toEqual('Tax class cannot be blank');
}); });
it('should update the tax of a given country of an item', async() => { it('should update the tax of a given country of an item', async() => {
let taxCountry = await app.models.ItemTaxCountry.findById(3); const tx = await models.Item.beginTransaction({});
const options = {transaction: tx};
expect(taxCountry.taxClassFk).toEqual(1); try {
let taxCountry = await models.ItemTaxCountry.findById(3, null, options);
let taxes = [{id: 3, taxClassFk: 2}]; expect(taxCountry.taxClassFk).toEqual(1);
await app.models.Item.updateTaxes(taxes); const taxes = [{id: 3, taxClassFk: 2}];
taxCountry = await app.models.ItemTaxCountry.findById(3);
expect(taxCountry.taxClassFk).toEqual(2); await models.Item.updateTaxes(taxes, options);
// restores taxCountry = await models.ItemTaxCountry.findById(3, null, options);
await app.models.Item.updateTaxes(taxesInFixtures);
expect(taxCountry.taxClassFk).toEqual(2);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });

View File

@ -21,18 +21,38 @@ module.exports = Self => {
} }
}); });
Self.updateTaxes = async taxes => { Self.updateTaxes = async(taxes, options) => {
let promises = []; const myOptions = {};
for (let tax of taxes) { let tx;
if (!tax.taxClassFk)
throw new UserError('Tax class cannot be blank');
promises.push(Self.app.models.ItemTaxCountry.update( if (typeof options == 'object')
{id: tax.id}, Object.assign(myOptions, options);
{taxClassFk: tax.taxClassFk}
)); if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
try {
const promises = [];
for (let tax of taxes) {
if (!tax.taxClassFk)
throw new UserError('Tax class cannot be blank');
promises.push(Self.app.models.ItemTaxCountry.update(
{id: tax.id},
{taxClassFk: tax.taxClassFk}
), myOptions);
}
await Promise.all(promises);
if (tx) await tx.commit();
return true;
} catch (e) {
if (tx) await tx.rollback();
throw e;
} }
await Promise.all(promises);
return true;
}; };
}; };

View File

@ -3,17 +3,20 @@ const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
module.exports = Self => { module.exports = Self => {
Self.remoteMethod('filterValue', { Self.remoteMethod('filterValue', {
description: 'Returns a list of tag values', description: 'Returns a list of tag values',
accepts: [{ accepts: [
arg: 'id', {
type: 'Number', arg: 'id',
required: true, type: 'number',
description: 'The tag id', required: true,
http: {source: 'path'} description: 'The tag id',
}, { http: {source: 'path'}
arg: 'filter', },
type: 'Object', {
description: `Filter defining where, order, offset, and limit - must be a JSON-encoded string` arg: 'filter',
}], type: 'object',
description: `Filter defining where, order, offset, and limit - must be a JSON-encoded string`
}
],
returns: { returns: {
type: ['object'], type: ['object'],
root: true root: true
@ -24,11 +27,16 @@ module.exports = Self => {
} }
}); });
Self.filterValue = async(id, filter) => { Self.filterValue = async(id, filter, options) => {
const conn = Self.dataSource.connector; const conn = Self.dataSource.connector;
const tag = await Self.findById(id); const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
const tag = await Self.findById(id);
let stmt; let stmt;
if (!tag.isFree && tag.sourceTable) { if (!tag.isFree && tag.sourceTable) {
stmt = new ParameterizedSQL( stmt = new ParameterizedSQL(
`SELECT value FROM ( `SELECT value FROM (
@ -36,7 +44,7 @@ module.exports = Self => {
} else } else
stmt = new ParameterizedSQL(`SELECT value FROM itemTag`); stmt = new ParameterizedSQL(`SELECT value FROM itemTag`);
let where = filter.where; const where = filter.where;
if (where && where.value) { if (where && where.value) {
stmt.merge(conn.makeWhere({value: {like: `%${where.value}%`}})); stmt.merge(conn.makeWhere({value: {like: `%${where.value}%`}}));
stmt.merge(` stmt.merge(`
@ -46,6 +54,6 @@ module.exports = Self => {
stmt.merge(conn.makeLimit(filter)); stmt.merge(conn.makeLimit(filter));
return conn.executeStmt(stmt); return conn.executeStmt(stmt, myOptions);
}; };
}; };

View File

@ -1,37 +1,76 @@
const app = require('vn-loopback/server/server'); const models = require('vn-loopback/server/server').models;
describe('tag filterValue()', () => { describe('tag filterValue()', () => {
const colorTagId = 1; const colorTagId = 1;
it('should return a list of color values', async() => { it('should return a list of color values', async() => {
const filter = {limit: 5}; const tx = await models.Item.beginTransaction({});
const result = await app.models.Tag.filterValue(colorTagId, filter); const options = {transaction: tx};
expect(result.length).toEqual(5); try {
const filter = {limit: 5};
const result = await models.Tag.filterValue(colorTagId, filter, options);
expect(result.length).toEqual(5);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should return the values matching color "Blue"', async() => { it('should return the values matching color "Blue"', async() => {
const filter = {where: {value: 'Blue'}, limit: 5}; const tx = await models.Item.beginTransaction({});
const result = await app.models.Tag.filterValue(colorTagId, filter); const options = {transaction: tx};
expect(result.length).toEqual(2); try {
expect(result[0].value).toEqual('Blue'); const filter = {where: {value: 'Blue'}, limit: 5};
expect(result[1].value).toEqual('Blue/Silver'); const result = await models.Tag.filterValue(colorTagId, filter, options);
expect(result.length).toEqual(2);
expect(result[0].value).toEqual('Blue');
expect(result[1].value).toEqual('Blue/Silver');
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should return the values matching color "Blue/Silver"', async() => { it('should return the values matching color "Blue/Silver"', async() => {
const filter = {where: {value: 'Blue/Silver'}, limit: 5}; const tx = await models.Item.beginTransaction({});
const result = await app.models.Tag.filterValue(colorTagId, filter); const options = {transaction: tx};
expect(result.length).toEqual(1); try {
expect(result[0].value).toEqual('Blue/Silver'); const filter = {where: {value: 'Blue/Silver'}, limit: 5};
const result = await models.Tag.filterValue(colorTagId, filter, options);
expect(result.length).toEqual(1);
expect(result[0].value).toEqual('Blue/Silver');
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
it('should return the values matching color "Silver"', async() => { it('should return the values matching color "Silver"', async() => {
const filter = {where: {value: 'Silver'}, limit: 5}; const tx = await models.Item.beginTransaction({});
const result = await app.models.Tag.filterValue(colorTagId, filter); const options = {transaction: tx};
expect(result.length).toEqual(2); try {
expect(result[0].value).toEqual('Silver'); const filter = {where: {value: 'Silver'}, limit: 5};
expect(result[1].value).toEqual('Blue/Silver'); const result = await models.Tag.filterValue(colorTagId, filter, options);
expect(result.length).toEqual(2);
expect(result[0].value).toEqual('Silver');
expect(result[1].value).toEqual('Blue/Silver');
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
}); });
}); });