2615 - Waste breakdown
gitea/salix/pipeline/head This commit looks good Details

This commit is contained in:
Joan Sanchez 2021-04-06 13:46:38 +02:00
parent 5ef3ff40ce
commit 65dc0e3780
17 changed files with 180 additions and 31 deletions

View File

@ -0,0 +1,24 @@
drop procedure weekWaste;
create definer = root@`%` procedure weekWaste__()
BEGIN
DECLARE vWeek INT;
DECLARE vYear INT;
SELECT week, year
INTO vWeek, vYear
FROM vn.time
WHERE dated = DATE_ADD(CURDATE(), INTERVAL -1 WEEK);
SELECT *, 100 * dwindle / total AS percentage
FROM (
SELECT buyer,
sum(saleTotal) as total,
sum(saleWaste) as dwindle
FROM bs.waste
WHERE year = vYear and week = vWeek
GROUP BY buyer
) sub
ORDER BY percentage DESC;
END;

View File

@ -0,0 +1,28 @@
drop procedure weekWaste_byWorker;
create definer = root@`%` procedure weekWaste_byWorker__(IN vWorkerFk int)
BEGIN
DECLARE vWeek INT;
DECLARE vYear INT;
SELECT week, year
INTO vWeek, vYear
FROM vn.time
WHERE dated = TIMESTAMPADD(WEEK,-1,CURDATE());
SELECT *, 100 * mermas / total as porcentaje
FROM (
SELECT ws.family,
sum(ws.saleTotal) as total,
sum(ws.saleWaste) as mermas
FROM bs.waste ws
JOIN vn.worker w ON w.user = ws.buyer
WHERE year = vYear AND week = vWeek
AND w.id = vWorkerFk
GROUP BY family
) sub
ORDER BY porcentaje DESC;
END;

View File

@ -0,0 +1,25 @@
drop procedure weekWaste_getDetail;
create definer = root@`%` procedure weekWaste_getDetail__()
BEGIN
DECLARE vLastWeek DATE;
DECLARE vWeek INT;
DECLARE vYear INT;
SET vLastWeek = TIMESTAMPADD(WEEK,-1,CURDATE());
SET vYear = YEAR(vLastWeek);
SET vWeek = WEEK(vLastWeek, 1);
SELECT *, 100 * dwindle / total AS percentage
FROM (
SELECT buyer,
ws.family,
sum(ws.saleTotal) AS total,
sum(ws.saleWaste) AS dwindle
FROM bs.waste ws
WHERE year = vYear AND week = vWeek
GROUP BY buyer, family
) sub
ORDER BY percentage DESC;
END;

View File

@ -14,3 +14,9 @@ ALTER TABLE `bs`.`waste`
FOREIGN KEY (itemFk) REFERENCES vn.item (id) FOREIGN KEY (itemFk) REFERENCES vn.item (id)
ON UPDATE CASCADE; ON UPDATE CASCADE;
ALTER TABLE `bs`.`waste` DROP PRIMARY KEY;
ALTER TABLE `bs`.`waste`
AD PRIMARY KEY (buyer, year, week, family, itemFk);

View File

@ -28,7 +28,7 @@ BEGIN
FROM vn.saleValue FROM vn.saleValue
where year = vYear and week = vWeek where year = vYear and week = vWeek
GROUP BY family GROUP BY family, itemFk
) sub ) sub
ORDER BY mermas DESC; ORDER BY mermas DESC;

View File

@ -77,9 +77,10 @@ class Controller extends Section {
if (sampleType.hasCompany) if (sampleType.hasCompany)
params.companyId = this.clientSample.companyFk; params.companyId = this.clientSample.companyFk;
if (isPreview) params.isPreview = true; let query = `email/${sampleType.code}`;
if (isPreview)
query = `email/${sampleType.code}/preview`;
const query = `email/${sampleType.code}`;
this.$http.get(query, {params}).then(cb); this.$http.get(query, {params}).then(cb);
} }
} }

View File

