Merge pull request 'Added client consumption campaign filter' (#400) from 2481-campaign_filter into dev
gitea/salix/pipeline/head This commit looks good
Details
gitea/salix/pipeline/head This commit looks good
Details
Reviewed-on: #400 Reviewed-by: Carlos Jimenez <carlosjr@verdnatura.es>
This commit is contained in:
commit
530a4026f8
|
@ -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);
|
||||||
|
};
|
||||||
|
};
|
|
@ -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);
|
||||||
|
});
|
||||||
|
});
|
|
@ -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);
|
||||||
|
});
|
||||||
|
});
|
|
@ -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'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
|
@ -8,6 +8,9 @@
|
||||||
"Bank": {
|
"Bank": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
|
"Campaign": {
|
||||||
|
"dataSource": "vn"
|
||||||
|
},
|
||||||
"Country": {
|
"Country": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
module.exports = Self => {
|
||||||
|
require('../methods/campaign/latest')(Self);
|
||||||
|
require('../methods/campaign/upcoming')(Self);
|
||||||
|
};
|
|
@ -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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -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;
|
|
@ -190,9 +190,24 @@ export default class Autocomplete extends Field {
|
||||||
|
|
||||||
this.input.value = display;
|
this.input.value = display;
|
||||||
|
|
||||||
if (this.translateFields) {
|
if (this.translateFields && this.selection) {
|
||||||
if (this.translateFields.indexOf(this.showField) > -1)
|
const translations = [];
|
||||||
this.input.value = this.$t(display);
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,6 +49,22 @@
|
||||||
ng-model="filter.categoryId">
|
ng-model="filter.categoryId">
|
||||||
</vn-autocomplete>
|
</vn-autocomplete>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
|
<vn-horizontal>
|
||||||
|
<vn-autocomplete vn-one
|
||||||
|
url="Campaigns/latest"
|
||||||
|
label="Campaign"
|
||||||
|
translate-fields="['code']"
|
||||||
|
show-field="code"
|
||||||
|
value-field="id"
|
||||||
|
ng-model="filter.campaign"
|
||||||
|
order="dated DESC"
|
||||||
|
selection="$ctrl.campaignSelection"
|
||||||
|
search-function="{dated: {like: '%'+ $search +'%'}}">
|
||||||
|
<tpl-item>
|
||||||
|
{{code}} {{dated | date: 'yyyy'}}
|
||||||
|
</tpl-item>
|
||||||
|
</vn-autocomplete>
|
||||||
|
</vn-horizontal>
|
||||||
<vn-horizontal>
|
<vn-horizontal>
|
||||||
<vn-date-picker
|
<vn-date-picker
|
||||||
vn-one
|
vn-one
|
||||||
|
|
|
@ -1,7 +1,39 @@
|
||||||
import ngModule from '../module';
|
import ngModule from '../module';
|
||||||
import SearchPanel from 'core/components/searchbar/search-panel';
|
import SearchPanel from 'core/components/searchbar/search-panel';
|
||||||
|
|
||||||
|
class Controller extends SearchPanel {
|
||||||
|
constructor($, $element) {
|
||||||
|
super($, $element);
|
||||||
|
|
||||||
|
this.getUpcomingCampaing();
|
||||||
|
}
|
||||||
|
|
||||||
|
getUpcomingCampaing() {
|
||||||
|
this.$http.get('Campaigns/upcoming').then(res => {
|
||||||
|
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', {
|
ngModule.vnComponent('vnConsumptionSearchPanel', {
|
||||||
template: require('./index.html'),
|
template: require('./index.html'),
|
||||||
controller: SearchPanel
|
controller: Controller
|
||||||
});
|
});
|
||||||
|
|
|
@ -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(`<div></div>`);
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,3 @@
|
||||||
|
allSaints: All Saints Day
|
||||||
|
valentinesDay: Valentine's Day
|
||||||
|
mothersDay: Mother's day
|
|
@ -1,3 +1,7 @@
|
||||||
Item id: Id artículo
|
Item id: Id artículo
|
||||||
From: Desde
|
From: Desde
|
||||||
To: Hasta
|
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
|
|
@ -3,12 +3,6 @@ const LoopBackContext = require('loopback-context');
|
||||||
|
|
||||||
describe('Worker createAbsence()', () => {
|
describe('Worker createAbsence()', () => {
|
||||||
const workerId = 18;
|
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() => {
|
it('should return an error for a user without enough privileges', async() => {
|
||||||
const ctx = {req: {accessToken: {userId: 18}}};
|
const ctx = {req: {accessToken: {userId: 18}}};
|
||||||
|
@ -40,12 +34,15 @@ describe('Worker createAbsence()', () => {
|
||||||
|
|
||||||
const absenceTypeId = 1;
|
const absenceTypeId = 1;
|
||||||
const dated = new Date();
|
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 expectedBusinessId = 18;
|
||||||
const expectedAbsenceTypeId = 1;
|
const expectedAbsenceTypeId = 1;
|
||||||
|
|
||||||
expect(createdAbsence.businessFk).toEqual(expectedBusinessId);
|
expect(createdAbsence.businessFk).toEqual(expectedBusinessId);
|
||||||
expect(createdAbsence.dayOffTypeFk).toEqual(expectedAbsenceTypeId);
|
expect(createdAbsence.dayOffTypeFk).toEqual(expectedAbsenceTypeId);
|
||||||
|
|
||||||
|
// Restores
|
||||||
|
await app.models.Calendar.destroyById(createdAbsence.id);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,29 +2,35 @@ const app = require('vn-loopback/server/server');
|
||||||
const LoopBackContext = require('loopback-context');
|
const LoopBackContext = require('loopback-context');
|
||||||
|
|
||||||
describe('Worker deleteAbsence()', () => {
|
describe('Worker deleteAbsence()', () => {
|
||||||
|
const businessId = 18;
|
||||||
const workerId = 18;
|
const workerId = 18;
|
||||||
let createdAbsence;
|
|
||||||
const activeCtx = {
|
const activeCtx = {
|
||||||
accessToken: {userId: 19},
|
accessToken: {userId: 106},
|
||||||
headers: {origin: 'http://localhost'}
|
headers: {origin: 'http://localhost'}
|
||||||
};
|
};
|
||||||
const ctx = {req: activeCtx};
|
const ctx = {req: activeCtx};
|
||||||
ctx.req.__ = value => {
|
ctx.req.__ = value => {
|
||||||
return value;
|
return value;
|
||||||
};
|
};
|
||||||
|
let createdAbsence;
|
||||||
|
|
||||||
it('should return an error for a user without enough privileges', async() => {
|
beforeEach(async() => {
|
||||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
|
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
|
||||||
active: activeCtx
|
active: activeCtx
|
||||||
});
|
});
|
||||||
|
|
||||||
activeCtx.accessToken.userId = 106;
|
|
||||||
const businessId = 18;
|
|
||||||
createdAbsence = await app.models.Calendar.create({
|
createdAbsence = await app.models.Calendar.create({
|
||||||
businessFk: businessId,
|
businessFk: businessId,
|
||||||
dayOffTypeFk: 1,
|
dayOffTypeFk: 1,
|
||||||
dated: new Date()
|
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;
|
let error;
|
||||||
await app.models.Worker.deleteAbsence(ctx, 18, createdAbsence.id).catch(e => {
|
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() => {
|
it('should create a new absence', async() => {
|
||||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
|
|
||||||
active: activeCtx
|
|
||||||
});
|
|
||||||
|
|
||||||
activeCtx.accessToken.userId = 19;
|
activeCtx.accessToken.userId = 19;
|
||||||
const businessId = 18;
|
|
||||||
|
|
||||||
expect(createdAbsence.businessFk).toEqual(businessId);
|
expect(createdAbsence.businessFk).toEqual(businessId);
|
||||||
|
|
||||||
|
|
|
@ -1,22 +1,37 @@
|
||||||
const app = require('vn-loopback/server/server');
|
const app = require('vn-loopback/server/server');
|
||||||
|
const LoopBackContext = require('loopback-context');
|
||||||
|
|
||||||
describe('Worker updateAbsence()', () => {
|
describe('Worker updateAbsence()', () => {
|
||||||
const workerId = 106;
|
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;
|
let createdAbsence;
|
||||||
|
|
||||||
afterAll(async() => {
|
beforeEach(async() => {
|
||||||
const absence = await app.models.Calendar.findById(createdAbsence.id);
|
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
|
||||||
await absence.destroy();
|
active: activeCtx
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return an error for a user without enough privileges', async() => {
|
|
||||||
const ctx = {req: {accessToken: {userId: 106}}};
|
|
||||||
const expectedAbsenceTypeId = 2;
|
|
||||||
createdAbsence = await app.models.Calendar.create({
|
createdAbsence = await app.models.Calendar.create({
|
||||||
businessFk: 106,
|
businessFk: businessId,
|
||||||
dayOffTypeFk: 1,
|
dayOffTypeFk: 1,
|
||||||
dated: new Date()
|
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;
|
let error;
|
||||||
await app.models.Worker.updateAbsence(ctx, workerId, createdAbsence.id, expectedAbsenceTypeId).catch(e => {
|
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() => {
|
it('should create a new absence', async() => {
|
||||||
const ctx = {req: {accessToken: {userId: 37}}};
|
activeCtx.accessToken.userId = 37;
|
||||||
const expectedAbsenceTypeId = 2;
|
const expectedAbsenceTypeId = 2;
|
||||||
const updatedAbsence = await app.models.Worker.updateAbsence(ctx, workerId, createdAbsence.id, expectedAbsenceTypeId);
|
const updatedAbsence = await app.models.Worker.updateAbsence(ctx, workerId, createdAbsence.id, expectedAbsenceTypeId);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue