Merge pull request '3676-zone_delivery-days' (#891) from 3676-zone_delivery-days into dev
gitea/salix/pipeline/head This commit looks good Details

Reviewed-on: #891
Reviewed-by: Carlos Jimenez Ruiz <carlosjr@verdnatura.es>
This commit is contained in:
Carlos Jimenez Ruiz 2022-03-07 10:26:04 +00:00
commit 76b63c8c45
10 changed files with 113 additions and 83 deletions

View File

@ -40,7 +40,6 @@ module.exports = Self => {
try { try {
const salesIds = []; const salesIds = [];
const params = [];
const userId = ctx.req.accessToken.userId; const userId = ctx.req.accessToken.userId;
const isClaimManager = await Self.app.models.Account.hasRole(userId, 'claimManager'); const isClaimManager = await Self.app.models.Account.hasRole(userId, 'claimManager');
@ -50,23 +49,19 @@ module.exports = Self => {
if (!hasValidRole) if (!hasValidRole)
throw new UserError(`You don't have privileges to create pay back`); throw new UserError(`You don't have privileges to create pay back`);
sales.forEach(sale => { for (let sale of sales)
salesIds.push(sale.id); salesIds.push(sale.id);
params.push('?');
});
const paramsString = params.join();
const query = ` const query = `
DROP TEMPORARY TABLE IF EXISTS tmp.sale; DROP TEMPORARY TABLE IF EXISTS tmp.sale;
CREATE TEMPORARY TABLE tmp.sale CREATE TEMPORARY TABLE tmp.sale
SELECT s.id, s.itemFk, - s.quantity, s.concept, s.price, s.discount SELECT s.id, s.itemFk, - s.quantity, s.concept, s.price, s.discount
FROM sale s FROM sale s
WHERE s.id IN (${paramsString}); WHERE s.id IN (?);
CALL vn.ticket_doRefund(${ticketId}, @newTicket); CALL vn.ticket_doRefund(?, @newTicket);
DROP TEMPORARY TABLE tmp.sale;`; DROP TEMPORARY TABLE tmp.sale;`;
await Self.rawSql(query, salesIds, myOptions); await Self.rawSql(query, [salesIds, ticketId], myOptions);
const [newTicket] = await Self.rawSql('SELECT @newTicket id', null, myOptions); const [newTicket] = await Self.rawSql('SELECT @newTicket id', null, myOptions);
ticketId = newTicket.id; ticketId = newTicket.id;

View File

@ -35,11 +35,8 @@ module.exports = Self => {
try { try {
const salesIds = []; const salesIds = [];
const params = []; for (let sale of sales)
sales.forEach(sale => {
salesIds.push(sale.id); salesIds.push(sale.id);
params.push('?');
});
const isEditable = await models.Ticket.isEditable(ctx, sales[0].ticketFk, myOptions); const isEditable = await models.Ticket.isEditable(ctx, sales[0].ticketFk, myOptions);
if (!isEditable) if (!isEditable)
@ -49,14 +46,12 @@ module.exports = Self => {
if (!canEditSale) if (!canEditSale)
throw new UserError(`Sale(s) blocked, please contact production`); throw new UserError(`Sale(s) blocked, please contact production`);
const paramsString = params.join();
const query = ` const query = `
DROP TEMPORARY TABLE IF EXISTS tmp.recalculateSales; DROP TEMPORARY TABLE IF EXISTS tmp.recalculateSales;
CREATE TEMPORARY TABLE tmp.recalculateSales CREATE TEMPORARY TABLE tmp.recalculateSales
SELECT s.id SELECT s.id
FROM sale s FROM sale s
WHERE s.id IN (${paramsString}); WHERE s.id IN (?);
CALL vn.sale_recalcComponent(null); CALL vn.sale_recalcComponent(null);
DROP TEMPORARY TABLE tmp.recalculateSales;`; DROP TEMPORARY TABLE tmp.recalculateSales;`;

View File

@ -11,12 +11,12 @@ module.exports = Self => {
{ {
arg: 'started', arg: 'started',
type: 'date', type: 'date',
description: 'The date calendar start', description: 'The calendar date start',
}, },
{ {
arg: 'ended', arg: 'ended',
type: 'date', type: 'date',
description: 'The date calendar end', description: 'The calendar date end',
} }
], ],
returns: { returns: {

View File

@ -0,0 +1,57 @@
module.exports = Self => {
Self.remoteMethod('getZoneClosing', {
description: 'Get zone events filtered for date and prioritized by type',
accepts: [
{
arg: 'zoneIds',
type: ['number'],
description: 'The zone ids',
required: true
},
{
arg: 'date',
type: 'date',
description: 'The calendar date',
}
],
returns: {
type: 'object',
root: true
},
http: {
path: `/getZoneClosing`,
verb: 'POST'
}
});
Self.getZoneClosing = async(zoneIds, date, options) => {
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
query = `
SELECT *
FROM (
SELECT
DISTINCT z.id,
z.name,
am.name agencyModeName,
IFNULL(ze.hour, z.hour) as hour,
IFNULL(ze.price, z.price) as price
FROM vn.zone z
JOIN agencyMode am ON am.id = z.agencyModeFk
LEFT JOIN zoneEvent ze ON ze.zoneFk = z.id
WHERE
(
dated = ?
OR ? BETWEEN started AND ended
OR INSTR(weekDays, SUBSTRING(DAYNAME(?), 1, 3) ) > 0
)
AND z.id IN (?)
ORDER BY type='day' DESC, type='range' DESC, type='indefinitely' DESC) z
GROUP BY z.id`;
return Self.rawSql(query, [date, date, date, zoneIds], myOptions);
};
};

View File

@ -0,0 +1,23 @@
const models = require('vn-loopback/server/server').models;
describe('zone getZoneClosing()', () => {
it('should return closing time of zones', async() => {
const tx = await models.Zone.beginTransaction({});
try {
const options = {transaction: tx};
const date = new Date();
const today = date.toISOString().split('T')[0];
const result = await models.Zone.getZoneClosing([1, 2, 3], today, options);
expect(result.length).toEqual(3);
expect(result[0].hour).toBeDefined();
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});

View File

@ -7,6 +7,7 @@ module.exports = Self => {
require('../methods/zone/getUpcomingDeliveries')(Self); require('../methods/zone/getUpcomingDeliveries')(Self);
require('../methods/zone/deleteZone')(Self); require('../methods/zone/deleteZone')(Self);
require('../methods/zone/includingExpired')(Self); require('../methods/zone/includingExpired')(Self);
require('../methods/zone/getZoneClosing')(Self);
Self.validatesPresenceOf('agencyModeFk', { Self.validatesPresenceOf('agencyModeFk', {
message: `Agency cannot be blank` message: `Agency cannot be blank`

View File

@ -52,23 +52,15 @@
</form> </form>
</vn-side-menu> </vn-side-menu>
<vn-crud-model vn-id="zoneModel"
url="Zones"
filter="::$ctrl.filter"
limit="20"
data="zones"
auto-load="false">
</vn-crud-model>
<!-- Zone Popover --> <!-- Zone Popover -->
<vn-popover vn-id="zoneEvents"> <vn-popover vn-id="zoneEvents">
<div class="zoneEvents"> <div class="zoneEvents">
<div class="header vn-pa-sm" translate>Zones</div> <div class="header vn-pa-sm" translate>Zones</div>
<vn-data-viewer <vn-data-viewer
model="zoneModel" data="::$ctrl.zoneClosing"
class="vn-w-md vn-mb-xl"> class="vn-w-md vn-mb-xl">
<vn-card> <vn-card>
<vn-table model="zoneModel"> <vn-table>
<vn-thead> <vn-thead>
<vn-tr> <vn-tr>
<vn-th field="id" number>Id</vn-th> <vn-th field="id" number>Id</vn-th>
@ -81,7 +73,7 @@
</vn-thead> </vn-thead>
<vn-tbody> <vn-tbody>
<vn-tr <vn-tr
ng-repeat="zone in zoneModel.data" ng-repeat="zone in $ctrl.zoneClosing"
ui-sref="zone.card.summary({id: zone.id})" ui-sref="zone.card.summary({id: zone.id})"
class="clickable search-result"> class="clickable search-result">
<vn-td number>{{::zone.id}}</vn-td> <vn-td number>{{::zone.id}}</vn-td>

View File

@ -74,33 +74,14 @@ class Controller extends Section {
zonesIds.push(event.zoneFk); zonesIds.push(event.zoneFk);
this.$.zoneEvents.show($event.target); this.$.zoneEvents.show($event.target);
const zoneModel = this.$.zoneModel;
zoneModel.applyFilter({ const params = {
include: [ zonesId: zonesIds,
{ date: day
relation: 'agencyMode', };
scope: {fields: ['name']}
}, this.$http.post(`Zones/getZoneClosing`, params)
{ .then(res => this.zoneClosing = res.data);
relation: 'events',
scope: {
where: {dated: day}
}
},
],
where: {
id: {inq: zonesIds}
}
}).then(() => {
const data = zoneModel.data;
for (let row of data) {
const [event] = row.events;
if (event && event.hour)
row.hour = event.hour;
if (event && event.price)
row.price = event.price;
}
});
} }
preview(zone) { preview(zone) {

View File

@ -96,46 +96,31 @@ describe('Zone Component vnZoneDeliveryDays', () => {
expect(controller.$.zoneEvents.show).not.toHaveBeenCalled(); expect(controller.$.zoneEvents.show).not.toHaveBeenCalled();
}); });
it('should call the show() method and then call the applyFilter() method with the expected ids', () => { it('should call the show() method and call getZoneClosing() with the expected ids', () => {
const zoneModel = controller.$.zoneModel;
jest.spyOn(controller.$.zoneEvents, 'show'); jest.spyOn(controller.$.zoneEvents, 'show');
jest.spyOn(zoneModel, 'applyFilter').mockReturnValue(new Promise(resolve => {
zoneModel.data = [
{id: 1, events: [{price: 25}]}
];
}));
const event = new Event('click'); const event = new Event('click');
const target = document.createElement('div'); const target = document.createElement('div');
target.dispatchEvent(event); target.dispatchEvent(event);
const day = new Date();
const events = [ const events = [
{zoneFk: 1}, {zoneFk: 1},
{zoneFk: 2}, {zoneFk: 2},
{zoneFk: 8} {zoneFk: 8}
]; ];
const params = {
const day = new Date(); zonesId: [1, 2, 8],
controller.onSelection(event, events, [day]); date: [day][0]
const expectedFilter = {
include: [
{
relation: 'agencyMode',
scope: {fields: ['name']}
},
{
relation: 'events',
scope: {
where: {dated: day}
}
}
],
where: {
id: {inq: [1, 2, 8]}
}
}; };
const response = [{id: 1, hour: ''}];
$httpBackend.when('POST', 'Zones/getZoneClosing', params).respond({response});
controller.onSelection(event, events, [day]);
$httpBackend.flush();
expect(controller.$.zoneEvents.show).toHaveBeenCalledWith(target); expect(controller.$.zoneEvents.show).toHaveBeenCalledWith(target);
expect(zoneModel.applyFilter).toHaveBeenCalledWith(expectedFilter); expect(controller.zoneClosing.id).toEqual(response.id);
}); });
}); });
}); });

View File

@ -15,6 +15,7 @@ vn-upcoming-deliveries {
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
background-color: $color-bg;
} }
vn-table vn-th.waste-family, vn-table vn-th.waste-family,