@ -2,7 +2,20 @@ module.exports = Self => {
Self.remoteMethod('getWasteByItem', { Self.remoteMethod('getWasteByItem', {
description: 'Returns the details of losses by worker', description: 'Returns the details of losses by worker',
accessType: 'READ', accessType: 'READ',
accepts: [], accepts: [
{
arg: 'buyer',
type: 'string',
required: true,
description: 'The buyer name'
},
{
arg: 'family',
type: 'string',
required: true,
description: 'The item family name'
}
],
returns: { returns: {
type: ['Object'], type: ['Object'],
root: true root: true
@ -13,20 +26,22 @@ module.exports = Self => {
} }
}); });
Self.getWasteByItem = async() => { Self.getWasteByItem = async(buyer, family) => {
const wastes = await Self.rawSql(` const wastes = await Self.rawSql(`
SELECT *, 100 * dwindle / total AS percentage SELECT *, 100 * dwindle / total AS percentage
FROM ( FROM (
SELECT buyer, SELECT buyer,
ws.family, ws.family,
ws.itemFk,
sum(ws.saleTotal) AS total, sum(ws.saleTotal) AS total,
sum(ws.saleWaste) AS dwindle sum(ws.saleWaste) AS dwindle
FROM bs.waste ws FROM bs.waste ws
WHERE year = YEAR(TIMESTAMPADD(WEEK,-1,CURDATE())) WHERE buyer = ? AND family = ?
AND week = WEEK(TIMESTAMPADD(WEEK,-1,CURDATE()), 1) AND year = YEAR(TIMESTAMPADD(WEEK,-1,CURDATE()))
AND week = WEEK(TIMESTAMPADD(WEEK,-1,CURDATE()), 1)
GROUP BY buyer, itemFk GROUP BY buyer, itemFk
) sub ) sub
ORDER BY percentage DESC`); ORDER BY family, percentage DESC`, [buyer, family]);
const details = []; const details = [];
@ -40,6 +55,7 @@ module.exports = Self => {
if (!buyerDetail) { if (!buyerDetail) {
buyerDetail = { buyerDetail = {
buyer: buyerName, buyer: buyerName,
family: waste.family,
lines: [] lines: []
}; };
details.push(buyerDetail); details.push(buyerDetail);

View File

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

View File

@ -1,8 +1,8 @@
const app = require('vn-loopback/server/server'); const app = require('vn-loopback/server/server');
describe('item getWasteDetail()', () => { 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.getWasteDetail(); const result = await app.models.Item.getWasteByWorker();
const length = result.length; const length = result.length;
const anyResult = result[Math.floor(Math.random() * Math.floor(length))]; const anyResult = result[Math.floor(Math.random() * Math.floor(length))];

View File

@ -64,3 +64,4 @@ Item diary: Registro de compra-venta
Last entries: Últimas entradas Last entries: Últimas entradas
Tags: Etiquetas Tags: Etiquetas
Waste breakdown: Desglose de mermas Waste breakdown: Desglose de mermas
Waste breakdown by item: Desglose de mermas por artículo

View File

@ -168,10 +168,10 @@
"acl": ["buyer"] "acl": ["buyer"]
}, },
{ {
"url" : "/detail", "url" : "/detail?buyer&family",
"state": "item.waste.detail", "state": "item.waste.detail",
"component": "vn-item-waste-detail", "component": "vn-item-waste-detail",
"description": "Waste breakdown by type", "description": "Waste breakdown by item",
"acl": ["buyer"] "acl": ["buyer"]
}, },
{ {

View File

@ -1,18 +1,24 @@
<vn-crud-model auto-load="true" <vn-crud-model auto-load="true"
vn-id="model" vn-id="model"
url="Items/getWasteByItem" url="Items/getWasteByItem"
params="$ctrl.$params"
data="details"> data="details">
</vn-crud-model> </vn-crud-model>
<vn-data-viewer model="model"> <vn-data-viewer model="model">
<vn-card> <vn-card class="vn-w-md">
<section ng-repeat="detail in details" class="vn-pa-md"> <section ng-repeat="detail in details" class="vn-pa-md">
<vn-horizontal class="header"> <vn-horizontal class="header">
<h5><span translate>{{detail.buyer}}</span></h5> <h5>
<a ui-sref="item.waste.index">
< <span translate>Back</span>
</a>
- <span>{{detail.family}} ({{detail.buyer}})</span>
</h5>
</vn-horizontal> </vn-horizontal>
<vn-table> <vn-table>
<vn-thead> <vn-thead>
<vn-tr> <vn-tr>
<vn-th class="waste-family">Family</vn-th> <vn-th shrink>Item</vn-th>
<vn-th number>Percentage</vn-th> <vn-th number>Percentage</vn-th>
<vn-th number>Dwindle</vn-th> <vn-th number>Dwindle</vn-th>
<vn-th number>Total</vn-th> <vn-th number>Total</vn-th>
@ -20,7 +26,13 @@
</vn-thead> </vn-thead>
<vn-tbody> <vn-tbody>
<vn-tr ng-repeat="waste in detail.lines"> <vn-tr ng-repeat="waste in detail.lines">
<vn-td class="waste-family">{{::waste.family}}</vn-td> <vn-td shrink>
<span
ng-click="descriptor.show($event, waste.itemFk)"
class="link">
{{::waste.itemFk}}
</span>
</vn-td>
<vn-td number>{{::(waste.percentage / 100) | percentage: 2}}</vn-td> <vn-td number>{{::(waste.percentage / 100) | percentage: 2}}</vn-td>
<vn-td number>{{::waste.dwindle | currency: 'EUR'}}</vn-td> <vn-td number>{{::waste.dwindle | currency: 'EUR'}}</vn-td>
<vn-td number>{{::waste.total | currency: 'EUR'}}</vn-td> <vn-td number>{{::waste.total | currency: 'EUR'}}</vn-td>
@ -30,3 +42,6 @@
</section> </section>
</vn-card> </vn-card>
</vn-data-viewer> </vn-data-viewer>
<vn-item-descriptor-popover
vn-id="descriptor">
</vn-item-descriptor-popover>

View File

@ -8,7 +8,7 @@
<vn-card> <vn-card>
<section ng-repeat="detail in details" class="vn-pa-md"> <section ng-repeat="detail in details" class="vn-pa-md">
<vn-horizontal class="header"> <vn-horizontal class="header">
<h5><span translate>{{detail.buyer}}</span></h5> <h5><span><span translate>{{detail.buyer}}</span></h5>
</vn-horizontal> </vn-horizontal>
<vn-table> <vn-table>
<vn-thead> <vn-thead>
@ -21,7 +21,7 @@
</vn-thead> </vn-thead>
<vn-tbody> <vn-tbody>
<a ng-repeat="waste in detail.lines" class="clickable vn-tr" <a ng-repeat="waste in detail.lines" class="clickable vn-tr"
ui-sref="item.waste.detail({id: item.id})" > ui-sref="item.waste.detail({buyer: waste.buyer, family: waste.family})" >
<vn-td class="waste-family">{{::waste.family}}</vn-td> <vn-td class="waste-family">{{::waste.family}}</vn-td>
<vn-td number>{{::(waste.percentage / 100) | percentage: 2}}</vn-td> <vn-td number>{{::(waste.percentage / 100) | percentage: 2}}</vn-td>
<vn-td number>{{::waste.dwindle | currency: 'EUR'}}</vn-td> <vn-td number>{{::waste.dwindle | currency: 'EUR'}}</vn-td>

View File

@ -6,7 +6,7 @@ const imageSrc = {
getEmailSrc(image) { getEmailSrc(image) {
let src = `cid:${image}`; let src = `cid:${image}`;
if (this.isPreview === 'true') if (this.isPreview)
src = `/api/${this.$options.name}/assets/images/${image}`; src = `/api/${this.$options.name}/assets/images/${image}`;
return src; return src;

View File

@ -6,17 +6,26 @@ module.exports = app => {
const reportName = req.params.name; const reportName = req.params.name;
const email = new Email(reportName, req.args); const email = new Email(reportName, req.args);
if (req.args.isPreview === 'true') { await email.send();
const rendered = await email.render();
res.send(rendered); res.status(200).json({
} else { message: 'Sent'
await email.send(); });
} catch (e) {
next(e);
}
});
res.status(200).json({ app.get(`/api/email/:name/preview`, async(req, res, next) => {
message: 'Sent' try {
}); const reportName = req.params.name;
} const args = req.args;
args.isPreview = true;
const email = new Email(reportName, args);
const rendered = await email.render();
res.send(rendered);
} catch (e) { } catch (e) {
next(e); next(e);
} }

View File

@ -1,5 +1,4 @@
const Component = require(`${appPath}/core/component`); const Component = require(`${appPath}/core/component`);
const db = require(`${appPath}/core/database`);
const emailHeader = new Component('email-header'); const emailHeader = new Component('email-header');
const emailFooter = new Component('email-footer'); const emailFooter = new Component('email-footer');
@ -20,7 +19,7 @@ module.exports = {
}, },
methods: { methods: {
fetchWastes() { fetchWastes() {
return db.findOne(`CALL bs.weekWaste()`); return this.rawSqlFromDef('wasteWeekly');
} }
}, },
components: { components: {

View File

@ -0,0 +1,11 @@
SELECT *, 100 * dwindle / total AS percentage
FROM (
SELECT buyer,
sum(saleTotal) as total,
sum(saleWaste) as dwindle
FROM bs.waste w
JOIN vn.time t ON w.year = t.year AND w.week = t.week
WHERE t.dated = DATE_ADD(CURDATE(), INTERVAL -1 WEEK)
GROUP BY buyer
) sub
ORDER BY percentage DESC;