diff --git a/db/changes/10180-holyWeek/00-time_createTable.sql b/db/changes/10180-holyWeek/00-time_createTable.sql new file mode 100644 index 000000000..62b60c4bf --- /dev/null +++ b/db/changes/10180-holyWeek/00-time_createTable.sql @@ -0,0 +1,20 @@ +USE `util`; +DROP procedure IF EXISTS `time_createTable`; + +DELIMITER $$ +USE `util`$$ +CREATE DEFINER=`root`@`%` PROCEDURE `time_createTable`(vStarted DATE, vEnded DATE) +BEGIN + DECLARE vCurrentDate DATE; + + DROP TEMPORARY TABLE IF EXISTS tmp.time; + CREATE TEMPORARY TABLE tmp.time (dated DATE PRIMARY KEY) ENGINE = MEMORY; + SET vCurrentDate = vStarted; + WHILE vCurrentDate <= vEnded DO + INSERT INTO tmp.time (dated) VALUES (vCurrentDate); + SET vCurrentDate = DATE_ADD(vCurrentDate, INTERVAL 1 DAY); + END WHILE; + +END$$ + +DELIMITER ; \ No newline at end of file diff --git a/db/changes/10180-holyWeek/01-zoneConfigAlterTable.sql b/db/changes/10180-holyWeek/01-zoneConfigAlterTable.sql new file mode 100644 index 000000000..5f4e7114b --- /dev/null +++ b/db/changes/10180-holyWeek/01-zoneConfigAlterTable.sql @@ -0,0 +1,2 @@ +ALTER TABLE `vn`.`zoneConfig` +ADD COLUMN `forwardDays` INT(10) NOT NULL DEFAULT 7 COMMENT 'days forward to show zone_upcomingDeliveries' AFTER `scope`; diff --git a/db/changes/10180-holyWeek/03-zone_UpcomingDeliveries.sql b/db/changes/10180-holyWeek/03-zone_UpcomingDeliveries.sql new file mode 100644 index 000000000..c8f85527e --- /dev/null +++ b/db/changes/10180-holyWeek/03-zone_UpcomingDeliveries.sql @@ -0,0 +1,80 @@ +USE `vn`; +DROP procedure IF EXISTS `zone_upcomingDeliveries`; + +DELIMITER $$ +USE `vn`$$ +CREATE DEFINER=`root`@`localhost` PROCEDURE `zone_upcomingDeliveries`() +BEGIN + DECLARE vForwardDays INT; + + SELECT forwardDays INTO vForwardDays FROM zoneConfig; + CALL util.time_createTable(CURDATE(), DATE_ADD(CURDATE(), INTERVAL vForwardDays DAY)); + + DROP TEMPORARY TABLE IF EXISTS tLandings; + CREATE TEMPORARY TABLE tLandings + (INDEX (eventFk)) + ENGINE = MEMORY + SELECT e.id eventFk, + @travelingDays := IFNULL(e.travelingDays, z.travelingDays) travelingDays, + TIMESTAMPADD(DAY, @travelingDays, ti.dated) landed, + ti.dated shipped + FROM zone z + JOIN zoneEvent e ON e.zoneFk = z.id + JOIN tmp.time ti ON ti.dated BETWEEN curdate() AND TIMESTAMPADD(DAY, vForwardDays, curdate()); + + DROP TEMPORARY TABLE IF EXISTS tmp.zoneOption; + CREATE TEMPORARY TABLE tmp.zoneOption + ENGINE = MEMORY + SELECT * + FROM ( + SELECT z.id zoneFk, + TIME(IFNULL(e.`hour`, z.`hour`)) `hour`, + l.travelingDays, + IFNULL(e.price, z.price) price, + IFNULL(e.bonus, z.bonus) bonus, + l.landed, + l.shipped + FROM zone z + JOIN zoneEvent e ON e.zoneFk = z.id + JOIN tLandings l ON l.eventFk = e.id + WHERE ( + e.`type` = 'day' + AND e.`dated` = l.landed + ) OR ( + e.`type` != 'day' + AND e.weekDays & (1 << WEEKDAY(l.landed)) + AND (e.`started` IS NULL OR l.landed >= e.`started`) + AND (e.`ended` IS NULL OR l.landed <= e.`ended`) + ) + ORDER BY + zoneFk, + CASE + WHEN e.`type` = 'day' + THEN 1 + WHEN e.`type` = 'range' + THEN 2 + ELSE 3 + END + ) t + GROUP BY zoneFk, landed; + + DELETE t FROM tmp.zoneOption t + JOIN zoneExclusion e + ON e.zoneFk = t.zoneFk AND e.`dated` = t.landed; + + SELECT MAX(zo.`hour`) `hour`, zg.`name`, zo.shipped + FROM tmp.zoneOption zo + JOIN `zone` z ON z.id = zo.zoneFk + JOIN agencyMode am ON am.id = z.agencyModeFk + JOIN deliveryMethod dm ON dm.id = am.deliveryMethodFk + JOIN zoneIncluded zi ON zi.zoneFk = z.id + JOIN zoneGeo zg ON zg.id = zi.geoFk AND zg.type = 'province' + WHERE dm.code = 'DELIVERY' + GROUP BY shipped, zg.`name` + ORDER BY shipped, zg.`name`; + + DROP TEMPORARY TABLE tmp.time, tLandings; +END$$ + +DELIMITER ; + diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql index 6b3e1905e..9f43b440f 100644 --- a/db/dump/fixtures.sql +++ b/db/dump/fixtures.sql @@ -1711,11 +1711,11 @@ INSERT INTO `vn`.`zoneIncluded` (`zoneFk`, `geoFk`, `isIncluded`) (2, 1, 1), (3, 3, 0), (3, 4, 0), - (3, 5, 0), + (3, 5, 0), (3, 1, 1), (4, 3, 0), (4, 4, 0), - (4, 5, 0), + (4, 5, 0), (4, 1, 1), (5, 3, 1), (5, 4, 0), @@ -1732,7 +1732,8 @@ INSERT INTO `vn`.`zoneIncluded` (`zoneFk`, `geoFk`, `isIncluded`) (8, 3, 0), (8, 4, 0), (8, 5, 0), - (8, 1, 1); + (8, 1, 1), + (10, 10, 1); INSERT INTO `vn`.`zoneEvent`(`zoneFk`, `type`, `dated`) VALUES @@ -1943,7 +1944,9 @@ INSERT INTO `vn`.`zoneEvent`(`zoneFk`, `type`, `dated`) (7, 'day', DATE_ADD(CURDATE(), INTERVAL +6 DAY)); INSERT INTO `vn`.`zoneEvent`(`zoneFk`, `type`, `weekDays`) - VALUES (8, 'indefinitely', 'mon,tue,wed,thu,fri,sat,sun'); + VALUES + (8, 'indefinitely', 'mon,tue,wed,thu,fri,sat,sun'), + (10, 'indefinitely', 'mon,tue,wed,thu,fri,sat,sun'); INSERT INTO `vn`.`workerTimeControl`(`userFk`, `timed`, `manual`, `direction`) VALUES diff --git a/e2e/paths/02-client/04_edit_billing_data.spec.js b/e2e/paths/02-client/04_edit_billing_data.spec.js index 394324509..d520a7e30 100644 --- a/e2e/paths/02-client/04_edit_billing_data.spec.js +++ b/e2e/paths/02-client/04_edit_billing_data.spec.js @@ -31,7 +31,7 @@ describe('Client Edit billing data path', () => { expect(message.text).toBe('That payment method requires an IBAN'); }); - // 2215: Windows (hidden mode): Entity code doesn't get the focus, '9999' is written in entity name. + // 2256: Windows (hidden mode): Entity code doesn't get the focus, '9999' is written in entity name. xit(`should create a new BIC code`, async() => { await page.waitToClick(selectors.clientBillingData.newBankEntityButton); await page.write(selectors.clientBillingData.newBankEntityName, 'Gotham City Bank'); diff --git a/front/core/services/week-days.js b/front/core/services/week-days.js index cf5722520..409b69b5c 100644 --- a/front/core/services/week-days.js +++ b/front/core/services/week-days.js @@ -39,7 +39,7 @@ export default class WeekDays { new WeekDay('wed', 'Wednesday'), new WeekDay('thu', 'Thursday'), new WeekDay('fri', 'Friday'), - new WeekDay('sat', 'Friday') + new WeekDay('sat', 'Saturday') ]; this.map = {}; diff --git a/modules/item/back/methods/item/regularize.js b/modules/item/back/methods/item/regularize.js index a532b0083..bfbc1e28c 100644 --- a/modules/item/back/methods/item/regularize.js +++ b/modules/item/back/methods/item/regularize.js @@ -61,7 +61,6 @@ module.exports = Self => { }, options); } - let query = ` CALL vn.item_getVisibleAvailable(?,curdate(),?,?)`; @@ -106,7 +105,6 @@ module.exports = Self => { return ticket.id; } - async function getTicketId(params, options) { const minDate = new Date(); minDate.setHours(0, 0, 0, 0); diff --git a/modules/item/back/methods/item/specs/regularize.spec.js b/modules/item/back/methods/item/specs/regularize.spec.js index a5d7c1c95..b285c15e1 100644 --- a/modules/item/back/methods/item/specs/regularize.spec.js +++ b/modules/item/back/methods/item/specs/regularize.spec.js @@ -15,7 +15,6 @@ describe('regularize()', () => { it('should create a new ticket and add a line', async() => { let ctx = {req: {accessToken: {userId: 18}}}; - let query = `CALL vn.item_getVisibleAvailable(?,curdate(),?,?)`; let options = [itemFk, warehouseFk, true]; diff --git a/modules/ticket/back/methods/sale/specs/updatePrice.spec.js b/modules/ticket/back/methods/sale/specs/updatePrice.spec.js index 2a751697f..2ca266769 100644 --- a/modules/ticket/back/methods/sale/specs/updatePrice.spec.js +++ b/modules/ticket/back/methods/sale/specs/updatePrice.spec.js @@ -24,9 +24,8 @@ describe('sale updatePrice()', () => { done(); }); - it('should throw an error if the ticket is not editable', async() => { - let ctx = {req: {accessToken: {userId: 9}}}; + let ctx = {req: {accessToken: {userId: 18}}}; let immutableSaleId = 1; let price = 5; @@ -40,7 +39,7 @@ describe('sale updatePrice()', () => { }); it('should return 0 if the price is an empty string', async() => { - let ctx = {req: {accessToken: {userId: 9}}}; + let ctx = {req: {accessToken: {userId: 18}}}; let price = ''; await app.models.Sale.updatePrice(ctx, saleId, price); @@ -50,7 +49,7 @@ describe('sale updatePrice()', () => { }); it('should now set price as a decimal number in a string', async() => { - let ctx = {req: {accessToken: {userId: 9}}}; + let ctx = {req: {accessToken: {userId: 18}}}; let price = '8'; await app.models.Sale.updatePrice(ctx, saleId, price); @@ -60,7 +59,7 @@ describe('sale updatePrice()', () => { }); it('should set price as a decimal number and check the sale has the mana component', async() => { - let ctx = {req: {accessToken: {userId: 9}}}; + let ctx = {req: {accessToken: {userId: 18}}}; let price = 5.4; await app.models.Sale.updatePrice(ctx, saleId, price); diff --git a/modules/ticket/back/methods/sale/updatePrice.js b/modules/ticket/back/methods/sale/updatePrice.js index 75e226c42..dac388034 100644 --- a/modules/ticket/back/methods/sale/updatePrice.js +++ b/modules/ticket/back/methods/sale/updatePrice.js @@ -55,8 +55,8 @@ module.exports = Self => { if (!isEditable) throw new UserError(`The sales of this ticket can't be modified`); - let salesPerson = sale.ticket().client().salesPersonFk; - let usesMana = await models.WorkerMana.findOne({where: {workerFk: salesPerson}, fields: 'amount'}, options); + const userId = ctx.req.accessToken.userId; + let usesMana = await models.WorkerMana.findOne({where: {workerFk: userId}, fields: 'amount'}, options); let componentCode = usesMana ? 'mana' : 'buyerDiscount'; let discount = await models.Component.findOne({where: {code: componentCode}}, options); @@ -83,8 +83,8 @@ module.exports = Self => { await sale.updateAttributes({price: newPrice}, options); - query = `call vn.manaSpellersRequery(?)`; - await Self.rawSql(query, [salesPerson], options); + query = `CALL vn.manaSpellersRequery(?)`; + await Self.rawSql(query, [userId], options); await tx.commit(); diff --git a/modules/ticket/back/methods/ticket/filter.js b/modules/ticket/back/methods/ticket/filter.js index aff26c63e..cedbe8f3b 100644 --- a/modules/ticket/back/methods/ticket/filter.js +++ b/modules/ticket/back/methods/ticket/filter.js @@ -163,7 +163,8 @@ module.exports = Self => { if (value) { return {and: [ {'st.alertLevel': 0}, - {'st.code': {neq: 'OK'}} + {'st.code': {neq: 'OK'}}, + {'st.code': {neq: 'BOARDING'}} ]}; } else { return {and: [ diff --git a/modules/ticket/back/methods/ticket/updateDiscount.js b/modules/ticket/back/methods/ticket/updateDiscount.js index 5ec887836..3b69c6b68 100644 --- a/modules/ticket/back/methods/ticket/updateDiscount.js +++ b/modules/ticket/back/methods/ticket/updateDiscount.js @@ -76,7 +76,7 @@ module.exports = Self => { }); const alertLevel = state ? state.alertLevel : null; - if (isLocked || (!isSalesPerson && alertLevel > 0 )) + if (isLocked || (!isSalesPerson && alertLevel > 0)) throw new UserError(`The sales of this ticket can't be modified`); const ticket = await models.Ticket.findById(id, { diff --git a/modules/ticket/front/descriptor/locale/es.yml b/modules/ticket/front/descriptor/locale/es.yml index d0e8b7bf5..0f98745bb 100644 --- a/modules/ticket/front/descriptor/locale/es.yml +++ b/modules/ticket/front/descriptor/locale/es.yml @@ -14,7 +14,7 @@ Show pallet report: Ver hoja de pallet Change shipped hour: Cambiar hora de envío Shipped hour: Hora de envío Make a payment: "Verdnatura le comunica:\rSu pedido está pendiente de pago.\rPor favor, entre en la página web y efectue el pago con tarjeta.\rMuchas gracias." -Minimum is needed: "Verdnatura le recuerda:\rEs necesario llegar a un importe mínimo de 50€ (Sin IVA) en su pedido {{ticketId}} del día {{created | date: 'dd/MM/yyyy'}} para recibirlo sin portes adicionales." +Minimum is needed: "Verdnatura le recuerda:\rEs necesario un importe mínimo de 50€ (Sin IVA) en su pedido {{ticketId}} del día {{created | date: 'dd/MM/yyyy'}} para recibirlo sin portes adicionales." Ticket invoiced: Ticket facturado Make invoice: Crear factura Regenerate invoice: Regenerar factura diff --git a/modules/zone/back/methods/zone/getUpcomingDeliveries.js b/modules/zone/back/methods/zone/getUpcomingDeliveries.js new file mode 100644 index 000000000..a917d7200 --- /dev/null +++ b/modules/zone/back/methods/zone/getUpcomingDeliveries.js @@ -0,0 +1,41 @@ +module.exports = Self => { + Self.remoteMethod('getUpcomingDeliveries', { + description: 'Returns the upcomings deliveries', + accessType: 'READ', + accepts: [], + returns: { + type: ['Object'], + root: true + }, + http: { + path: `/getUpcomingDeliveries`, + verb: 'GET' + } + }); + + Self.getUpcomingDeliveries = async() => { + const [zones] = await Self.rawSql(`CALL vn.zone_upcomingDeliveries()`); + + const details = []; + + for (let zone of zones) { + const shipped = zone.shipped; + + let zoneDetail = details.find(zone => { + return zone.shipped.toString() == shipped.toString(); + }); + + if (!zoneDetail) { + zoneDetail = { + shipped: shipped, + lines: [] + }; + details.push(zoneDetail); + } + + zoneDetail.lines.push(zone); + } + + return details; + }; +}; diff --git a/modules/zone/back/methods/zone/specs/getUpcomingDeliveries.spec.js b/modules/zone/back/methods/zone/specs/getUpcomingDeliveries.spec.js new file mode 100644 index 000000000..263ea598f --- /dev/null +++ b/modules/zone/back/methods/zone/specs/getUpcomingDeliveries.spec.js @@ -0,0 +1,16 @@ +const app = require('vn-loopback/server/server'); + +describe('zone getUpcomingDeliveries()', () => { + it('should check returns data', async() => { + let result = await app.models.Zone.getUpcomingDeliveries(); + + const firstResultLines = result[0].lines; + const secondResultLines = result[1].lines; + const thirdResultLines = result[2].lines; + + expect(result.length).toEqual(8); + expect(firstResultLines.length).toEqual(1); + expect(secondResultLines.length).toEqual(1); + expect(thirdResultLines.length).toEqual(1); + }); +}); diff --git a/modules/zone/back/models/zone.js b/modules/zone/back/models/zone.js index 0c3ac24f6..07fec96ce 100644 --- a/modules/zone/back/models/zone.js +++ b/modules/zone/back/models/zone.js @@ -3,6 +3,7 @@ module.exports = Self => { require('../methods/zone/getLeaves')(Self); require('../methods/zone/getEvents')(Self); require('../methods/zone/toggleIsIncluded')(Self); + require('../methods/zone/getUpcomingDeliveries')(Self); Self.validatesPresenceOf('agencyModeFk', { message: `Agency cannot be blank` diff --git a/modules/zone/front/delivery-days/index.spec.js b/modules/zone/front/delivery-days/index.spec.js index 8ad4af80e..156407420 100644 --- a/modules/zone/front/delivery-days/index.spec.js +++ b/modules/zone/front/delivery-days/index.spec.js @@ -61,7 +61,7 @@ describe('Zone Component vnZoneDeliveryDays', () => { expect(controller.$.data).toEqual(expectedData); }); }); - + // Petición #2259 cread xdescribe('onSelection()', () => { it('should not call the show popover method if events array is empty', () => { jest.spyOn(controller.$.zoneEvents, 'show'); diff --git a/modules/zone/front/index.js b/modules/zone/front/index.js index 556ec58ad..76a6fdd9b 100644 --- a/modules/zone/front/index.js +++ b/modules/zone/front/index.js @@ -14,3 +14,4 @@ import './events'; import './calendar'; import './location'; import './calendar'; +import './upcoming-deliveries'; diff --git a/modules/zone/front/locale/es.yml b/modules/zone/front/locale/es.yml index d525491e2..afe63bafc 100644 --- a/modules/zone/front/locale/es.yml +++ b/modules/zone/front/locale/es.yml @@ -24,6 +24,7 @@ Range of dates: Rango de fechas Search zone by id or name: Buscar zonas por identificador o nombre This zone will be removed: La zona será eliminada To: Hasta +Upcoming deliveries: Próximos repartos Volumetric: Volumétrico Warehouse: Almacén Warehouses: Almacenes diff --git a/modules/zone/front/routes.json b/modules/zone/front/routes.json index b5f0e76ab..6c799dcc8 100644 --- a/modules/zone/front/routes.json +++ b/modules/zone/front/routes.json @@ -7,7 +7,8 @@ "menus": { "main": [ {"state": "zone.index", "icon": "icon-zone"}, - {"state": "zone.deliveryDays", "icon": "today"} + {"state": "zone.deliveryDays", "icon": "today"}, + {"state": "zone.upcomingDeliveries", "icon": "today"} ], "card": [ {"state": "zone.card.basicData", "icon": "settings"}, @@ -33,6 +34,11 @@ "state": "zone.deliveryDays", "component": "vn-zone-delivery-days", "description": "Delivery days" + }, { + "url": "/upcoming-deliveries", + "state": "zone.upcomingDeliveries", + "component": "vn-upcoming-deliveries", + "description": "Upcoming deliveries" }, { "url": "/create", "state": "zone.create", diff --git a/modules/zone/front/upcoming-deliveries/index.html b/modules/zone/front/upcoming-deliveries/index.html new file mode 100644 index 000000000..1089c9c89 --- /dev/null +++ b/modules/zone/front/upcoming-deliveries/index.html @@ -0,0 +1,30 @@ + + + + +
+ +
{{$ctrl.getWeekDay(detail.shipped)}} - {{detail.shipped | date: 'dd/MM/yyyy'}}
+
+ + + + Province + Closing + Id + + + + + {{::zone.name}} + {{::zone.hour}} + {{::zone.zoneFk}} + + + +
+
+
diff --git a/modules/zone/front/upcoming-deliveries/index.js b/modules/zone/front/upcoming-deliveries/index.js new file mode 100644 index 000000000..e8e6909ae --- /dev/null +++ b/modules/zone/front/upcoming-deliveries/index.js @@ -0,0 +1,23 @@ +import ngModule from '../module'; +import Section from 'salix/components/section'; +import './style.scss'; + +class Controller extends Section { + constructor($element, $, vnWeekDays) { + super($element, $); + this.days = vnWeekDays.days; + } + + getWeekDay(jsonDate) { + const weekDay = new Date(jsonDate).getDay(); + + return this.days[weekDay].locale; + } +} + +Controller.$inject = ['$element', '$scope', 'vnWeekDays']; + +ngModule.component('vnUpcomingDeliveries', { + template: require('./index.html'), + controller: Controller +}); diff --git a/modules/zone/front/upcoming-deliveries/index.spec.js b/modules/zone/front/upcoming-deliveries/index.spec.js new file mode 100644 index 000000000..9f5c322a4 --- /dev/null +++ b/modules/zone/front/upcoming-deliveries/index.spec.js @@ -0,0 +1,22 @@ +import './index'; + +describe('component vnUpcomingDeliveries', () => { + let $scope; + let controller; + + beforeEach(ngModule('zone')); + + beforeEach(angular.mock.inject(($componentController, $rootScope) => { + $scope = $rootScope.$new(); + const $element = angular.element(``); + controller = $componentController('vnUpcomingDeliveries', {$element, $scope}); + })); + + fdescribe('getWeekDay()', () => { + it('should retrieve a weekday for a json passed', () => { + let jsonDate = '1970-01-01T22:00:00.000Z'; + + expect(controller.getWeekDay(jsonDate)).toEqual('Thursday'); + }); + }); +}); diff --git a/modules/zone/front/upcoming-deliveries/locale/es.yml b/modules/zone/front/upcoming-deliveries/locale/es.yml new file mode 100644 index 000000000..9f08e3a72 --- /dev/null +++ b/modules/zone/front/upcoming-deliveries/locale/es.yml @@ -0,0 +1,3 @@ +Family: Familia +Percentage: Porcentaje +Dwindle: Mermas \ No newline at end of file diff --git a/modules/zone/front/upcoming-deliveries/style.scss b/modules/zone/front/upcoming-deliveries/style.scss new file mode 100644 index 000000000..d3f33260a --- /dev/null +++ b/modules/zone/front/upcoming-deliveries/style.scss @@ -0,0 +1,25 @@ +@import "variables"; + +vn-upcoming-deliveries { + .header { + margin-bottom: 16px; + text-transform: uppercase; + font-size: 1.25rem; + line-height: 1; + padding: 7px; + padding-bottom: 7px; + padding-bottom: 4px; + font-weight: lighter; + background-color: $color-main-light; + border-bottom: 1px solid $color-primary; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + vn-table vn-th.waste-family, + vn-table vn-td.waste-family { + max-width: 64px; + width: 64px + } +} \ No newline at end of file