Merge pull request '#7323 redirect woker module to Lilium' (!2825) from Worker_Migration into dev
gitea/salix/pipeline/head This commit looks good
Details
gitea/salix/pipeline/head This commit looks good
Details
Reviewed-on: #2825 Reviewed-by: Alex Moreno <alexm@verdnatura.es>
This commit is contained in:
commit
00ba0bbe6d
|
@ -1,29 +0,0 @@
|
||||||
import selectors from '../../../helpers/selectors.js';
|
|
||||||
import getBrowser from '../../../helpers/puppeteer';
|
|
||||||
|
|
||||||
describe('department summary path', () => {
|
|
||||||
let browser;
|
|
||||||
let page;
|
|
||||||
beforeAll(async() => {
|
|
||||||
browser = await getBrowser();
|
|
||||||
page = browser.page;
|
|
||||||
await page.loginAndModule('hr', 'worker');
|
|
||||||
await page.accessToSection('worker.department');
|
|
||||||
await page.doSearch('INFORMATICA');
|
|
||||||
await page.click(selectors.department.firstDepartment);
|
|
||||||
});
|
|
||||||
|
|
||||||
afterAll(async() => {
|
|
||||||
await browser.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should reach the employee summary section and check all properties', async() => {
|
|
||||||
expect(await page.waitToGetProperty(selectors.departmentSummary.header, 'innerText')).toEqual('INFORMATICA');
|
|
||||||
expect(await page.getProperty(selectors.departmentSummary.name, 'innerText')).toEqual('INFORMATICA');
|
|
||||||
expect(await page.getProperty(selectors.departmentSummary.code, 'innerText')).toEqual('it');
|
|
||||||
expect(await page.getProperty(selectors.departmentSummary.chat, 'innerText')).toEqual('informatica-cau');
|
|
||||||
expect(await page.getProperty(selectors.departmentSummary.bossDepartment, 'innerText')).toEqual('');
|
|
||||||
expect(await page.getProperty(selectors.departmentSummary.email, 'innerText')).toEqual('-');
|
|
||||||
expect(await page.getProperty(selectors.departmentSummary.clientFk, 'innerText')).toEqual('-');
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,43 +0,0 @@
|
||||||
import getBrowser from '../../../helpers/puppeteer';
|
|
||||||
import selectors from '../../../helpers/selectors.js';
|
|
||||||
|
|
||||||
const $ = {
|
|
||||||
form: 'vn-worker-department-basic-data form',
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('department summary path', () => {
|
|
||||||
let browser;
|
|
||||||
let page;
|
|
||||||
beforeAll(async() => {
|
|
||||||
browser = await getBrowser();
|
|
||||||
page = browser.page;
|
|
||||||
await page.loginAndModule('hr', 'worker');
|
|
||||||
await page.accessToSection('worker.department');
|
|
||||||
await page.doSearch('INFORMATICA');
|
|
||||||
await page.click(selectors.department.firstDepartment);
|
|
||||||
});
|
|
||||||
|
|
||||||
beforeEach(async() => {
|
|
||||||
await page.accessToSection('worker.department.card.basicData');
|
|
||||||
});
|
|
||||||
|
|
||||||
afterAll(async() => {
|
|
||||||
await browser.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should edit the department basic data and confirm the department data was edited`, async() => {
|
|
||||||
const values = {
|
|
||||||
Name: 'Informatica',
|
|
||||||
Code: 'IT',
|
|
||||||
Chat: 'informatica-cau',
|
|
||||||
Email: 'it@verdnatura.es',
|
|
||||||
};
|
|
||||||
|
|
||||||
await page.fillForm($.form, values);
|
|
||||||
const formValues = await page.fetchForm($.form, Object.keys(values));
|
|
||||||
const message = await page.sendForm($.form, values);
|
|
||||||
|
|
||||||
expect(message.isSuccess).toBeTrue();
|
|
||||||
expect(formValues).toEqual(values);
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,34 +0,0 @@
|
||||||
import selectors from '../../helpers/selectors.js';
|
|
||||||
import getBrowser from '../../helpers/puppeteer';
|
|
||||||
|
|
||||||
describe('Worker summary path', () => {
|
|
||||||
const workerId = 3;
|
|
||||||
let browser;
|
|
||||||
let page;
|
|
||||||
beforeAll(async() => {
|
|
||||||
browser = await getBrowser();
|
|
||||||
page = browser.page;
|
|
||||||
await page.loginAndModule('employee', 'worker');
|
|
||||||
const httpDataResponse = page.waitForResponse(response => {
|
|
||||||
return response.status() === 200 && response.url().includes(`Workers/${workerId}`);
|
|
||||||
});
|
|
||||||
await page.accessToSearchResult('agencyNick');
|
|
||||||
await httpDataResponse;
|
|
||||||
});
|
|
||||||
|
|
||||||
afterAll(async() => {
|
|
||||||
await browser.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should reach the employee summary section and check all properties', async() => {
|
|
||||||
expect(await page.getProperty(selectors.workerSummary.header, 'innerText')).toEqual('agency agency');
|
|
||||||
expect(await page.getProperty(selectors.workerSummary.id, 'innerText')).toEqual('3');
|
|
||||||
expect(await page.getProperty(selectors.workerSummary.email, 'innerText')).toEqual('agency@verdnatura.es');
|
|
||||||
expect(await page.getProperty(selectors.workerSummary.department, 'innerText')).toEqual('CAMARA');
|
|
||||||
expect(await page.getProperty(selectors.workerSummary.userId, 'innerText')).toEqual('3');
|
|
||||||
expect(await page.getProperty(selectors.workerSummary.userName, 'innerText')).toEqual('agency');
|
|
||||||
expect(await page.getProperty(selectors.workerSummary.role, 'innerText')).toEqual('agency');
|
|
||||||
expect(await page.getProperty(selectors.workerSummary.extension, 'innerText')).toEqual('1101');
|
|
||||||
expect(await page.getProperty(selectors.workerSummary.locker, 'innerText')).toEqual('-');
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,40 +0,0 @@
|
||||||
import selectors from '../../helpers/selectors.js';
|
|
||||||
import getBrowser from '../../helpers/puppeteer';
|
|
||||||
|
|
||||||
describe('Worker basic data path', () => {
|
|
||||||
const workerId = 1106;
|
|
||||||
let browser;
|
|
||||||
let page;
|
|
||||||
beforeAll(async() => {
|
|
||||||
browser = await getBrowser();
|
|
||||||
page = browser.page;
|
|
||||||
await page.loginAndModule('hr', 'worker');
|
|
||||||
const httpDataResponse = page.waitForResponse(response => {
|
|
||||||
return response.status() === 200 && response.url().includes(`Workers/${workerId}`);
|
|
||||||
});
|
|
||||||
await page.accessToSearchResult('David Charles Haller');
|
|
||||||
await httpDataResponse;
|
|
||||||
await page.accessToSection('worker.card.basicData');
|
|
||||||
});
|
|
||||||
|
|
||||||
afterAll(async() => {
|
|
||||||
await browser.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should edit the form and then reload the section and check the data was edited', async() => {
|
|
||||||
await page.overwrite(selectors.workerBasicData.name, 'David C.');
|
|
||||||
await page.overwrite(selectors.workerBasicData.surname, 'H.');
|
|
||||||
await page.overwrite(selectors.workerBasicData.phone, '444332211');
|
|
||||||
await page.click(selectors.workerBasicData.saveButton);
|
|
||||||
|
|
||||||
const message = await page.waitForSnackbar();
|
|
||||||
|
|
||||||
expect(message.text).toContain('Data saved!');
|
|
||||||
|
|
||||||
await page.reloadSection('worker.card.basicData');
|
|
||||||
|
|
||||||
expect(await page.waitToGetProperty(selectors.workerBasicData.name, 'value')).toEqual('David C.');
|
|
||||||
expect(await page.waitToGetProperty(selectors.workerBasicData.surname, 'value')).toEqual('H.');
|
|
||||||
expect(await page.waitToGetProperty(selectors.workerBasicData.phone, 'value')).toEqual('444332211');
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,32 +0,0 @@
|
||||||
import selectors from '../../helpers/selectors.js';
|
|
||||||
import getBrowser from '../../helpers/puppeteer';
|
|
||||||
|
|
||||||
describe('Worker pbx path', () => {
|
|
||||||
let browser;
|
|
||||||
let page;
|
|
||||||
beforeAll(async() => {
|
|
||||||
browser = await getBrowser();
|
|
||||||
page = browser.page;
|
|
||||||
await page.loginAndModule('hr', 'worker');
|
|
||||||
await page.accessToSearchResult('employee');
|
|
||||||
await page.accessToSection('worker.card.pbx');
|
|
||||||
});
|
|
||||||
|
|
||||||
afterAll(async() => {
|
|
||||||
await browser.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should receive an error when the extension exceeds 4 characters and then sucessfully save the changes', async() => {
|
|
||||||
await page.write(selectors.workerPbx.extension, '55555');
|
|
||||||
await page.click(selectors.workerPbx.saveButton);
|
|
||||||
let message = await page.waitForSnackbar();
|
|
||||||
|
|
||||||
expect(message.text).toContain('Extension format is invalid');
|
|
||||||
|
|
||||||
await page.overwrite(selectors.workerPbx.extension, '4444');
|
|
||||||
await page.click(selectors.workerPbx.saveButton);
|
|
||||||
message = await page.waitForSnackbar();
|
|
||||||
|
|
||||||
expect(message.text).toContain('Data saved! User must access web');
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,65 +0,0 @@
|
||||||
/* eslint max-len: ["error", { "code": 150 }]*/
|
|
||||||
import selectors from '../../helpers/selectors.js';
|
|
||||||
import getBrowser from '../../helpers/puppeteer';
|
|
||||||
|
|
||||||
describe('Worker time control path', () => {
|
|
||||||
let browser;
|
|
||||||
let page;
|
|
||||||
beforeAll(async() => {
|
|
||||||
browser = await getBrowser();
|
|
||||||
page = browser.page;
|
|
||||||
await page.loginAndModule('salesBoss', 'worker');
|
|
||||||
await page.accessToSearchResult('HankPym');
|
|
||||||
await page.accessToSection('worker.card.timeControl');
|
|
||||||
});
|
|
||||||
|
|
||||||
afterAll(async() => {
|
|
||||||
await browser.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
const eightAm = '08:00';
|
|
||||||
const fourPm = '16:00';
|
|
||||||
const hankPymId = 1107;
|
|
||||||
|
|
||||||
it('should go to the next month, go to current month and go 1 month in the past', async() => {
|
|
||||||
let date = Date.vnNew();
|
|
||||||
date.setDate(1);
|
|
||||||
date.setMonth(date.getMonth() + 1);
|
|
||||||
let month = date.toLocaleString('default', {month: 'long'});
|
|
||||||
|
|
||||||
await page.waitToClick(selectors.workerTimeControl.nextMonthButton);
|
|
||||||
let result = await page.getProperty(selectors.workerTimeControl.monthName, 'innerText');
|
|
||||||
|
|
||||||
expect(result).toContain(month);
|
|
||||||
|
|
||||||
date = Date.vnNew();
|
|
||||||
date.setDate(1);
|
|
||||||
month = date.toLocaleString('default', {month: 'long'});
|
|
||||||
|
|
||||||
await page.waitToClick(selectors.workerTimeControl.previousMonthButton);
|
|
||||||
result = await page.getProperty(selectors.workerTimeControl.monthName, 'innerText');
|
|
||||||
|
|
||||||
expect(result).toContain(month);
|
|
||||||
|
|
||||||
date = Date.vnNew();
|
|
||||||
date.setDate(1);
|
|
||||||
date.setMonth(date.getMonth() - 1);
|
|
||||||
const timestamp = Math.round(date.getTime() / 1000);
|
|
||||||
month = date.toLocaleString('default', {month: 'long'});
|
|
||||||
|
|
||||||
await page.loginAndModule('salesBoss', 'worker');
|
|
||||||
await page.goto(`http://localhost:5000/#!/worker/${hankPymId}/time-control?timestamp=${timestamp}`);
|
|
||||||
await page.waitToClick(selectors.workerTimeControl.secondWeekDay);
|
|
||||||
|
|
||||||
result = await page.getProperty(selectors.workerTimeControl.monthName, 'innerText');
|
|
||||||
|
|
||||||
expect(result).toContain(month);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should change week of month', async() => {
|
|
||||||
await page.click(selectors.workerTimeControl.thrirdWeekDay);
|
|
||||||
const result = await page.getProperty(selectors.workerTimeControl.mondayWorkedHours, 'innerText');
|
|
||||||
|
|
||||||
expect(result).toEqual('00:00 h.');
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,114 +0,0 @@
|
||||||
/* eslint-disable max-len */
|
|
||||||
import selectors from '../../helpers/selectors.js';
|
|
||||||
import getBrowser from '../../helpers/puppeteer';
|
|
||||||
|
|
||||||
describe('Worker calendar path', () => {
|
|
||||||
const reasonableTimeBetweenClicks = 300;
|
|
||||||
const date = Date.vnNew();
|
|
||||||
const lastYear = (date.getFullYear() - 1).toString();
|
|
||||||
|
|
||||||
let browser;
|
|
||||||
let page;
|
|
||||||
|
|
||||||
async function accessAs(user) {
|
|
||||||
await page.loginAndModule(user, 'worker');
|
|
||||||
await page.accessToSearchResult('Charles Xavier');
|
|
||||||
await page.accessToSection('worker.card.calendar');
|
|
||||||
}
|
|
||||||
|
|
||||||
beforeAll(async() => {
|
|
||||||
browser = await getBrowser();
|
|
||||||
page = browser.page;
|
|
||||||
accessAs('hr');
|
|
||||||
});
|
|
||||||
|
|
||||||
afterAll(async() => {
|
|
||||||
await browser.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('as hr', () => {
|
|
||||||
it('should set two days as holidays on the calendar and check the total holidays increased by 1.5', async() => {
|
|
||||||
await page.waitToClick(selectors.workerCalendar.holidays);
|
|
||||||
await page.waitForTimeout(reasonableTimeBetweenClicks);
|
|
||||||
await page.click(selectors.workerCalendar.penultimateMondayOfJanuary);
|
|
||||||
|
|
||||||
await page.waitForTimeout(reasonableTimeBetweenClicks);
|
|
||||||
await page.click(selectors.workerCalendar.absence);
|
|
||||||
await page.waitForTimeout(reasonableTimeBetweenClicks);
|
|
||||||
await page.click(selectors.workerCalendar.lastMondayOfMarch);
|
|
||||||
|
|
||||||
await page.waitForTimeout(reasonableTimeBetweenClicks);
|
|
||||||
await page.click(selectors.workerCalendar.halfHoliday);
|
|
||||||
await page.waitForTimeout(reasonableTimeBetweenClicks);
|
|
||||||
await page.click(selectors.workerCalendar.fistMondayOfMay);
|
|
||||||
|
|
||||||
await page.waitForTimeout(reasonableTimeBetweenClicks);
|
|
||||||
await page.click(selectors.workerCalendar.furlough);
|
|
||||||
await page.waitForTimeout(reasonableTimeBetweenClicks);
|
|
||||||
await page.click(selectors.workerCalendar.secondTuesdayOfMay);
|
|
||||||
await page.waitForTimeout(reasonableTimeBetweenClicks);
|
|
||||||
await page.click(selectors.workerCalendar.secondWednesdayOfMay);
|
|
||||||
await page.waitForTimeout(reasonableTimeBetweenClicks);
|
|
||||||
await page.click(selectors.workerCalendar.secondThursdayOfMay);
|
|
||||||
|
|
||||||
await page.waitForTimeout(reasonableTimeBetweenClicks);
|
|
||||||
await page.click(selectors.workerCalendar.halfFurlough);
|
|
||||||
await page.waitForTimeout(reasonableTimeBetweenClicks);
|
|
||||||
await page.click(selectors.workerCalendar.secondFridayOfJun);
|
|
||||||
|
|
||||||
expect(await page.getProperty(selectors.workerCalendar.totalHolidaysUsed, 'innerText')).toContain(' 1.5 ');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe(`as salesBoss`, () => {
|
|
||||||
it(`should log in, get to Charles Xavier's calendar, undo what was done here, and check the total holidays used are back to what it was`, async() => {
|
|
||||||
accessAs('salesBoss');
|
|
||||||
|
|
||||||
await page.waitToClick(selectors.workerCalendar.holidays);
|
|
||||||
await page.waitForTimeout(reasonableTimeBetweenClicks);
|
|
||||||
await page.waitToClick(selectors.workerCalendar.penultimateMondayOfJanuary);
|
|
||||||
|
|
||||||
await page.waitForTimeout(reasonableTimeBetweenClicks);
|
|
||||||
await page.waitToClick(selectors.workerCalendar.absence);
|
|
||||||
await page.waitForTimeout(reasonableTimeBetweenClicks);
|
|
||||||
await page.waitToClick(selectors.workerCalendar.lastMondayOfMarch);
|
|
||||||
|
|
||||||
await page.waitForTimeout(reasonableTimeBetweenClicks);
|
|
||||||
await page.waitToClick(selectors.workerCalendar.halfHoliday);
|
|
||||||
await page.waitForTimeout(reasonableTimeBetweenClicks);
|
|
||||||
await page.waitToClick(selectors.workerCalendar.fistMondayOfMay);
|
|
||||||
|
|
||||||
await page.waitForTimeout(reasonableTimeBetweenClicks);
|
|
||||||
await page.waitToClick(selectors.workerCalendar.furlough);
|
|
||||||
await page.waitForTimeout(reasonableTimeBetweenClicks);
|
|
||||||
await page.waitToClick(selectors.workerCalendar.secondTuesdayOfMay);
|
|
||||||
await page.waitForTimeout(reasonableTimeBetweenClicks);
|
|
||||||
await page.waitToClick(selectors.workerCalendar.secondWednesdayOfMay);
|
|
||||||
await page.waitForTimeout(reasonableTimeBetweenClicks);
|
|
||||||
await page.waitToClick(selectors.workerCalendar.secondThursdayOfMay);
|
|
||||||
|
|
||||||
await page.waitForTimeout(reasonableTimeBetweenClicks);
|
|
||||||
await page.waitToClick(selectors.workerCalendar.halfFurlough);
|
|
||||||
await page.waitForTimeout(reasonableTimeBetweenClicks);
|
|
||||||
await page.waitToClick(selectors.workerCalendar.secondFridayOfJun);
|
|
||||||
|
|
||||||
expect(await page.getProperty(selectors.workerCalendar.totalHolidaysUsed, 'innerText')).toContain(' 0 ');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe(`as Charles Xavier`, () => {
|
|
||||||
it('should log in and get to his calendar, make a futile attempt to add holidays, check the total holidays used are now the initial ones and use the year selector to go to the previous year', async() => {
|
|
||||||
accessAs('CharlesXavier');
|
|
||||||
await page.waitToClick(selectors.workerCalendar.holidays);
|
|
||||||
await page.waitForTimeout(reasonableTimeBetweenClicks);
|
|
||||||
|
|
||||||
await page.click(selectors.workerCalendar.penultimateMondayOfJanuary);
|
|
||||||
|
|
||||||
expect(await page.getProperty(selectors.workerCalendar.totalHolidaysUsed, 'innerText')).toContain(' 0 ');
|
|
||||||
|
|
||||||
await page.autocompleteSearch(selectors.workerCalendar.year, lastYear);
|
|
||||||
|
|
||||||
expect(await page.getProperty(selectors.workerCalendar.totalHolidaysUsed, 'innerText')).toContain(' 0 ');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,73 +0,0 @@
|
||||||
import selectors from '../../helpers/selectors.js';
|
|
||||||
import getBrowser from '../../helpers/puppeteer';
|
|
||||||
|
|
||||||
describe('Worker create path', () => {
|
|
||||||
let browser;
|
|
||||||
let page;
|
|
||||||
let newWorker;
|
|
||||||
beforeAll(async() => {
|
|
||||||
browser = await getBrowser();
|
|
||||||
page = browser.page;
|
|
||||||
await page.loginAndModule('hr', 'worker');
|
|
||||||
await page.waitToClick(selectors.workerCreate.newWorkerButton);
|
|
||||||
await page.waitForState('worker.create');
|
|
||||||
});
|
|
||||||
|
|
||||||
afterAll(async() => {
|
|
||||||
await browser.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should insert default data', async() => {
|
|
||||||
await page.write(selectors.workerCreate.firstname, 'Victor');
|
|
||||||
await page.write(selectors.workerCreate.lastname, 'Von Doom');
|
|
||||||
await page.write(selectors.workerCreate.fi, '78457139E');
|
|
||||||
await page.write(selectors.workerCreate.phone, '12356789');
|
|
||||||
await page.write(selectors.workerCreate.postcode, '46680');
|
|
||||||
await page.write(selectors.workerCreate.street, 'S/ DOOMSTADT');
|
|
||||||
await page.write(selectors.workerCreate.email, 'doctorDoom@marvel.com');
|
|
||||||
await page.write(selectors.workerCreate.iban, 'ES9121000418450200051332');
|
|
||||||
|
|
||||||
// should check for autocompleted worker code and worker user name
|
|
||||||
const workerCode = await page
|
|
||||||
.waitToGetProperty(selectors.workerCreate.code, 'value');
|
|
||||||
|
|
||||||
newWorker = await page
|
|
||||||
.waitToGetProperty(selectors.workerCreate.user, 'value');
|
|
||||||
|
|
||||||
expect(workerCode).toEqual('VVD');
|
|
||||||
expect(newWorker).toContain('victorvd');
|
|
||||||
|
|
||||||
// should fail if necessary data is void
|
|
||||||
await page.waitToClick(selectors.workerCreate.createButton);
|
|
||||||
let message = await page.waitForSnackbar();
|
|
||||||
|
|
||||||
expect(message.text).toContain('is a required argument');
|
|
||||||
|
|
||||||
// should create a new worker and go to worker basic data'
|
|
||||||
await page.pickDate(selectors.workerCreate.birth, new Date(1962, 8, 5));
|
|
||||||
await page.autocompleteSearch(selectors.workerCreate.boss, 'deliveryAssistant');
|
|
||||||
await page.waitToClick(selectors.workerCreate.createButton);
|
|
||||||
message = await page.waitForSnackbar();
|
|
||||||
await page.waitForState('worker.card.basicData');
|
|
||||||
|
|
||||||
expect(message.text).toContain('Data saved!');
|
|
||||||
|
|
||||||
// 'rollback'
|
|
||||||
await page.loginAndModule('itManagement', 'account');
|
|
||||||
await page.accessToSearchResult(newWorker);
|
|
||||||
|
|
||||||
await page.waitToClick(selectors.accountDescriptor.menuButton);
|
|
||||||
await page.waitToClick(selectors.accountDescriptor.deactivateUser);
|
|
||||||
await page.waitToClick(selectors.accountDescriptor.acceptButton);
|
|
||||||
message = await page.waitForSnackbar();
|
|
||||||
|
|
||||||
expect(message.text).toContain('User deactivated!');
|
|
||||||
|
|
||||||
await page.waitToClick(selectors.accountDescriptor.menuButton);
|
|
||||||
await page.waitToClick(selectors.accountDescriptor.disableAccount);
|
|
||||||
await page.waitToClick(selectors.accountDescriptor.acceptButton);
|
|
||||||
message = await page.waitForSnackbar();
|
|
||||||
|
|
||||||
expect(message.text).toContain('Account disabled!');
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,42 +0,0 @@
|
||||||
import selectors from '../../helpers/selectors';
|
|
||||||
import getBrowser from '../../helpers/puppeteer';
|
|
||||||
|
|
||||||
describe('Worker Add notes path', () => {
|
|
||||||
let browser;
|
|
||||||
let page;
|
|
||||||
beforeAll(async() => {
|
|
||||||
browser = await getBrowser();
|
|
||||||
page = browser.page;
|
|
||||||
await page.loginAndModule('hr', 'worker');
|
|
||||||
await page.accessToSearchResult('Bruce Banner');
|
|
||||||
await page.accessToSection('worker.card.note.index');
|
|
||||||
});
|
|
||||||
|
|
||||||
afterAll(async() => {
|
|
||||||
await browser.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should reach the notes index`, async() => {
|
|
||||||
await page.waitForState('worker.card.note.index');
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should click on the add note button`, async() => {
|
|
||||||
await page.waitToClick(selectors.workerNotes.addNoteFloatButton);
|
|
||||||
await page.waitForState('worker.card.note.create');
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should create a note`, async() => {
|
|
||||||
await page.waitForSelector(selectors.workerNotes.note);
|
|
||||||
await page.type(`${selectors.workerNotes.note} textarea`, 'Meeting with Black Widow 21st 9am');
|
|
||||||
await page.waitToClick(selectors.workerNotes.saveButton);
|
|
||||||
const message = await page.waitForSnackbar();
|
|
||||||
|
|
||||||
expect(message.text).toContain('Data saved!');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should confirm the note was created', async() => {
|
|
||||||
const result = await page.waitToGetProperty(selectors.workerNotes.firstNoteText, 'innerText');
|
|
||||||
|
|
||||||
expect(result).toEqual('Meeting with Black Widow 21st 9am');
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,93 +0,0 @@
|
||||||
<mg-ajax path="Workers/{{patch.params.id}}" options="vnPatch"></mg-ajax>
|
|
||||||
<vn-watcher
|
|
||||||
vn-id="watcher"
|
|
||||||
data="$ctrl.worker"
|
|
||||||
form="form"
|
|
||||||
save="patch">
|
|
||||||
</vn-watcher>
|
|
||||||
<form name="form" ng-submit="$ctrl.onSubmit()" class="vn-w-md">
|
|
||||||
<vn-card class="vn-pa-lg">
|
|
||||||
<vn-vertical>
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-textfield
|
|
||||||
vn-one
|
|
||||||
label="Name"
|
|
||||||
ng-model="$ctrl.worker.firstName"
|
|
||||||
rule>
|
|
||||||
</vn-textfield>
|
|
||||||
<vn-textfield
|
|
||||||
vn-one
|
|
||||||
label="Last name"
|
|
||||||
ng-model="$ctrl.worker.lastName"
|
|
||||||
rule>
|
|
||||||
</vn-textfield>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-textfield
|
|
||||||
vn-one
|
|
||||||
label="Business phone"
|
|
||||||
ng-model="$ctrl.worker.phone"
|
|
||||||
rule>
|
|
||||||
</vn-textfield>
|
|
||||||
<vn-textfield
|
|
||||||
vn-one
|
|
||||||
label="Mobile extension"
|
|
||||||
ng-model="$ctrl.worker.mobileExtension"
|
|
||||||
rule>
|
|
||||||
</vn-textfield>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-worker-autocomplete
|
|
||||||
ng-model="$ctrl.worker.bossFk"
|
|
||||||
show-field="nickname"
|
|
||||||
label="Boss">
|
|
||||||
</vn-worker-autocomplete>
|
|
||||||
<vn-autocomplete
|
|
||||||
label="Marital status"
|
|
||||||
data="$ctrl.maritalStatus"
|
|
||||||
show-field="name"
|
|
||||||
value-field="code"
|
|
||||||
ng-model="$ctrl.worker.maritalStatus">
|
|
||||||
</vn-autocomplete>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-autocomplete
|
|
||||||
ng-model="$ctrl.worker.originCountryFk"
|
|
||||||
url="Countries"
|
|
||||||
fields="['id', 'name', 'code']"
|
|
||||||
show-field="name"
|
|
||||||
value-field="id"
|
|
||||||
label="Origin country">
|
|
||||||
</vn-autocomplete>
|
|
||||||
<vn-autocomplete
|
|
||||||
ng-model="$ctrl.worker.educationLevelFk"
|
|
||||||
url="EducationLevels"
|
|
||||||
fields="['id', 'name']"
|
|
||||||
show-field="name"
|
|
||||||
value-field="id"
|
|
||||||
label="Education level">
|
|
||||||
</vn-autocomplete>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-textfield
|
|
||||||
vn-one
|
|
||||||
label="SSN"
|
|
||||||
ng-model="$ctrl.worker.SSN"
|
|
||||||
rule>
|
|
||||||
</vn-textfield>
|
|
||||||
</vn-horizontal>
|
|
||||||
</vn-vertical>
|
|
||||||
</vn-card>
|
|
||||||
<vn-button-bar>
|
|
||||||
<vn-submit
|
|
||||||
disabled="!watcher.dataChanged()"
|
|
||||||
label="Save">
|
|
||||||
</vn-submit>
|
|
||||||
<vn-button
|
|
||||||
class="cancel"
|
|
||||||
label="Undo changes"
|
|
||||||
disabled="!watcher.dataChanged()"
|
|
||||||
ng-click="watcher.loadOriginalData()">
|
|
||||||
</vn-button>
|
|
||||||
</vn-button-bar>
|
|
||||||
</form>
|
|
|
@ -1,27 +0,0 @@
|
||||||
import ngModule from '../module';
|
|
||||||
import Section from 'salix/components/section';
|
|
||||||
|
|
||||||
class Controller extends Section {
|
|
||||||
constructor($element, $) {
|
|
||||||
super($element, $);
|
|
||||||
this.maritalStatus = [
|
|
||||||
{code: 'M', name: this.$t('Married')},
|
|
||||||
{code: 'S', name: this.$t('Single')}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
onSubmit() {
|
|
||||||
return this.$.watcher.submit()
|
|
||||||
.then(() => this.card.reload());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ngModule.vnComponent('vnWorkerBasicData', {
|
|
||||||
template: require('./index.html'),
|
|
||||||
controller: Controller,
|
|
||||||
bindings: {
|
|
||||||
worker: '<'
|
|
||||||
},
|
|
||||||
require: {
|
|
||||||
card: '^vnWorkerCard'
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,9 +0,0 @@
|
||||||
Marital status: Estado civil
|
|
||||||
Origin country: País origen
|
|
||||||
Education level: Nivel educación
|
|
||||||
SSN: NSS
|
|
||||||
Married: Casado/a
|
|
||||||
Single: Soltero/a
|
|
||||||
Business phone: Teléfono de empresa
|
|
||||||
Mobile extension: Extensión móvil
|
|
||||||
Locker: Taquilla
|
|
|
@ -1,114 +0,0 @@
|
||||||
<vn-crud-model
|
|
||||||
url="AbsenceTypes"
|
|
||||||
data="absenceTypes"
|
|
||||||
auto-load="true">
|
|
||||||
</vn-crud-model>
|
|
||||||
<div ng-if="$ctrl.card.hasWorkCenter">
|
|
||||||
<div class="vn-w-lg">
|
|
||||||
<vn-card class="vn-pa-sm calendars">
|
|
||||||
<vn-icon ng-if="::$ctrl.isSubordinate" icon="info" color-marginal
|
|
||||||
vn-tooltip="To start adding absences, click an absence type from the right menu and then on the day you want to add an absence">
|
|
||||||
</vn-icon>
|
|
||||||
<vn-calendar
|
|
||||||
ng-repeat="month in $ctrl.months"
|
|
||||||
data="$ctrl.events"
|
|
||||||
default-date="month"
|
|
||||||
format-day="$ctrl.formatDay($day, $element)"
|
|
||||||
display-controls="false"
|
|
||||||
hide-contiguous="true"
|
|
||||||
hide-year="true"
|
|
||||||
on-selection="$ctrl.onSelection($event, $days)">
|
|
||||||
</vn-calendar>
|
|
||||||
</vn-card>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
ng-if="!$ctrl.card.hasWorkCenter"
|
|
||||||
class="bg-title"
|
|
||||||
translate>
|
|
||||||
Autonomous worker
|
|
||||||
</div>
|
|
||||||
<vn-side-menu side="right">
|
|
||||||
<div class="vn-pa-md">
|
|
||||||
<div class="totalBox vn-mb-sm" style="text-align: center;">
|
|
||||||
<h6>{{'Contract' | translate}} #{{$ctrl.businessId}}</h6>
|
|
||||||
<div>
|
|
||||||
{{'Used' | translate}} {{$ctrl.contractHolidays.holidaysEnjoyed || 0}}
|
|
||||||
{{'of' | translate}} {{$ctrl.contractHolidays.totalHolidays || 0}} {{'days' | translate}}
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
{{'Spent' | translate}} {{$ctrl.contractHolidays.hoursEnjoyed || 0}}
|
|
||||||
{{'of' | translate}} {{$ctrl.contractHolidays.totalHours || 0}} {{'hours' | translate}}
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
{{'Paid holidays' | translate}} {{$ctrl.contractHolidays.payedHolidays || 0}} {{'days' | translate}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="totalBox" style="text-align: center;">
|
|
||||||
<h6>{{'Year' | translate}} {{$ctrl.year}}</h6>
|
|
||||||
<div>
|
|
||||||
{{'Used' | translate}} {{$ctrl.yearHolidays.holidaysEnjoyed || 0}}
|
|
||||||
{{'of' | translate}} {{$ctrl.yearHolidays.totalHolidays || 0}} {{'days' | translate}}
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
{{'Spent' | translate}} {{$ctrl.yearHolidays.hoursEnjoyed || 0}}
|
|
||||||
{{'of' | translate}} {{$ctrl.yearHolidays.totalHours || 0}} {{'hours' | translate}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="vn-pt-md">
|
|
||||||
<vn-autocomplete label="Year"
|
|
||||||
data="$ctrl.yearFilter"
|
|
||||||
ng-model="$ctrl.year"
|
|
||||||
show-field="year"
|
|
||||||
value-field="year"
|
|
||||||
order="DESC">
|
|
||||||
</vn-autocomplete>
|
|
||||||
<vn-autocomplete label="Contract"
|
|
||||||
url="Workers/{{$ctrl.$params.id}}/contracts"
|
|
||||||
fields="['started', 'ended']"
|
|
||||||
ng-model="$ctrl.businessId"
|
|
||||||
search-function="{businessFk: $search}"
|
|
||||||
show-field="businessFk"
|
|
||||||
value-field="businessFk"
|
|
||||||
order="businessFk DESC"
|
|
||||||
limit="5">
|
|
||||||
<tpl-item>
|
|
||||||
<div>#{{businessFk}}</div>
|
|
||||||
<div class="text-caption text-secondary">
|
|
||||||
{{started | date: 'dd/MM/yyyy'}} - {{ended ? (ended | date: 'dd/MM/yyyy') : 'Indef.'}}
|
|
||||||
</div>
|
|
||||||
</tpl-item>
|
|
||||||
</vn-autocomplete>
|
|
||||||
</div>
|
|
||||||
<div name="absenceTypes" class="input vn-py-md" style="overflow: hidden;">
|
|
||||||
<vn-chip ng-repeat="absenceType in absenceTypes" ng-class="::{'selectable': $ctrl.isSubordinate}" ng-click="$ctrl.pick(absenceType)">
|
|
||||||
<vn-avatar ng-style="{backgroundColor: absenceType.rgb}">
|
|
||||||
<vn-icon class="check" icon="check" ng-if="absenceType.id == $ctrl.absenceType.id"></vn-icon>
|
|
||||||
|
|
||||||
</vn-avatar>
|
|
||||||
{{absenceType.name}}
|
|
||||||
</vn-chip>
|
|
||||||
</div>
|
|
||||||
<div class="vn-py-md">
|
|
||||||
<vn-chip>
|
|
||||||
<vn-avatar class="festive">
|
|
||||||
</vn-avatar>
|
|
||||||
<span translate>Festive</span>
|
|
||||||
</vn-chip>
|
|
||||||
<vn-chip>
|
|
||||||
<vn-avatar class="today">
|
|
||||||
</vn-avatar>
|
|
||||||
<span translate>Current day</span>
|
|
||||||
</vn-chip>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</vn-side-menu>
|
|
||||||
|
|
||||||
<vn-confirm
|
|
||||||
vn-id="confirm"
|
|
||||||
message="This item will be deleted"
|
|
||||||
question="Are you sure you want to continue?">
|
|
||||||
</vn-confirm>
|
|
||||||
|
|
|
@ -1,302 +0,0 @@
|
||||||
import ngModule from '../module';
|
|
||||||
import Section from 'salix/components/section';
|
|
||||||
import './style.scss';
|
|
||||||
|
|
||||||
class Controller extends Section {
|
|
||||||
constructor($element, $) {
|
|
||||||
super($element, $);
|
|
||||||
this.date = Date.vnNew();
|
|
||||||
this.events = {};
|
|
||||||
this.buildYearFilter();
|
|
||||||
}
|
|
||||||
|
|
||||||
get year() {
|
|
||||||
return this.date.getFullYear();
|
|
||||||
}
|
|
||||||
|
|
||||||
set year(value) {
|
|
||||||
const newYear = Date.vnNew();
|
|
||||||
newYear.setFullYear(value);
|
|
||||||
|
|
||||||
this.date = newYear;
|
|
||||||
|
|
||||||
this.refresh()
|
|
||||||
.then(() => this.repaint())
|
|
||||||
.then(() => this.getContractHolidays())
|
|
||||||
.then(() => this.getYearHolidays());
|
|
||||||
}
|
|
||||||
|
|
||||||
get businessId() {
|
|
||||||
return this._businessId;
|
|
||||||
}
|
|
||||||
|
|
||||||
set businessId(value) {
|
|
||||||
if (!this.card.hasWorkCenter) return;
|
|
||||||
|
|
||||||
this._businessId = value;
|
|
||||||
if (value) {
|
|
||||||
this.refresh()
|
|
||||||
.then(() => this.repaint())
|
|
||||||
.then(() => this.getContractHolidays())
|
|
||||||
.then(() => this.getYearHolidays());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get date() {
|
|
||||||
return this._date;
|
|
||||||
}
|
|
||||||
|
|
||||||
set date(value) {
|
|
||||||
this._date = value;
|
|
||||||
value.setHours(0, 0, 0, 0);
|
|
||||||
|
|
||||||
this.months = new Array(12);
|
|
||||||
|
|
||||||
for (let i = 0; i < this.months.length; i++) {
|
|
||||||
const now = new Date(value.getTime());
|
|
||||||
now.setDate(1);
|
|
||||||
now.setMonth(i);
|
|
||||||
this.months[i] = now;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get worker() {
|
|
||||||
return this._worker;
|
|
||||||
}
|
|
||||||
|
|
||||||
set worker(value) {
|
|
||||||
this._worker = value;
|
|
||||||
if (value) {
|
|
||||||
this.getIsSubordinate();
|
|
||||||
this.getActiveContract();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
buildYearFilter() {
|
|
||||||
const now = Date.vnNew();
|
|
||||||
now.setFullYear(now.getFullYear() + 1);
|
|
||||||
|
|
||||||
const maxYear = now.getFullYear();
|
|
||||||
const minRange = maxYear - 5;
|
|
||||||
|
|
||||||
const years = [];
|
|
||||||
for (let i = maxYear; i > minRange; i--)
|
|
||||||
years.push({year: i});
|
|
||||||
|
|
||||||
this.yearFilter = years;
|
|
||||||
}
|
|
||||||
|
|
||||||
getIsSubordinate() {
|
|
||||||
this.$http.get(`Workers/${this.worker.id}/isSubordinate`)
|
|
||||||
.then(res => this.isSubordinate = res.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
getActiveContract() {
|
|
||||||
this.$http.get(`Workers/${this.worker.id}/activeContract`)
|
|
||||||
.then(res => {
|
|
||||||
if (res.data) this.businessId = res.data.businessFk;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getContractHolidays() {
|
|
||||||
this.getHolidays({
|
|
||||||
businessFk: this.businessId,
|
|
||||||
year: this.year
|
|
||||||
}, data => this.contractHolidays = data);
|
|
||||||
}
|
|
||||||
|
|
||||||
getYearHolidays() {
|
|
||||||
this.getHolidays({
|
|
||||||
year: this.year
|
|
||||||
}, data => this.yearHolidays = data);
|
|
||||||
}
|
|
||||||
|
|
||||||
getHolidays(params, cb) {
|
|
||||||
this.$http.get(`Workers/${this.worker.id}/holidays`, {params})
|
|
||||||
.then(res => cb(res.data));
|
|
||||||
}
|
|
||||||
|
|
||||||
onData(data) {
|
|
||||||
this.events = {};
|
|
||||||
this.calendar = data.calendar;
|
|
||||||
|
|
||||||
let addEvent = (day, newEvent) => {
|
|
||||||
const timestamp = new Date(day).getTime();
|
|
||||||
const event = this.events[timestamp];
|
|
||||||
|
|
||||||
if (event) {
|
|
||||||
const oldName = event.name;
|
|
||||||
Object.assign(event, newEvent);
|
|
||||||
event.name = `${oldName}, ${event.name}`;
|
|
||||||
} else
|
|
||||||
this.events[timestamp] = newEvent;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (data.holidays) {
|
|
||||||
data.holidays.forEach(holiday => {
|
|
||||||
const holidayDetail = holiday.detail && holiday.detail.name;
|
|
||||||
const holidayType = holiday.type && holiday.type.name;
|
|
||||||
const holidayName = holidayDetail || holidayType;
|
|
||||||
|
|
||||||
addEvent(holiday.dated, {
|
|
||||||
name: holidayName,
|
|
||||||
className: 'festive'
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (data.absences) {
|
|
||||||
data.absences.forEach(absence => {
|
|
||||||
let type = absence.absenceType;
|
|
||||||
addEvent(absence.dated, {
|
|
||||||
name: type.name,
|
|
||||||
color: type.rgb,
|
|
||||||
type: type.code,
|
|
||||||
absenceId: absence.id
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
repaint() {
|
|
||||||
let calendars = this.element.querySelectorAll('vn-calendar');
|
|
||||||
for (let calendar of calendars)
|
|
||||||
calendar.$ctrl.repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
formatDay(day, element) {
|
|
||||||
let event = this.events[day.getTime()];
|
|
||||||
if (!event) return;
|
|
||||||
|
|
||||||
let dayNumber = element.firstElementChild;
|
|
||||||
dayNumber.title = event.name;
|
|
||||||
dayNumber.style.backgroundColor = event.color;
|
|
||||||
|
|
||||||
if (event.border)
|
|
||||||
dayNumber.style.border = event.border;
|
|
||||||
|
|
||||||
if (event.className)
|
|
||||||
dayNumber.classList.add(event.className);
|
|
||||||
}
|
|
||||||
|
|
||||||
pick(absenceType) {
|
|
||||||
if (!this.isSubordinate) return;
|
|
||||||
if (absenceType == this.absenceType)
|
|
||||||
absenceType = null;
|
|
||||||
|
|
||||||
this.absenceType = absenceType;
|
|
||||||
}
|
|
||||||
|
|
||||||
onSelection($event, $days) {
|
|
||||||
if (!this.absenceType)
|
|
||||||
return this.vnApp.showMessage(this.$t('Choose an absence type from the right menu'));
|
|
||||||
|
|
||||||
const day = $days[0];
|
|
||||||
const stamp = day.getTime();
|
|
||||||
const event = this.events[stamp];
|
|
||||||
const calendar = $event.target.closest('vn-calendar').$ctrl;
|
|
||||||
|
|
||||||
if (event && event.absenceId) {
|
|
||||||
if (event.type == this.absenceType.code)
|
|
||||||
this.delete(calendar, day, event);
|
|
||||||
else
|
|
||||||
this.edit(calendar, event);
|
|
||||||
} else
|
|
||||||
this.create(calendar, day);
|
|
||||||
}
|
|
||||||
|
|
||||||
create(calendar, dated) {
|
|
||||||
const absenceType = this.absenceType;
|
|
||||||
const params = {
|
|
||||||
dated: dated,
|
|
||||||
absenceTypeId: absenceType.id,
|
|
||||||
businessFk: this.businessId
|
|
||||||
};
|
|
||||||
|
|
||||||
const path = `Workers/${this.$params.id}/createAbsence`;
|
|
||||||
this.$http.post(path, params).then(res => {
|
|
||||||
const newEvent = res.data;
|
|
||||||
this.events[dated.getTime()] = {
|
|
||||||
name: absenceType.name,
|
|
||||||
color: absenceType.rgb,
|
|
||||||
type: absenceType.code,
|
|
||||||
absenceId: newEvent.id
|
|
||||||
};
|
|
||||||
|
|
||||||
this.repaintCanceller(() =>
|
|
||||||
this.refresh()
|
|
||||||
.then(calendar.repaint())
|
|
||||||
.then(() => this.getContractHolidays())
|
|
||||||
.then(() => this.getYearHolidays())
|
|
||||||
.then(() => this.repaint())
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
edit(calendar, event) {
|
|
||||||
const absenceType = this.absenceType;
|
|
||||||
const params = {
|
|
||||||
absenceId: event.absenceId,
|
|
||||||
absenceTypeId: absenceType.id
|
|
||||||
};
|
|
||||||
const path = `Workers/${this.$params.id}/updateAbsence`;
|
|
||||||
this.$http.patch(path, params).then(() => {
|
|
||||||
event.color = absenceType.rgb;
|
|
||||||
event.name = absenceType.name;
|
|
||||||
event.type = absenceType.code;
|
|
||||||
|
|
||||||
this.repaintCanceller(() =>
|
|
||||||
this.refresh()
|
|
||||||
.then(calendar.repaint())
|
|
||||||
.then(() => this.getContractHolidays())
|
|
||||||
.then(() => this.getYearHolidays())
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
delete(calendar, day, event) {
|
|
||||||
const params = {absenceId: event.absenceId};
|
|
||||||
const path = `Workers/${this.$params.id}/deleteAbsence`;
|
|
||||||
this.$http.delete(path, {params}).then(() => {
|
|
||||||
delete this.events[day.getTime()];
|
|
||||||
|
|
||||||
this.repaintCanceller(() =>
|
|
||||||
this.refresh()
|
|
||||||
.then(calendar.repaint())
|
|
||||||
.then(() => this.getContractHolidays())
|
|
||||||
.then(() => this.getYearHolidays())
|
|
||||||
.then(() => this.repaint())
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
repaintCanceller(cb) {
|
|
||||||
if (this.canceller) {
|
|
||||||
clearTimeout(this.canceller);
|
|
||||||
this.canceller = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.canceller = setTimeout(
|
|
||||||
() => cb(), 500);
|
|
||||||
}
|
|
||||||
|
|
||||||
refresh() {
|
|
||||||
const params = {
|
|
||||||
workerFk: this.$params.id,
|
|
||||||
businessFk: this.businessId,
|
|
||||||
year: this.year
|
|
||||||
};
|
|
||||||
return this.$http.get(`Calendars/absences`, {params})
|
|
||||||
.then(res => this.onData(res.data));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ngModule.vnComponent('vnWorkerCalendar', {
|
|
||||||
template: require('./index.html'),
|
|
||||||
controller: Controller,
|
|
||||||
bindings: {
|
|
||||||
worker: '<'
|
|
||||||
},
|
|
||||||
require: {
|
|
||||||
card: '^vnWorkerCard'
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,346 +0,0 @@
|
||||||
import './index';
|
|
||||||
|
|
||||||
describe('Worker', () => {
|
|
||||||
describe('Component vnWorkerCalendar', () => {
|
|
||||||
let $httpBackend;
|
|
||||||
let $httpParamSerializer;
|
|
||||||
let $scope;
|
|
||||||
let controller;
|
|
||||||
let year = Date.vnNew().getFullYear();
|
|
||||||
|
|
||||||
beforeEach(ngModule('worker'));
|
|
||||||
|
|
||||||
beforeEach(inject(($componentController, $rootScope, _$httpParamSerializer_, _$httpBackend_) => {
|
|
||||||
$scope = $rootScope.$new();
|
|
||||||
$httpBackend = _$httpBackend_;
|
|
||||||
$httpParamSerializer = _$httpParamSerializer_;
|
|
||||||
const $element = angular.element('<vn-worker-calendar></vn-worker-calendar>');
|
|
||||||
controller = $componentController('vnWorkerCalendar', {$element, $scope});
|
|
||||||
controller.isSubordinate = true;
|
|
||||||
controller.absenceType = {id: 1, name: 'Holiday', code: 'holiday', rgb: 'red'};
|
|
||||||
controller.$params.id = 1106;
|
|
||||||
controller._worker = {id: 1106};
|
|
||||||
controller.card = {
|
|
||||||
hasWorkCenter: true
|
|
||||||
};
|
|
||||||
}));
|
|
||||||
|
|
||||||
describe('year() getter', () => {
|
|
||||||
it(`should return the year number of the calendar date`, () => {
|
|
||||||
expect(controller.year).toEqual(year);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('year() setter', () => {
|
|
||||||
it(`should set the year of the calendar date`, () => {
|
|
||||||
jest.spyOn(controller, 'refresh').mockReturnValue(Promise.resolve());
|
|
||||||
|
|
||||||
const previousYear = year - 1;
|
|
||||||
controller.year = previousYear;
|
|
||||||
|
|
||||||
expect(controller.year).toEqual(previousYear);
|
|
||||||
expect(controller.date.getFullYear()).toEqual(previousYear);
|
|
||||||
expect(controller.refresh).toHaveBeenCalledWith();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('businessId() setter', () => {
|
|
||||||
it(`should set the contract id and then call to the refresh method`, () => {
|
|
||||||
jest.spyOn(controller, 'refresh').mockReturnValue(Promise.resolve());
|
|
||||||
|
|
||||||
controller.businessId = 1106;
|
|
||||||
|
|
||||||
expect(controller.refresh).toHaveBeenCalledWith();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('months property', () => {
|
|
||||||
it(`should return an array of twelve months length`, () => {
|
|
||||||
const started = new Date(year, 0, 1);
|
|
||||||
const ended = new Date(year, 11, 1);
|
|
||||||
|
|
||||||
expect(controller.months.length).toEqual(12);
|
|
||||||
expect(controller.months[0]).toEqual(started);
|
|
||||||
expect(controller.months[11]).toEqual(ended);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('worker() setter', () => {
|
|
||||||
it(`should perform a get query and set the reponse data on the model`, () => {
|
|
||||||
controller.getIsSubordinate = jest.fn();
|
|
||||||
controller.getActiveContract = jest.fn();
|
|
||||||
|
|
||||||
let today = Date.vnNew();
|
|
||||||
let tomorrow = new Date(today.getTime());
|
|
||||||
tomorrow.setDate(tomorrow.getDate() + 1);
|
|
||||||
|
|
||||||
let yesterday = new Date(today.getTime());
|
|
||||||
yesterday.setDate(yesterday.getDate() - 1);
|
|
||||||
|
|
||||||
controller.worker = {id: 1107};
|
|
||||||
|
|
||||||
expect(controller.getIsSubordinate).toHaveBeenCalledWith();
|
|
||||||
expect(controller.getActiveContract).toHaveBeenCalledWith();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('getIsSubordinate()', () => {
|
|
||||||
it(`should return whether the worker is a subordinate`, () => {
|
|
||||||
$httpBackend.expect('GET', `Workers/1106/isSubordinate`).respond(true);
|
|
||||||
controller.getIsSubordinate();
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(controller.isSubordinate).toBe(true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('getActiveContract()', () => {
|
|
||||||
it(`should return the current contract and then set the businessId property`, () => {
|
|
||||||
jest.spyOn(controller, 'refresh').mockReturnValue(Promise.resolve());
|
|
||||||
|
|
||||||
$httpBackend.expect('GET', `Workers/1106/activeContract`).respond({businessFk: 1106});
|
|
||||||
controller.getActiveContract();
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(controller.businessId).toEqual(1106);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('getContractHolidays()', () => {
|
|
||||||
it(`should return the worker holidays amount and then set the contractHolidays property`, () => {
|
|
||||||
const today = Date.vnNew();
|
|
||||||
const year = today.getFullYear();
|
|
||||||
|
|
||||||
const serializedParams = $httpParamSerializer({year});
|
|
||||||
$httpBackend.expect('GET', `Workers/1106/holidays?${serializedParams}`).respond({totalHolidays: 28});
|
|
||||||
controller.getContractHolidays();
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(controller.contractHolidays).toEqual({totalHolidays: 28});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('formatDay()', () => {
|
|
||||||
it(`should set the day element style`, () => {
|
|
||||||
const today = Date.vnNew();
|
|
||||||
|
|
||||||
controller.events[today.getTime()] = {
|
|
||||||
name: 'Holiday',
|
|
||||||
color: '#000'
|
|
||||||
};
|
|
||||||
|
|
||||||
const dayElement = angular.element('<div><section></section></div>')[0];
|
|
||||||
const dayNumber = dayElement.firstElementChild;
|
|
||||||
|
|
||||||
controller.formatDay(today, dayElement);
|
|
||||||
|
|
||||||
expect(dayNumber.title).toEqual('Holiday');
|
|
||||||
expect(dayNumber.style.backgroundColor).toEqual('rgb(0, 0, 0)');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('pick()', () => {
|
|
||||||
it(`should set the absenceType property to null if they match with the current one`, () => {
|
|
||||||
const absenceType = {id: 1, name: 'Holiday'};
|
|
||||||
controller.absenceType = absenceType;
|
|
||||||
controller.pick(absenceType);
|
|
||||||
|
|
||||||
expect(controller.absenceType).toBeNull();
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should set the absenceType property`, () => {
|
|
||||||
const absenceType = {id: 1, name: 'Holiday'};
|
|
||||||
const expectedAbsence = {id: 2, name: 'Leave of absence'};
|
|
||||||
controller.absenceType = absenceType;
|
|
||||||
controller.pick(expectedAbsence);
|
|
||||||
|
|
||||||
expect(controller.absenceType).toEqual(expectedAbsence);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('onSelection()', () => {
|
|
||||||
it(`should show an snackbar message if no absence type is selected`, () => {
|
|
||||||
jest.spyOn(controller.vnApp, 'showMessage').mockReturnThis();
|
|
||||||
|
|
||||||
const $event = {};
|
|
||||||
const $days = [];
|
|
||||||
controller.absenceType = null;
|
|
||||||
controller.onSelection($event, $days);
|
|
||||||
|
|
||||||
expect(controller.vnApp.showMessage).toHaveBeenCalledWith('Choose an absence type from the right menu');
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should call to the create() method`, () => {
|
|
||||||
jest.spyOn(controller, 'create').mockReturnThis();
|
|
||||||
|
|
||||||
const selectedDay = Date.vnNew();
|
|
||||||
const $event = {
|
|
||||||
target: {
|
|
||||||
closest: () => {
|
|
||||||
return {$ctrl: {}};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const $days = [selectedDay];
|
|
||||||
controller.absenceType = {id: 1};
|
|
||||||
controller.onSelection($event, $days);
|
|
||||||
|
|
||||||
expect(controller.create).toHaveBeenCalledWith(jasmine.any(Object), selectedDay);
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should call to the delete() method`, () => {
|
|
||||||
jest.spyOn(controller, 'delete').mockReturnThis();
|
|
||||||
|
|
||||||
const selectedDay = Date.vnNew();
|
|
||||||
const expectedEvent = {
|
|
||||||
dated: selectedDay,
|
|
||||||
type: 'holiday',
|
|
||||||
absenceId: 1
|
|
||||||
};
|
|
||||||
const $event = {
|
|
||||||
target: {
|
|
||||||
closest: () => {
|
|
||||||
return {$ctrl: {}};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const $days = [selectedDay];
|
|
||||||
controller.events[selectedDay.getTime()] = expectedEvent;
|
|
||||||
controller.absenceType = {id: 1, code: 'holiday'};
|
|
||||||
controller.onSelection($event, $days);
|
|
||||||
|
|
||||||
expect(controller.delete).toHaveBeenCalledWith(jasmine.any(Object), selectedDay, expectedEvent);
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should call to the edit() method`, () => {
|
|
||||||
jest.spyOn(controller, 'edit').mockReturnThis();
|
|
||||||
|
|
||||||
const selectedDay = Date.vnNew();
|
|
||||||
const expectedEvent = {
|
|
||||||
dated: selectedDay,
|
|
||||||
type: 'leaveOfAbsence',
|
|
||||||
absenceId: 1
|
|
||||||
};
|
|
||||||
const $event = {
|
|
||||||
target: {
|
|
||||||
closest: () => {
|
|
||||||
return {$ctrl: {}};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const $days = [selectedDay];
|
|
||||||
controller.events[selectedDay.getTime()] = expectedEvent;
|
|
||||||
controller.absenceType = {id: 1, code: 'holiday'};
|
|
||||||
controller.onSelection($event, $days);
|
|
||||||
|
|
||||||
expect(controller.edit).toHaveBeenCalledWith(jasmine.any(Object), expectedEvent);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('create()', () => {
|
|
||||||
it(`should make a HTTP POST query and then call to the repaintCanceller() method`, () => {
|
|
||||||
jest.spyOn(controller, 'repaintCanceller').mockReturnThis();
|
|
||||||
|
|
||||||
const dated = Date.vnNew();
|
|
||||||
const calendarElement = {};
|
|
||||||
const expectedResponse = {id: 10};
|
|
||||||
|
|
||||||
$httpBackend.expect('POST', `Workers/1106/createAbsence`).respond(200, expectedResponse);
|
|
||||||
controller.create(calendarElement, dated);
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
const createdEvent = controller.events[dated.getTime()];
|
|
||||||
const absenceType = controller.absenceType;
|
|
||||||
|
|
||||||
expect(createdEvent.absenceId).toEqual(expectedResponse.id);
|
|
||||||
expect(createdEvent.color).toEqual(absenceType.rgb);
|
|
||||||
expect(controller.repaintCanceller).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('edit()', () => {
|
|
||||||
it(`should make a HTTP PATCH query and then call to the repaintCanceller() method`, () => {
|
|
||||||
jest.spyOn(controller, 'repaintCanceller').mockReturnThis();
|
|
||||||
|
|
||||||
const event = {absenceId: 10};
|
|
||||||
const calendarElement = {};
|
|
||||||
const newAbsenceType = {
|
|
||||||
id: 2,
|
|
||||||
name: 'Leave of absence',
|
|
||||||
code: 'leaveOfAbsence',
|
|
||||||
rgb: 'purple'
|
|
||||||
};
|
|
||||||
controller.absenceType = newAbsenceType;
|
|
||||||
|
|
||||||
const expectedParams = {absenceId: 10, absenceTypeId: 2};
|
|
||||||
$httpBackend.expect('PATCH', `Workers/1106/updateAbsence`, expectedParams).respond(200);
|
|
||||||
controller.edit(calendarElement, event);
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(event.name).toEqual(newAbsenceType.name);
|
|
||||||
expect(event.color).toEqual(newAbsenceType.rgb);
|
|
||||||
expect(event.type).toEqual(newAbsenceType.code);
|
|
||||||
expect(controller.repaintCanceller).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('delete()', () => {
|
|
||||||
it(`should make a HTTP DELETE query and then call to the repaintCanceller() method`, () => {
|
|
||||||
jest.spyOn(controller, 'repaintCanceller').mockReturnThis();
|
|
||||||
|
|
||||||
const expectedParams = {absenceId: 10};
|
|
||||||
const calendarElement = {};
|
|
||||||
const selectedDay = Date.vnNew();
|
|
||||||
const expectedEvent = {
|
|
||||||
dated: selectedDay,
|
|
||||||
type: 'leaveOfAbsence',
|
|
||||||
absenceId: 10
|
|
||||||
};
|
|
||||||
|
|
||||||
controller.events[selectedDay.getTime()] = expectedEvent;
|
|
||||||
|
|
||||||
const serializedParams = $httpParamSerializer(expectedParams);
|
|
||||||
$httpBackend.expect('DELETE', `Workers/1106/deleteAbsence?${serializedParams}`).respond(200);
|
|
||||||
controller.delete(calendarElement, selectedDay, expectedEvent);
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
const event = controller.events[selectedDay.getTime()];
|
|
||||||
|
|
||||||
expect(event).toBeUndefined();
|
|
||||||
expect(controller.repaintCanceller).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('repaintCanceller()', () => {
|
|
||||||
it(`should cancell the callback execution timer`, () => {
|
|
||||||
jest.spyOn(window, 'clearTimeout');
|
|
||||||
jest.spyOn(window, 'setTimeout');
|
|
||||||
|
|
||||||
const timeoutId = 90;
|
|
||||||
controller.canceller = timeoutId;
|
|
||||||
|
|
||||||
controller.repaintCanceller(() => {
|
|
||||||
return 'My callback';
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(window.clearTimeout).toHaveBeenCalledWith(timeoutId);
|
|
||||||
expect(window.setTimeout).toHaveBeenCalledWith(jasmine.any(Function), 500);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('refresh()', () => {
|
|
||||||
it(`should make a HTTP GET query and then call to the onData() method`, () => {
|
|
||||||
jest.spyOn(controller, 'onData').mockReturnThis();
|
|
||||||
|
|
||||||
const expecteResponse = [{id: 1}];
|
|
||||||
const expectedParams = {workerFk: controller.worker.id, year: year};
|
|
||||||
const serializedParams = $httpParamSerializer(expectedParams);
|
|
||||||
$httpBackend.expect('GET', `Calendars/absences?${serializedParams}`).respond(200, expecteResponse);
|
|
||||||
controller.refresh();
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(controller.onData).toHaveBeenCalledWith(expecteResponse);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,15 +0,0 @@
|
||||||
Calendar: Calendario
|
|
||||||
Contract: Contrato
|
|
||||||
Festive: Festivo
|
|
||||||
Used: Utilizados
|
|
||||||
Spent: Utilizadas
|
|
||||||
Year: Año
|
|
||||||
of: de
|
|
||||||
days: días
|
|
||||||
hours: horas
|
|
||||||
Choose an absence type from the right menu: Elige un tipo de ausencia desde el menú de la derecha
|
|
||||||
To start adding absences, click an absence type from the right menu and then on the day you want to add an absence: Para empezar a añadir ausencias, haz clic en un tipo de ausencia desde el menu de la derecha y después en el día que quieres añadir la ausencia
|
|
||||||
You can just add absences within the current year: Solo puedes añadir ausencias dentro del año actual
|
|
||||||
Current day: Día actual
|
|
||||||
Paid holidays: Vacaciones pagadas
|
|
||||||
Autonomous worker: Trabajador autónomo
|
|
|
@ -1,65 +0,0 @@
|
||||||
@import "variables";
|
|
||||||
|
|
||||||
vn-worker-calendar {
|
|
||||||
.calendars {
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
box-sizing: border-box;
|
|
||||||
padding: $spacing-md;
|
|
||||||
|
|
||||||
& > vn-calendar {
|
|
||||||
border: $border-thin;
|
|
||||||
margin: $spacing-md;
|
|
||||||
padding: $spacing-xs;
|
|
||||||
max-width: 288px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vn-chip.selectable {
|
|
||||||
cursor: pointer
|
|
||||||
}
|
|
||||||
|
|
||||||
vn-chip.selectable:hover {
|
|
||||||
opacity: 0.8
|
|
||||||
}
|
|
||||||
|
|
||||||
vn-chip vn-avatar {
|
|
||||||
text-align: center;
|
|
||||||
color: white
|
|
||||||
}
|
|
||||||
|
|
||||||
vn-icon[icon="info"] {
|
|
||||||
position: absolute;
|
|
||||||
top: 16px;
|
|
||||||
right: 16px
|
|
||||||
}
|
|
||||||
|
|
||||||
vn-side-menu div > .input {
|
|
||||||
border-bottom: $border-thin;
|
|
||||||
}
|
|
||||||
|
|
||||||
.festive,
|
|
||||||
vn-avatar.today {
|
|
||||||
color: $color-font;
|
|
||||||
width: 24px;
|
|
||||||
min-width: 24px;
|
|
||||||
height: 24px
|
|
||||||
}
|
|
||||||
|
|
||||||
.festive {
|
|
||||||
border: 2px solid $color-alert
|
|
||||||
}
|
|
||||||
|
|
||||||
vn-avatar.today {
|
|
||||||
border: 2px solid $color-font-link
|
|
||||||
}
|
|
||||||
|
|
||||||
.check {
|
|
||||||
margin-top: 0.5px;
|
|
||||||
margin-left: -3px;
|
|
||||||
font-size: 125%;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,198 +0,0 @@
|
||||||
<vn-watcher
|
|
||||||
vn-id="watcher"
|
|
||||||
url="Workers/new"
|
|
||||||
data="$ctrl.worker"
|
|
||||||
insert-mode="true"
|
|
||||||
form="form">
|
|
||||||
</vn-watcher>
|
|
||||||
<form name="form" vn-http-submit="$ctrl.onSubmit()" class="vn-w-md">
|
|
||||||
<vn-card class="vn-pa-lg">
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-textfield
|
|
||||||
vn-one
|
|
||||||
label="Firstname"
|
|
||||||
ng-model="$ctrl.worker.firstName"
|
|
||||||
rule
|
|
||||||
on-change="$ctrl.generateCodeUser()"
|
|
||||||
vn-focus>
|
|
||||||
</vn-textfield>
|
|
||||||
<vn-textfield
|
|
||||||
vn-one
|
|
||||||
label="Lastname"
|
|
||||||
on-change="$ctrl.generateCodeUser()"
|
|
||||||
ng-model="$ctrl.worker.lastNames"
|
|
||||||
rule>
|
|
||||||
</vn-textfield>
|
|
||||||
<vn-date-picker
|
|
||||||
vn-one
|
|
||||||
label="Birth"
|
|
||||||
ng-model="$ctrl.worker.birth">
|
|
||||||
</vn-date-picker>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-textfield
|
|
||||||
vn-one
|
|
||||||
label="Fi"
|
|
||||||
ng-model="$ctrl.worker.fi"
|
|
||||||
rule>
|
|
||||||
</vn-textfield>
|
|
||||||
<vn-textfield
|
|
||||||
vn-one
|
|
||||||
label="Worker code"
|
|
||||||
ng-model="$ctrl.worker.code"
|
|
||||||
maxLength="3"
|
|
||||||
on-change="$ctrl.worker.code = $ctrl.worker.code.toUpperCase()"
|
|
||||||
rule>
|
|
||||||
</vn-textfield>
|
|
||||||
<vn-textfield
|
|
||||||
vn-one
|
|
||||||
label="Phone"
|
|
||||||
ng-model="$ctrl.worker.phone"
|
|
||||||
rule>
|
|
||||||
</vn-textfield>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-datalist
|
|
||||||
label="Postcode"
|
|
||||||
vn-one
|
|
||||||
ng-model="$ctrl.worker.postcode"
|
|
||||||
selection="$ctrl.postcode"
|
|
||||||
url="Postcodes/location"
|
|
||||||
fields="['code','townFk']"
|
|
||||||
order="code, townFk"
|
|
||||||
value-field="code"
|
|
||||||
show-field="code"
|
|
||||||
rule>
|
|
||||||
<tpl-item>
|
|
||||||
{{code}} - {{town.name}} ({{town.province.name}},
|
|
||||||
{{town.province.country.name}})
|
|
||||||
</tpl-item>
|
|
||||||
<append>
|
|
||||||
<vn-icon-button
|
|
||||||
icon="add_circle"
|
|
||||||
vn-tooltip="New postcode"
|
|
||||||
ng-click="postcode.open()"
|
|
||||||
vn-acl="deliveryAssistant"
|
|
||||||
vn-acl-action="remove">
|
|
||||||
</vn-icon-button>
|
|
||||||
</append>
|
|
||||||
</vn-datalist>
|
|
||||||
<vn-autocomplete
|
|
||||||
vn-id="province"
|
|
||||||
label="Province"
|
|
||||||
ng-model="$ctrl.worker.provinceFk"
|
|
||||||
selection="$ctrl.province"
|
|
||||||
url="Provinces/location"
|
|
||||||
fields="['id', 'name', 'countryFk']"
|
|
||||||
rule>
|
|
||||||
<tpl-item>{{name}} ({{country.name}})</tpl-item>
|
|
||||||
</vn-autocomplete>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-datalist
|
|
||||||
vn-id="town"
|
|
||||||
label="City"
|
|
||||||
ng-model="$ctrl.worker.city"
|
|
||||||
selection="$ctrl.town"
|
|
||||||
url="Towns/location"
|
|
||||||
fields="['id', 'name', 'provinceFk']"
|
|
||||||
value-field="name">
|
|
||||||
<tpl-item>
|
|
||||||
{{name}}, {{province.name}}
|
|
||||||
({{province.country.name}})
|
|
||||||
</tpl-item>
|
|
||||||
</vn-datalist>
|
|
||||||
<vn-textfield
|
|
||||||
vn-two
|
|
||||||
label="Street"
|
|
||||||
ng-model="$ctrl.worker.street"
|
|
||||||
rule>
|
|
||||||
</vn-textfield>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-textfield
|
|
||||||
label="Web user"
|
|
||||||
ng-model="$ctrl.worker.name"
|
|
||||||
rule>
|
|
||||||
</vn-textfield>
|
|
||||||
<vn-textfield
|
|
||||||
label="Personal email"
|
|
||||||
ng-model="$ctrl.worker.email"
|
|
||||||
rule>
|
|
||||||
</vn-textfield>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-autocomplete
|
|
||||||
vn-one
|
|
||||||
vn-id="company"
|
|
||||||
ng-model="$ctrl.worker.companyFk"
|
|
||||||
url="Companies"
|
|
||||||
show-field="code"
|
|
||||||
value-field="id"
|
|
||||||
label="Company">
|
|
||||||
</vn-autocomplete>
|
|
||||||
<vn-worker-autocomplete
|
|
||||||
vn-one
|
|
||||||
ng-model="$ctrl.worker.bossFk"
|
|
||||||
show-field="nickname"
|
|
||||||
label="Boss">
|
|
||||||
</vn-worker-autocomplete>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-autocomplete
|
|
||||||
vn-one
|
|
||||||
label="Pay method"
|
|
||||||
url="Paymethods"
|
|
||||||
ng-model="$ctrl.worker.payMethodFk"
|
|
||||||
initial-data="$ctrl.workerConfig.payMethodFk">
|
|
||||||
</vn-autocomplete>
|
|
||||||
<vn-textfield
|
|
||||||
vn-one
|
|
||||||
label="IBAN"
|
|
||||||
ng-model="$ctrl.worker.iban"
|
|
||||||
on-change="$ctrl.autofillBic()"
|
|
||||||
rule>
|
|
||||||
</vn-textfield>
|
|
||||||
<vn-autocomplete
|
|
||||||
vn-one
|
|
||||||
label="Swift / BIC"
|
|
||||||
url="BankEntities"
|
|
||||||
ng-model="$ctrl.worker.bankEntityFk"
|
|
||||||
fields="['name']"
|
|
||||||
initial-data="$ctrl.worker.bankEntityFk"
|
|
||||||
on-change="$ctrl.autofillBic()"
|
|
||||||
search-function="{or: [{bic: {like: $search +'%'}}, {name: {like: '%'+ $search +'%'}}]}"
|
|
||||||
value-field="id"
|
|
||||||
show-field="bic"
|
|
||||||
vn-acl="salesAssistant, hr"
|
|
||||||
disabled="$ctrl.ibanCountry == 'ES'">
|
|
||||||
<tpl-item>{{bic}} {{name}}</tpl-item>
|
|
||||||
<append>
|
|
||||||
<vn-icon-button
|
|
||||||
vn-auto
|
|
||||||
icon="add_circle"
|
|
||||||
vn-click-stop="bankEntity.show({countryFk: $ctrl.worker.countryFk})"
|
|
||||||
vn-tooltip="New bank entity"
|
|
||||||
vn-acl="salesAssistant, hr">
|
|
||||||
</vn-icon-button>
|
|
||||||
</append>
|
|
||||||
</vn-autocomplete>
|
|
||||||
</vn-horizontal>
|
|
||||||
</vn-card>
|
|
||||||
<vn-button-bar>
|
|
||||||
<vn-submit
|
|
||||||
disabled="!watcher.dataChanged()"
|
|
||||||
label="Create">
|
|
||||||
</vn-submit>
|
|
||||||
<vn-button
|
|
||||||
class="cancel"
|
|
||||||
label="Cancel"
|
|
||||||
ui-sref="worker.index">
|
|
||||||
</vn-button>
|
|
||||||
</vn-button-bar>
|
|
||||||
</form>
|
|
||||||
<!-- New postcode dialog -->
|
|
||||||
<vn-geo-postcode
|
|
||||||
vn-id="postcode"
|
|
||||||
on-response="$ctrl.onResponse($response)">
|
|
||||||
</vn-geo-postcode>
|
|
|
@ -1,141 +0,0 @@
|
||||||
import ngModule from '../module';
|
|
||||||
import Section from 'salix/components/section';
|
|
||||||
|
|
||||||
export default class Controller extends Section {
|
|
||||||
constructor($element, $) {
|
|
||||||
super($element, $);
|
|
||||||
this.worker = {companyFk: this.vnConfig.user.companyFk};
|
|
||||||
this.$http.get(`WorkerConfigs/findOne`, {field: ['payMethodFk']}).then(res => {
|
|
||||||
if (res.data) this.worker.payMethodFk = res.data.payMethodFk;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onSubmit() {
|
|
||||||
if (!this.worker.iban && !this.worker.bankEntityFk) {
|
|
||||||
delete this.worker.iban;
|
|
||||||
delete this.worker.bankEntityFk;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.$.watcher.submit().then(json => {
|
|
||||||
this.$state.go('worker.card.basicData', {id: json.data.id});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
get ibanCountry() {
|
|
||||||
if (!this.worker || !this.worker.iban) return false;
|
|
||||||
|
|
||||||
let countryCode = this.worker.iban.substr(0, 2);
|
|
||||||
|
|
||||||
return countryCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
autofillBic() {
|
|
||||||
if (!this.worker || !this.worker.iban) return;
|
|
||||||
|
|
||||||
let bankEntityId = parseInt(this.worker.iban.substr(4, 4));
|
|
||||||
let filter = {where: {id: bankEntityId}};
|
|
||||||
|
|
||||||
this.$http.get(`BankEntities`, {filter}).then(response => {
|
|
||||||
const hasData = response.data && response.data[0];
|
|
||||||
|
|
||||||
if (hasData)
|
|
||||||
this.worker.bankEntityFk = response.data[0].id;
|
|
||||||
else if (!hasData)
|
|
||||||
this.worker.bankEntityFk = null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
generateCodeUser() {
|
|
||||||
if (!this.worker.firstName || !this.worker.lastNames) return;
|
|
||||||
|
|
||||||
const totalName = this.worker.firstName.concat(' ' + this.worker.lastNames).toLowerCase();
|
|
||||||
const totalNameArray = totalName.split(' ');
|
|
||||||
let newCode = '';
|
|
||||||
|
|
||||||
for (let part of totalNameArray)
|
|
||||||
newCode += part.charAt(0);
|
|
||||||
|
|
||||||
this.worker.code = newCode.toUpperCase().slice(0, 3);
|
|
||||||
this.worker.name = totalNameArray[0] + newCode.slice(1);
|
|
||||||
|
|
||||||
if (!this.worker.companyFk)
|
|
||||||
this.worker.companyFk = this.vnConfig.user.companyFk;
|
|
||||||
}
|
|
||||||
|
|
||||||
get province() {
|
|
||||||
return this._province;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Province auto complete
|
|
||||||
set province(selection) {
|
|
||||||
this._province = selection;
|
|
||||||
|
|
||||||
if (!selection) return;
|
|
||||||
|
|
||||||
const country = selection.country;
|
|
||||||
|
|
||||||
if (!this.worker.countryFk)
|
|
||||||
this.worker.countryFk = country.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
get town() {
|
|
||||||
return this._town;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Town auto complete
|
|
||||||
set town(selection) {
|
|
||||||
this._town = selection;
|
|
||||||
|
|
||||||
if (!selection) return;
|
|
||||||
|
|
||||||
const province = selection.province;
|
|
||||||
const country = province.country;
|
|
||||||
const postcodes = selection.postcodes;
|
|
||||||
|
|
||||||
if (!this.worker.provinceFk)
|
|
||||||
this.worker.provinceFk = province.id;
|
|
||||||
|
|
||||||
if (!this.worker.countryFk)
|
|
||||||
this.worker.countryFk = country.id;
|
|
||||||
|
|
||||||
if (postcodes.length === 1)
|
|
||||||
this.worker.postcode = postcodes[0].code;
|
|
||||||
}
|
|
||||||
|
|
||||||
get postcode() {
|
|
||||||
return this._postcode;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Postcode auto complete
|
|
||||||
set postcode(selection) {
|
|
||||||
this._postcode = selection;
|
|
||||||
|
|
||||||
if (!selection) return;
|
|
||||||
|
|
||||||
const town = selection.town;
|
|
||||||
const province = town.province;
|
|
||||||
const country = province.country;
|
|
||||||
|
|
||||||
if (!this.worker.city)
|
|
||||||
this.worker.city = town.name;
|
|
||||||
|
|
||||||
if (!this.worker.provinceFk)
|
|
||||||
this.worker.provinceFk = province.id;
|
|
||||||
|
|
||||||
if (!this.worker.countryFk)
|
|
||||||
this.worker.countryFk = country.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
onResponse(response) {
|
|
||||||
this.worker.postcode = response.code;
|
|
||||||
this.worker.city = response.city;
|
|
||||||
this.worker.provinceFk = response.provinceFk;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Controller.$inject = ['$element', '$scope'];
|
|
||||||
|
|
||||||
ngModule.vnComponent('vnWorkerCreate', {
|
|
||||||
template: require('./index.html'),
|
|
||||||
controller: Controller
|
|
||||||
});
|
|
|
@ -1,133 +0,0 @@
|
||||||
import './index';
|
|
||||||
|
|
||||||
describe('Worker', () => {
|
|
||||||
describe('Component vnWorkerCreate', () => {
|
|
||||||
let $scope;
|
|
||||||
let $state;
|
|
||||||
let controller;
|
|
||||||
|
|
||||||
beforeEach(ngModule('worker'));
|
|
||||||
|
|
||||||
beforeEach(inject(($componentController, $rootScope, _$state_) => {
|
|
||||||
$scope = $rootScope.$new();
|
|
||||||
$state = _$state_;
|
|
||||||
$scope.watcher = {
|
|
||||||
submit: () => {
|
|
||||||
return {
|
|
||||||
then: callback => {
|
|
||||||
callback({data: {id: '1234'}});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const $element = angular.element('<vn-worker-create></vn-worker-create>');
|
|
||||||
controller = $componentController('vnWorkerCreate', {$element, $scope});
|
|
||||||
controller.worker = {};
|
|
||||||
controller.vnConfig = {user: {companyFk: 1}};
|
|
||||||
}));
|
|
||||||
|
|
||||||
describe('onSubmit()', () => {
|
|
||||||
it(`should call submit() on the watcher then expect a callback`, () => {
|
|
||||||
jest.spyOn($state, 'go');
|
|
||||||
controller.onSubmit();
|
|
||||||
|
|
||||||
expect(controller.$state.go).toHaveBeenCalledWith('worker.card.basicData', {id: '1234'});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('province() setter', () => {
|
|
||||||
it(`should set countryFk property`, () => {
|
|
||||||
controller.worker.countryFk = null;
|
|
||||||
controller.province = {
|
|
||||||
id: 1,
|
|
||||||
name: 'New york',
|
|
||||||
country: {
|
|
||||||
id: 2,
|
|
||||||
name: 'USA'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(controller.worker.countryFk).toEqual(2);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('town() setter', () => {
|
|
||||||
it(`should set provinceFk property`, () => {
|
|
||||||
controller.town = {
|
|
||||||
provinceFk: 1,
|
|
||||||
code: 46001,
|
|
||||||
province: {
|
|
||||||
id: 1,
|
|
||||||
name: 'New york',
|
|
||||||
country: {
|
|
||||||
id: 2,
|
|
||||||
name: 'USA'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
postcodes: []
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(controller.worker.provinceFk).toEqual(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should set provinceFk property and fill the postalCode if there's just one`, () => {
|
|
||||||
controller.town = {
|
|
||||||
provinceFk: 1,
|
|
||||||
code: 46001,
|
|
||||||
province: {
|
|
||||||
id: 1,
|
|
||||||
name: 'New york',
|
|
||||||
country: {
|
|
||||||
id: 2,
|
|
||||||
name: 'USA'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
postcodes: [{code: '46001'}]
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(controller.worker.provinceFk).toEqual(1);
|
|
||||||
expect(controller.worker.postcode).toEqual('46001');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('postcode() setter', () => {
|
|
||||||
it(`should set the town, provinceFk and contryFk properties`, () => {
|
|
||||||
controller.postcode = {
|
|
||||||
townFk: 1,
|
|
||||||
code: 46001,
|
|
||||||
town: {
|
|
||||||
id: 1,
|
|
||||||
name: 'New York',
|
|
||||||
province: {
|
|
||||||
id: 1,
|
|
||||||
name: 'New york',
|
|
||||||
country: {
|
|
||||||
id: 2,
|
|
||||||
name: 'USA'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(controller.worker.city).toEqual('New York');
|
|
||||||
expect(controller.worker.provinceFk).toEqual(1);
|
|
||||||
expect(controller.worker.countryFk).toEqual(2);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('generateCodeUser()', () => {
|
|
||||||
it(`should generate worker code, name and company `, () => {
|
|
||||||
controller.worker = {
|
|
||||||
firstName: 'default',
|
|
||||||
lastNames: 'generate worker'
|
|
||||||
};
|
|
||||||
|
|
||||||
controller.generateCodeUser();
|
|
||||||
|
|
||||||
expect(controller.worker.code).toEqual('DGW');
|
|
||||||
expect(controller.worker.name).toEqual('defaultgw');
|
|
||||||
expect(controller.worker.companyFk).toEqual(controller.vnConfig.user.companyFk);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,13 +0,0 @@
|
||||||
Firstname: Nombre
|
|
||||||
Lastname: Apellidos
|
|
||||||
Fi: DNI/NIF/NIE
|
|
||||||
Birth: Fecha de nacimiento
|
|
||||||
Worker code: Código de trabajador
|
|
||||||
Province: Provincia
|
|
||||||
City: Población
|
|
||||||
ProfileType: Tipo de perfil
|
|
||||||
Street: Dirección
|
|
||||||
Postcode: Código postal
|
|
||||||
Web user: Usuario Web
|
|
||||||
Access permission: Permiso de acceso
|
|
||||||
Pay method: Método de pago
|
|
|
@ -1,94 +0,0 @@
|
||||||
<mg-ajax path="dms/upload" options="vnPost"></mg-ajax>
|
|
||||||
<vn-watcher
|
|
||||||
vn-id="watcher"
|
|
||||||
data="$ctrl.dms">
|
|
||||||
</vn-watcher>
|
|
||||||
<vn-crud-model
|
|
||||||
auto-load="true"
|
|
||||||
url="Warehouses"
|
|
||||||
data="warehouses">
|
|
||||||
</vn-crud-model>
|
|
||||||
<form
|
|
||||||
name="form"
|
|
||||||
ng-submit="$ctrl.onSubmit()"
|
|
||||||
class="vn-ma-md"
|
|
||||||
enctype="multipart/form-data">
|
|
||||||
<div class="vn-w-md">
|
|
||||||
<vn-card class="vn-pa-lg">
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-textfield
|
|
||||||
vn-one
|
|
||||||
vn-focus
|
|
||||||
label="Reference"
|
|
||||||
ng-model="$ctrl.dms.reference"
|
|
||||||
rule>
|
|
||||||
</vn-textfield>
|
|
||||||
<vn-autocomplete vn-one
|
|
||||||
label="Company"
|
|
||||||
ng-model="$ctrl.dms.companyId"
|
|
||||||
url="Companies"
|
|
||||||
show-field="code"
|
|
||||||
value-field="id">
|
|
||||||
</vn-autocomplete>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-autocomplete vn-one
|
|
||||||
label="Warehouse"
|
|
||||||
ng-model="$ctrl.dms.warehouseId"
|
|
||||||
data="warehouses"
|
|
||||||
show-field="name"
|
|
||||||
value-field="id">
|
|
||||||
</vn-autocomplete>
|
|
||||||
<vn-autocomplete vn-one
|
|
||||||
label="Type"
|
|
||||||
ng-model="$ctrl.dms.dmsTypeId"
|
|
||||||
url="DmsTypes"
|
|
||||||
show-field="name"
|
|
||||||
value-field="id">
|
|
||||||
</vn-autocomplete>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-textarea
|
|
||||||
vn-one
|
|
||||||
label="Description"
|
|
||||||
ng-model="$ctrl.dms.description"
|
|
||||||
rule>
|
|
||||||
</vn-textarea>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-input-file
|
|
||||||
vn-one
|
|
||||||
label="File"
|
|
||||||
ng-model="$ctrl.dms.files"
|
|
||||||
on-change="$ctrl.onFileChange($files)"
|
|
||||||
accept="{{$ctrl.allowedContentTypes}}"
|
|
||||||
required="true"
|
|
||||||
multiple="true">
|
|
||||||
<append>
|
|
||||||
<vn-icon vn-none
|
|
||||||
color-marginal
|
|
||||||
title="{{$ctrl.contentTypesInfo}}"
|
|
||||||
icon="info">
|
|
||||||
</vn-icon>
|
|
||||||
</append>
|
|
||||||
</vn-input-file>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-vertical>
|
|
||||||
<vn-check
|
|
||||||
label="Generate identifier for original file"
|
|
||||||
ng-model="$ctrl.dms.hasFile">
|
|
||||||
</vn-check>
|
|
||||||
</vn-vertical>
|
|
||||||
</vn-card>
|
|
||||||
<vn-button-bar>
|
|
||||||
<vn-submit
|
|
||||||
label="Upload">
|
|
||||||
</vn-submit>
|
|
||||||
<vn-button
|
|
||||||
class="cancel"
|
|
||||||
label="Cancel"
|
|
||||||
ui-sref="worker.card.dms.index"></vn-button>
|
|
||||||
</vn-button>
|
|
||||||
</vn-button-bar>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
|
@ -1,113 +0,0 @@
|
||||||
import ngModule from '../../module';
|
|
||||||
import Section from 'salix/components/section';
|
|
||||||
import './style.scss';
|
|
||||||
|
|
||||||
class Controller extends Section {
|
|
||||||
constructor($element, $) {
|
|
||||||
super($element, $);
|
|
||||||
this.dms = {
|
|
||||||
files: [],
|
|
||||||
hasFile: false,
|
|
||||||
hasFileAttached: false
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
get worker() {
|
|
||||||
return this._worker;
|
|
||||||
}
|
|
||||||
|
|
||||||
set worker(value) {
|
|
||||||
this._worker = value;
|
|
||||||
|
|
||||||
if (value) {
|
|
||||||
this.setDefaultParams();
|
|
||||||
this.getAllowedContentTypes();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getAllowedContentTypes() {
|
|
||||||
this.$http.get('DmsContainers/allowedContentTypes').then(res => {
|
|
||||||
const contentTypes = res.data.join(', ');
|
|
||||||
this.allowedContentTypes = contentTypes;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
get contentTypesInfo() {
|
|
||||||
return this.$t('ContentTypesInfo', {
|
|
||||||
allowedContentTypes: this.allowedContentTypes
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
setDefaultParams() {
|
|
||||||
const params = {filter: {
|
|
||||||
where: {code: 'hhrrData'}
|
|
||||||
}};
|
|
||||||
this.$http.get('DmsTypes/findOne', {params}).then(res => {
|
|
||||||
const dmsType = res.data && res.data;
|
|
||||||
const companyId = this.vnConfig.companyFk;
|
|
||||||
const warehouseId = this.vnConfig.warehouseFk;
|
|
||||||
const defaultParams = {
|
|
||||||
reference: this.worker.id,
|
|
||||||
warehouseId: warehouseId,
|
|
||||||
companyId: companyId,
|
|
||||||
dmsTypeId: dmsType.id,
|
|
||||||
description: this.$t('WorkerFileDescription', {
|
|
||||||
dmsTypeName: dmsType.name,
|
|
||||||
workerId: this.worker.id,
|
|
||||||
workerName: this.worker.name
|
|
||||||
}).toUpperCase()
|
|
||||||
};
|
|
||||||
|
|
||||||
this.dms = Object.assign(this.dms, defaultParams);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onSubmit() {
|
|
||||||
const query = `Workers/${this.worker.id}/uploadFile`;
|
|
||||||
const options = {
|
|
||||||
method: 'POST',
|
|
||||||
url: query,
|
|
||||||
params: this.dms,
|
|
||||||
headers: {
|
|
||||||
'Content-Type': undefined
|
|
||||||
},
|
|
||||||
transformRequest: files => {
|
|
||||||
const formData = new FormData();
|
|
||||||
|
|
||||||
for (let i = 0; i < files.length; i++)
|
|
||||||
formData.append(files[i].name, files[i]);
|
|
||||||
|
|
||||||
return formData;
|
|
||||||
},
|
|
||||||
data: this.dms.files
|
|
||||||
};
|
|
||||||
this.$http(options).then(res => {
|
|
||||||
if (res) {
|
|
||||||
this.vnApp.showSuccess(this.$t('Data saved!'));
|
|
||||||
this.$.watcher.updateOriginalData();
|
|
||||||
this.$state.go('worker.card.dms.index');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onFileChange(files) {
|
|
||||||
let hasFileAttached = false;
|
|
||||||
|
|
||||||
if (files.length > 0)
|
|
||||||
hasFileAttached = true;
|
|
||||||
|
|
||||||
this.$.$applyAsync(() => {
|
|
||||||
this.dms.hasFileAttached = hasFileAttached;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Controller.$inject = ['$element', '$scope'];
|
|
||||||
|
|
||||||
ngModule.vnComponent('vnWorkerDmsCreate', {
|
|
||||||
template: require('./index.html'),
|
|
||||||
controller: Controller,
|
|
||||||
bindings: {
|
|
||||||
worker: '<'
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,77 +0,0 @@
|
||||||
import './index';
|
|
||||||
|
|
||||||
describe('Client', () => {
|
|
||||||
describe('Component vnWorkerDmsCreate', () => {
|
|
||||||
let $element;
|
|
||||||
let controller;
|
|
||||||
let $scope;
|
|
||||||
let $httpBackend;
|
|
||||||
let $httpParamSerializer;
|
|
||||||
|
|
||||||
beforeEach(ngModule('worker'));
|
|
||||||
|
|
||||||
beforeEach(inject(($compile, $rootScope, _$httpBackend_, _$httpParamSerializer_) => {
|
|
||||||
$scope = $rootScope.$new();
|
|
||||||
$httpBackend = _$httpBackend_;
|
|
||||||
$httpParamSerializer = _$httpParamSerializer_;
|
|
||||||
$element = $compile(`<vn-worker-dms-create></vn-worker-dms-create>`)($rootScope);
|
|
||||||
controller = $element.controller('vnWorkerDmsCreate');
|
|
||||||
controller._worker = {id: 1101, name: 'Bruce wayne'};
|
|
||||||
$httpBackend.whenRoute('GET', `Warehouses?filter=%7B%7D`).respond([{$oldData: {}}]);
|
|
||||||
}));
|
|
||||||
|
|
||||||
describe('worker() setter', () => {
|
|
||||||
it('should set the worker data and then call setDefaultParams() and getAllowedContentTypes()', () => {
|
|
||||||
jest.spyOn(controller, 'setDefaultParams');
|
|
||||||
jest.spyOn(controller, 'getAllowedContentTypes');
|
|
||||||
controller.worker = {
|
|
||||||
id: 15,
|
|
||||||
name: 'Bruce wayne'
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(controller.worker).toBeDefined();
|
|
||||||
expect(controller.setDefaultParams).toHaveBeenCalledWith();
|
|
||||||
expect(controller.getAllowedContentTypes).toHaveBeenCalledWith();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('setDefaultParams()', () => {
|
|
||||||
it('should perform a GET query and define the dms property on controller', () => {
|
|
||||||
$httpBackend.whenRoute('GET', `DmsTypes`).respond({id: 12, code: 'hhrrData'});
|
|
||||||
const params = {filter: {
|
|
||||||
where: {code: 'hhrrData'}
|
|
||||||
}};
|
|
||||||
let serializedParams = $httpParamSerializer(params);
|
|
||||||
$httpBackend.when('GET', `DmsTypes/findOne?${serializedParams}`).respond({id: 12, code: 'hhrrData'});
|
|
||||||
controller.setDefaultParams();
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(controller.dms).toBeDefined();
|
|
||||||
expect(controller.dms.reference).toEqual(1101);
|
|
||||||
expect(controller.dms.dmsTypeId).toEqual(12);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('onFileChange()', () => {
|
|
||||||
it('should set dms hasFileAttached property to true if has any files', () => {
|
|
||||||
const files = [{id: 1, name: 'MyFile'}];
|
|
||||||
controller.onFileChange(files);
|
|
||||||
$scope.$apply();
|
|
||||||
|
|
||||||
expect(controller.dms.hasFileAttached).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('getAllowedContentTypes()', () => {
|
|
||||||
it('should make an HTTP GET request to get the allowed content types', () => {
|
|
||||||
const expectedResponse = ['image/png', 'image/jpg'];
|
|
||||||
$httpBackend.expect('GET', `DmsContainers/allowedContentTypes`).respond(expectedResponse);
|
|
||||||
controller.getAllowedContentTypes();
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(controller.allowedContentTypes).toBeDefined();
|
|
||||||
expect(controller.allowedContentTypes).toEqual('image/png, image/jpg');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,7 +0,0 @@
|
||||||
vn-ticket-request {
|
|
||||||
.vn-textfield {
|
|
||||||
margin: 0!important;
|
|
||||||
max-width: 100px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,87 +0,0 @@
|
||||||
<vn-watcher
|
|
||||||
vn-id="watcher"
|
|
||||||
data="$ctrl.dms">
|
|
||||||
</vn-watcher>
|
|
||||||
<vn-crud-model
|
|
||||||
auto-load="true"
|
|
||||||
url="Warehouses"
|
|
||||||
data="warehouses">
|
|
||||||
</vn-crud-model>
|
|
||||||
<form
|
|
||||||
name="form"
|
|
||||||
ng-submit="$ctrl.onSubmit()"
|
|
||||||
class="vn-ma-md"
|
|
||||||
enctype="multipart/form-data">
|
|
||||||
<div class="vn-w-md">
|
|
||||||
<vn-card class="vn-pa-lg">
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-textfield
|
|
||||||
vn-one
|
|
||||||
vn-focus
|
|
||||||
label="Reference"
|
|
||||||
ng-model="$ctrl.dms.reference"
|
|
||||||
rule>
|
|
||||||
</vn-textfield>
|
|
||||||
<vn-autocomplete vn-one required="true"
|
|
||||||
label="Company"
|
|
||||||
ng-model="$ctrl.dms.companyId"
|
|
||||||
url="Companies"
|
|
||||||
show-field="code"
|
|
||||||
value-field="id">
|
|
||||||
</vn-autocomplete>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-autocomplete vn-one required="true"
|
|
||||||
label="Warehouse"
|
|
||||||
ng-model="$ctrl.dms.warehouseId"
|
|
||||||
data="warehouses"
|
|
||||||
show-field="name"
|
|
||||||
value-field="id">
|
|
||||||
</vn-autocomplete>
|
|
||||||
<vn-autocomplete vn-one required="true"
|
|
||||||
label="Type"
|
|
||||||
ng-model="$ctrl.dms.dmsTypeId"
|
|
||||||
url="DmsTypes"
|
|
||||||
show-field="name"
|
|
||||||
value-field="id">
|
|
||||||
</vn-autocomplete>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-textarea
|
|
||||||
vn-one
|
|
||||||
required="true"
|
|
||||||
label="Description"
|
|
||||||
ng-model="$ctrl.dms.description"
|
|
||||||
rule>
|
|
||||||
</vn-textarea>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-input-file
|
|
||||||
vn-one
|
|
||||||
label="File"
|
|
||||||
ng-model="$ctrl.dms.files"
|
|
||||||
on-change="$ctrl.onFileChange($files)"
|
|
||||||
accept="{{$ctrl.allowedContentTypes}}"
|
|
||||||
multiple="true">
|
|
||||||
<append>
|
|
||||||
<vn-icon vn-none
|
|
||||||
color-marginal
|
|
||||||
title="{{$ctrl.contentTypesInfo}}"
|
|
||||||
icon="info">
|
|
||||||
</vn-icon>
|
|
||||||
</append>
|
|
||||||
</vn-input-file>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-vertical>
|
|
||||||
<vn-check disabled="watcher.orgData.hasFile"
|
|
||||||
label="Generate identifier for original file"
|
|
||||||
ng-model="$ctrl.dms.hasFile">
|
|
||||||
</vn-check>
|
|
||||||
</vn-vertical>
|
|
||||||
</vn-card>
|
|
||||||
<vn-button-bar>
|
|
||||||
<vn-submit label="Save"></vn-submit>
|
|
||||||
<vn-button ui-sref="worker.card.dms.index" label="Cancel"></vn-button>
|
|
||||||
</vn-button-bar>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
|
@ -1,94 +0,0 @@
|
||||||
import ngModule from '../../module';
|
|
||||||
import Section from 'salix/components/section';
|
|
||||||
import './style.scss';
|
|
||||||
|
|
||||||
class Controller extends Section {
|
|
||||||
get worker() {
|
|
||||||
return this._worker;
|
|
||||||
}
|
|
||||||
|
|
||||||
set worker(value) {
|
|
||||||
this._worker = value;
|
|
||||||
|
|
||||||
if (value) {
|
|
||||||
this.setDefaultParams();
|
|
||||||
this.getAllowedContentTypes();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getAllowedContentTypes() {
|
|
||||||
this.$http.get('DmsContainers/allowedContentTypes').then(res => {
|
|
||||||
const contentTypes = res.data.join(', ');
|
|
||||||
this.allowedContentTypes = contentTypes;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
get contentTypesInfo() {
|
|
||||||
return this.$t('ContentTypesInfo', {
|
|
||||||
allowedContentTypes: this.allowedContentTypes
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
setDefaultParams() {
|
|
||||||
const path = `Dms/${this.$params.dmsId}`;
|
|
||||||
this.$http.get(path).then(res => {
|
|
||||||
const dms = res.data && res.data;
|
|
||||||
this.dms = {
|
|
||||||
reference: dms.reference,
|
|
||||||
warehouseId: dms.warehouseFk,
|
|
||||||
companyId: dms.companyFk,
|
|
||||||
dmsTypeId: dms.dmsTypeFk,
|
|
||||||
description: dms.description,
|
|
||||||
hasFile: dms.hasFile,
|
|
||||||
hasFileAttached: false,
|
|
||||||
files: []
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onSubmit() {
|
|
||||||
const query = `dms/${this.$params.dmsId}/updateFile`;
|
|
||||||
const options = {
|
|
||||||
method: 'POST',
|
|
||||||
url: query,
|
|
||||||
params: this.dms,
|
|
||||||
headers: {
|
|
||||||
'Content-Type': undefined
|
|
||||||
},
|
|
||||||
transformRequest: files => {
|
|
||||||
const formData = new FormData();
|
|
||||||
|
|
||||||
for (let i = 0; i < files.length; i++)
|
|
||||||
formData.append(files[i].name, files[i]);
|
|
||||||
|
|
||||||
return formData;
|
|
||||||
},
|
|
||||||
data: this.dms.files
|
|
||||||
};
|
|
||||||
this.$http(options).then(res => {
|
|
||||||
if (res) {
|
|
||||||
this.vnApp.showSuccess(this.$t('Data saved!'));
|
|
||||||
this.$.watcher.updateOriginalData();
|
|
||||||
this.$state.go('worker.card.dms.index');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onFileChange(files) {
|
|
||||||
let hasFileAttached = false;
|
|
||||||
if (files.length > 0)
|
|
||||||
hasFileAttached = true;
|
|
||||||
|
|
||||||
this.$.$applyAsync(() => {
|
|
||||||
this.dms.hasFileAttached = hasFileAttached;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ngModule.vnComponent('vnWorkerDmsEdit', {
|
|
||||||
template: require('./index.html'),
|
|
||||||
controller: Controller,
|
|
||||||
bindings: {
|
|
||||||
worker: '<'
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,82 +0,0 @@
|
||||||
import './index';
|
|
||||||
|
|
||||||
describe('Worker', () => {
|
|
||||||
describe('Component vnClientDmsEdit', () => {
|
|
||||||
let controller;
|
|
||||||
let $scope;
|
|
||||||
let $element;
|
|
||||||
let $httpBackend;
|
|
||||||
|
|
||||||
beforeEach(ngModule('worker'));
|
|
||||||
|
|
||||||
beforeEach(inject(($componentController, $rootScope, _$httpBackend_) => {
|
|
||||||
$scope = $rootScope.$new();
|
|
||||||
$httpBackend = _$httpBackend_;
|
|
||||||
$element = angular.element(`<vn-worker-dms-edit></vn-worker-dms-edit`);
|
|
||||||
controller = $componentController('vnWorkerDmsEdit', {$element, $scope});
|
|
||||||
controller._worker = {id: 1106};
|
|
||||||
controller.$params = {dmsId: 4};
|
|
||||||
}));
|
|
||||||
|
|
||||||
describe('worker() setter', () => {
|
|
||||||
it('should set the worker data and then call setDefaultParams() and getAllowedContentTypes()', () => {
|
|
||||||
jest.spyOn(controller, 'setDefaultParams');
|
|
||||||
jest.spyOn(controller, 'getAllowedContentTypes');
|
|
||||||
controller._worker = undefined;
|
|
||||||
controller.worker = {
|
|
||||||
id: 1106
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(controller.setDefaultParams).toHaveBeenCalledWith();
|
|
||||||
expect(controller.worker).toBeDefined();
|
|
||||||
expect(controller.getAllowedContentTypes).toHaveBeenCalledWith();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('setDefaultParams()', () => {
|
|
||||||
it('should perform a GET query and define the dms property on controller', () => {
|
|
||||||
const dmsId = 4;
|
|
||||||
const expectedResponse = {
|
|
||||||
reference: 1101,
|
|
||||||
warehouseFk: 1,
|
|
||||||
companyFk: 442,
|
|
||||||
dmsTypeFk: 3,
|
|
||||||
description: 'Test',
|
|
||||||
hasFile: false,
|
|
||||||
hasFileAttached: false
|
|
||||||
};
|
|
||||||
|
|
||||||
$httpBackend.expect('GET', `Dms/${dmsId}`).respond(expectedResponse);
|
|
||||||
controller.setDefaultParams();
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(controller.dms).toBeDefined();
|
|
||||||
expect(controller.dms.reference).toEqual(1101);
|
|
||||||
expect(controller.dms.dmsTypeId).toEqual(3);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('onFileChange()', () => {
|
|
||||||
it('should set dms hasFileAttached property to true if has any files', () => {
|
|
||||||
const files = [{id: 1, name: 'MyFile'}];
|
|
||||||
controller.dms = {hasFileAttached: false};
|
|
||||||
controller.onFileChange(files);
|
|
||||||
$scope.$apply();
|
|
||||||
|
|
||||||
expect(controller.dms.hasFileAttached).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('getAllowedContentTypes()', () => {
|
|
||||||
it('should make an HTTP GET request to get the allowed content types', () => {
|
|
||||||
const expectedResponse = ['image/png', 'image/jpg'];
|
|
||||||
$httpBackend.expect('GET', `DmsContainers/allowedContentTypes`).respond(expectedResponse);
|
|
||||||
controller.getAllowedContentTypes();
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(controller.allowedContentTypes).toBeDefined();
|
|
||||||
expect(controller.allowedContentTypes).toEqual('image/png, image/jpg');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,7 +0,0 @@
|
||||||
vn-ticket-request {
|
|
||||||
.vn-textfield {
|
|
||||||
margin: 0!important;
|
|
||||||
max-width: 100px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,106 +0,0 @@
|
||||||
<vn-crud-model
|
|
||||||
vn-id="model"
|
|
||||||
url="WorkerDms/{{$ctrl.$params.id}}/filter"
|
|
||||||
link="{worker: $ctrl.$params.id}"
|
|
||||||
filter="$ctrl.filter"
|
|
||||||
limit="20"
|
|
||||||
data="$ctrl.workerDms"
|
|
||||||
order="dmsFk DESC"
|
|
||||||
auto-load="true">
|
|
||||||
</vn-crud-model>
|
|
||||||
<vn-data-viewer
|
|
||||||
model="model"
|
|
||||||
class="vn-w-lg">
|
|
||||||
<vn-card>
|
|
||||||
<vn-table model="model">
|
|
||||||
<vn-thead>
|
|
||||||
<vn-tr>
|
|
||||||
<vn-th field="dmsFk" shrink>Id</vn-th>
|
|
||||||
<vn-th field="hardCopyNumber" shrink number>Order</vn-th>
|
|
||||||
<vn-th field="reference" shrink>Reference</vn-th>
|
|
||||||
<vn-th expand>Description</vn-th>
|
|
||||||
<vn-th field="hasFile" shrink>Original</vn-th>
|
|
||||||
<vn-th shrink>File</vn-th>
|
|
||||||
<vn-th field="created">Created</vn-th>
|
|
||||||
<vn-th shrink></vn-th>
|
|
||||||
<vn-th shrink></vn-th>
|
|
||||||
<vn-th shrink></vn-th>
|
|
||||||
</vn-tr>
|
|
||||||
</vn-thead>
|
|
||||||
<vn-tbody>
|
|
||||||
<vn-tr ng-repeat="document in $ctrl.workerDms">
|
|
||||||
<vn-td number shrink>{{::document.id}}</vn-td>
|
|
||||||
<vn-td shrink number>
|
|
||||||
<span class="chip" title="{{::document.dms.hardCopyNumber}}"
|
|
||||||
ng-class="{'message': document.hardCopyNumber}">
|
|
||||||
{{::document.dms.hardCopyNumber}}
|
|
||||||
</span>
|
|
||||||
</vn-td>
|
|
||||||
<vn-td expand>
|
|
||||||
<span title="{{::document.dms.reference}}">
|
|
||||||
{{::document.dms.reference}}
|
|
||||||
</span>
|
|
||||||
</vn-td>
|
|
||||||
<vn-td expand>
|
|
||||||
<span title="{{::document.dms.description}}">
|
|
||||||
{{::document.dms.description}}
|
|
||||||
</span>
|
|
||||||
</vn-td>
|
|
||||||
<vn-td shrink>
|
|
||||||
<vn-check
|
|
||||||
ng-model="document.dms.hasFile"
|
|
||||||
disabled="true">
|
|
||||||
</vn-check>
|
|
||||||
</vn-td>
|
|
||||||
<vn-td shrink>
|
|
||||||
<span title="{{'Download file' | translate}}" class="link"
|
|
||||||
ng-click="$ctrl.downloadFile(document.dmsFk, document.isDocuware)">
|
|
||||||
{{::document.dms.file}}
|
|
||||||
</span>
|
|
||||||
</vn-td>
|
|
||||||
<vn-td shrink-datetime>
|
|
||||||
{{::document.dms.created | date:'dd/MM/yyyy HH:mm'}}
|
|
||||||
</vn-td>
|
|
||||||
<vn-td shrink>
|
|
||||||
<vn-icon-button title="{{'Download file' | translate}}"
|
|
||||||
icon="cloud_download"
|
|
||||||
ng-click="$ctrl.downloadFile(document.dmsFk, document.isDocuware)">
|
|
||||||
</vn-icon-button>
|
|
||||||
</vn-td>
|
|
||||||
<vn-td expand ng-if="::!document.dms.isDocuware">
|
|
||||||
<vn-icon-button ui-sref="worker.card.dms.edit({dmsId: {{::document.dmsFk}}})"
|
|
||||||
icon="edit"
|
|
||||||
title="{{'Edit file' | translate}}">
|
|
||||||
</vn-icon-button>
|
|
||||||
<vn-icon-button
|
|
||||||
icon="delete"
|
|
||||||
ng-click="confirm.show($index)"
|
|
||||||
title="{{'Remove file' | translate}}"
|
|
||||||
tabindex="-1">
|
|
||||||
</vn-icon-button>
|
|
||||||
</vn-td>
|
|
||||||
<vn-td expand ng-if="::document.dms.isDocuware">
|
|
||||||
<vn-icon-button
|
|
||||||
icon="open_in_new"
|
|
||||||
ng-click="$ctrl.openDocuware()"
|
|
||||||
title="{{'Open in docuware' | translate}}"
|
|
||||||
tabindex="-1">
|
|
||||||
</vn-icon-button>
|
|
||||||
</vn-td>
|
|
||||||
</vn-tr>
|
|
||||||
</vn-tbody>
|
|
||||||
</vn-table>
|
|
||||||
</vn-card>
|
|
||||||
</vn-data-viewer>
|
|
||||||
<a ui-sref="worker.card.dms.create"
|
|
||||||
vn-tooltip="Upload file"
|
|
||||||
vn-bind="+"
|
|
||||||
fixed-bottom-right>
|
|
||||||
<vn-float-button icon="add"></vn-float-button>
|
|
||||||
</a>
|
|
||||||
<vn-confirm
|
|
||||||
vn-id="confirm"
|
|
||||||
message="This file will be deleted"
|
|
||||||
question="Are you sure you want to continue?"
|
|
||||||
on-accept="$ctrl.deleteDms($data)">
|
|
||||||
</vn-confirm>
|
|
|
@ -1,75 +0,0 @@
|
||||||
import ngModule from '../../module';
|
|
||||||
import Component from 'core/lib/component';
|
|
||||||
import './style.scss';
|
|
||||||
|
|
||||||
class Controller extends Component {
|
|
||||||
constructor($element, $, vnFile) {
|
|
||||||
super($element, $);
|
|
||||||
this.vnFile = vnFile;
|
|
||||||
this.filter = {
|
|
||||||
include: {
|
|
||||||
relation: 'dms',
|
|
||||||
scope: {
|
|
||||||
fields: [
|
|
||||||
'dmsTypeFk',
|
|
||||||
'reference',
|
|
||||||
'hardCopyNumber',
|
|
||||||
'workerFk',
|
|
||||||
'description',
|
|
||||||
'hasFile',
|
|
||||||
'file',
|
|
||||||
'created',
|
|
||||||
'companyFk',
|
|
||||||
'warehouseFk',
|
|
||||||
],
|
|
||||||
include: [
|
|
||||||
{
|
|
||||||
relation: 'dmsType',
|
|
||||||
scope: {
|
|
||||||
fields: ['name'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
relation: 'worker',
|
|
||||||
scope: {
|
|
||||||
fields: ['id'],
|
|
||||||
include: {
|
|
||||||
relation: 'user',
|
|
||||||
scope: {
|
|
||||||
fields: ['name'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
deleteDms(index) {
|
|
||||||
const workerDmsId = this.workerDms[index].dmsFk;
|
|
||||||
return this.$http.post(`WorkerDms/${workerDmsId}/removeFile`)
|
|
||||||
.then(() => {
|
|
||||||
this.$.model.remove(index);
|
|
||||||
this.vnApp.showSuccess(this.$t('Data saved!'));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
downloadFile(dmsId, isDocuware) {
|
|
||||||
if (isDocuware) return this.vnFile.download(`api/workerDms/${dmsId}/docuwareDownload`);
|
|
||||||
this.vnFile.download(`api/workerDms/${dmsId}/downloadFile`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async openDocuware() {
|
|
||||||
const url = await this.vnApp.getUrl(`WebClient`, 'docuware');
|
|
||||||
if (url) window.open(url).focus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Controller.$inject = ['$element', '$scope', 'vnFile'];
|
|
||||||
|
|
||||||
ngModule.vnComponent('vnWorkerDmsIndex', {
|
|
||||||
template: require('./index.html'),
|
|
||||||
controller: Controller,
|
|
||||||
});
|
|
|
@ -1,37 +0,0 @@
|
||||||
import './index';
|
|
||||||
import crudModel from 'core/mocks/crud-model';
|
|
||||||
|
|
||||||
describe('Worker', () => {
|
|
||||||
describe('Component vnWorkerDmsIndex', () => {
|
|
||||||
let $scope;
|
|
||||||
let $httpBackend;
|
|
||||||
let controller;
|
|
||||||
|
|
||||||
beforeEach(ngModule('worker'));
|
|
||||||
|
|
||||||
beforeEach(inject(($componentController, $rootScope, _$httpBackend_) => {
|
|
||||||
$httpBackend = _$httpBackend_;
|
|
||||||
$scope = $rootScope.$new();
|
|
||||||
controller = $componentController('vnWorkerDmsIndex', {$element: null, $scope});
|
|
||||||
controller.$.model = crudModel;
|
|
||||||
}));
|
|
||||||
|
|
||||||
describe('deleteDms()', () => {
|
|
||||||
it('should make an HTTP Post query', () => {
|
|
||||||
jest.spyOn(controller.vnApp, 'showSuccess');
|
|
||||||
jest.spyOn(controller.$.model, 'remove');
|
|
||||||
|
|
||||||
const workerDmsId = 4;
|
|
||||||
const dmsIndex = 0;
|
|
||||||
controller.workerDms = [{id: 1, dmsFk: 4}];
|
|
||||||
|
|
||||||
$httpBackend.expectPOST(`WorkerDms/${workerDmsId}/removeFile`).respond();
|
|
||||||
controller.deleteDms(dmsIndex);
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(controller.$.model.remove).toHaveBeenCalledWith(dmsIndex);
|
|
||||||
expect(controller.vnApp.showSuccess).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,9 +0,0 @@
|
||||||
Are you sure?: Estas seguro?
|
|
||||||
Download file: Descargar fichero
|
|
||||||
File: Fichero
|
|
||||||
File deleted: Fichero eliminado
|
|
||||||
Hard copy: Copia
|
|
||||||
My documentation: Mi documentacion
|
|
||||||
Remove file: Eliminar fichero
|
|
||||||
This file will be deleted: Este fichero va a ser borrado
|
|
||||||
Type: Tipo
|
|
|
@ -1,6 +0,0 @@
|
||||||
vn-client-risk-index {
|
|
||||||
.totalBox {
|
|
||||||
display: table;
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,2 +0,0 @@
|
||||||
ClientFileDescription: "{{dmsTypeName}} from client {{clientName}} id {{clientId}}"
|
|
||||||
ContentTypesInfo: Allowed file types {{allowedContentTypes}}
|
|
|
@ -1,20 +0,0 @@
|
||||||
Reference: Referencia
|
|
||||||
Description: Descripción
|
|
||||||
Company: Empresa
|
|
||||||
Upload file: Subir fichero
|
|
||||||
Edit file: Editar fichero
|
|
||||||
Upload: Subir
|
|
||||||
File: Fichero
|
|
||||||
WorkerFileDescription: "{{dmsTypeName}} del empleado {{workerName}} id {{workerId}}"
|
|
||||||
ContentTypesInfo: "Tipos de archivo permitidos: {{allowedContentTypes}}"
|
|
||||||
Generate identifier for original file: Generar identificador para archivo original
|
|
||||||
Are you sure you want to continue?: ¿Seguro que quieres continuar?
|
|
||||||
File management: Gestión documental
|
|
||||||
Hard copy: Copia
|
|
||||||
This file will be deleted: Este fichero va a ser borrado
|
|
||||||
Are you sure?: ¿Seguro?
|
|
||||||
File deleted: Fichero eliminado
|
|
||||||
Remove file: Eliminar fichero
|
|
||||||
Download file: Descargar fichero
|
|
||||||
Created: Creado
|
|
||||||
Employee: Empleado
|
|
|
@ -1,24 +1,9 @@
|
||||||
export * from './module';
|
export * from './module';
|
||||||
|
|
||||||
import './main';
|
import './main';
|
||||||
import './index/';
|
|
||||||
import './summary';
|
import './summary';
|
||||||
import './card';
|
import './card';
|
||||||
import './create';
|
|
||||||
import './descriptor';
|
import './descriptor';
|
||||||
import './descriptor-popover';
|
import './descriptor-popover';
|
||||||
import './search-panel';
|
|
||||||
import './basic-data';
|
|
||||||
import './pbx';
|
|
||||||
import './pda';
|
|
||||||
import './department';
|
import './department';
|
||||||
import './calendar';
|
|
||||||
import './time-control';
|
|
||||||
import './log';
|
|
||||||
import './dms/index';
|
|
||||||
import './dms/create';
|
|
||||||
import './dms/edit';
|
|
||||||
import './note/index';
|
|
||||||
import './note/create';
|
|
||||||
import './notifications';
|
|
||||||
|
|
||||||
|
|
|
@ -1,57 +0,0 @@
|
||||||
<vn-auto-search
|
|
||||||
model="model">
|
|
||||||
</vn-auto-search>
|
|
||||||
<vn-data-viewer
|
|
||||||
model="model"
|
|
||||||
class="vn-w-sm">
|
|
||||||
<vn-card>
|
|
||||||
<div class="vn-list separated">
|
|
||||||
<a
|
|
||||||
ng-repeat="worker in model.data track by worker.id"
|
|
||||||
ui-sref="worker.card.summary({id: worker.id})"
|
|
||||||
translate-attr="{title: 'View worker'}"
|
|
||||||
class="vn-item search-result">
|
|
||||||
<vn-item-section>
|
|
||||||
<h6>{{::worker.nickname}}</h6>
|
|
||||||
<vn-label-value label="Id"
|
|
||||||
value="{{::worker.id}}">
|
|
||||||
</vn-label-value>
|
|
||||||
<vn-label-value label="User"
|
|
||||||
value="{{::worker.userName}}">
|
|
||||||
</vn-label-value>
|
|
||||||
<vn-label-value label="Email"
|
|
||||||
value="{{::worker.email}}">
|
|
||||||
</vn-label-value>
|
|
||||||
<vn-label-value label="Department"
|
|
||||||
value="{{::worker.department}}">
|
|
||||||
</vn-label-value>
|
|
||||||
</vn-item-section>
|
|
||||||
<vn-item-section side>
|
|
||||||
<vn-icon-button
|
|
||||||
ng-click="$ctrl.goToTimeControl($event, worker.id)"
|
|
||||||
vn-tooltip="Time control"
|
|
||||||
icon="access_time">
|
|
||||||
</vn-icon-button>
|
|
||||||
<vn-icon-button
|
|
||||||
ng-click="$ctrl.preview($event, worker)"
|
|
||||||
vn-tooltip="Preview"
|
|
||||||
icon="preview">
|
|
||||||
</vn-icon-button>
|
|
||||||
</vn-item-section>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</vn-card>
|
|
||||||
</vn-data-viewer>
|
|
||||||
<a ui-sref="worker.create"
|
|
||||||
vn-tooltip="New worker"
|
|
||||||
vn-bind="+"
|
|
||||||
vn-acl="hr"
|
|
||||||
vn-acl-action="remove"
|
|
||||||
fixed-bottom-right>
|
|
||||||
<vn-float-button icon="person_add"></vn-float-button>
|
|
||||||
</a>
|
|
||||||
<vn-popup vn-id="preview">
|
|
||||||
<vn-worker-summary
|
|
||||||
worker="$ctrl.selectedWorker">
|
|
||||||
</vn-worker-summary>
|
|
||||||
</vn-popup>
|
|
|
@ -1,31 +0,0 @@
|
||||||
import ngModule from '../module';
|
|
||||||
import Section from 'salix/components/section';
|
|
||||||
|
|
||||||
export default class Controller extends Section {
|
|
||||||
preview(event, worker) {
|
|
||||||
if (event.defaultPrevented) return;
|
|
||||||
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
|
|
||||||
this.selectedWorker = worker;
|
|
||||||
this.$.preview.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
goToTimeControl(event, workerId) {
|
|
||||||
if (event.defaultPrevented) return;
|
|
||||||
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
this.$state.go('worker.card.timeControl', {id: workerId}, {absolute: true});
|
|
||||||
}
|
|
||||||
|
|
||||||
onMoreChange(callback) {
|
|
||||||
callback.call(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ngModule.vnComponent('vnWorkerIndex', {
|
|
||||||
template: require('./index.html'),
|
|
||||||
controller: Controller
|
|
||||||
});
|
|
|
@ -1 +0,0 @@
|
||||||
New worker: Nuevo trabajador
|
|
|
@ -1 +0,0 @@
|
||||||
<vn-log url="WorkerLogs" origin-id="$ctrl.$params.id"></vn-log>
|
|
|
@ -1,7 +0,0 @@
|
||||||
import ngModule from '../module';
|
|
||||||
import Section from 'salix/components/section';
|
|
||||||
|
|
||||||
ngModule.vnComponent('vnWorkerLog', {
|
|
||||||
template: require('./index.html'),
|
|
||||||
controller: Section,
|
|
||||||
});
|
|
|
@ -1,18 +0,0 @@
|
||||||
<vn-crud-model
|
|
||||||
vn-id="model"
|
|
||||||
url="Workers/filter"
|
|
||||||
limit="20"
|
|
||||||
order="id">
|
|
||||||
</vn-crud-model>
|
|
||||||
<vn-portal slot="topbar">
|
|
||||||
<vn-searchbar
|
|
||||||
vn-focus
|
|
||||||
panel="vn-worker-search-panel"
|
|
||||||
info="Search workers by id, firstName, lastName or user name"
|
|
||||||
model="model">
|
|
||||||
</vn-searchbar>
|
|
||||||
</vn-portal>
|
|
||||||
<vn-portal slot="menu">
|
|
||||||
<vn-left-menu></vn-left-menu>
|
|
||||||
</vn-portal>
|
|
||||||
<ui-view></ui-view>
|
|
|
@ -1,7 +1,15 @@
|
||||||
import ngModule from '../module';
|
import ngModule from '../module';
|
||||||
import ModuleMain from 'salix/components/module-main';
|
import ModuleMain from 'salix/components/module-main';
|
||||||
|
|
||||||
export default class Worker extends ModuleMain {}
|
export default class Worker extends ModuleMain {
|
||||||
|
constructor($element, $) {
|
||||||
|
super($element, $);
|
||||||
|
}
|
||||||
|
async $onInit() {
|
||||||
|
this.$state.go('home');
|
||||||
|
window.location.href = await this.vnApp.getUrl(`worker/`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ngModule.vnComponent('vnWorker', {
|
ngModule.vnComponent('vnWorker', {
|
||||||
controller: Worker,
|
controller: Worker,
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
<vn-watcher
|
|
||||||
vn-id="watcher"
|
|
||||||
url="WorkerObservations"
|
|
||||||
id-field="id"
|
|
||||||
data="$ctrl.note"
|
|
||||||
insert-mode="true"
|
|
||||||
form="form">
|
|
||||||
</vn-watcher>
|
|
||||||
<form name="form" ng-submit="watcher.submitGo('worker.card.note.index')" class="vn-w-md">
|
|
||||||
<vn-card class="vn-pa-lg">
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-textarea
|
|
||||||
vn-one
|
|
||||||
label="Note"
|
|
||||||
ng-model="$ctrl.note.text"
|
|
||||||
vn-focus>
|
|
||||||
</vn-textarea>
|
|
||||||
</vn-horizontal>
|
|
||||||
</vn-card>
|
|
||||||
<vn-button-bar>
|
|
||||||
<vn-submit
|
|
||||||
ng-if="watcher.dataChanged()"
|
|
||||||
label="Save">
|
|
||||||
</vn-submit>
|
|
||||||
<vn-button
|
|
||||||
ng-click="$ctrl.cancel()"
|
|
||||||
label="Cancel">
|
|
||||||
</vn-button>
|
|
||||||
</vn-button-bar>
|
|
||||||
</form>
|
|
|
@ -1,21 +0,0 @@
|
||||||
import ngModule from '../../module';
|
|
||||||
import Section from 'salix/components/section';
|
|
||||||
|
|
||||||
export default class Controller extends Section {
|
|
||||||
constructor($element, $) {
|
|
||||||
super($element, $);
|
|
||||||
this.note = {
|
|
||||||
workerFk: parseInt(this.$params.id),
|
|
||||||
text: null
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
cancel() {
|
|
||||||
this.$state.go('worker.card.note.index', {id: this.$params.id});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ngModule.vnComponent('vnNoteWorkerCreate', {
|
|
||||||
template: require('./index.html'),
|
|
||||||
controller: Controller
|
|
||||||
});
|
|
|
@ -1,22 +0,0 @@
|
||||||
import './index';
|
|
||||||
|
|
||||||
describe('Worker', () => {
|
|
||||||
describe('Component vnNoteWorkerCreate', () => {
|
|
||||||
let $state;
|
|
||||||
let controller;
|
|
||||||
|
|
||||||
beforeEach(ngModule('worker'));
|
|
||||||
|
|
||||||
beforeEach(inject(($componentController, _$state_) => {
|
|
||||||
$state = _$state_;
|
|
||||||
$state.params.id = '1234';
|
|
||||||
const $element = angular.element('<vn-note-create></vn-note-create>');
|
|
||||||
controller = $componentController('vnNoteWorkerCreate', {$element, $state});
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should define workerFk using $state.params.id', () => {
|
|
||||||
expect(controller.note.workerFk).toBe(1234);
|
|
||||||
expect(controller.note.worker).toBe(undefined);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,2 +0,0 @@
|
||||||
New note: Nueva nota
|
|
||||||
Note: Nota
|
|
|
@ -1,32 +0,0 @@
|
||||||
<vn-crud-model
|
|
||||||
vn-id="model"
|
|
||||||
url="WorkerObservations"
|
|
||||||
filter="$ctrl.filter"
|
|
||||||
link="{workerFk: $ctrl.$params.id}"
|
|
||||||
include="{relation: 'user'}"
|
|
||||||
data="notes"
|
|
||||||
auto-load="true">
|
|
||||||
</vn-crud-model>
|
|
||||||
<vn-data-viewer
|
|
||||||
model="model"
|
|
||||||
class="vn-w-md">
|
|
||||||
<vn-card class="vn-pa-md">
|
|
||||||
<div
|
|
||||||
ng-repeat="note in notes"
|
|
||||||
class="note vn-pa-sm border-solid border-radius vn-mb-md">
|
|
||||||
<vn-horizontal class="vn-mb-sm" style="color: #666">
|
|
||||||
<vn-one>{{::note.user.nickname}}</vn-one>
|
|
||||||
<vn-auto>{{::note.created | date:'dd/MM/yyyy HH:mm'}}</vn-auto>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal class="text">
|
|
||||||
{{::note.text}}
|
|
||||||
</vn-horizontal>
|
|
||||||
</div>
|
|
||||||
</vn-card>
|
|
||||||
</vn-data-viewer>
|
|
||||||
<a vn-tooltip="New note"
|
|
||||||
ui-sref="worker.card.note.create({id: $ctrl.$params.id})"
|
|
||||||
vn-bind="+"
|
|
||||||
fixed-bottom-right>
|
|
||||||
<vn-float-button icon="add"></vn-float-button>
|
|
||||||
</a>
|
|
|
@ -1,22 +0,0 @@
|
||||||
import ngModule from '../../module';
|
|
||||||
import Section from 'salix/components/section';
|
|
||||||
import './style.scss';
|
|
||||||
|
|
||||||
export default class Controller extends Section {
|
|
||||||
constructor($element, $) {
|
|
||||||
super($element, $);
|
|
||||||
this.filter = {
|
|
||||||
order: 'created DESC',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Controller.$inject = ['$element', '$scope'];
|
|
||||||
|
|
||||||
ngModule.vnComponent('vnWorkerNote', {
|
|
||||||
template: require('./index.html'),
|
|
||||||
controller: Controller,
|
|
||||||
bindings: {
|
|
||||||
worker: '<'
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,5 +0,0 @@
|
||||||
vn-worker-note {
|
|
||||||
.note:last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,2 +0,0 @@
|
||||||
<vn-card>
|
|
||||||
</vn-card>
|
|
|
@ -1,21 +0,0 @@
|
||||||
import ngModule from '../module';
|
|
||||||
import Section from 'salix/components/section';
|
|
||||||
|
|
||||||
class Controller extends Section {
|
|
||||||
constructor($element, $) {
|
|
||||||
super($element, $);
|
|
||||||
}
|
|
||||||
|
|
||||||
async $onInit() {
|
|
||||||
const url = await this.vnApp.getUrl(`worker/${this.$params.id}/notifications`);
|
|
||||||
window.open(url).focus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ngModule.vnComponent('vnWorkerNotifications', {
|
|
||||||
template: require('./index.html'),
|
|
||||||
controller: Controller,
|
|
||||||
bindings: {
|
|
||||||
ticket: '<'
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,28 +0,0 @@
|
||||||
<vn-watcher
|
|
||||||
vn-id="watcher"
|
|
||||||
data="$ctrl.worker.sip">
|
|
||||||
</vn-watcher>
|
|
||||||
<form name="form" ng-submit="$ctrl.onSubmit()" class="vn-w-md">
|
|
||||||
<vn-card class="vn-pa-lg">
|
|
||||||
<vn-vertical>
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-textfield
|
|
||||||
label="Extension"
|
|
||||||
ng-model="$ctrl.worker.sip.extension">
|
|
||||||
</vn-textfield>
|
|
||||||
</vn-horizontal>
|
|
||||||
</vn-vertical>
|
|
||||||
</vn-card>
|
|
||||||
<vn-button-bar>
|
|
||||||
<vn-submit
|
|
||||||
disabled="!watcher.dataChanged()"
|
|
||||||
label="Save">
|
|
||||||
</vn-submit>
|
|
||||||
<vn-button
|
|
||||||
class="cancel"
|
|
||||||
label="Undo changes"
|
|
||||||
disabled="!watcher.dataChanged()"
|
|
||||||
ng-click="watcher.loadOriginalData()">
|
|
||||||
</vn-button>
|
|
||||||
</vn-button-bar>
|
|
||||||
</form>
|
|
|
@ -1,25 +0,0 @@
|
||||||
import ngModule from '../module';
|
|
||||||
import Section from 'salix/components/section';
|
|
||||||
|
|
||||||
class Controller extends Section {
|
|
||||||
onSubmit() {
|
|
||||||
const sip = this.worker.sip;
|
|
||||||
const params = {
|
|
||||||
userFk: this.worker.id,
|
|
||||||
extension: sip.extension
|
|
||||||
};
|
|
||||||
this.$.watcher.check();
|
|
||||||
this.$http.patch('Sips', params).then(() => {
|
|
||||||
this.$.watcher.updateOriginalData();
|
|
||||||
this.vnApp.showSuccess(this.$t('Data saved! User must access web'));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ngModule.vnComponent('vnWorkerPbx', {
|
|
||||||
template: require('./index.html'),
|
|
||||||
controller: Controller,
|
|
||||||
bindings: {
|
|
||||||
worker: '<'
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,18 +0,0 @@
|
||||||
import ngModule from '../module';
|
|
||||||
import Section from 'salix/components/section';
|
|
||||||
|
|
||||||
class Controller extends Section {
|
|
||||||
constructor($element, $) {
|
|
||||||
super($element, $);
|
|
||||||
}
|
|
||||||
|
|
||||||
async $onInit() {
|
|
||||||
const url = await this.vnApp.getUrl(`worker/${this.$params.id}/pda`);
|
|
||||||
this.$state.go('worker.card.summary', {id: this.$params.id});
|
|
||||||
window.location.href = url;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ngModule.vnComponent('vnWorkerPda', {
|
|
||||||
controller: Controller
|
|
||||||
});
|
|
|
@ -9,23 +9,6 @@
|
||||||
{"state": "worker.index", "icon": "icon-worker"},
|
{"state": "worker.index", "icon": "icon-worker"},
|
||||||
{"state": "worker.department", "icon": "work"}
|
{"state": "worker.department", "icon": "work"}
|
||||||
],
|
],
|
||||||
"card": [
|
|
||||||
{"state": "worker.card.basicData", "icon": "settings"},
|
|
||||||
{"state": "worker.card.note.index", "icon": "insert_drive_file"},
|
|
||||||
{"state": "worker.card.timeControl", "icon": "access_time"},
|
|
||||||
{"state": "worker.card.calendar", "icon": "icon-calendar"},
|
|
||||||
{"state": "worker.card.pda", "icon": "phone_android"},
|
|
||||||
{"state": "worker.card.notifications", "icon": "notifications"},
|
|
||||||
{"state": "worker.card.pbx", "icon": "icon-pbx"},
|
|
||||||
{"state": "worker.card.dms.index", "icon": "cloud_upload"},
|
|
||||||
{
|
|
||||||
"icon": "icon-wiki",
|
|
||||||
"external":true,
|
|
||||||
"url": "http://wiki.verdnatura.es",
|
|
||||||
"description": "Wikipedia"
|
|
||||||
},
|
|
||||||
{"state": "worker.card.workerLog", "icon": "history"}
|
|
||||||
],
|
|
||||||
"department": [
|
"department": [
|
||||||
{"state": "worker.department.card.basicData", "icon": "settings"}
|
{"state": "worker.department.card.basicData", "icon": "settings"}
|
||||||
]
|
]
|
||||||
|
@ -43,12 +26,14 @@
|
||||||
"abstract": true,
|
"abstract": true,
|
||||||
"component": "vn-worker",
|
"component": "vn-worker",
|
||||||
"description": "Workers"
|
"description": "Workers"
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"url": "/index?q",
|
"url": "/index?q",
|
||||||
"state": "worker.index",
|
"state": "worker.index",
|
||||||
"component": "vn-worker-index",
|
"component": "vn-worker-index",
|
||||||
"description": "Workers"
|
"description": "Workers"
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"url" : "/summary",
|
"url" : "/summary",
|
||||||
"state": "worker.card.summary",
|
"state": "worker.card.summary",
|
||||||
"component": "vn-worker-summary",
|
"component": "vn-worker-summary",
|
||||||
|
@ -56,91 +41,14 @@
|
||||||
"params": {
|
"params": {
|
||||||
"worker": "$ctrl.worker"
|
"worker": "$ctrl.worker"
|
||||||
}
|
}
|
||||||
}, {
|
|
||||||
"url": "/:id",
|
|
||||||
"state": "worker.card",
|
|
||||||
"component": "vn-worker-card",
|
|
||||||
"abstract": true,
|
|
||||||
"description": "Detail"
|
|
||||||
}, {
|
|
||||||
"url": "/basic-data",
|
|
||||||
"state": "worker.card.basicData",
|
|
||||||
"component": "vn-worker-basic-data",
|
|
||||||
"description": "Basic data",
|
|
||||||
"params": {
|
|
||||||
"worker": "$ctrl.worker"
|
|
||||||
},
|
},
|
||||||
"acl": ["hr"]
|
{
|
||||||
}, {
|
|
||||||
"url" : "/log",
|
|
||||||
"state": "worker.card.workerLog",
|
|
||||||
"component": "vn-worker-log",
|
|
||||||
"description": "Log",
|
|
||||||
"acl": ["hr"]
|
|
||||||
}, {
|
|
||||||
"url": "/note",
|
|
||||||
"state": "worker.card.note",
|
|
||||||
"component": "ui-view",
|
|
||||||
"abstract": true
|
|
||||||
}, {
|
|
||||||
"url": "/index",
|
|
||||||
"state": "worker.card.note.index",
|
|
||||||
"component": "vn-worker-note",
|
|
||||||
"description": "Notes",
|
|
||||||
"params": {
|
|
||||||
"worker": "$ctrl.worker"
|
|
||||||
},
|
|
||||||
"acl": ["hr"]
|
|
||||||
}, {
|
|
||||||
"url": "/create",
|
|
||||||
"state": "worker.card.note.create",
|
|
||||||
"component": "vn-note-worker-create",
|
|
||||||
"description": "New note"
|
|
||||||
}, {
|
|
||||||
"url": "/pbx",
|
|
||||||
"state": "worker.card.pbx",
|
|
||||||
"component": "vn-worker-pbx",
|
|
||||||
"description": "Private Branch Exchange",
|
|
||||||
"params": {
|
|
||||||
"worker": "$ctrl.worker"
|
|
||||||
},
|
|
||||||
"acl": ["hr"]
|
|
||||||
}, {
|
|
||||||
"url": "/calendar",
|
|
||||||
"state": "worker.card.calendar",
|
|
||||||
"component": "vn-worker-calendar",
|
|
||||||
"description": "Calendar",
|
|
||||||
"params": {
|
|
||||||
"worker": "$ctrl.worker"
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
"url": "/notifications",
|
|
||||||
"state": "worker.card.notifications",
|
|
||||||
"component": "vn-worker-notifications",
|
|
||||||
"description": "Notifications",
|
|
||||||
"params": {
|
|
||||||
"worker": "$ctrl.worker"
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
"url": "/time-control?timestamp",
|
|
||||||
"state": "worker.card.timeControl",
|
|
||||||
"component": "vn-worker-time-control",
|
|
||||||
"description": "Time control",
|
|
||||||
"params": {
|
|
||||||
"worker": "$ctrl.worker"
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
"url": "/department?q",
|
"url": "/department?q",
|
||||||
"state": "worker.department",
|
"state": "worker.department",
|
||||||
"component": "vn-worker-department",
|
"component": "vn-worker-department",
|
||||||
"description":"Departments"
|
"description":"Departments"
|
||||||
}, {
|
},
|
||||||
"url": "/:id",
|
{
|
||||||
"state": "worker.department.card",
|
|
||||||
"component": "vn-worker-department-card",
|
|
||||||
"abstract": true,
|
|
||||||
"description": "Detail"
|
|
||||||
}, {
|
|
||||||
"url" : "/summary",
|
"url" : "/summary",
|
||||||
"state": "worker.department.card.summary",
|
"state": "worker.department.card.summary",
|
||||||
"component": "vn-worker-department-summary",
|
"component": "vn-worker-department-summary",
|
||||||
|
@ -148,62 +56,6 @@
|
||||||
"params": {
|
"params": {
|
||||||
"department": "$ctrl.department"
|
"department": "$ctrl.department"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "/basic-data",
|
|
||||||
"state": "worker.department.card.basicData",
|
|
||||||
"component": "vn-worker-department-basic-data",
|
|
||||||
"description": "Basic data",
|
|
||||||
"params": {
|
|
||||||
"department": "$ctrl.department"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "/dms",
|
|
||||||
"state": "worker.card.dms",
|
|
||||||
"abstract": true,
|
|
||||||
"component": "ui-view"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "/index",
|
|
||||||
"state": "worker.card.dms.index",
|
|
||||||
"component": "vn-worker-dms-index",
|
|
||||||
"description": "My documentation",
|
|
||||||
"acl": ["employee"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "/create",
|
|
||||||
"state": "worker.card.dms.create",
|
|
||||||
"component": "vn-worker-dms-create",
|
|
||||||
"description": "Upload file",
|
|
||||||
"params": {
|
|
||||||
"worker": "$ctrl.worker"
|
|
||||||
},
|
|
||||||
"acl": ["hr"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "/:dmsId/edit",
|
|
||||||
"state": "worker.card.dms.edit",
|
|
||||||
"component": "vn-worker-dms-edit",
|
|
||||||
"description": "Edit file",
|
|
||||||
"params": {
|
|
||||||
"worker": "$ctrl.worker"
|
|
||||||
},
|
|
||||||
"acl": ["hr"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "/create",
|
|
||||||
"state": "worker.create",
|
|
||||||
"component": "vn-worker-create",
|
|
||||||
"description": "New worker",
|
|
||||||
"acl": ["hr"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "/pda",
|
|
||||||
"state": "worker.card.pda",
|
|
||||||
"component": "vn-worker-pda",
|
|
||||||
"description": "PDA",
|
|
||||||
"acl": ["hr", "productionAssi"]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,67 +0,0 @@
|
||||||
<div class="search-panel">
|
|
||||||
<form ng-submit="$ctrl.onSearch()">
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-textfield
|
|
||||||
vn-one
|
|
||||||
label="General search"
|
|
||||||
ng-model="filter.search"
|
|
||||||
info="Search workers by id, firstName, lastName or user name"
|
|
||||||
vn-focus>
|
|
||||||
</vn-textfield>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-textfield
|
|
||||||
vn-one
|
|
||||||
label="Worker id"
|
|
||||||
ng-model="filter.id">
|
|
||||||
</vn-textfield>
|
|
||||||
<vn-textfield
|
|
||||||
vn-one
|
|
||||||
label="User id"
|
|
||||||
ng-model="filter.id">
|
|
||||||
</vn-textfield>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-textfield
|
|
||||||
vn-one
|
|
||||||
label="Name"
|
|
||||||
ng-model="filter.firstName">
|
|
||||||
</vn-textfield>
|
|
||||||
<vn-textfield
|
|
||||||
vn-one
|
|
||||||
label="Last name"
|
|
||||||
ng-model="filter.lastName">
|
|
||||||
</vn-textfield>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-textfield
|
|
||||||
vn-one
|
|
||||||
label="User name"
|
|
||||||
ng-model="filter.userName">
|
|
||||||
</vn-textfield>
|
|
||||||
<vn-textfield
|
|
||||||
vn-one
|
|
||||||
label="Fiscal identifier"
|
|
||||||
ng-model="filter.fi">
|
|
||||||
</vn-textfield>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal>
|
|
||||||
<vn-autocomplete
|
|
||||||
vn-one
|
|
||||||
ng-model="filter.departmentFk"
|
|
||||||
url="Departments"
|
|
||||||
show-field="name"
|
|
||||||
value-field="id"
|
|
||||||
label="Department">
|
|
||||||
</vn-autocomplete>
|
|
||||||
<vn-textfield
|
|
||||||
vn-one
|
|
||||||
label="Extension"
|
|
||||||
ng-model="filter.extension">
|
|
||||||
</vn-textfield>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal class="vn-mt-lg">
|
|
||||||
<vn-submit label="Search"></vn-submit>
|
|
||||||
</vn-horizontal>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
|
@ -1,7 +0,0 @@
|
||||||
import ngModule from '../module';
|
|
||||||
import SearchPanel from 'core/components/searchbar/search-panel';
|
|
||||||
|
|
||||||
ngModule.vnComponent('vnWorkerSearchPanel', {
|
|
||||||
template: require('./index.html'),
|
|
||||||
controller: SearchPanel
|
|
||||||
});
|
|
|
@ -1,219 +0,0 @@
|
||||||
<vn-crud-model
|
|
||||||
vn-id="model"
|
|
||||||
url="WorkerTimeControls/filter"
|
|
||||||
filter="::$ctrl.filter"
|
|
||||||
data="$ctrl.hours">
|
|
||||||
</vn-crud-model>
|
|
||||||
<div>
|
|
||||||
<vn-card class="vn-pa-lg vn-w-lg">
|
|
||||||
<vn-table model="model" auto-load="false">
|
|
||||||
<vn-thead>
|
|
||||||
<vn-tr>
|
|
||||||
<vn-td ng-repeat="weekday in $ctrl.weekDays" center>
|
|
||||||
<div class="weekday" translate>{{::$ctrl.weekdayNames[$index].name}}</div>
|
|
||||||
<div>
|
|
||||||
<span>{{::weekday.dated | date: 'dd'}}</span>
|
|
||||||
<span title="{{::weekday.dated | date: 'MMMM' | translate}}" translate>
|
|
||||||
{{::weekday.dated | date: 'MMMM'}}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<vn-chip
|
|
||||||
title="{{::weekday.event.name}}"
|
|
||||||
ng-class="{invisible: !weekday.event}">
|
|
||||||
<vn-avatar
|
|
||||||
ng-style="::{backgroundColor: weekday.event.color}">
|
|
||||||
</vn-avatar>
|
|
||||||
<div>
|
|
||||||
{{::weekday.event.name}}
|
|
||||||
</div>
|
|
||||||
</vn-chip>
|
|
||||||
</vn-td>
|
|
||||||
</vn-tr>
|
|
||||||
</vn-thead>
|
|
||||||
<vn-tbody>
|
|
||||||
<vn-tr>
|
|
||||||
<vn-td ng-repeat="weekday in $ctrl.weekDays" class="hours vn-pa-none" expand>
|
|
||||||
<section ng-repeat="hour in weekday.hours">
|
|
||||||
<vn-icon
|
|
||||||
icon="{{
|
|
||||||
::hour.direction == 'in' ? 'arrow_forward' : 'arrow_back'
|
|
||||||
}}"
|
|
||||||
title="{{
|
|
||||||
::(hour.direction == 'in' ? 'In' : 'Out') | translate
|
|
||||||
}}"
|
|
||||||
ng-class="::{'invisible': hour.direction == 'middle'}">
|
|
||||||
</vn-icon>
|
|
||||||
<vn-chip
|
|
||||||
ng-class="::{'colored': hour.manual, 'clickable': true}"
|
|
||||||
removable="::hour.manual"
|
|
||||||
on-remove="$ctrl.showDeleteDialog($event, hour)"
|
|
||||||
ng-click="$ctrl.edit($event, hour)"
|
|
||||||
>
|
|
||||||
<prepend>
|
|
||||||
<vn-icon icon="edit"
|
|
||||||
vn-tooltip="Edit">
|
|
||||||
</vn-icon>
|
|
||||||
</prepend>
|
|
||||||
{{::hour.timed | date: 'HH:mm'}}
|
|
||||||
</vn-chip>
|
|
||||||
</section>
|
|
||||||
</vn-td>
|
|
||||||
</vn-tr>
|
|
||||||
</vn-tbody>
|
|
||||||
<vn-tfoot>
|
|
||||||
<vn-tr>
|
|
||||||
<vn-td ng-repeat="weekday in $ctrl.weekDays" center>
|
|
||||||
{{$ctrl.formatHours(weekday.workedHours)}} h.
|
|
||||||
</vn-td>
|
|
||||||
</vn-tr>
|
|
||||||
<vn-tr>
|
|
||||||
<vn-td center ng-repeat="weekday in $ctrl.weekDays">
|
|
||||||
<vn-icon-button
|
|
||||||
icon="add_circle"
|
|
||||||
vn-tooltip="Add time"
|
|
||||||
ng-click="$ctrl.showAddTimeDialog(weekday)">
|
|
||||||
</vn-icon-button>
|
|
||||||
</vn-td>
|
|
||||||
</vn-tr>
|
|
||||||
</vn-tfoot>
|
|
||||||
</vn-table>
|
|
||||||
</vn-card>
|
|
||||||
|
|
||||||
<vn-button-bar class="vn-w-lg">
|
|
||||||
<div ng-show="$ctrl.state">
|
|
||||||
<vn-button
|
|
||||||
label="Satisfied"
|
|
||||||
disabled="$ctrl.state == 'CONFIRMED'"
|
|
||||||
ng-show="$ctrl.isHimSelf"
|
|
||||||
ng-click="$ctrl.isSatisfied()">
|
|
||||||
</vn-button>
|
|
||||||
<vn-button
|
|
||||||
label="Not satisfied"
|
|
||||||
disabled="$ctrl.state == 'REVISE'"
|
|
||||||
ng-show="$ctrl.isHimSelf"
|
|
||||||
ng-click="reason.show()">
|
|
||||||
</vn-button>
|
|
||||||
<vn-button
|
|
||||||
label="Reason"
|
|
||||||
ng-show="$ctrl.reason && ($ctrl.isHimSelf || $ctrl.isHr)"
|
|
||||||
ng-click="reason.show()">
|
|
||||||
</vn-button>
|
|
||||||
</div>
|
|
||||||
<vn-button
|
|
||||||
label="{{$ctrl.state ? 'Resend' : 'Send'}}"
|
|
||||||
ng-click="sendEmailConfirmation.show()"
|
|
||||||
class="right"
|
|
||||||
vn-tooltip="{{$ctrl.state ? 'Resend' : 'Send'}} email of this week to the user"
|
|
||||||
ng-if="$ctrl.isHr && $ctrl.state != 'CONFIRMED' && $ctrl.canResend">
|
|
||||||
</vn-button>
|
|
||||||
</vn-button-bar>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<vn-side-menu side="right">
|
|
||||||
<div class="vn-pa-md">
|
|
||||||
<div class="totalBox" style="text-align: center;">
|
|
||||||
<h6 translate>Hours</h6>
|
|
||||||
<vn-label-value
|
|
||||||
label="Week total"
|
|
||||||
value="{{$ctrl.weekTotalHours}} h.">
|
|
||||||
</vn-label-value>
|
|
||||||
<vn-label-value
|
|
||||||
label="Finish at"
|
|
||||||
value="{{$ctrl.getFinishTime()}}">
|
|
||||||
</vn-label-value>
|
|
||||||
</div>
|
|
||||||
<vn-calendar
|
|
||||||
vn-id="calendar"
|
|
||||||
class="vn-pt-md"
|
|
||||||
ng-model="$ctrl.date"
|
|
||||||
format-week="$ctrl.formatWeek($element)"
|
|
||||||
on-move="$ctrl.getMailStates($date)"
|
|
||||||
has-events="$ctrl.hasEvents($day)">
|
|
||||||
</vn-calendar>
|
|
||||||
</div>
|
|
||||||
</vn-side-menu>
|
|
||||||
|
|
||||||
<vn-dialog
|
|
||||||
vn-id="addTimeDialog"
|
|
||||||
on-accept="$ctrl.addTime()"
|
|
||||||
message="Add time">
|
|
||||||
<tpl-body>
|
|
||||||
<vn-input-time
|
|
||||||
vn-one
|
|
||||||
vn-focus
|
|
||||||
ng-model="$ctrl.newTimeEntry.timed"
|
|
||||||
label="Hour"
|
|
||||||
required="true">
|
|
||||||
</vn-input-time>
|
|
||||||
<vn-autocomplete
|
|
||||||
label="Type"
|
|
||||||
ng-model="$ctrl.newTimeEntry.direction"
|
|
||||||
data="$ctrl.entryDirections"
|
|
||||||
select-fields="['code','description']"
|
|
||||||
show-field="description"
|
|
||||||
value-field="code"
|
|
||||||
required="true">
|
|
||||||
</vn-autocomplete>
|
|
||||||
</tpl-body>
|
|
||||||
<tpl-buttons>
|
|
||||||
<input type="button" response="cancel" translate-attr="{value: 'Cancel'}"/>
|
|
||||||
<button response="accept" translate>Save</button>
|
|
||||||
</tpl-buttons>
|
|
||||||
</vn-dialog>
|
|
||||||
<vn-confirm
|
|
||||||
vn-id="delete-entry-dialog"
|
|
||||||
on-accept="$ctrl.deleteTimeEntry()"
|
|
||||||
message="This time entry will be deleted"
|
|
||||||
question="Are you sure you want to delete this entry?">
|
|
||||||
</vn-confirm>
|
|
||||||
|
|
||||||
<!-- Edit entry Popover -->
|
|
||||||
<vn-popover vn-id="editEntry">
|
|
||||||
<vn-horizontal class="vn-pa-sm edit-time-entry">
|
|
||||||
<vn-autocomplete class="dense"
|
|
||||||
ng-model="$ctrl.selectedRow.direction"
|
|
||||||
data="$ctrl.entryDirections"
|
|
||||||
select-fields="['code','description']"
|
|
||||||
show-field="description"
|
|
||||||
value-field="code">
|
|
||||||
</vn-autocomplete>
|
|
||||||
<vn-icon-button vn-none
|
|
||||||
icon="check"
|
|
||||||
vn-tooltip="Save"
|
|
||||||
ng-click="$ctrl.save()">
|
|
||||||
</vn-icon-button>
|
|
||||||
</vn-horizontal>
|
|
||||||
</vn-popover>
|
|
||||||
|
|
||||||
<vn-dialog
|
|
||||||
vn-id="reason"
|
|
||||||
on-accept="$ctrl.isUnsatisfied()">
|
|
||||||
<tpl-body>
|
|
||||||
<div class="reasonDialog">
|
|
||||||
<vn-textarea
|
|
||||||
label="Reason"
|
|
||||||
ng-model="$ctrl.reason"
|
|
||||||
disabled="!$ctrl.isHimSelf"
|
|
||||||
rows="5"
|
|
||||||
required="true">
|
|
||||||
</vn-textarea>
|
|
||||||
</div>
|
|
||||||
</tpl-body>
|
|
||||||
<tpl-buttons ng-if="$ctrl.isHimSelf">
|
|
||||||
<input type="button" response="cancel" translate-attr="{value: 'Cancel'}"/>
|
|
||||||
<button response="accept" translate>Save</button>
|
|
||||||
</tpl-buttons>
|
|
||||||
</vn-dialog>
|
|
||||||
|
|
||||||
<vn-dialog
|
|
||||||
vn-id="sendEmailConfirmation"
|
|
||||||
on-accept="$ctrl.resendEmail()"
|
|
||||||
message="Send time control email">
|
|
||||||
<tpl-body>
|
|
||||||
<span translate>Are you sure you want to send it?</span>
|
|
||||||
</tpl-body>
|
|
||||||
<tpl-buttons>
|
|
||||||
<input type="button" response="cancel" translate-attr="{value: 'Cancel'}"/>
|
|
||||||
<button response="accept" translate>Confirm</button>
|
|
||||||
</tpl-buttons>
|
|
||||||
</vn-dialog>
|
|
|
@ -1,507 +0,0 @@
|
||||||
import ngModule from '../module';
|
|
||||||
import Section from 'salix/components/section';
|
|
||||||
import './style.scss';
|
|
||||||
import UserError from 'core/lib/user-error';
|
|
||||||
|
|
||||||
class Controller extends Section {
|
|
||||||
constructor($element, $, vnWeekDays, moment) {
|
|
||||||
super($element, $);
|
|
||||||
this.weekDays = [];
|
|
||||||
this.weekdayNames = vnWeekDays.locales;
|
|
||||||
this.moment = moment;
|
|
||||||
this.entryDirections = [
|
|
||||||
{code: 'in', description: this.$t('In')},
|
|
||||||
{code: 'middle', description: this.$t('Intermediate')},
|
|
||||||
{code: 'out', description: this.$t('Out')}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
$postLink() {
|
|
||||||
const timestamp = this.$params.timestamp;
|
|
||||||
let initialDate = Date.vnNew();
|
|
||||||
|
|
||||||
if (timestamp) {
|
|
||||||
initialDate = new Date(timestamp * 1000);
|
|
||||||
this.$.calendar.defaultDate = initialDate;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.date = initialDate;
|
|
||||||
|
|
||||||
this.getMailStates(this.date);
|
|
||||||
}
|
|
||||||
|
|
||||||
get isHr() {
|
|
||||||
return this.aclService.hasAny(['hr']);
|
|
||||||
}
|
|
||||||
|
|
||||||
get isHimSelf() {
|
|
||||||
const userId = window.localStorage.currentUserWorkerId;
|
|
||||||
return userId == this.$params.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
get worker() {
|
|
||||||
return this._worker;
|
|
||||||
}
|
|
||||||
|
|
||||||
get weekNumber() {
|
|
||||||
return this.getWeekNumber(this.date);
|
|
||||||
}
|
|
||||||
|
|
||||||
set weekNumber(value) {
|
|
||||||
this._weekNumber = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
set worker(value) {
|
|
||||||
this._worker = value;
|
|
||||||
this.fetchHours();
|
|
||||||
if (this.date)
|
|
||||||
this.getWeekData();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Worker hours data
|
|
||||||
*/
|
|
||||||
get hours() {
|
|
||||||
return this._hours;
|
|
||||||
}
|
|
||||||
|
|
||||||
set hours(value) {
|
|
||||||
this._hours = value;
|
|
||||||
|
|
||||||
for (const weekDay of this.weekDays) {
|
|
||||||
if (value) {
|
|
||||||
let day = weekDay.dated.getDay();
|
|
||||||
weekDay.hours = value
|
|
||||||
.filter(hour => new Date(hour.timed).getDay() == day)
|
|
||||||
.sort((a, b) => new Date(a.timed) - new Date(b.timed));
|
|
||||||
} else
|
|
||||||
weekDay.hours = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The current selected date
|
|
||||||
*/
|
|
||||||
get date() {
|
|
||||||
return this._date;
|
|
||||||
}
|
|
||||||
|
|
||||||
set date(value) {
|
|
||||||
this._date = value;
|
|
||||||
value.setHours(0, 0, 0, 0);
|
|
||||||
|
|
||||||
let weekOffset = value.getDay() - 1;
|
|
||||||
if (weekOffset < 0) weekOffset = 6;
|
|
||||||
|
|
||||||
let started = new Date(value.getTime());
|
|
||||||
started.setDate(started.getDate() - weekOffset);
|
|
||||||
this.started = started;
|
|
||||||
|
|
||||||
let ended = new Date(started.getTime());
|
|
||||||
ended.setHours(23, 59, 59, 59);
|
|
||||||
ended.setDate(ended.getDate() + 6);
|
|
||||||
this.ended = ended;
|
|
||||||
|
|
||||||
this.weekDays = [];
|
|
||||||
let dayIndex = new Date(started.getTime());
|
|
||||||
|
|
||||||
while (dayIndex < ended) {
|
|
||||||
this.weekDays.push({
|
|
||||||
dated: new Date(dayIndex.getTime())
|
|
||||||
});
|
|
||||||
dayIndex.setDate(dayIndex.getDate() + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.worker) {
|
|
||||||
this.fetchHours();
|
|
||||||
this.getWeekData();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
set weekTotalHours(totalHours) {
|
|
||||||
this._weekTotalHours = this.formatHours(totalHours);
|
|
||||||
}
|
|
||||||
|
|
||||||
get weekTotalHours() {
|
|
||||||
return this._weekTotalHours;
|
|
||||||
}
|
|
||||||
|
|
||||||
getWeekData() {
|
|
||||||
const filter = {
|
|
||||||
where: {
|
|
||||||
workerFk: this.$params.id,
|
|
||||||
year: this._date.getFullYear(),
|
|
||||||
week: this.getWeekNumber(this._date)
|
|
||||||
},
|
|
||||||
};
|
|
||||||
this.$http.get('WorkerTimeControlMails', {filter})
|
|
||||||
.then(res => {
|
|
||||||
if (!res.data.length) {
|
|
||||||
this.state = null;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const [mail] = res.data;
|
|
||||||
this.state = mail.state;
|
|
||||||
this.reason = mail.reason;
|
|
||||||
});
|
|
||||||
this.canBeResend();
|
|
||||||
}
|
|
||||||
|
|
||||||
canBeResend() {
|
|
||||||
this.canResend = false;
|
|
||||||
const filter = {
|
|
||||||
where: {
|
|
||||||
year: this._date.getFullYear(),
|
|
||||||
week: this.getWeekNumber(this._date)
|
|
||||||
},
|
|
||||||
limit: 1
|
|
||||||
};
|
|
||||||
this.$http.get('WorkerTimeControlMails', {filter})
|
|
||||||
.then(res => {
|
|
||||||
if (res.data.length)
|
|
||||||
this.canResend = true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fetchHours() {
|
|
||||||
if (!this.worker || !this.date) return;
|
|
||||||
|
|
||||||
const params = {workerFk: this.$params.id};
|
|
||||||
const filter = {
|
|
||||||
where: {and: [
|
|
||||||
{timed: {gte: this.started}},
|
|
||||||
{timed: {lte: this.ended}}
|
|
||||||
]}
|
|
||||||
};
|
|
||||||
this.$.model.applyFilter(filter, params).then(() => {
|
|
||||||
this.getWorkedHours(this.started, this.ended);
|
|
||||||
this.getAbsences();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getWorkedHours(from, to) {
|
|
||||||
this.weekTotalHours = null;
|
|
||||||
let weekTotalHours = 0;
|
|
||||||
let params = {
|
|
||||||
id: this.$params.id,
|
|
||||||
from: from,
|
|
||||||
to: to
|
|
||||||
};
|
|
||||||
const query = `Workers/${this.$params.id}/getWorkedHours`;
|
|
||||||
return this.$http.get(query, {params}).then(res => {
|
|
||||||
const workDays = res.data;
|
|
||||||
const map = new Map();
|
|
||||||
|
|
||||||
for (const workDay of workDays) {
|
|
||||||
workDay.dated = new Date(workDay.dated);
|
|
||||||
map.set(workDay.dated, workDay);
|
|
||||||
weekTotalHours += workDay.workedHours;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const weekDay of this.weekDays) {
|
|
||||||
const workDay = workDays.find(day => {
|
|
||||||
let from = new Date(day.dated);
|
|
||||||
from.setHours(0, 0, 0, 0);
|
|
||||||
|
|
||||||
let to = new Date(day.dated);
|
|
||||||
to.setHours(23, 59, 59, 59);
|
|
||||||
|
|
||||||
return weekDay.dated >= from && weekDay.dated <= to;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (workDay) {
|
|
||||||
weekDay.expectedHours = workDay.expectedHours;
|
|
||||||
weekDay.workedHours = workDay.workedHours;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.weekTotalHours = weekTotalHours;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getAbsences() {
|
|
||||||
const fullYear = this.started.getFullYear();
|
|
||||||
let params = {
|
|
||||||
workerFk: this.$params.id,
|
|
||||||
businessFk: null,
|
|
||||||
year: fullYear
|
|
||||||
};
|
|
||||||
|
|
||||||
return this.$http.get(`Calendars/absences`, {params})
|
|
||||||
.then(res => this.onData(res.data));
|
|
||||||
}
|
|
||||||
|
|
||||||
hasEvents(day) {
|
|
||||||
return day >= this.started && day < this.ended;
|
|
||||||
}
|
|
||||||
|
|
||||||
onData(data) {
|
|
||||||
const events = {};
|
|
||||||
|
|
||||||
const addEvent = (day, event) => {
|
|
||||||
events[new Date(day).getTime()] = event;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (data.holidays) {
|
|
||||||
data.holidays.forEach(holiday => {
|
|
||||||
const holidayDetail = holiday.detail && holiday.detail.description;
|
|
||||||
const holidayType = holiday.type && holiday.type.name;
|
|
||||||
const holidayName = holidayDetail || holidayType;
|
|
||||||
|
|
||||||
addEvent(holiday.dated, {
|
|
||||||
name: holidayName,
|
|
||||||
color: '#ff0'
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (data.absences) {
|
|
||||||
data.absences.forEach(absence => {
|
|
||||||
const type = absence.absenceType;
|
|
||||||
addEvent(absence.dated, {
|
|
||||||
name: type.name,
|
|
||||||
color: type.rgb
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.weekDays.forEach(day => {
|
|
||||||
const timestamp = day.dated.getTime();
|
|
||||||
if (events[timestamp])
|
|
||||||
day.event = events[timestamp];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getFinishTime() {
|
|
||||||
if (!this.weekDays) return;
|
|
||||||
|
|
||||||
let today = Date.vnNew();
|
|
||||||
today.setHours(0, 0, 0, 0);
|
|
||||||
|
|
||||||
let todayInWeek = this.weekDays.find(day => day.dated.getTime() === today.getTime());
|
|
||||||
|
|
||||||
if (todayInWeek && todayInWeek.hours && todayInWeek.hours.length) {
|
|
||||||
const remainingTime = todayInWeek.workedHours ?
|
|
||||||
((todayInWeek.expectedHours - todayInWeek.workedHours) * 1000) : null;
|
|
||||||
const lastKnownEntry = todayInWeek.hours[todayInWeek.hours.length - 1];
|
|
||||||
const lastKnownTime = new Date(lastKnownEntry.timed).getTime();
|
|
||||||
const finishTimeStamp = lastKnownTime && remainingTime ? lastKnownTime + remainingTime : null;
|
|
||||||
|
|
||||||
if (finishTimeStamp) {
|
|
||||||
let finishDate = new Date(finishTimeStamp);
|
|
||||||
let hour = finishDate.getHours();
|
|
||||||
let minute = finishDate.getMinutes();
|
|
||||||
|
|
||||||
if (hour < 10) hour = `0${hour}`;
|
|
||||||
if (minute < 10) minute = `0${minute}`;
|
|
||||||
|
|
||||||
return `${hour}:${minute} h.`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
formatHours(timestamp = 0) {
|
|
||||||
let hour = Math.floor(timestamp / 3600);
|
|
||||||
let min = Math.floor(timestamp / 60 - 60 * hour);
|
|
||||||
|
|
||||||
if (hour < 10) hour = `0${hour}`;
|
|
||||||
if (min < 10) min = `0${min}`;
|
|
||||||
|
|
||||||
return `${hour}:${min}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
showAddTimeDialog(weekday) {
|
|
||||||
const timed = new Date(weekday.dated.getTime());
|
|
||||||
timed.setHours(0, 0, 0, 0);
|
|
||||||
|
|
||||||
this.newTimeEntry = {
|
|
||||||
workerFk: this.$params.id,
|
|
||||||
timed: timed
|
|
||||||
};
|
|
||||||
this.selectedWeekday = weekday;
|
|
||||||
this.$.addTimeDialog.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
addTime() {
|
|
||||||
try {
|
|
||||||
const entry = this.newTimeEntry;
|
|
||||||
if (!entry.direction)
|
|
||||||
throw new Error(`The entry type can't be empty`);
|
|
||||||
|
|
||||||
const query = `WorkerTimeControls/${this.worker.id}/addTimeEntry`;
|
|
||||||
this.$http.post(query, entry)
|
|
||||||
.then(() => {
|
|
||||||
this.fetchHours();
|
|
||||||
this.getMailStates(this.date);
|
|
||||||
});
|
|
||||||
} catch (e) {
|
|
||||||
this.vnApp.showError(this.$t(e.message));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
showDeleteDialog($event, hour) {
|
|
||||||
$event.preventDefault();
|
|
||||||
|
|
||||||
this.timeEntryToDelete = hour;
|
|
||||||
this.$.deleteEntryDialog.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
deleteTimeEntry() {
|
|
||||||
const entryId = this.timeEntryToDelete.id;
|
|
||||||
|
|
||||||
this.$http.post(`WorkerTimeControls/${entryId}/deleteTimeEntry`).then(() => {
|
|
||||||
this.fetchHours();
|
|
||||||
this.getMailStates(this.date);
|
|
||||||
this.vnApp.showSuccess(this.$t('Entry removed'));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
edit($event, hour) {
|
|
||||||
if ($event.defaultPrevented) return;
|
|
||||||
|
|
||||||
this.selectedRow = hour;
|
|
||||||
this.$.editEntry.show($event);
|
|
||||||
}
|
|
||||||
|
|
||||||
getWeekNumber(date) {
|
|
||||||
const tempDate = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
|
|
||||||
return this.moment(tempDate).isoWeek();
|
|
||||||
}
|
|
||||||
|
|
||||||
isSatisfied() {
|
|
||||||
this.updateWorkerTimeControlMail('CONFIRMED');
|
|
||||||
}
|
|
||||||
|
|
||||||
isUnsatisfied() {
|
|
||||||
if (!this.reason) throw new UserError(`You must indicate a reason`);
|
|
||||||
this.updateWorkerTimeControlMail('REVISE', this.reason);
|
|
||||||
}
|
|
||||||
|
|
||||||
updateWorkerTimeControlMail(state, reason) {
|
|
||||||
const params = {
|
|
||||||
year: this.date.getFullYear(),
|
|
||||||
week: this.weekNumber,
|
|
||||||
state
|
|
||||||
};
|
|
||||||
|
|
||||||
if (reason)
|
|
||||||
params.reason = reason;
|
|
||||||
|
|
||||||
const query = `WorkerTimeControls/${this.worker.id}/updateMailState`;
|
|
||||||
this.$http.post(query, params).then(() => {
|
|
||||||
this.getMailStates(this.date);
|
|
||||||
this.getWeekData();
|
|
||||||
this.vnApp.showSuccess(this.$t('Data saved!'));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
state(state, reason) {
|
|
||||||
this.state = state;
|
|
||||||
this.reason = reason;
|
|
||||||
this.repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
save() {
|
|
||||||
try {
|
|
||||||
const entry = this.selectedRow;
|
|
||||||
if (!entry.direction)
|
|
||||||
throw new Error(`The entry type can't be empty`);
|
|
||||||
|
|
||||||
const query = `WorkerTimeControls/${entry.id}/updateTimeEntry`;
|
|
||||||
if (entry.direction !== entry.$orgRow.direction) {
|
|
||||||
this.$http.post(query, {direction: entry.direction})
|
|
||||||
.then(() => this.vnApp.showSuccess(this.$t('Data saved!')))
|
|
||||||
.then(() => this.$.editEntry.hide())
|
|
||||||
.then(() => this.fetchHours())
|
|
||||||
.then(() => this.getMailStates(this.date));
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
this.vnApp.showError(this.$t(e.message));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
resendEmail() {
|
|
||||||
const params = {
|
|
||||||
recipient: this.worker.user.emailUser.email,
|
|
||||||
week: this.weekNumber,
|
|
||||||
year: this.date.getFullYear(),
|
|
||||||
workerId: this.worker.id,
|
|
||||||
state: 'SENDED'
|
|
||||||
};
|
|
||||||
this.$http.post(`WorkerTimeControls/weekly-hour-record-email`, params)
|
|
||||||
.then(() => {
|
|
||||||
this.getMailStates(this.date);
|
|
||||||
this.vnApp.showSuccess(this.$t('Email sended'));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getTime(timeString) {
|
|
||||||
const [hours, minutes, seconds] = timeString.split(':');
|
|
||||||
return [parseInt(hours), parseInt(minutes), parseInt(seconds)];
|
|
||||||
}
|
|
||||||
|
|
||||||
getMailStates(date) {
|
|
||||||
const params = {
|
|
||||||
month: date.getMonth() + 1,
|
|
||||||
year: date.getFullYear()
|
|
||||||
};
|
|
||||||
const query = `WorkerTimeControls/${this.$params.id}/getMailStates`;
|
|
||||||
this.$http.get(query, {params})
|
|
||||||
.then(res => {
|
|
||||||
this.workerTimeControlMails = res.data;
|
|
||||||
this.repaint();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
formatWeek($element) {
|
|
||||||
const weekNumberHTML = $element.firstElementChild;
|
|
||||||
const weekNumberValue = weekNumberHTML.innerHTML;
|
|
||||||
|
|
||||||
if (!this.workerTimeControlMails) return;
|
|
||||||
const workerTimeControlMail = this.workerTimeControlMails.find(
|
|
||||||
workerTimeControlMail => workerTimeControlMail.week == weekNumberValue
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!workerTimeControlMail) return;
|
|
||||||
const state = workerTimeControlMail.state;
|
|
||||||
|
|
||||||
if (state == 'CONFIRMED') {
|
|
||||||
weekNumberHTML.classList.remove('revise');
|
|
||||||
weekNumberHTML.classList.remove('sended');
|
|
||||||
|
|
||||||
weekNumberHTML.classList.add('confirmed');
|
|
||||||
weekNumberHTML.setAttribute('title', 'Conforme');
|
|
||||||
}
|
|
||||||
if (state == 'REVISE') {
|
|
||||||
weekNumberHTML.classList.remove('confirmed');
|
|
||||||
weekNumberHTML.classList.remove('sended');
|
|
||||||
|
|
||||||
weekNumberHTML.classList.add('revise');
|
|
||||||
weekNumberHTML.setAttribute('title', 'No conforme');
|
|
||||||
}
|
|
||||||
if (state == 'SENDED') {
|
|
||||||
weekNumberHTML.classList.add('sended');
|
|
||||||
weekNumberHTML.setAttribute('title', 'Pendiente');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
repaint() {
|
|
||||||
let calendars = this.element.querySelectorAll('vn-calendar');
|
|
||||||
for (let calendar of calendars)
|
|
||||||
calendar.$ctrl.repaint();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Controller.$inject = ['$element', '$scope', 'vnWeekDays', 'moment'];
|
|
||||||
|
|
||||||
ngModule.vnComponent('vnWorkerTimeControl', {
|
|
||||||
template: require('./index.html'),
|
|
||||||
controller: Controller,
|
|
||||||
bindings: {
|
|
||||||
worker: '<'
|
|
||||||
},
|
|
||||||
require: {
|
|
||||||
card: '^vnWorkerCard'
|
|
||||||
}
|
|
||||||
});
|
|
|
@ -1,286 +0,0 @@
|
||||||
import './index.js';
|
|
||||||
|
|
||||||
describe('Component vnWorkerTimeControl', () => {
|
|
||||||
let $httpBackend;
|
|
||||||
let $scope;
|
|
||||||
let $element;
|
|
||||||
let controller;
|
|
||||||
let $httpParamSerializer;
|
|
||||||
|
|
||||||
beforeEach(ngModule('worker'));
|
|
||||||
|
|
||||||
beforeEach(inject(($componentController, $rootScope, $stateParams, _$httpBackend_, _$httpParamSerializer_) => {
|
|
||||||
$stateParams.id = 1;
|
|
||||||
$httpBackend = _$httpBackend_;
|
|
||||||
$httpParamSerializer = _$httpParamSerializer_;
|
|
||||||
$scope = $rootScope.$new();
|
|
||||||
$element = angular.element('<vn-worker-time-control></vn-worker-time-control>');
|
|
||||||
controller = $componentController('vnWorkerTimeControl', {$element, $scope});
|
|
||||||
controller.card = {
|
|
||||||
hasWorkCenter: true
|
|
||||||
};
|
|
||||||
}));
|
|
||||||
|
|
||||||
describe('date() setter', () => {
|
|
||||||
it(`should set the weekDays and the date in the controller`, () => {
|
|
||||||
let today = Date.vnNew();
|
|
||||||
jest.spyOn(controller, 'fetchHours').mockReturnThis();
|
|
||||||
|
|
||||||
controller.date = today;
|
|
||||||
|
|
||||||
expect(controller._date).toEqual(today);
|
|
||||||
expect(controller.started).toBeDefined();
|
|
||||||
expect(controller.ended).toBeDefined();
|
|
||||||
expect(controller.weekDays.length).toEqual(7);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('hours() setter', () => {
|
|
||||||
it(`should set hours data at it's corresponding week day`, () => {
|
|
||||||
let today = Date.vnNew();
|
|
||||||
jest.spyOn(controller, 'fetchHours').mockReturnThis();
|
|
||||||
|
|
||||||
controller.date = today;
|
|
||||||
|
|
||||||
let hours = [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
timed: controller.started.toJSON(),
|
|
||||||
userFk: 1
|
|
||||||
}, {
|
|
||||||
id: 2,
|
|
||||||
timed: controller.ended.toJSON(),
|
|
||||||
userFk: 1
|
|
||||||
}, {
|
|
||||||
id: 3,
|
|
||||||
timed: controller.ended.toJSON(),
|
|
||||||
userFk: 1
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
controller.hours = hours;
|
|
||||||
|
|
||||||
expect(controller.weekDays.length).toEqual(7);
|
|
||||||
expect(controller.weekDays[0].hours.length).toEqual(1);
|
|
||||||
expect(controller.weekDays[6].hours.length).toEqual(2);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('getWorkedHours() ', () => {
|
|
||||||
it('should set the weekdays expected and worked hours plus the total worked hours', () => {
|
|
||||||
let today = Date.vnNew();
|
|
||||||
jest.spyOn(controller, 'fetchHours').mockReturnThis();
|
|
||||||
|
|
||||||
controller.date = today;
|
|
||||||
|
|
||||||
let sixHoursInSeconds = 6 * 60 * 60;
|
|
||||||
let tenHoursInSeconds = 10 * 60 * 60;
|
|
||||||
let response = [
|
|
||||||
{
|
|
||||||
dated: today,
|
|
||||||
expectedHours: sixHoursInSeconds,
|
|
||||||
workedHours: tenHoursInSeconds,
|
|
||||||
|
|
||||||
},
|
|
||||||
];
|
|
||||||
$httpBackend.whenRoute('GET', 'Workers/:id/getWorkedHours')
|
|
||||||
.respond(response);
|
|
||||||
|
|
||||||
$httpBackend.whenRoute('GET', 'WorkerTimeControlMails')
|
|
||||||
.respond([]);
|
|
||||||
|
|
||||||
today.setHours(0, 0, 0, 0);
|
|
||||||
|
|
||||||
let weekOffset = today.getDay() - 1;
|
|
||||||
if (weekOffset < 0) weekOffset = 6;
|
|
||||||
|
|
||||||
let started = new Date(today.getTime());
|
|
||||||
started.setDate(started.getDate() - weekOffset);
|
|
||||||
controller.started = started;
|
|
||||||
|
|
||||||
let ended = new Date(started.getTime());
|
|
||||||
ended.setHours(23, 59, 59, 59);
|
|
||||||
ended.setDate(ended.getDate() + 6);
|
|
||||||
controller.ended = ended;
|
|
||||||
|
|
||||||
controller.getWorkedHours(controller.started, controller.ended);
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(controller.weekDays.length).toEqual(7);
|
|
||||||
expect(controller.weekDays[weekOffset].expectedHours).toEqual(response[0].expectedHours);
|
|
||||||
expect(controller.weekDays[weekOffset].workedHours).toEqual(response[0].workedHours);
|
|
||||||
expect(controller.weekTotalHours).toEqual('10:00');
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('formatHours() ', () => {
|
|
||||||
it(`should format a passed timestamp to hours and minutes`, () => {
|
|
||||||
const result = controller.formatHours(3600);
|
|
||||||
|
|
||||||
expect(result).toEqual('01:00');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('save() ', () => {
|
|
||||||
it(`should make a query an then call to the fetchHours() method`, () => {
|
|
||||||
const today = Date.vnNew();
|
|
||||||
|
|
||||||
jest.spyOn(controller, 'getWeekData').mockReturnThis();
|
|
||||||
jest.spyOn(controller, 'getMailStates').mockReturnThis();
|
|
||||||
|
|
||||||
controller.$.model = {applyFilter: jest.fn().mockReturnValue(Promise.resolve())};
|
|
||||||
controller.date = today;
|
|
||||||
controller.fetchHours = jest.fn();
|
|
||||||
controller.selectedRow = {id: 1, timed: Date.vnNew(), direction: 'in', $orgRow: {direction: null}};
|
|
||||||
controller.$.editEntry = {
|
|
||||||
hide: () => {}
|
|
||||||
};
|
|
||||||
const expectedParams = {direction: 'in'};
|
|
||||||
$httpBackend.expect('POST', 'WorkerTimeControls/1/updateTimeEntry', expectedParams).respond(200);
|
|
||||||
controller.save();
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(controller.fetchHours).toHaveBeenCalledWith();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('$postLink() ', () => {
|
|
||||||
it(`should set the controller date as today if no timestamp is defined`, () => {
|
|
||||||
controller.$.model = {applyFilter: jest.fn().mockReturnValue(Promise.resolve())};
|
|
||||||
controller.$params = {timestamp: undefined};
|
|
||||||
controller.$postLink();
|
|
||||||
|
|
||||||
expect(controller.date).toEqual(jasmine.any(Date));
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should set the controller date using the received timestamp`, () => {
|
|
||||||
const timestamp = 1;
|
|
||||||
const date = new Date(timestamp);
|
|
||||||
|
|
||||||
controller.$.model = {applyFilter: jest.fn().mockReturnValue(Promise.resolve())};
|
|
||||||
controller.$.calendar = {};
|
|
||||||
controller.$params = {timestamp: timestamp};
|
|
||||||
|
|
||||||
controller.$postLink();
|
|
||||||
|
|
||||||
expect(controller.date.toDateString()).toEqual(date.toDateString());
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('getWeekData() ', () => {
|
|
||||||
it(`should make a query an then update the state and reason`, () => {
|
|
||||||
const today = Date.vnNew();
|
|
||||||
const response = [
|
|
||||||
{
|
|
||||||
state: 'SENDED',
|
|
||||||
reason: null
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
controller._date = today;
|
|
||||||
|
|
||||||
$httpBackend.whenRoute('GET', 'WorkerTimeControlMails')
|
|
||||||
.respond(response);
|
|
||||||
|
|
||||||
controller.getWeekData();
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(controller.state).toBe('SENDED');
|
|
||||||
expect(controller.reason).toBe(null);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('isSatisfied() ', () => {
|
|
||||||
it(`should make a query an then call three methods`, () => {
|
|
||||||
const today = Date.vnNew();
|
|
||||||
jest.spyOn(controller, 'getWeekData').mockReturnThis();
|
|
||||||
jest.spyOn(controller, 'getMailStates').mockReturnThis();
|
|
||||||
jest.spyOn(controller.vnApp, 'showSuccess');
|
|
||||||
|
|
||||||
controller.$.model = {applyFilter: jest.fn().mockReturnValue(Promise.resolve())};
|
|
||||||
controller.worker = {id: 1};
|
|
||||||
controller.date = today;
|
|
||||||
controller.weekNumber = 1;
|
|
||||||
|
|
||||||
$httpBackend.expect('POST', 'WorkerTimeControls/1/updateMailState').respond();
|
|
||||||
controller.isSatisfied();
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(controller.getMailStates).toHaveBeenCalledWith(controller.date);
|
|
||||||
expect(controller.getWeekData).toHaveBeenCalled();
|
|
||||||
expect(controller.vnApp.showSuccess).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('isUnsatisfied() ', () => {
|
|
||||||
it(`should throw an error is reason is empty`, () => {
|
|
||||||
let error;
|
|
||||||
try {
|
|
||||||
controller.isUnsatisfied();
|
|
||||||
} catch (e) {
|
|
||||||
error = e;
|
|
||||||
}
|
|
||||||
|
|
||||||
expect(error).toBeDefined();
|
|
||||||
expect(error.message).toBe(`You must indicate a reason`);
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should make a query an then call three methods`, () => {
|
|
||||||
const today = Date.vnNew();
|
|
||||||
jest.spyOn(controller, 'getWeekData').mockReturnThis();
|
|
||||||
jest.spyOn(controller, 'getMailStates').mockReturnThis();
|
|
||||||
jest.spyOn(controller.vnApp, 'showSuccess');
|
|
||||||
|
|
||||||
controller.$.model = {applyFilter: jest.fn().mockReturnValue(Promise.resolve())};
|
|
||||||
controller.worker = {id: 1};
|
|
||||||
controller.date = today;
|
|
||||||
controller.weekNumber = 1;
|
|
||||||
controller.reason = 'reason';
|
|
||||||
|
|
||||||
$httpBackend.expect('POST', 'WorkerTimeControls/1/updateMailState').respond();
|
|
||||||
controller.isSatisfied();
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(controller.getMailStates).toHaveBeenCalledWith(controller.date);
|
|
||||||
expect(controller.getWeekData).toHaveBeenCalled();
|
|
||||||
expect(controller.vnApp.showSuccess).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('resendEmail() ', () => {
|
|
||||||
it(`should make a query an then call showSuccess method`, () => {
|
|
||||||
const today = Date.vnNew();
|
|
||||||
|
|
||||||
jest.spyOn(controller, 'getWeekData').mockReturnThis();
|
|
||||||
jest.spyOn(controller, 'getMailStates').mockReturnThis();
|
|
||||||
jest.spyOn(controller.vnApp, 'showSuccess');
|
|
||||||
|
|
||||||
controller.$.model = {applyFilter: jest.fn().mockReturnValue(Promise.resolve())};
|
|
||||||
controller.worker = {id: 1};
|
|
||||||
controller.worker = {user: {emailUser: {email: 'employee@verdnatura.es'}}};
|
|
||||||
controller.date = today;
|
|
||||||
controller.weekNumber = 1;
|
|
||||||
|
|
||||||
$httpBackend.expect('POST', 'WorkerTimeControls/weekly-hour-record-email').respond();
|
|
||||||
controller.resendEmail();
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(controller.vnApp.showSuccess).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('getMailStates() ', () => {
|
|
||||||
it(`should make a query an then call showSuccess method`, () => {
|
|
||||||
const today = Date.vnNew();
|
|
||||||
jest.spyOn(controller, 'repaint').mockReturnThis();
|
|
||||||
|
|
||||||
controller.$params = {id: 1};
|
|
||||||
|
|
||||||
$httpBackend.expect('GET', `WorkerTimeControls/1/getMailStates?month=1&year=2001`).respond();
|
|
||||||
controller.getMailStates(today);
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(controller.repaint).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,22 +0,0 @@
|
||||||
In: Entrada
|
|
||||||
Out: Salida
|
|
||||||
Intermediate: Intermedio
|
|
||||||
Hour: Hora
|
|
||||||
Hours: Horas
|
|
||||||
Add time: Añadir hora
|
|
||||||
Week total: Total semana
|
|
||||||
Current week: Semana actual
|
|
||||||
This time entry will be deleted: Se eliminará la hora fichada
|
|
||||||
Are you sure you want to delete this entry?: ¿Seguro que quieres eliminarla?
|
|
||||||
Finish at: Termina a las
|
|
||||||
Entry removed: Fichada borrada
|
|
||||||
The entry type can't be empty: El tipo de fichada no puede quedar vacía
|
|
||||||
Satisfied: Conforme
|
|
||||||
Not satisfied: No conforme
|
|
||||||
Reason: Motivo
|
|
||||||
Resend: Reenviar
|
|
||||||
Email sended: Email enviado
|
|
||||||
You must indicate a reason: Debes indicar un motivo
|
|
||||||
Send time control email: Enviar email control horario
|
|
||||||
Are you sure you want to send it?: ¿Seguro que quieres enviarlo?
|
|
||||||
Resend email of this week to the user: Reenviar email de esta semana al usuario
|
|
|
@ -1,52 +0,0 @@
|
||||||
@import "variables";
|
|
||||||
|
|
||||||
vn-worker-time-control {
|
|
||||||
vn-thead > vn-tr > vn-td > div.weekday {
|
|
||||||
margin-bottom: 5px;
|
|
||||||
color: $color-main
|
|
||||||
}
|
|
||||||
vn-td.hours {
|
|
||||||
min-width: 100px;
|
|
||||||
vertical-align: top;
|
|
||||||
|
|
||||||
& > section {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
padding: 4px 0;
|
|
||||||
|
|
||||||
& > vn-icon {
|
|
||||||
color: $color-font-secondary;
|
|
||||||
padding-right: 1px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.totalBox {
|
|
||||||
max-width: none
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.reasonDialog{
|
|
||||||
min-width: 500px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.edit-time-entry {
|
|
||||||
width: 200px
|
|
||||||
}
|
|
||||||
|
|
||||||
.right {
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
.confirmed {
|
|
||||||
color: #97B92F;
|
|
||||||
}
|
|
||||||
|
|
||||||
.revise {
|
|
||||||
color: #f61e1e;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sended {
|
|
||||||
color: #d19b25;
|
|
||||||
}
|
|
Loading…
Reference in New Issue