diff --git a/back/methods/campaign/latest.js b/back/methods/campaign/latest.js
new file mode 100644
index 0000000000..f1449dfecf
--- /dev/null
+++ b/back/methods/campaign/latest.js
@@ -0,0 +1,41 @@
+const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
+const mergeFilters = require('vn-loopback/util/filter').mergeFilters;
+
+module.exports = Self => {
+ Self.remoteMethod('latest', {
+ description: 'Returns the lastest campaigns',
+ accessType: 'READ',
+ accepts: [{
+ arg: 'filter',
+ type: 'Object',
+ description: `Filter defining where, order, offset, and limit - must be a JSON-encoded string`
+ }],
+ returns: {
+ type: ['object'],
+ root: true
+ },
+ http: {
+ path: `/latest`,
+ verb: 'GET'
+ }
+ });
+
+ Self.latest = async filter => {
+ const conn = Self.dataSource.connector;
+ const minDate = new Date();
+ minDate.setFullYear(minDate.getFullYear() - 1);
+ minDate.setMonth(0);
+ minDate.setDate(1);
+
+ const where = {dated: {gte: minDate}};
+ filter = mergeFilters(filter, {where});
+
+ const stmt = new ParameterizedSQL(
+ `SELECT * FROM campaign`);
+ stmt.merge(conn.makeWhere(filter.where));
+ stmt.merge('GROUP BY code');
+ stmt.merge(conn.makePagination(filter));
+
+ return conn.executeStmt(stmt);
+ };
+};
diff --git a/back/methods/campaign/spec/latest.spec.js b/back/methods/campaign/spec/latest.spec.js
new file mode 100644
index 0000000000..b76e4fd0a1
--- /dev/null
+++ b/back/methods/campaign/spec/latest.spec.js
@@ -0,0 +1,34 @@
+const app = require('vn-loopback/server/server');
+
+describe('campaign latest()', () => {
+ it('should return the campaigns from the last year', async() => {
+ let result = await app.models.Campaign.latest();
+
+ const lastYearDate = new Date();
+ lastYearDate.setFullYear(lastYearDate.getFullYear() - 1);
+ const lastYear = lastYearDate.getFullYear();
+
+ const randomIndex = Math.floor(Math.random() * result.length);
+ const campaignDated = result[randomIndex].dated;
+ const campaignYear = campaignDated.getFullYear();
+
+ expect(result.length).toEqual(3);
+ expect(campaignYear).toEqual(lastYear);
+ });
+
+ it('should return the campaigns from the current year', async() => {
+ const currentDate = new Date();
+ const currentYear = currentDate.getFullYear();
+
+ const result = await app.models.Campaign.latest({
+ where: {dated: {like: `%${currentYear}%`}}
+ });
+
+ const randomIndex = Math.floor(Math.random() * result.length);
+ const campaignDated = result[randomIndex].dated;
+ const campaignYear = campaignDated.getFullYear();
+
+ expect(result.length).toEqual(3);
+ expect(campaignYear).toEqual(currentYear);
+ });
+});
diff --git a/back/methods/campaign/spec/upcoming.spec.js b/back/methods/campaign/spec/upcoming.spec.js
new file mode 100644
index 0000000000..953683e7a3
--- /dev/null
+++ b/back/methods/campaign/spec/upcoming.spec.js
@@ -0,0 +1,16 @@
+const app = require('vn-loopback/server/server');
+
+describe('campaign upcoming()', () => {
+ it('should return the upcoming campaign but from the last year', async() => {
+ let response = await app.models.Campaign.upcoming();
+
+ const lastYearDate = new Date();
+ lastYearDate.setFullYear(lastYearDate.getFullYear() - 1);
+ const lastYear = lastYearDate.getFullYear();
+
+ const campaignDated = response.dated;
+ const campaignYear = campaignDated.getFullYear();
+
+ expect(campaignYear).toEqual(lastYear);
+ });
+});
diff --git a/back/methods/campaign/upcoming.js b/back/methods/campaign/upcoming.js
new file mode 100644
index 0000000000..2f1a5a3776
--- /dev/null
+++ b/back/methods/campaign/upcoming.js
@@ -0,0 +1,29 @@
+module.exports = Self => {
+ Self.remoteMethod('upcoming', {
+ description: 'Returns the upcoming campaign',
+ accessType: 'READ',
+ accepts: [],
+ returns: {
+ type: ['object'],
+ root: true
+ },
+ http: {
+ path: `/upcoming`,
+ verb: 'GET'
+ }
+ });
+
+ Self.upcoming = async() => {
+ const minDate = new Date();
+ minDate.setFullYear(minDate.getFullYear() - 1);
+
+ return Self.findOne({
+ where: {
+ dated: {
+ gte: minDate
+ }
+ },
+ order: 'dated ASC'
+ });
+ };
+};
diff --git a/back/model-config.json b/back/model-config.json
index b8a8f04ac9..7a59aaf9aa 100644
--- a/back/model-config.json
+++ b/back/model-config.json
@@ -8,6 +8,9 @@
"Bank": {
"dataSource": "vn"
},
+ "Campaign": {
+ "dataSource": "vn"
+ },
"Country": {
"dataSource": "vn"
},
diff --git a/back/models/campaign.js b/back/models/campaign.js
new file mode 100644
index 0000000000..db5f2e8286
--- /dev/null
+++ b/back/models/campaign.js
@@ -0,0 +1,4 @@
+module.exports = Self => {
+ require('../methods/campaign/latest')(Self);
+ require('../methods/campaign/upcoming')(Self);
+};
diff --git a/back/models/campaign.json b/back/models/campaign.json
new file mode 100644
index 0000000000..e99e8d8193
--- /dev/null
+++ b/back/models/campaign.json
@@ -0,0 +1,33 @@
+{
+ "name": "Campaign",
+ "base": "VnModel",
+ "options": {
+ "mysql": {
+ "table": "campaign"
+ }
+ },
+ "properties": {
+ "id": {
+ "type": "number",
+ "required": true
+ },
+ "code": {
+ "type": "string",
+ "required": true
+ },
+ "dated": {
+ "type": "date"
+ },
+ "scopeDays": {
+ "type": "number"
+ }
+ },
+ "acls": [
+ {
+ "accessType": "READ",
+ "principalType": "ROLE",
+ "principalId": "$everyone",
+ "permission": "ALLOW"
+ }
+ ]
+}
diff --git a/db/changes/10230-oktoberFest/00-campaign.sql b/db/changes/10230-oktoberFest/00-campaign.sql
new file mode 100644
index 0000000000..0e5b91170e
--- /dev/null
+++ b/db/changes/10230-oktoberFest/00-campaign.sql
@@ -0,0 +1,37 @@
+CREATE TABLE `vn`.campaign
+(
+ id INT AUTO_INCREMENT,
+ code ENUM('mothersDay', 'allSaints', 'valentinesDay') NOT NULL,
+ dated DATE DEFAULT CURDATE() NOT NULL,
+ scopeDays INT NOT NULL DEFAULT '15',
+ CONSTRAINT campaign_pk
+ PRIMARY KEY (id)
+);
+
+CREATE UNIQUE INDEX campaign_dated_uindex
+ ON `vn`.campaign (dated);
+
+-- TODOS SANTOS
+INSERT INTO `vn`.campaign(code, dated)
+SELECT 'allSaints' AS code, dated
+ FROM `vn`.time
+WHERE dated >= CONCAT(YEAR(CURDATE()) - 1, '-01-01')
+ AND month = 11
+ AND day = 1;
+
+-- SAN VALENTIN
+INSERT INTO `vn`.campaign(code, dated)
+SELECT 'valentinesDay' AS code, dated
+ FROM `vn`.time
+WHERE dated >= CONCAT(YEAR(CURDATE()) - 1, '-01-01')
+ AND month = 2
+ AND day = 14;
+
+-- DIA DE LA MADRE
+INSERT INTO `vn`.campaign(code, dated)
+SELECT 'mothersDay' AS code, dated
+ FROM `vn`.time
+WHERE dated >= CONCAT(YEAR(CURDATE()) - 1, '-01-01')
+ AND month = 5
+ AND WEEK(dated, 5) - WEEK(DATE_SUB(dated, INTERVAL DAYOFMONTH(dated) - 1 DAY), 5) + 1 = 1 -- WEEK OF MONTH
+ AND DAYOFWEEK(dated) = 1;
diff --git a/front/core/components/autocomplete/index.js b/front/core/components/autocomplete/index.js
index b335d266f0..18c277f062 100755
--- a/front/core/components/autocomplete/index.js
+++ b/front/core/components/autocomplete/index.js
@@ -190,9 +190,24 @@ export default class Autocomplete extends Field {
this.input.value = display;
- if (this.translateFields) {
- if (this.translateFields.indexOf(this.showField) > -1)
- this.input.value = this.$t(display);
+ if (this.translateFields && this.selection) {
+ const translations = [];
+ for (let field of this.translateFields) {
+ const fieldValue = this._selection[field];
+ translations.push({
+ original: fieldValue,
+ value: this.$t(fieldValue)
+ });
+ }
+
+ for (let translation of translations) {
+ const orgValue = translation.original;
+ const value = translation.value;
+
+ display = display.replace(orgValue, value);
+ }
+
+ this.input.value = display;
}
}
diff --git a/modules/client/front/consumption-search-panel/index.html b/modules/client/front/consumption-search-panel/index.html
index e957c891b3..f8d633c718 100644
--- a/modules/client/front/consumption-search-panel/index.html
+++ b/modules/client/front/consumption-search-panel/index.html
@@ -49,6 +49,22 @@
ng-model="filter.categoryId">
+
+
+
+ {{code}} {{dated | date: 'yyyy'}}
+
+
+
{
+ const filter = this.$.filter;
+ filter.campaign = res.data.id;
+ });
+ }
+
+ get campaignSelection() {
+ return this._campaignSelection;
+ }
+
+ set campaignSelection(value) {
+ this._campaignSelection = value;
+
+ if (!value) return;
+
+ const filter = this.$.filter;
+ const from = new Date(value.dated);
+ from.setDate(from.getDate() - value.scopeDays);
+
+ filter.to = value.dated;
+ filter.from = from;
+ }
+}
+
ngModule.vnComponent('vnConsumptionSearchPanel', {
template: require('./index.html'),
- controller: SearchPanel
+ controller: Controller
});
diff --git a/modules/client/front/consumption-search-panel/index.spec.js b/modules/client/front/consumption-search-panel/index.spec.js
new file mode 100644
index 0000000000..7209fe3c3a
--- /dev/null
+++ b/modules/client/front/consumption-search-panel/index.spec.js
@@ -0,0 +1,31 @@
+import './index.js';
+
+describe('Client', () => {
+ describe('Component vnConsumptionSearchPanel', () => {
+ let $httpBackend;
+ let $element;
+ let controller;
+
+ beforeEach(ngModule('client'));
+
+ beforeEach(inject(($componentController, _$httpBackend_) => {
+ $httpBackend = _$httpBackend_;
+ $element = angular.element(``);
+ controller = $componentController('vnConsumptionSearchPanel', {$element});
+ controller.$.filter = {};
+ $httpBackend.expect('GET', 'Campaigns/upcoming').respond(200, {id: 1});
+ }));
+
+ describe('getUpcomingCampaing()', () => {
+ it(`should make an HTTP query and then set the campaign property`, () => {
+ $httpBackend.expect('GET', 'Campaigns/upcoming').respond(200, {id: 2, code: 'allSaints'});
+ controller.getUpcomingCampaing();
+ $httpBackend.flush();
+
+ const filter = controller.$.filter;
+
+ expect(filter.campaign).toEqual(2);
+ });
+ });
+ });
+});
diff --git a/modules/client/front/consumption-search-panel/locale/en.yml b/modules/client/front/consumption-search-panel/locale/en.yml
new file mode 100644
index 0000000000..03364d7cff
--- /dev/null
+++ b/modules/client/front/consumption-search-panel/locale/en.yml
@@ -0,0 +1,3 @@
+allSaints: All Saints Day
+valentinesDay: Valentine's Day
+mothersDay: Mother's day
\ No newline at end of file
diff --git a/modules/client/front/consumption-search-panel/locale/es.yml b/modules/client/front/consumption-search-panel/locale/es.yml
index 68de42b23a..f136283f87 100644
--- a/modules/client/front/consumption-search-panel/locale/es.yml
+++ b/modules/client/front/consumption-search-panel/locale/es.yml
@@ -1,3 +1,7 @@
Item id: Id artículo
From: Desde
-To: Hasta
\ No newline at end of file
+To: Hasta
+Campaign: Campaña
+allSaints: Día de todos los Santos
+valentinesDay: Día de San Valentín
+mothersDay: Día de la madre
\ No newline at end of file
diff --git a/modules/worker/back/methods/worker/specs/createAbsence.spec.js b/modules/worker/back/methods/worker/specs/createAbsence.spec.js
index 324dab99dd..ace412890f 100644
--- a/modules/worker/back/methods/worker/specs/createAbsence.spec.js
+++ b/modules/worker/back/methods/worker/specs/createAbsence.spec.js
@@ -3,12 +3,6 @@ const LoopBackContext = require('loopback-context');
describe('Worker createAbsence()', () => {
const workerId = 18;
- let createdAbsence;
-
- afterAll(async() => {
- const absence = await app.models.Calendar.findById(createdAbsence.id);
- await absence.destroy();
- });
it('should return an error for a user without enough privileges', async() => {
const ctx = {req: {accessToken: {userId: 18}}};
@@ -40,12 +34,15 @@ describe('Worker createAbsence()', () => {
const absenceTypeId = 1;
const dated = new Date();
- createdAbsence = await app.models.Worker.createAbsence(ctx, workerId, absenceTypeId, dated);
+ const createdAbsence = await app.models.Worker.createAbsence(ctx, workerId, absenceTypeId, dated);
const expectedBusinessId = 18;
const expectedAbsenceTypeId = 1;
expect(createdAbsence.businessFk).toEqual(expectedBusinessId);
expect(createdAbsence.dayOffTypeFk).toEqual(expectedAbsenceTypeId);
+
+ // Restores
+ await app.models.Calendar.destroyById(createdAbsence.id);
});
});
diff --git a/modules/worker/back/methods/worker/specs/deleteAbsence.spec.js b/modules/worker/back/methods/worker/specs/deleteAbsence.spec.js
index 2f72a8435a..15bd854ed1 100644
--- a/modules/worker/back/methods/worker/specs/deleteAbsence.spec.js
+++ b/modules/worker/back/methods/worker/specs/deleteAbsence.spec.js
@@ -2,29 +2,35 @@ const app = require('vn-loopback/server/server');
const LoopBackContext = require('loopback-context');
describe('Worker deleteAbsence()', () => {
+ const businessId = 18;
const workerId = 18;
- let createdAbsence;
const activeCtx = {
- accessToken: {userId: 19},
+ accessToken: {userId: 106},
headers: {origin: 'http://localhost'}
};
const ctx = {req: activeCtx};
ctx.req.__ = value => {
return value;
};
+ let createdAbsence;
- it('should return an error for a user without enough privileges', async() => {
+ beforeEach(async() => {
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
active: activeCtx
});
-
- activeCtx.accessToken.userId = 106;
- const businessId = 18;
createdAbsence = await app.models.Calendar.create({
businessFk: businessId,
dayOffTypeFk: 1,
dated: new Date()
});
+ });
+
+ afterEach(async() => {
+ await app.models.Calendar.destroyById(createdAbsence.id);
+ });
+
+ it('should return an error for a user without enough privileges', async() => {
+ activeCtx.accessToken.userId = 106;
let error;
await app.models.Worker.deleteAbsence(ctx, 18, createdAbsence.id).catch(e => {
@@ -37,12 +43,7 @@ describe('Worker deleteAbsence()', () => {
});
it('should create a new absence', async() => {
- spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
- active: activeCtx
- });
-
activeCtx.accessToken.userId = 19;
- const businessId = 18;
expect(createdAbsence.businessFk).toEqual(businessId);
diff --git a/modules/worker/back/methods/worker/specs/updateAbsence.spec.js b/modules/worker/back/methods/worker/specs/updateAbsence.spec.js
index 1b34cf2e01..2ff8e64e1e 100644
--- a/modules/worker/back/methods/worker/specs/updateAbsence.spec.js
+++ b/modules/worker/back/methods/worker/specs/updateAbsence.spec.js
@@ -1,22 +1,37 @@
const app = require('vn-loopback/server/server');
+const LoopBackContext = require('loopback-context');
describe('Worker updateAbsence()', () => {
const workerId = 106;
+ const businessId = 106;
+ const activeCtx = {
+ accessToken: {userId: 106},
+ headers: {origin: 'http://localhost'}
+ };
+ const ctx = {req: activeCtx};
+ ctx.req.__ = value => {
+ return value;
+ };
let createdAbsence;
- afterAll(async() => {
- const absence = await app.models.Calendar.findById(createdAbsence.id);
- await absence.destroy();
- });
-
- it('should return an error for a user without enough privileges', async() => {
- const ctx = {req: {accessToken: {userId: 106}}};
- const expectedAbsenceTypeId = 2;
+ beforeEach(async() => {
+ spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
+ active: activeCtx
+ });
createdAbsence = await app.models.Calendar.create({
- businessFk: 106,
+ businessFk: businessId,
dayOffTypeFk: 1,
dated: new Date()
});
+ });
+
+ afterEach(async() => {
+ await app.models.Calendar.destroyById(createdAbsence.id);
+ });
+
+ it('should return an error for a user without enough privileges', async() => {
+ activeCtx.accessToken.userId = 106;
+ const expectedAbsenceTypeId = 2;
let error;
await app.models.Worker.updateAbsence(ctx, workerId, createdAbsence.id, expectedAbsenceTypeId).catch(e => {
@@ -29,7 +44,7 @@ describe('Worker updateAbsence()', () => {
});
it('should create a new absence', async() => {
- const ctx = {req: {accessToken: {userId: 37}}};
+ activeCtx.accessToken.userId = 37;
const expectedAbsenceTypeId = 2;
const updatedAbsence = await app.models.Worker.updateAbsence(ctx, workerId, createdAbsence.id, expectedAbsenceTypeId);