diff --git a/back/methods/dms/downloadFile.js b/back/methods/dms/downloadFile.js
index 523bd39bd..72090f33b 100644
--- a/back/methods/dms/downloadFile.js
+++ b/back/methods/dms/downloadFile.js
@@ -1,5 +1,4 @@
const UserError = require('vn-loopback/util/user-error');
-const fs = require('fs-extra');
module.exports = Self => {
Self.remoteMethodCtx('downloadFile', {
@@ -8,7 +7,7 @@ module.exports = Self => {
accepts: [
{
arg: 'id',
- type: 'String',
+ type: 'Number',
description: 'The document id',
http: {source: 'path'}
}
diff --git a/back/methods/dms/uploadFile.js b/back/methods/dms/uploadFile.js
index 2d4cc94da..9ef60c005 100644
--- a/back/methods/dms/uploadFile.js
+++ b/back/methods/dms/uploadFile.js
@@ -1,6 +1,5 @@
const UserError = require('vn-loopback/util/user-error');
const fs = require('fs-extra');
-const md5 = require('md5');
module.exports = Self => {
Self.remoteMethodCtx('uploadFile', {
diff --git a/db/changes/10060-verano/00-zoneCalendar.sql b/db/changes/10060-verano/00-zoneCalendar.sql
new file mode 100644
index 000000000..a3c091643
--- /dev/null
+++ b/db/changes/10060-verano/00-zoneCalendar.sql
@@ -0,0 +1,3 @@
+ALTER TABLE `vn`.`zoneCalendar`
+ADD COLUMN `price` DOUBLE NOT NULL AFTER `delivered`,
+ADD COLUMN `bonus` DOUBLE NOT NULL AFTER `price`;
diff --git a/front/core/components/calendar/index.html b/front/core/components/calendar/index.html
index e505bfad9..189e9b4eb 100644
--- a/front/core/components/calendar/index.html
+++ b/front/core/components/calendar/index.html
@@ -26,37 +26,55 @@
-
-
-
- {{::day.dated | date: 'd'}}
-
- {{::day.dated | date: 'd'}}
+
+
+
+ {{::day.dated | date: 'd'}}
+
+
+
+
+ {{::event.name}}
+
+
+
+
diff --git a/front/core/components/calendar/index.js b/front/core/components/calendar/index.js
index ada238d67..9e920eea2 100644
--- a/front/core/components/calendar/index.js
+++ b/front/core/components/calendar/index.js
@@ -13,6 +13,23 @@ export default class Calendar extends Component {
this.defaultDate = new Date();
this.displayControls = true;
this.skip = 1;
+
+ this.window.addEventListener('resize', () => {
+ this.checkSize();
+ });
+ }
+
+ /**
+ * Resizes the calendar
+ * based on component height
+ */
+ checkSize() {
+ const height = this.$element[0].clientHeight;
+
+ if (height < 530)
+ this.$element.addClass('small');
+ else
+ this.$element.removeClass('small');
}
/**
@@ -49,8 +66,10 @@ export default class Calendar extends Component {
this.addEvent(event);
});
- if (value.length && this.defaultDate)
+ if (value.length && this.defaultDate) {
this.repaint();
+ this.checkSize();
+ }
}
/**
@@ -165,16 +184,28 @@ export default class Calendar extends Component {
* @param {Date} dated - Date of month
* @param {String} className - Default class style
*/
- insertDay(dated, className = '') {
- let event = this.events.find(event => {
+ insertDay(dated) {
+ let events = this.events.filter(event => {
return event.dated >= dated && event.dated <= dated;
});
- // Weeekends
- if (dated.getMonth() === this.currentMonth.getMonth() && dated.getDay() == 0)
- className = 'red';
+ const params = {dated, events};
- this.days.push({dated, className, event});
+ const isSaturday = dated.getDay() === 6;
+ const isSunday = dated.getDay() === 0;
+ const isCurrentMonth = dated.getMonth() === this.currentMonth.getMonth();
+ const hasEvents = events.length > 0;
+
+ if (isCurrentMonth && isSunday && !hasEvents)
+ params.style = {color: '#f42121'};
+
+ if (isCurrentMonth && isSaturday && !hasEvents)
+ params.style = {color: '#666666'};
+
+ if (!isCurrentMonth && !hasEvents)
+ params.style = {color: '#9b9b9b'};
+
+ this.days.push(params);
}
/**
@@ -182,7 +213,7 @@ export default class Calendar extends Component {
*
* @param {Object} options - Event params
* @param {Date} options.dated - Day to add event
- * @param {String} options.title - Tooltip description
+ * @param {String} options.name - Tooltip description
* @param {String} options.className - ClassName style
* @param {Object} options.style - Style properties
* @param {Boolean} options.isRemovable - True if is removable by users
@@ -194,12 +225,7 @@ export default class Calendar extends Component {
options.dated = new Date(options.dated);
options.dated.setHours(0, 0, 0, 0);
- const event = this.events.findIndex(event => {
- return event.dated >= options.dated && event.dated <= options.dated;
- });
-
- if (event < 0)
- this.events.push(options);
+ this.events.push(options);
}
/**
@@ -274,6 +300,16 @@ export default class Calendar extends Component {
}
this.emit('selection', {values: selected});
}
+
+ renderStyle(style) {
+ if (style) {
+ return {
+ 'background-color': style.backgroundColor,
+ 'font-weight': style.fontWeight,
+ 'color': style.color
+ };
+ }
+ }
}
Calendar.$inject = ['$element', '$scope'];
diff --git a/front/core/components/calendar/index.spec.js b/front/core/components/calendar/index.spec.js
index 6a082a236..86bf3c240 100644
--- a/front/core/components/calendar/index.spec.js
+++ b/front/core/components/calendar/index.spec.js
@@ -20,8 +20,8 @@ describe('Component vnCalendar', () => {
let currentDate = new Date().toString();
controller.data = [
- {dated: currentDate, title: 'Event 1'},
- {dated: currentDate, title: 'Event 2'},
+ {dated: currentDate, name: 'Event 1'},
+ {dated: currentDate, name: 'Event 2'},
];
expect(controller.events[0].dated instanceof Object).toBeTruthy();
@@ -34,12 +34,11 @@ describe('Component vnCalendar', () => {
controller.events = [];
controller.addEvent({
dated: new Date(),
- title: 'My event',
- className: 'color'
+ name: 'My event'
});
const firstEvent = controller.events[0];
- expect(firstEvent.title).toEqual('My event');
+ expect(firstEvent.name).toEqual('My event');
expect(firstEvent.isRemovable).toBeDefined();
expect(firstEvent.isRemovable).toBeTruthy();
});
@@ -50,19 +49,17 @@ describe('Component vnCalendar', () => {
controller.events = [{
dated: curDate,
- title: 'My event 1',
- className: 'color'
+ name: 'My event 1'
}];
controller.addEvent({
dated: curDate,
- title: 'My event 2',
- className: 'color'
+ name: 'My event 2'
});
const firstEvent = controller.events[0];
- expect(controller.events.length).toEqual(1);
- expect(firstEvent.title).toEqual('My event 1');
+ expect(controller.events.length).toEqual(2);
+ expect(firstEvent.name).toEqual('My event 1');
});
});
@@ -71,7 +68,7 @@ describe('Component vnCalendar', () => {
const curDate = new Date();
controller._events = [{
dated: curDate,
- title: 'My event 1',
+ name: 'My event 1',
className: 'color'
}];
controller.removeEvent(curDate);
diff --git a/front/core/components/calendar/style.scss b/front/core/components/calendar/style.scss
index 6baaa0f65..333bfb428 100644
--- a/front/core/components/calendar/style.scss
+++ b/front/core/components/calendar/style.scss
@@ -1,143 +1,123 @@
@import "variables";
+vn-calendar.small {
+ .events {
+ display: none
+ }
+}
+
vn-calendar {
display: block;
- max-width: 250px;
.header vn-one {
text-align: center;
- padding: 0.2em 0
+ padding: 0.2em 0;
+ height: 1.5em
}
- .body {
- .days {
- justify-content: flex-start;
- align-items: flex-start;
- flex-wrap: wrap;
+
+ .weekdays {
+ color: $color-font-secondary;
+ margin-bottom: 0.5em;
+ padding: 0.5em 0;
+ font-weight: bold;
+ font-size: 0.8em;
+ }
+
+ .weekdays section {
+ cursor: pointer
+ }
+
+ .weekdays section, .day {
+ position: relative;
+ text-align: center;
+ box-sizing: border-box;
+ width: 14.28%;
+ outline: 0;
+ }
+
+ .days {
+ justify-content: flex-start;
+ align-items: flex-start;
+ flex-wrap: wrap;
+ }
+
+
+ .day {
+ .content {
+ position: absolute;
+ bottom: 0;
+ right: 0;
+ left: 0;
+ top: 0
}
- .weekdays {
- border-bottom: 1px solid $color-hover-cd;
- border-top: 1px solid $color-hover-cd;
- color: $color-font-secondary;
- font-weight: bold
+ .day-number {
+ transition: background-color 0.3s;
+ text-align:center;
+ float:inline-end;
+ margin: 0 auto;
+ border-radius: 50%;
+ font-size: 0.85em;
+ width:2.2em;
+ height: 1.2em;
+ padding: 0.5em 0;
+ cursor: pointer;
+ outline: 0
}
- .day {
- box-sizing: border-box;
- padding: 0.1em;
- width: 14.2857143%;
- line-height: 1.5em;
- outline: 0;
-
- span {
- transition: background-color 0.3s;
- text-align: center;
- font-size: .8em;
- border-radius: 50%;
- display: block;
- padding: 0.2em;
- cursor: pointer
- }
+ .day-number:hover {
+ background-color: lighten($color-font-secondary, 20%);
+ opacity: 0.8
}
+ }
- .day:hover span {
- background-color: #DDD
+ .day::after {
+ content: "";
+ display: block;
+ padding-top: 100%;
+ }
+
+ .day.primary .day-number {
+ background-color: $color-main;
+ color: $color-font-bg;
+ }
+
+ .events {
+ margin-top: 0.5em;
+ font-size: 0.6em
+ }
+
+
+ .events {
+ color: $color-font-secondary;
+
+ .event {
+ margin-bottom: .1em;
}
+ }
- .day.gray {
+ .chip {
+ background-color: $color-main;
+ color: $color-font-bg;
+ display: inline-block;
+ border-radius: .3em;
+ padding: 0.3em .8em;
+ max-width: 5em;
+ }
+
+ .day.gray {
+ .day-number {
color: $color-font-secondary
}
+ }
- .day.orange {
- font-weight: bold;
- color: $color-main;
- }
-
- .day.orange-circle {
- color: $color-font;
- & > span {
- background-color: $color-main
- }
- }
+
- .day.orange-circle:hover {
- & > span {
- background-color: $color-main-medium
- }
- }
-
- .day.light-orange {
- color: $color-main-medium
- }
-
- .day.green {
- font-weight: bold;
- color: $color-success;
- }
-
- .day.green-circle {
- color: $color-font;
- & > span {
- background-color: $color-success
- }
- }
-
- .day.green-circle:hover {
- & > span {
- background-color: $color-success-medium
- }
- }
-
- .day.light-green {
- font-weight: bold;
- color: $color-success-medium
- }
-
- .day.blue {
- font-weight: bold;
- color: $color-notice;
- }
-
- .day.blue-circle {
- color: $color-font;
- & > span {
- background-color: $color-notice
- }
- }
-
- .day.blue-circle:hover {
- & > span {
- background-color: $color-notice-medium
- }
- }
-
- .day.light-blue {
- font-weight: bold;
- color: $color-notice-medium
- }
-
- .day.red {
- font-weight: bold;
- color: $color-alert
- }
-
- .day.red-circle {
- color: $color-font;
- & > span {
- background-color: $color-alert
- }
- }
-
- .day.red-circle:hover {
- & > span {
- background-color: $color-alert-medium
- }
- }
-
- .day.light-red {
- font-weight: bold;
- color: $color-alert-medium;
+ .day.sunday {
+ .day-number {
+ color: $color-alert;
+ font-weight: bold
}
}
}
diff --git a/front/core/components/dialog/dialog.js b/front/core/components/dialog/dialog.js
index 7ea588a27..4c4535b4c 100644
--- a/front/core/components/dialog/dialog.js
+++ b/front/core/components/dialog/dialog.js
@@ -45,8 +45,7 @@ export default class Dialog extends Component {
this.element.style.display = 'flex';
this.transitionTimeout = setTimeout(() => this.$element.addClass('shown'), 30);
- if (this.onOpen)
- this.onOpen();
+ this.emit('open');
}
/**
@@ -55,6 +54,7 @@ export default class Dialog extends Component {
hide() {
this.fireResponse();
this.realHide();
+ this.emit('close');
}
/**
@@ -120,7 +120,6 @@ ngModule.component('vnDialog', {
buttons: '?tplButtons'
},
bindings: {
- onOpen: '&?',
onResponse: '&?'
},
controller: Dialog
diff --git a/front/core/components/dialog/dialog.spec.js b/front/core/components/dialog/dialog.spec.js
index 4937fdba3..b889f1bc0 100644
--- a/front/core/components/dialog/dialog.spec.js
+++ b/front/core/components/dialog/dialog.spec.js
@@ -7,7 +7,7 @@ describe('Component vnDialog', () => {
beforeEach(angular.mock.inject($componentController => {
$element = angular.element('');
controller = $componentController('vnDialog', {$element, $transclude: null});
- controller.onOpen = jasmine.createSpy('onOpen');
+ controller.emit = jasmine.createSpy('emit');
}));
describe('show()', () => {
@@ -17,15 +17,15 @@ describe('Component vnDialog', () => {
controller.show();
expect(controller.element.style.display).toEqual('none');
- expect(controller.onOpen).not.toHaveBeenCalledWith();
+ expect(controller.emit).not.toHaveBeenCalledWith('open');
});
- it(`should set shown on the controller, set style.display on the element and call onOpen()`, () => {
+ it(`should set shown on the controller, set style.display on the element and emit onOpen() event`, () => {
controller.show();
expect(controller.element.style.display).toEqual('flex');
expect(controller.shown).toBeTruthy();
- expect(controller.onOpen).toHaveBeenCalledWith();
+ expect(controller.emit).toHaveBeenCalledWith('open');
});
});
diff --git a/front/core/components/index.js b/front/core/components/index.js
index d626470c3..09ee97963 100644
--- a/front/core/components/index.js
+++ b/front/core/components/index.js
@@ -20,7 +20,7 @@ import './multi-check/multi-check';
import './date-picker/date-picker';
import './button/button';
import './check/check';
-import './radio/radio';
+import './radio-group/radio-group';
import './textarea/textarea';
import './icon-button/icon-button';
import './submit/submit';
diff --git a/front/core/components/input-number/index.html b/front/core/components/input-number/index.html
index cb3f24bd5..9fd024280 100644
--- a/front/core/components/input-number/index.html
+++ b/front/core/components/input-number/index.html
@@ -22,7 +22,10 @@
ng-focus="$ctrl.hasFocus = true"
ng-blur="$ctrl.hasFocus = false"
tabindex="{{$ctrl.input.tabindex}}"/>
-
+
diff --git a/front/core/components/input-number/index.js b/front/core/components/input-number/index.js
index 7eb8cbd54..6c9f378e8 100644
--- a/front/core/components/input-number/index.js
+++ b/front/core/components/input-number/index.js
@@ -192,6 +192,7 @@ ngModule.component('vnInputNumber', {
label: '@?',
name: '@?',
disabled: '',
+ required: '@?',
min: '',
max: '',
step: '',
diff --git a/front/core/components/radio-group/radio-group.html b/front/core/components/radio-group/radio-group.html
new file mode 100644
index 000000000..3b389d2be
--- /dev/null
+++ b/front/core/components/radio-group/radio-group.html
@@ -0,0 +1,8 @@
+
+
+ {{::option.label}}
+
+
\ No newline at end of file
diff --git a/front/core/components/radio-group/radio-group.js b/front/core/components/radio-group/radio-group.js
new file mode 100644
index 000000000..80c77a7e2
--- /dev/null
+++ b/front/core/components/radio-group/radio-group.js
@@ -0,0 +1,41 @@
+import ngModule from '../../module';
+import Component from '../../lib/component';
+import './style.scss';
+
+export default class Controller extends Component {
+ constructor($element, $scope, $attrs) {
+ super($element, $scope);
+ this.hasInfo = Boolean($attrs.info);
+ this.info = $attrs.info || null;
+ }
+
+ get model() {
+ return this._model;
+ }
+
+ set model(value) {
+ this._model = value;
+ }
+
+ get field() {
+ return this._model;
+ }
+
+ set field(value) {
+ this._model = value;
+ }
+}
+
+Controller.$inject = ['$element', '$scope', '$attrs'];
+
+ngModule.component('vnRadioGroup', {
+ template: require('./radio-group.html'),
+ controller: Controller,
+
+ bindings: {
+ field: '=?',
+ options: '',
+ disabled: '',
+ checked: ''
+ }
+});
diff --git a/front/core/components/radio-group/style.scss b/front/core/components/radio-group/style.scss
new file mode 100644
index 000000000..fee154541
--- /dev/null
+++ b/front/core/components/radio-group/style.scss
@@ -0,0 +1,11 @@
+@import "variables";
+
+md-radio-group md-radio-button.md-checked .md-container {
+ .md-on {
+ background-color: $color-main
+ }
+
+ .md-off {
+ border-color: $color-main
+ }
+}
diff --git a/front/core/components/radio/radio.html b/front/core/components/radio/radio.html
deleted file mode 100644
index 887a97c04..000000000
--- a/front/core/components/radio/radio.html
+++ /dev/null
@@ -1,7 +0,0 @@
-
-*[text]*
diff --git a/front/core/components/radio/radio.js b/front/core/components/radio/radio.js
deleted file mode 100644
index 70dbc059d..000000000
--- a/front/core/components/radio/radio.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import ngModule from '../../module';
-import template from './radio.html';
-
-directive.$inject = ['vnTemplate'];
-export default function directive(vnTemplate) {
- return {
- restrict: 'E',
- template: (_, $attrs) =>
- vnTemplate.get(template, $attrs, {
- enabled: 'true',
- className: 'mdl-radio mdl-js-radio mdl-js-ripple-effect'
- })
- };
-}
-ngModule.directive('vnRadio', directive);
diff --git a/front/core/components/textfield/textfield.html b/front/core/components/textfield/textfield.html
index 0c1058148..22756497f 100644
--- a/front/core/components/textfield/textfield.html
+++ b/front/core/components/textfield/textfield.html
@@ -16,7 +16,7 @@
tabindex="{{$ctrl.input.tabindex}}"/>
diff --git a/front/salix/styles/variables.scss b/front/salix/styles/variables.scss
index 732389fb9..5fd31a8c6 100644
--- a/front/salix/styles/variables.scss
+++ b/front/salix/styles/variables.scss
@@ -52,6 +52,8 @@ $color-hover-cd: rgba(0, 0, 0, .1);
$color-hover-dc: .7;
$color-disabled: .6;
+$color-font-link-medium: lighten($color-font-link, 20%);
+$color-font-link-light: lighten($color-font-link, 35%);
$color-main-medium: lighten($color-main, 20%);
$color-main-light: lighten($color-main, 35%);
$color-success-medium: lighten($color-success, 20%);
diff --git a/modules/agency/back/methods/zone/editPrices.js b/modules/agency/back/methods/zone/editPrices.js
new file mode 100644
index 000000000..b0203dc4b
--- /dev/null
+++ b/modules/agency/back/methods/zone/editPrices.js
@@ -0,0 +1,81 @@
+const mergeFilters = require('vn-loopback/util/filter').mergeFilters;
+
+module.exports = Self => {
+ Self.remoteMethod('editPrices', {
+ description: 'Changes the price and bonus of a delivery day',
+ accessType: 'WRITE',
+ accepts: [{
+ arg: 'id',
+ type: 'Number',
+ description: 'The zone id',
+ http: {source: 'path'}
+ },
+ {
+ arg: 'delivered',
+ type: 'Date',
+ required: true,
+ },
+ {
+ arg: 'price',
+ type: 'Number',
+ required: true,
+ },
+ {
+ arg: 'bonus',
+ type: 'Number',
+ required: true,
+ },
+ {
+ arg: 'option',
+ type: 'String',
+ required: true,
+ }],
+ returns: {
+ type: 'object',
+ root: true
+ },
+ http: {
+ path: `/:id/editPrices`,
+ verb: 'POST'
+ }
+ });
+
+ Self.editPrices = async(id, delivered, price, bonus, option) => {
+ const models = Self.app.models;
+
+ let filter = {
+ where: {
+ zoneFk: id
+ }
+ };
+
+ let where;
+ let shouldPropagate = true;
+
+ if (option == 'Only this day') {
+ shouldPropagate = false;
+ where = {delivered};
+ } else if (option == 'From this day') {
+ where = {
+ delivered: {
+ gte: delivered
+ }
+ };
+ }
+
+ filter = mergeFilters(filter, {where});
+
+ const days = await models.ZoneCalendar.find(filter);
+ const areAllFromSameZone = days.every(day => day.zoneFk === id);
+
+ if (!areAllFromSameZone)
+ throw new UserError('All delivery days must belong to the same zone');
+
+ if (shouldPropagate) {
+ const zone = await models.Zone.findById(id);
+ zone.updateAttributes({price, bonus});
+ }
+
+ return models.ZoneCalendar.updateAll(filter.where, {price, bonus});
+ };
+};
diff --git a/modules/agency/back/methods/zone/specs/editPrices.spec.js b/modules/agency/back/methods/zone/specs/editPrices.spec.js
new file mode 100644
index 000000000..610496425
--- /dev/null
+++ b/modules/agency/back/methods/zone/specs/editPrices.spec.js
@@ -0,0 +1,84 @@
+const app = require('vn-loopback/server/server');
+
+describe('agency editPrices()', () => {
+ const zoneId = 1;
+ let originalZone;
+
+ beforeAll(async done => {
+ originalZone = await app.models.Zone.findById(zoneId);
+ done();
+ });
+
+ afterAll(async done => {
+ await await app.models.ZoneCalendar.updateAll({zoneFk: zoneId}, {
+ price: originalZone.price,
+ bonus: originalZone.bonus
+ });
+ done();
+ });
+
+ it('should apply price and bonus for a selected day', async() => {
+ const delivered = new Date();
+ delivered.setHours(0, 0, 0, 0);
+ delivered.setDate(delivered.getDate() + 1);
+ await app.models.Zone.editPrices(zoneId, delivered, 4.00, 2.00, 'Only this day');
+
+ const editedDays = await app.models.ZoneCalendar.find({
+ where: {
+ zoneFk: zoneId,
+ delivered: delivered
+ }
+ });
+ const firstEditedDay = editedDays[0];
+
+ expect(editedDays.length).toEqual(1);
+ expect(firstEditedDay.price).toEqual(4.00);
+ expect(firstEditedDay.bonus).toEqual(2.00);
+ });
+
+ it('should apply price and bonus for all delivery days starting from selected day', async() => {
+ const delivered = new Date();
+ delivered.setHours(0, 0, 0, 0);
+ delivered.setDate(delivered.getDate() + 1);
+ await app.models.Zone.editPrices(1, delivered, 5.50, 1.00, 'From this day');
+
+ const editedDays = await app.models.ZoneCalendar.find({
+ where: {
+ zoneFk: zoneId,
+ delivered: {
+ gte: delivered
+ }
+ }
+ });
+ const firstEditedDay = editedDays[0];
+ const lastEditedDay = editedDays[editedDays.length - 1];
+
+ expect(editedDays.length).toEqual(4);
+ expect(firstEditedDay.price).toEqual(5.50);
+ expect(firstEditedDay.bonus).toEqual(1.00);
+ expect(lastEditedDay.price).toEqual(5.50);
+ expect(lastEditedDay.bonus).toEqual(1.00);
+ });
+
+ it('should apply price and bonus for all delivery days', async() => {
+ const delivered = new Date();
+ delivered.setHours(0, 0, 0, 0);
+ delivered.setDate(delivered.getDate() + 1);
+ await app.models.Zone.editPrices(1, delivered, 7.00, 0.00, 'All days');
+
+ const editedDays = await app.models.ZoneCalendar.find({
+ where: {
+ zoneFk: zoneId
+ }
+ });
+ const firstEditedDay = editedDays[0];
+ const lastEditedDay = editedDays[editedDays.length - 1];
+
+ expect(editedDays.length).toEqual(5);
+ expect(firstEditedDay.price).toEqual(7.00);
+ expect(firstEditedDay.bonus).toEqual(0.00);
+ expect(lastEditedDay.price).toEqual(7.00);
+ expect(lastEditedDay.bonus).toEqual(0.00);
+ });
+});
+
diff --git a/modules/agency/back/models/zone-calendar.json b/modules/agency/back/models/zone-calendar.json
index 35926a0db..bed9a8011 100644
--- a/modules/agency/back/models/zone-calendar.json
+++ b/modules/agency/back/models/zone-calendar.json
@@ -14,6 +14,12 @@
"delivered": {
"id": true,
"type": "Date"
+ },
+ "price": {
+ "type": "Number"
+ },
+ "bonus": {
+ "type": "Number"
}
},
"relations": {
diff --git a/modules/agency/back/models/zone.js b/modules/agency/back/models/zone.js
index d282224b9..c7ba642f3 100644
--- a/modules/agency/back/models/zone.js
+++ b/modules/agency/back/models/zone.js
@@ -1,5 +1,6 @@
module.exports = Self => {
require('../methods/zone/clone')(Self);
+ require('../methods/zone/editPrices')(Self);
Self.validatesPresenceOf('warehouseFk', {
message: `Warehouse cannot be blank`
diff --git a/modules/agency/front/calendar/index.html b/modules/agency/front/calendar/index.html
index d02be3059..0a86d2254 100644
--- a/modules/agency/front/calendar/index.html
+++ b/modules/agency/front/calendar/index.html
@@ -1,21 +1,74 @@
-
-
-
-
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Edit price
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/agency/front/calendar/index.js b/modules/agency/front/calendar/index.js
index bf1625585..5e6cb19b9 100644
--- a/modules/agency/front/calendar/index.js
+++ b/modules/agency/front/calendar/index.js
@@ -1,49 +1,26 @@
import ngModule from '../module';
+import './style.scss';
class Controller {
- constructor($element, $scope, $stateParams, $http) {
+ constructor($element, $scope, $http, $filter, $translate, $stateParams, vnApp) {
this.$element = $element;
- this.$stateParams = $stateParams;
- this.$scope = $scope;
+ this.$ = $scope;
this.$http = $http;
+ this.$filter = $filter;
+ this.$translate = $translate;
+ this.$stateParams = $stateParams;
+ this.vnApp = vnApp;
this.stMonthDate = new Date();
this.ndMonthDate = new Date();
this.ndMonthDate.setMonth(this.ndMonthDate.getMonth() + 1);
+ this.selectedDay = {};
}
$postLink() {
- this.stMonth = this.$scope.stMonth;
- this.ndMonth = this.$scope.ndMonth;
+ this.stMonth = this.$.stMonth;
+ this.ndMonth = this.$.ndMonth;
}
- // Disabled until implementation
- // of holidays by node
- /* get zone() {
- return this._zone;
- }
-
- set zone(value) {
- this._zone = value;
-
- if (!value) return;
-
- let query = '/agency/api/LabourHolidays/getByWarehouse';
- this.$http.get(query, {params: {warehouseFk: value.warehouseFk}}).then(res => {
- if (!res.data) return;
- const events = [];
- res.data.forEach(holiday => {
- events.push({
- date: holiday.dated,
- className: 'red',
- title: holiday.description || holiday.name,
- isRemovable: false
- });
- });
-
- this.events = this.events.concat(events);
- });
- } */
-
get data() {
return this._data;
}
@@ -52,97 +29,106 @@ class Controller {
this._data = value;
if (!value) return;
+
const events = [];
value.forEach(event => {
events.push({
+ name: `P: ${this.$filter('currency')(event.price)}`,
+ description: 'Price',
dated: event.delivered,
- className: 'green-circle',
- title: 'Has delivery'
+ style: {backgroundColor: '#a3d131'},
+ data: {price: event.price}
+ });
+ events.push({
+ name: `B: ${this.$filter('currency')(event.bonus)}`,
+ description: 'Bonus',
+ dated: event.delivered,
+ data: {bonus: event.bonus}
});
});
this.events = events;
}
- onSelection(calendar, values) {
- let totalEvents = 0;
- values.forEach(day => {
- const exists = calendar.events.findIndex(event => {
- return event.dated >= day.dated && event.dated <= day.dated
- && event.isRemovable;
- });
+ onSelection(values) {
+ if (values.length > 1) return false;
- if (exists > -1) totalEvents++;
+ this.options = [
+ {label: 'Only this day', value: 'Only this day'},
+ {label: 'From this day', value: 'From this day'},
+ {label: 'All days', value: 'All days'}
+ ];
+ const selection = values[0];
+ const events = selection.events;
+ const hasEvents = events.length > 0;
+
+ if (!hasEvents)
+ return this.vnApp.showMessage(this.$translate.instant(`There's no delivery for this day`));
+
+ this.selectedDay = {
+ delivered: selection.dated,
+ option: 'Only this day'
+ };
+
+ events.forEach(event => {
+ this.selectedDay = Object.assign(this.selectedDay, event.data);
});
-
- if (totalEvents > (values.length / 2))
- this.removeEvents(calendar, values);
- else
- this.insertEvents(calendar, values);
+ this.$.priceDialog.show();
}
- insertEvents(calendar, days) {
- days.forEach(day => {
- const event = calendar.events.find(event => {
- return event.dated >= day.dated && event.dated <= day.dated;
- });
+ onResponse(response) {
+ if (response == 'ACCEPT') {
+ try {
+ const data = {
+ delivered: this.selectedDay.delivered,
+ price: this.selectedDay.price,
+ bonus: this.selectedDay.bonus,
+ option: this.selectedDay.option
+ };
- if (event) return false;
+ this.$.watcher.check();
- this.$scope.model.insert({
- zoneFk: this.zone.id,
- delivered: day.dated
- });
-
- calendar.addEvent({
- dated: day.dated,
- className: 'green-circle',
- title: 'Has delivery'
- });
- });
-
- this.$scope.model.save().then(() => {
- this.events = calendar.events;
- });
- }
-
- removeEvents(calendar, days) {
- let dates = [];
- days.forEach(day => {
- const event = calendar.events.find(event => {
- return event.dated >= day.dated && event.dated <= day.dated;
- });
-
- if (event && !event.isRemovable)
+ const path = `/api/Zones/${this.zone.id}/editPrices`;
+ this.$http.post(path, data).then(() => {
+ this.vnApp.showSuccess(this.$translate.instant('Data saved!'));
+ this.$.model.refresh();
+ this.card.reload();
+ });
+ } catch (e) {
+ this.vnApp.showError(this.$translate.instant(e.message));
return false;
+ }
+ }
- dates.push(day.dated);
+ return this.onClose();
+ }
- calendar.removeEvent(day.dated);
- });
+ onClose() {
+ this.$.watcher.updateOriginalData();
+ }
- if (dates.length == 0) return;
- const params = {zoneFk: this.zone.id, dates};
- this.$http.post('/agency/api/zoneCalendars/removeByDate', params).then(() => {
- this.events = calendar.events;
+ onMoveNext(calendars) {
+ calendars.forEach(calendar => {
+ calendar.moveNext(2);
});
}
- onMoveNext(calendar) {
- calendar.moveNext(2);
- }
-
- onMovePrevious(calendar) {
- calendar.movePrevious(2);
+ onMovePrevious(calendars) {
+ calendars.forEach(calendar => {
+ calendar.movePrevious(2);
+ });
}
}
-Controller.$inject = ['$element', '$scope', '$stateParams', '$http'];
+Controller.$inject = ['$element', '$scope', '$http', '$filter', '$translate', '$stateParams', 'vnApp'];
ngModule.component('vnZoneCalendar', {
template: require('./index.html'),
controller: Controller,
bindings: {
zone: '<'
+ },
+ require: {
+ card: '^vnZoneCard'
}
});
diff --git a/modules/agency/front/calendar/locale/es.yml b/modules/agency/front/calendar/locale/es.yml
new file mode 100644
index 000000000..a37eeb272
--- /dev/null
+++ b/modules/agency/front/calendar/locale/es.yml
@@ -0,0 +1,6 @@
+Prices: Precios
+Edit price: Modificar precio
+Only this day: Solo este día
+From this day: A partir de este día
+All days: Todos los días
+There's no delivery for this day: No hay reparto para este día
\ No newline at end of file
diff --git a/modules/agency/front/calendar/style.scss b/modules/agency/front/calendar/style.scss
new file mode 100644
index 000000000..783bad77d
--- /dev/null
+++ b/modules/agency/front/calendar/style.scss
@@ -0,0 +1,3 @@
+vn-calendar:nth-child(2n + 1) {
+ border-right:1px solid #ddd
+}
\ No newline at end of file
diff --git a/modules/agency/front/index.js b/modules/agency/front/index.js
index f58cc8f60..5e4103b43 100644
--- a/modules/agency/front/index.js
+++ b/modules/agency/front/index.js
@@ -8,4 +8,5 @@ import './search-panel';
import './create';
import './basic-data';
import './location';
+import './location/calendar';
import './calendar';
diff --git a/modules/agency/front/location/calendar.html b/modules/agency/front/location/calendar.html
new file mode 100644
index 000000000..a1db6f08a
--- /dev/null
+++ b/modules/agency/front/location/calendar.html
@@ -0,0 +1,21 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/agency/front/location/calendar.js b/modules/agency/front/location/calendar.js
new file mode 100644
index 000000000..802a9946e
--- /dev/null
+++ b/modules/agency/front/location/calendar.js
@@ -0,0 +1,150 @@
+import ngModule from '../module';
+
+class Controller {
+ constructor($element, $scope, $stateParams, $http) {
+ this.$element = $element;
+ this.$stateParams = $stateParams;
+ this.$scope = $scope;
+ this.$http = $http;
+ this.stMonthDate = new Date();
+ this.ndMonthDate = new Date();
+ this.ndMonthDate.setMonth(this.ndMonthDate.getMonth() + 1);
+ }
+
+ $postLink() {
+ this.stMonth = this.$scope.stMonth;
+ this.ndMonth = this.$scope.ndMonth;
+ }
+
+ // Disabled until implementation
+ // of holidays by node
+ /* get zone() {
+ return this._zone;
+ }
+
+ set zone(value) {
+ this._zone = value;
+
+ if (!value) return;
+
+ let query = '/agency/api/LabourHolidays/getByWarehouse';
+ this.$http.get(query, {params: {warehouseFk: value.warehouseFk}}).then(res => {
+ if (!res.data) return;
+ const events = [];
+ res.data.forEach(holiday => {
+ events.push({
+ date: holiday.dated,
+ className: 'red',
+ title: holiday.description || holiday.name,
+ isRemovable: false
+ });
+ });
+
+ this.events = this.events.concat(events);
+ });
+ } */
+
+ get data() {
+ return this._data;
+ }
+
+ set data(value) {
+ this._data = value;
+
+ if (!value) return;
+ const events = [];
+ value.forEach(event => {
+ events.push({
+ name: 'Has delivery',
+ dated: event.delivered,
+ style: {backgroundColor: '#a3d131'}
+ });
+ });
+
+ this.events = events;
+ }
+
+ onSelection(values, calendar) {
+ let totalEvents = 0;
+ values.forEach(day => {
+ const exists = calendar.events.findIndex(event => {
+ return event.dated >= day.dated && event.dated <= day.dated
+ && event.isRemovable;
+ });
+
+ if (exists > -1) totalEvents++;
+ });
+
+ if (totalEvents > (values.length / 2))
+ this.removeEvents(calendar, values);
+ else
+ this.insertEvents(calendar, values);
+ }
+
+ insertEvents(calendar, days) {
+ days.forEach(day => {
+ const event = calendar.events.find(event => {
+ return event.dated >= day.dated && event.dated <= day.dated;
+ });
+
+ if (event) return false;
+
+ this.$scope.model.insert({
+ zoneFk: this.zone.id,
+ delivered: day.dated,
+ price: this.zone.price,
+ bonus: this.zone.bonus
+ });
+
+ calendar.addEvent({
+ name: 'Has delivery',
+ dated: day.dated,
+ style: {backgroundColor: '#a3d131'}
+ });
+ });
+
+ this.$scope.model.save().then(() => {
+ this.events = calendar.events;
+ });
+ }
+
+ removeEvents(calendar, days) {
+ let dates = [];
+ days.forEach(day => {
+ const event = calendar.events.find(event => {
+ return event.dated >= day.dated && event.dated <= day.dated;
+ });
+
+ if (event && !event.isRemovable)
+ return false;
+
+ dates.push(day.dated);
+
+ calendar.removeEvent(day.dated);
+ });
+
+ if (dates.length == 0) return;
+ const params = {zoneFk: this.zone.id, dates};
+ this.$http.post('/agency/api/zoneCalendars/removeByDate', params).then(() => {
+ this.events = calendar.events;
+ });
+ }
+
+ onMoveNext(calendar) {
+ calendar.moveNext(2);
+ }
+
+ onMovePrevious(calendar) {
+ calendar.movePrevious(2);
+ }
+}
+
+Controller.$inject = ['$element', '$scope', '$stateParams', '$http'];
+
+ngModule.component('vnZoneLocationCalendar', {
+ template: require('./calendar.html'),
+ controller: Controller,
+ bindings: {
+ zone: '<'
+ }
+});
diff --git a/modules/agency/front/location/index.html b/modules/agency/front/location/index.html
index 42662ef2b..fb9bf863c 100644
--- a/modules/agency/front/location/index.html
+++ b/modules/agency/front/location/index.html
@@ -18,6 +18,6 @@
-
+
\ No newline at end of file
diff --git a/modules/agency/front/routes.json b/modules/agency/front/routes.json
index fe4e74707..2125b1172 100644
--- a/modules/agency/front/routes.json
+++ b/modules/agency/front/routes.json
@@ -6,7 +6,8 @@
"dependencies": ["worker"],
"menu": [
{"state": "zone.card.basicData", "icon": "settings"},
- {"state": "zone.card.location", "icon": "my_location"}
+ {"state": "zone.card.location", "icon": "my_location"},
+ {"state": "zone.card.calendar"}
],
"routes": [
{
@@ -15,27 +16,31 @@
"abstract": true,
"component": "ui-view",
"description": "Zones"
- }, {
+ },
+ {
"url": "/index?q",
"state": "zone.index",
"component": "vn-zone-index",
"description": "Zones"
- }, {
+ },
+ {
"url": "/create",
"state": "zone.create",
"component": "vn-zone-create",
"description": "New zone"
- }, {
+ },
+ {
"url": "/:id",
"state": "zone.card",
"component": "vn-zone-card",
"abstract": true,
"description": "Detail"
- }, {
- "url": "/location?q",
- "state": "zone.card.location",
- "component": "vn-zone-location",
- "description": "Locations",
+ },
+ {
+ "url": "/summary",
+ "state": "zone.card.summary",
+ "component": "vn-zone-summary",
+ "description": "Summary",
"params": {
"zone": "$ctrl.zone"
}
@@ -50,10 +55,19 @@
}
},
{
- "url": "/summary",
- "state": "zone.card.summary",
- "component": "vn-zone-summary",
- "description": "Summary",
+ "url": "/location?q",
+ "state": "zone.card.location",
+ "component": "vn-zone-location",
+ "description": "Locations",
+ "params": {
+ "zone": "$ctrl.zone"
+ }
+ },
+ {
+ "url": "/calendar",
+ "state": "zone.card.calendar",
+ "component": "vn-zone-calendar",
+ "description": "Prices",
"params": {
"zone": "$ctrl.zone"
}
diff --git a/modules/worker/front/calendar/index.html b/modules/worker/front/calendar/index.html
index 9952e1d81..9427ca9e8 100644
--- a/modules/worker/front/calendar/index.html
+++ b/modules/worker/front/calendar/index.html
@@ -3,7 +3,7 @@
data="$ctrl.absenceTypes" auto-load="true">
-
+
{
const absenceType = absence.absenceType;
events.push({
+ name: absenceType.name,
+ description: absenceType.name,
dated: absence.dated,
- title: absenceType.name,
- style: {
- background: absenceType.rgb
- }
+ style: {backgroundColor: absenceType.rgb}
});
});
this.events = this.events.concat(events);
diff --git a/modules/worker/front/calendar/index.spec.js b/modules/worker/front/calendar/index.spec.js
index 194ea8f8b..f29b8fecc 100644
--- a/modules/worker/front/calendar/index.spec.js
+++ b/modules/worker/front/calendar/index.spec.js
@@ -93,7 +93,7 @@ describe('Worker', () => {
controller.setHolidays(data);
expect(controller.events.length).toEqual(2);
- expect(controller.events[0].title).toEqual('New year');
+ expect(controller.events[0].name).toEqual('New year');
expect(controller.events[0].isRemovable).toEqual(false);
});
});
@@ -107,9 +107,9 @@ describe('Worker', () => {
controller.setWorkerCalendar(data);
expect(controller.events.length).toEqual(2);
- expect(controller.events[0].title).toEqual('Holiday');
+ expect(controller.events[0].name).toEqual('Holiday');
expect(controller.events[0].style).toBeDefined();
- expect(controller.events[1].title).toEqual('Leave');
+ expect(controller.events[1].name).toEqual('Leave');
expect(controller.events[1].style).toBeDefined();
});
});
diff --git a/modules/worker/front/calendar/style.scss b/modules/worker/front/calendar/style.scss
index 70503336a..5028edf32 100644
--- a/modules/worker/front/calendar/style.scss
+++ b/modules/worker/front/calendar/style.scss
@@ -1,5 +1,13 @@
@import "variables";
+.calendar-list .calendar {
+ border-bottom:1px solid #ddd
+}
+
+.calendar-list .calendar:nth-child(2n + 1) {
+ border-right:1px solid #ddd
+}
+
.calendar-list {
align-items: flex-start;
flex-wrap: wrap;
@@ -9,7 +17,7 @@
box-sizing: border-box;
padding: $pad-medium;
overflow: hidden;
- width: 20em
+ width: 50%
}
}