Merge pull request '7648_myEntries' (!2744) from 7648_myEntries into master
gitea/salix/pipeline/head This commit looks good Details

Reviewed-on: #2744
Reviewed-by: Javi Gallego <jgallego@verdnatura.es>
Reviewed-by: Alex Moreno <alexm@verdnatura.es>
This commit is contained in:
Javier Segarra 2024-07-19 10:27:39 +00:00
commit 3d20908a42
13 changed files with 251 additions and 63 deletions

View File

@ -314,5 +314,4 @@ INSERT INTO mysql.roles_mapping (`User`, `Host`, `Role`, `Admin_option`)
SELECT SUBSTR(`User`, @prefixLen + 1), `Host`, `Role`, `Admin_option`
FROM mysql.roles_mapping
WHERE `User` LIKE @prefixedLike AND `Host` = @genRoleHost;
FLUSH PRIVILEGES;

View File

@ -118,7 +118,7 @@ INSERT INTO `hedera`.`tpvConfig`(`id`, `currency`, `terminal`, `transactionType`
INSERT INTO `account`.`user`(`id`,`name`,`nickname`, `password`,`role`,`active`,`email`,`lang`, `image`)
VALUES
(1101, 'brucewayne', 'Bruce Wayne', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 2, 1, 'BruceWayne@mydomain.com', 'es','1101'),
(1102, 'petterparker', 'Petter Parker', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 2, 1, 'PetterParker@mydomain.com', 'en','1102'),
(1102, 'petterparker', 'Petter Parker', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 131, 1, 'PetterParker@mydomain.com', 'en','1102'),
(1103, 'clarkkent', 'Clark Kent', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 2, 1, 'ClarkKent@mydomain.com', 'fr','1103'),
(1104, 'tonystark', 'Tony Stark', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 2, 1, 'TonyStark@mydomain.com', 'es','1104'),
(1105, 'maxeisenhardt', 'Max Eisenhardt', '$2b$10$UzQHth.9UUQ1T5aiQJ21lOU0oVlbxoqH4PFM9V8T90KNSAcg0eEL2', 2, 1, 'MaxEisenhardt@mydomain.com', 'pt','1105'),
@ -1477,7 +1477,8 @@ INSERT INTO `vn`.`travel`(`id`,`shipped`, `landed`, `warehouseInFk`, `warehouseO
(5, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 3, 3, 1, 50.00, 500, 'fifth travel', 1, 1, 5),
(6, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 4, 4, 1, 50.00, 500, 'sixth travel', 1, 2, 6),
(7, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 5, 4, 1, 50.00, 500, 'seventh travel', 2, 1, 7),
(8, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 5, 1, 1, 50.00, 500, 'eight travel', 1, 2, 10);
(8, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 5, 1, 1, 50.00, 500, 'eight travel', 1, 2, 10),
(10, DATE_ADD(util.VN_CURDATE(), INTERVAL + 5 DAY), DATE_ADD(util.VN_CURDATE(), INTERVAL + 5 DAY), 5, 1, 1, 50.00, 500, 'nineth travel', 1, 2, 10);
INSERT INTO `vn`.`entry`(`id`, `supplierFk`, `created`, `travelFk`, `isConfirmed`, `companyFk`, `invoiceNumber`, `reference`, `isExcludedFromAvailable`, `isRaid`, `evaNotes`)
VALUES
@ -1488,7 +1489,9 @@ INSERT INTO `vn`.`entry`(`id`, `supplierFk`, `created`, `travelFk`, `isConfirmed
(5, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 5, 0, 442, 'IN2005', 'Movement 5', 0, 0, 'observation five'),
(6, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 6, 0, 442, 'IN2006', 'Movement 6', 0, 0, 'observation six'),
(7, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 7, 0, 442, 'IN2007', 'Movement 7', 0, 0, 'observation seven'),
(8, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 7, 0, 442, 'IN2008', 'Movement 8', 1, 1, '');
(8, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 7, 0, 442, 'IN2008', 'Movement 8', 1, 1, ''),
(9, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL +2 DAY), 10, 0, 442, 'IN2009', 'Movement 9', 1, 1, ''),
(10, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL +2 DAY), 10, 0, 442, 'IN2009', 'Movement 9', 1, 1, '');
INSERT INTO `bs`.`waste`(`buyer`, `year`, `week`, `family`, `itemFk`, `itemTypeFk`, `saleTotal`, `saleWaste`, `rate`)
VALUES

