2615 - Waste breakdown
gitea/salix/pipeline/head This commit looks good
Details
gitea/salix/pipeline/head This commit looks good
Details
This commit is contained in:
parent
5ef3ff40ce
commit
65dc0e3780
|
@ -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;
|
||||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
|
|
@ -14,3 +14,9 @@ ALTER TABLE `bs`.`waste`
|
|||
FOREIGN KEY (itemFk) REFERENCES vn.item (id)
|
||||
ON UPDATE CASCADE;
|
||||
|
||||
ALTER TABLE `bs`.`waste` DROP PRIMARY KEY;
|
||||
|
||||
ALTER TABLE `bs`.`waste`
|
||||
AD PRIMARY KEY (buyer, year, week, family, itemFk);
|
||||
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ BEGIN
|
|||
FROM vn.saleValue
|
||||
where year = vYear and week = vWeek
|
||||
|
||||
GROUP BY family
|
||||
GROUP BY family, itemFk
|
||||
|
||||
) sub
|
||||
ORDER BY mermas DESC;
|
||||
|
|
|
@ -77,9 +77,10 @@ class Controller extends Section {
|
|||
if (sampleType.hasCompany)
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,20 @@ module.exports = Self => {
|
|||
Self.remoteMethod('getWasteByItem', {
|
||||
description: 'Returns the details of losses by worker',
|
||||
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: {
|
||||
type: ['Object'],
|
||||
root: true
|
||||
|
@ -13,20 +26,22 @@ module.exports = Self => {
|
|||
}
|
||||
});
|
||||
|
||||
Self.getWasteByItem = async() => {
|
||||
Self.getWasteByItem = async(buyer, family) => {
|
||||
const wastes = await Self.rawSql(`
|
||||
SELECT *, 100 * dwindle / total AS percentage
|
||||
FROM (
|
||||
SELECT buyer,
|
||||
ws.family,
|
||||
ws.itemFk,
|
||||
sum(ws.saleTotal) AS total,
|
||||
sum(ws.saleWaste) AS dwindle
|
||||
FROM bs.waste ws
|
||||
WHERE year = YEAR(TIMESTAMPADD(WEEK,-1,CURDATE()))
|
||||
WHERE buyer = ? AND family = ?
|
||||
AND year = YEAR(TIMESTAMPADD(WEEK,-1,CURDATE()))
|
||||
AND week = WEEK(TIMESTAMPADD(WEEK,-1,CURDATE()), 1)
|
||||
GROUP BY buyer, itemFk
|
||||
) sub
|
||||
ORDER BY percentage DESC`);
|
||||
ORDER BY family, percentage DESC`, [buyer, family]);
|
||||
|
||||
const details = [];
|
||||
|
||||
|
@ -40,6 +55,7 @@ module.exports = Self => {
|
|||
if (!buyerDetail) {
|
||||
buyerDetail = {
|
||||
buyer: buyerName,
|
||||
family: waste.family,
|
||||
lines: []
|
||||
};
|
||||
details.push(buyerDetail);
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
|
@ -1,8 +1,8 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
|
||||
describe('item getWasteDetail()', () => {
|
||||
describe('Item getWasteByWorker()', () => {
|
||||
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 anyResult = result[Math.floor(Math.random() * Math.floor(length))];
|
|
@ -64,3 +64,4 @@ Item diary: Registro de compra-venta
|
|||
Last entries: Últimas entradas
|
||||
Tags: Etiquetas
|
||||
Waste breakdown: Desglose de mermas
|
||||
Waste breakdown by item: Desglose de mermas por artículo
|
|
@ -168,10 +168,10 @@
|
|||
"acl": ["buyer"]
|
||||
},
|
||||
{
|
||||
"url" : "/detail",
|
||||
"url" : "/detail?buyer&family",
|
||||
"state": "item.waste.detail",
|
||||
"component": "vn-item-waste-detail",
|
||||
"description": "Waste breakdown by type",
|
||||
"description": "Waste breakdown by item",
|
||||
"acl": ["buyer"]
|
||||
},
|
||||
{
|
||||
|
|
|
@ -1,18 +1,24 @@
|
|||
<vn-crud-model auto-load="true"
|
||||
vn-id="model"
|
||||
url="Items/getWasteByItem"
|
||||
params="$ctrl.$params"
|
||||
data="details">
|
||||
</vn-crud-model>
|
||||
<vn-data-viewer model="model">
|
||||
<vn-card>
|
||||
<vn-card class="vn-w-md">
|
||||
<section ng-repeat="detail in details" class="vn-pa-md">
|
||||
<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-table>
|
||||
<vn-thead>
|
||||
<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>Dwindle</vn-th>
|
||||
<vn-th number>Total</vn-th>
|
||||
|
@ -20,7 +26,13 @@
|
|||
</vn-thead>
|
||||
<vn-tbody>
|
||||
<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.dwindle | currency: 'EUR'}}</vn-td>
|
||||
<vn-td number>{{::waste.total | currency: 'EUR'}}</vn-td>
|
||||
|
@ -30,3 +42,6 @@
|
|||
</section>
|
||||
</vn-card>
|
||||
</vn-data-viewer>
|
||||
<vn-item-descriptor-popover
|
||||
vn-id="descriptor">
|
||||
</vn-item-descriptor-popover>
|
|
@ -8,7 +8,7 @@
|
|||
<vn-card>
|
||||
<section ng-repeat="detail in details" class="vn-pa-md">
|
||||
<vn-horizontal class="header">
|
||||
<h5><span translate>{{detail.buyer}}</span></h5>
|
||||
<h5><span><span translate>{{detail.buyer}}</span></h5>
|
||||
</vn-horizontal>
|
||||
<vn-table>
|
||||
<vn-thead>
|
||||
|
@ -21,7 +21,7 @@
|
|||
</vn-thead>
|
||||
<vn-tbody>
|
||||
<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 number>{{::(waste.percentage / 100) | percentage: 2}}</vn-td>
|
||||
<vn-td number>{{::waste.dwindle | currency: 'EUR'}}</vn-td>
|
||||
|
|
|
@ -6,7 +6,7 @@ const imageSrc = {
|
|||
getEmailSrc(image) {
|
||||
let src = `cid:${image}`;
|
||||
|
||||
if (this.isPreview === 'true')
|
||||
if (this.isPreview)
|
||||
src = `/api/${this.$options.name}/assets/images/${image}`;
|
||||
|
||||
return src;
|
||||
|
|
|
@ -6,17 +6,26 @@ module.exports = app => {
|
|||
const reportName = req.params.name;
|
||||
const email = new Email(reportName, req.args);
|
||||
|
||||
if (req.args.isPreview === 'true') {
|
||||
const rendered = await email.render();
|
||||
|
||||
res.send(rendered);
|
||||
} else {
|
||||
await email.send();
|
||||
|
||||
res.status(200).json({
|
||||
message: 'Sent'
|
||||
});
|
||||
} catch (e) {
|
||||
next(e);
|
||||
}
|
||||
});
|
||||
|
||||
app.get(`/api/email/:name/preview`, async(req, res, next) => {
|
||||
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) {
|
||||
next(e);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
const Component = require(`${appPath}/core/component`);
|
||||
const db = require(`${appPath}/core/database`);
|
||||
const emailHeader = new Component('email-header');
|
||||
const emailFooter = new Component('email-footer');
|
||||
|
||||
|
@ -20,7 +19,7 @@ module.exports = {
|
|||
},
|
||||
methods: {
|
||||
fetchWastes() {
|
||||
return db.findOne(`CALL bs.weekWaste()`);
|
||||
return this.rawSqlFromDef('wasteWeekly');
|
||||
}
|
||||
},
|
||||
components: {
|
||||
|
|
|
@ -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;
|
Loading…
Reference in New Issue