View File

@ -0,0 +1,15 @@
INSERT IGNORE INTO salix.ACL (`model`,`property`,`accessType`,`permission`,`principalType`,`principalId`)
VALUES ('Entry','filter','READ','ALLOW','ROLE','supplier');
INSERT IGNORE INTO salix.ACL (`model`,`property`,`accessType`,`permission`,`principalType`,`principalId`)
VALUES ('Entry','getBuys','READ','ALLOW','ROLE','supplier');
INSERT IGNORE INTO salix.ACL (`model`,`property`,`accessType`,`permission`,`principalType`,`principalId`)
VALUES ('Entry','buyLabel','READ','ALLOW','ROLE','supplier');
UPDATE salix.ACL
SET principalId='$authenticated'
WHERE id=(SELECT id FROM salix.ACL WHERE model='StarredModule' and property='*' and `accessType`='*' );

View File

@ -29,7 +29,8 @@ module.exports = Self => {
http: {
path: '/:id/buy-label',
verb: 'GET'
}
},
accessScopes: ['DEFAULT', 'read:multimedia']
});
Self.buyLabel = (ctx, id) => Self.printReport(ctx, id, 'buy-label');

View File

@ -95,6 +95,11 @@ module.exports = Self => {
arg: 'to',
type: 'date',
description: `The to date filter`
},
{
arg: 'days',
type: 'number',
description: `N days interval`
}
],
returns: {
@ -112,7 +117,6 @@ module.exports = Self => {
if (typeof options == 'object')
Object.assign(myOptions, options);
const conn = Self.dataSource.connector;
const where = buildFilter(ctx.args, (param, value) => {
switch (param) {
@ -146,7 +150,13 @@ module.exports = Self => {
}
});
filter = mergeFilters(ctx.args.filter, {where});
const userId = ctx.req.accessToken.userId;
const client = await Self.app.models.Client.findById(userId, myOptions);
const supplier = await Self.app.models.Supplier.findOne({where: {nif: client.fi}}, myOptions);
if (supplier) {
if (!filter.where) filter.where = {};
filter.where[`e.supplierFk`] = supplier.id;
}
const stmts = [];
let stmt;
stmt = new ParameterizedSQL(
@ -158,7 +168,7 @@ module.exports = Self => {
e.invoiceNumber,
e.isBooked,
e.isExcludedFromAvailable,
e.evaNotes AS observation,
e.evaNotes observation,
e.isConfirmed,
e.isOrdered,
e.isRaid,
@ -170,17 +180,32 @@ module.exports = Self => {
e.gestDocFk,
e.invoiceInFk,
t.landed,
s.name AS supplierName,
s.nickname AS supplierAlias,
co.code AS companyCode,
cu.code AS currencyCode
s.name supplierName,
s.nickname supplierAlias,
co.code companyCode,
cu.code currencyCode,
t.shipped,
t.landed,
t.ref AS travelRef,
t.warehouseInFk,
w.name warehouseInName
FROM vn.entry e
JOIN vn.supplier s ON s.id = e.supplierFk
JOIN vn.travel t ON t.id = e.travelFk
JOIN vn.warehouse w ON w.id = t.warehouseInFk
JOIN vn.company co ON co.id = e.companyFk
JOIN vn.currency cu ON cu.id = e.currencyFk`
);
if (ctx.args.days) {
stmt.merge({
sql: `
AND t.shipped <= util.VN_CURDATE() + INTERVAL ? DAY
AND t.shipped >= util.VN_CURDATE()
`,
params: [ctx.args.days]
});
}
stmt.merge(conn.makeSuffix(filter));
const itemsIndex = stmts.push(stmt) - 1;

View File

@ -1,7 +1,8 @@
const UserError = require('vn-loopback/util/user-error');
const mergeFilters = require('vn-loopback/util/filter').mergeFilters;
module.exports = Self => {
Self.remoteMethod('getBuys', {
Self.remoteMethodCtx('getBuys', {
description: 'Returns buys for one entry',
accessType: 'READ',
accepts: [{
@ -27,13 +28,20 @@ module.exports = Self => {
}
});
Self.getBuys = async(id, filter, options) => {
Self.getBuys = async(ctx, id, filter, options) => {
const userId = ctx.req.accessToken.userId;
const models = Self.app.models;
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
const client = await Self.app.models.Client.findById(userId, myOptions);
const supplier = await Self.app.models.Supplier.findOne({where: {nif: client.fi}}, myOptions);
if (supplier) {
const isEntryOwner = (await Self.findById(id)).supplierFk === supplier.id;
if (!isEntryOwner) throw new UserError('Access Denied');
}
let defaultFilter = {
where: {entryFk: id},
fields: [
@ -49,9 +57,23 @@ module.exports = Self => {
'buyingValue',
'price2',
'price3',
'printedStickers'
'printedStickers',
'entryFk'
],
include: {
include: [{
relation: 'entry',
scope: {
fields: [
'id', 'supplierFk'
],
include: {
relation: 'supplier', scope: {
fields: ['id']
}
}
}
},
{
relation: 'item',
scope: {
fields: [
@ -82,9 +104,8 @@ module.exports = Self => {
}
}
}
}
}]
};
defaultFilter = mergeFilters(defaultFilter, filter);
return models.Buy.find(defaultFilter, myOptions);

View File

@ -9,7 +9,8 @@ describe('Entry filter()', () => {
const ctx = {
args: {
search: 1
}
},
req: {accessToken: {userId: 9}}
};
const result = await models.Entry.filter(ctx, options);
@ -32,12 +33,13 @@ describe('Entry filter()', () => {
const ctx = {
args: {
currencyFk: 1
}
},
req: {accessToken: {userId: 9}}
};
const result = await models.Entry.filter(ctx, options);
expect(result.length).toEqual(9);
expect(result.length).toEqual(11);
await tx.rollback();
} catch (e) {
@ -46,26 +48,73 @@ describe('Entry filter()', () => {
}
});
it('should return the entry matching the supplier', async() => {
const tx = await models.Entry.beginTransaction({});
const options = {transaction: tx};
describe('should return the entry matching the supplier', () => {
it('when userId is supplier ', async() => {
const tx = await models.Entry.beginTransaction({});
const options = {transaction: tx};
try {
const ctx = {
args: {
supplierFk: 2
}
};
try {
const ctx = {
args: {days: 6},
req: {accessToken: {userId: 1102}}
};
const result = await models.Entry.filter(ctx, options);
const result = await models.Entry.filter(ctx, options);
expect(result.length).toEqual(6);
expect(result.length).toEqual(2);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('when userId is supplier fetching other supplier', async() => {
const tx = await models.Entry.beginTransaction({});
const options = {transaction: tx};
try {
const ctx = {
args: {
supplierFk: 1
},
req: {accessToken: {userId: 1102}}
};
const result = await models.Entry.filter(ctx, options);
expect(result.length).toEqual(8);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('when userId is not supplier', async() => {
const tx = await models.Entry.beginTransaction({});
const options = {transaction: tx};
try {
const ctx = {
args: {
supplierFk: 2
},
req: {accessToken: {userId: 9}}
};
const result = await models.Entry.filter(ctx, options);
expect(result.length).toEqual(8);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});
it('should return the entry matching the company', async() => {
@ -76,12 +125,13 @@ describe('Entry filter()', () => {
const ctx = {
args: {
companyFk: 442
}
},
req: {accessToken: {userId: 9}}
};
const result = await models.Entry.filter(ctx, options);
expect(result.length).toEqual(8);
expect(result.length).toEqual(10);
await tx.rollback();
} catch (e) {
@ -98,7 +148,8 @@ describe('Entry filter()', () => {
const ctx = {
args: {
isBooked: true,
}
},
req: {accessToken: {userId: 9}}
};
const result = await models.Entry.filter(ctx, options);
@ -121,7 +172,8 @@ describe('Entry filter()', () => {
args: {
reference: 'movement',
travelFk: '2'
}
},
req: {accessToken: {userId: 9}}
};
const result = await models.Entry.filter(ctx, options);

View File

@ -1,24 +1,82 @@
const UserError = require('vn-loopback/util/user-error');
const models = require('vn-loopback/server/server').models;
describe('entry getBuys()', () => {
const entryId = 4;
it('should get the buys and items of an entry', async() => {
const tx = await models.Entry.beginTransaction({});
const options = {transaction: tx};
describe('should get the buys and items of an entry ', () => {
it('when is supplier and entry owner', async() => {
const tx = await models.Entry.beginTransaction({});
const options = {transaction: tx};
try {
const result = await models.Entry.getBuys(entryId, options);
try {
const ctx = {
args: {
search: 1
},
req: {accessToken: {userId: 2}}
};
const length = result.length;
const anyResult = result[Math.floor(Math.random() * Math.floor(length))];
const result = await models.Entry.getBuys(ctx, entryId, options);
expect(result.length).toEqual(4);
expect(anyResult.item).toBeDefined();
const length = result.length;
const anyResult = result[Math.floor(Math.random() * Math.floor(length))];
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
expect(result.length).toEqual(4);
expect(anyResult.item).toBeDefined();
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('when is supplier but not entry owner', async() => {
const tx = await models.Entry.beginTransaction({});
const options = {transaction: tx};
const entryId = 1;
try {
const ctx = {
args: {
search: 1
},
req: {accessToken: {userId: 1102}}
};
const result = await models.Entry.getBuys(ctx, entryId, options);
expect(result).toBeUndefined();
} catch (error) {
expect(error).toBeInstanceOf(UserError);
expect(error.message).toBe('Access Denied');
}
});
it('when is not supplier', async() => {
const tx = await models.Entry.beginTransaction({});
const options = {transaction: tx};
try {
const ctx = {
args: {
search: 1
},
req: {accessToken: {userId: 9}}
};
const result = await models.Entry.getBuys(ctx, entryId, options);
const length = result.length;
const anyResult = result[Math.floor(Math.random() * Math.floor(length))];
expect(result.length).toEqual(4);
expect(anyResult.item).toBeDefined();
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});
});

View File

@ -79,7 +79,7 @@ describe('Travel extraCommunityFilter()', () => {
const result = await app.models.Travel.extraCommunityFilter(ctx, filter);
expect(result.length).toEqual(8);
expect(result.length).toEqual(9);
});
it('should return the travel matching "cargoSupplierFk"', async() => {
@ -110,6 +110,6 @@ describe('Travel extraCommunityFilter()', () => {
const result = await app.models.Travel.extraCommunityFilter(ctx, filter);
expect(result.length).toEqual(1);
expect(result.length).toEqual(2);
});
});

View File

@ -50,7 +50,7 @@ describe('Travel filter()', () => {
const result = await app.models.Travel.filter(ctx);
expect(result.length).toEqual(5);
expect(result.length).toEqual(6);
});
it('should return the routes matching "shipped from" and "shipped to"', async() => {
@ -80,6 +80,6 @@ describe('Travel filter()', () => {
const result = await app.models.Travel.filter(ctx);
expect(result.length).toEqual(5);
expect(result.length).toEqual(6);
});
});

View File

@ -59,7 +59,7 @@
<tr>
<td colspan="3" class="barcode">
<div v-html="getBarcode(buy.id)"></div>
<span>{{buy.id}}</span>
<span>{{buy.itemFk}}</span>
</td>
</tr>
<tr>

View File

@ -7,7 +7,7 @@ module.exports = {
name: 'buy-label',
mixins: [vnReport],
async serverPrefetch() {
this.buys = await this.rawSqlFromDef('buys', [this.id]);
this.buys = await this.rawSqlFromDef('buys', [this.id, this.id]);
this.maxLabelNum = Math.max(...this.buys.map(buy => buy.labelNum));
const date = new Date();
this.weekNum = moment(date).isoWeek();

View File

@ -1,4 +1,15 @@
SELECT ROW_NUMBER() OVER(ORDER BY b.id) labelNum,
WITH RECURSIVE numbers AS (
SELECT 1 n
UNION ALL
SELECT n + 1
FROM numbers
WHERE n < (
SELECT MAX(stickers)
FROM buy
WHERE entryFk = ?
)
)
SELECT ROW_NUMBER() OVER(ORDER BY b.id, num.n) labelNum,
i.name,
i.`size`,
i.category,
@ -8,10 +19,13 @@ SELECT ROW_NUMBER() OVER(ORDER BY b.id) labelNum,
b.`grouping`,
i.stems,
b.id,
b.itemFk,
p.name producer
FROM buy b
JOIN item i ON i.id = b.itemFk
LEFT JOIN producer p ON p.id = i.producerFk
LEFT JOIN ink ON ink.id = i.inkFk
LEFT JOIN origin o ON o.id = i.originFk
WHERE b.entryFk = ?
JOIN numbers num
WHERE b.entryFk = ?
AND num.n <= b.stickers