Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix into 5475-email_2fa
gitea/salix/pipeline/head This commit looks good
Details
gitea/salix/pipeline/head This commit looks good
Details
This commit is contained in:
commit
63a8f40443
|
@ -0,0 +1,89 @@
|
|||
DROP PROCEDURE IF EXISTS vn.clientCreate;
|
||||
|
||||
DELIMITER $$
|
||||
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`client_create`(
|
||||
vFirstname VARCHAR(50),
|
||||
vSurnames VARCHAR(50),
|
||||
vFi VARCHAR(9),
|
||||
vAddress TEXT,
|
||||
vPostcode CHAR(5),
|
||||
vCity VARCHAR(25),
|
||||
vProvinceFk SMALLINT(5),
|
||||
vCompanyFk SMALLINT(5),
|
||||
vPhone VARCHAR(11),
|
||||
vEmail VARCHAR(255),
|
||||
vUserFk INT
|
||||
)
|
||||
BEGIN
|
||||
/**
|
||||
* Create new client
|
||||
*
|
||||
* @params vFirstname firstName
|
||||
* @params vSurnames surnames
|
||||
* @params vFi company code from accounting transactions
|
||||
* @params vAddress address
|
||||
* @params vPostcode postCode
|
||||
* @params vCity city
|
||||
* @params vProvinceFk province
|
||||
* @params vCompanyFk company in which he has become a client
|
||||
* @params vPhone telephone number
|
||||
* @params vEmail email address
|
||||
* @params vUserFk user id
|
||||
*/
|
||||
DECLARE vPayMethodFk INT;
|
||||
DECLARE vDueDay INT;
|
||||
DECLARE vDefaultCredit DECIMAL(10, 2);
|
||||
DECLARE vIsTaxDataChecked TINYINT(1);
|
||||
DECLARE vHasCoreVnl BOOLEAN;
|
||||
DECLARE vMandateTypeFk INT;
|
||||
|
||||
SELECT defaultPayMethodFk,
|
||||
defaultDueDay,
|
||||
defaultCredit,
|
||||
defaultIsTaxDataChecked,
|
||||
defaultHasCoreVnl,
|
||||
defaultMandateTypeFk
|
||||
INTO vPayMethodFk,
|
||||
vDueDay,
|
||||
vDefaultCredit,
|
||||
vIsTaxDataChecked,
|
||||
vHasCoreVnl,
|
||||
vMandateTypeFk
|
||||
FROM clientConfig;
|
||||
|
||||
INSERT INTO `client`
|
||||
SET id = vUserFk,
|
||||
name = CONCAT(vFirstname, ' ', vSurnames),
|
||||
street = vAddress,
|
||||
fi = TRIM(vFi),
|
||||
phone = vPhone,
|
||||
email = vEmail,
|
||||
provinceFk = vProvinceFk,
|
||||
city = vCity,
|
||||
postcode = vPostcode,
|
||||
socialName = CONCAT(vSurnames, ' ', vFirstname),
|
||||
payMethodFk = vPayMethodFk,
|
||||
dueDay = vDueDay,
|
||||
credit = vDefaultCredit,
|
||||
isTaxDataChecked = vIsTaxDataChecked,
|
||||
hasCoreVnl = vHasCoreVnl,
|
||||
isEqualizated = FALSE
|
||||
ON duplicate KEY UPDATE
|
||||
payMethodFk = vPayMethodFk,
|
||||
dueDay = vDueDay,
|
||||
credit = vDefaultCredit,
|
||||
isTaxDataChecked = vIsTaxDataChecked,
|
||||
hasCoreVnl = vHasCoreVnl,
|
||||
isActive = TRUE;
|
||||
|
||||
INSERT INTO mandate (clientFk, companyFk, mandateTypeFk)
|
||||
SELECT vUserFk, vCompanyFk, vMandateTypeFk
|
||||
WHERE NOT EXISTS (
|
||||
SELECT id
|
||||
FROM mandate
|
||||
WHERE clientFk = vUserFk
|
||||
AND companyFk = vCompanyFk
|
||||
AND mandateTypeFk = vMandateTypeFk
|
||||
);
|
||||
END$$
|
||||
DELIMITER ;
|
|
@ -0,0 +1,17 @@
|
|||
ALTER TABLE vn.clientConfig ADD defaultPayMethodFk tinyint(3) unsigned NULL;
|
||||
ALTER TABLE vn.clientConfig ADD defaultDueDay int unsigned NULL;
|
||||
ALTER TABLE vn.clientConfig ADD defaultCredit decimal(10, 2) NULL;
|
||||
ALTER TABLE vn.clientConfig ADD defaultIsTaxDataChecked tinyint(1) NULL;
|
||||
ALTER TABLE vn.clientConfig ADD defaultHasCoreVnl boolean NULL;
|
||||
ALTER TABLE vn.clientConfig ADD defaultMandateTypeFk smallint(5) NULL;
|
||||
ALTER TABLE vn.clientConfig ADD CONSTRAINT clientNewConfigPayMethod_FK FOREIGN KEY (dafaultPayMethodFk) REFERENCES vn.payMethod(id);
|
||||
ALTER TABLE vn.clientConfig ADD CONSTRAINT clientNewConfigMandateType_FK FOREIGN KEY (defaultMandateTypeFk) REFERENCES vn.mandateType(id);
|
||||
|
||||
UPDATE vn.clientConfig
|
||||
SET defaultPayMethodFk = 4,
|
||||
defaultDueDay = 5,
|
||||
defaultCredit = 300.0,
|
||||
defaultIsTaxDataChecked = 1,
|
||||
defaultHasCoreVnl = 1,
|
||||
defaultMandateTypeFk = 2
|
||||
WHERE id = 1;
|
|
@ -385,9 +385,10 @@ INSERT INTO `vn`.`clientManaCache`(`clientFk`, `mana`, `dated`)
|
|||
(1103, 0, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH)),
|
||||
(1104, -30, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH));
|
||||
|
||||
INSERT INTO `vn`.`clientConfig`(`riskTolerance`, `maxCreditRows`)
|
||||
INSERT INTO `vn`.`clientConfig`(`id`, `riskTolerance`, `maxCreditRows`, `maxPriceIncreasingRatio`, `riskScope`, `defaultPayMethodFk`, `defaultDueDay`, `defaultCredit`, `defaultIsTaxDataChecked`, `defaultHasCoreVnl`, `defaultMandateTypeFk`)
|
||||
VALUES
|
||||
(200, 10);
|
||||
(1, 200, 10, 0.25, 2, 4, 5, 300.00, 1, 1, 2);
|
||||
|
||||
|
||||
INSERT INTO `vn`.`address`(`id`, `nickname`, `street`, `city`, `postalCode`, `provinceFk`, `phone`, `mobile`, `isActive`, `clientFk`, `agencyModeFk`, `longitude`, `latitude`, `isEqualizated`, `isDefaultAddress`)
|
||||
VALUES
|
||||
|
|
|
@ -894,6 +894,18 @@ export default {
|
|||
extension: 'vn-worker-summary vn-one:nth-child(2) > vn-label-value:nth-child(5) > section > span',
|
||||
|
||||
},
|
||||
department: {
|
||||
firstDepartment: 'vn-worker-department-index vn-card > vn-treeview vn-treeview-childs vn-treeview-childs vn-treeview-childs a'
|
||||
},
|
||||
departmentSummary: {
|
||||
header: 'vn-worker-department-summary h5',
|
||||
name: 'vn-worker-department-summary vn-horizontal > vn-one > vn-vertical > vn-label-value:nth-child(1) > section > span',
|
||||
code: 'vn-worker-department-summary vn-horizontal > vn-one > vn-vertical > vn-label-value:nth-child(2) > section > span',
|
||||
chat: 'vn-worker-department-summary vn-horizontal > vn-one > vn-vertical > vn-label-value:nth-child(3) > section > span',
|
||||
bossDepartment: 'vn-worker-department-summary vn-horizontal > vn-one > vn-vertical > vn-label-value:nth-child(4) > section > span',
|
||||
email: 'vn-worker-department-summary vn-horizontal > vn-one > vn-vertical > vn-label-value:nth-child(5) > section > span',
|
||||
clientFk: 'vn-worker-department-summary vn-horizontal > vn-one > vn-vertical > vn-label-value:nth-child(6) > section > span',
|
||||
},
|
||||
workerBasicData: {
|
||||
name: 'vn-worker-basic-data vn-textfield[ng-model="$ctrl.worker.firstName"]',
|
||||
surname: 'vn-worker-basic-data vn-textfield[ng-model="$ctrl.worker.lastName"]',
|
||||
|
@ -901,6 +913,13 @@ export default {
|
|||
locker: 'vn-worker-basic-data vn-input-number[ng-model="$ctrl.worker.locker"]',
|
||||
saveButton: 'vn-worker-basic-data button[type=submit]'
|
||||
},
|
||||
departmentBasicData: {
|
||||
Name: 'vn-worker-department-basic-data vn-textfield[ng-model="$ctrl.department.name"]',
|
||||
Code: 'vn-worker-department-basic-data vn-textfield[ng-model="$ctrl.department.code"]',
|
||||
Chat: 'vn-worker-department-basic-data vn-textfield[ng-model="$ctrl.department.chat"]',
|
||||
Email: 'vn-worker-department-basic-data vn-textfield[ng-model="$ctrl.department.notificationEmail"]',
|
||||
saveButton: 'vn-worker-department-basic-data button[type=submit]'
|
||||
},
|
||||
workerNotes: {
|
||||
addNoteFloatButton: 'vn-worker-note vn-icon[icon="add"]',
|
||||
note: 'vn-note-worker-create vn-textarea[ng-model="$ctrl.note.text"]',
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
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('-');
|
||||
});
|
||||
});
|
|
@ -0,0 +1,43 @@
|
|||
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);
|
||||
});
|
||||
});
|
|
@ -147,14 +147,12 @@
|
|||
"Receipt's bank was not found": "Receipt's bank was not found",
|
||||
"This receipt was not compensated": "This receipt was not compensated",
|
||||
"Client's email was not found": "Client's email was not found",
|
||||
"Tickets with associated refunds": "Tickets with associated refunds can't be deleted. This ticket is associated with refund Nº {{id}}",
|
||||
"Tickets with associated refunds": "Tickets with associated refunds can't be deleted. This ticket is associated with refund Nº %d",
|
||||
"It is not possible to modify tracked sales": "It is not possible to modify tracked sales",
|
||||
"It is not possible to modify sales that their articles are from Floramondo": "It is not possible to modify sales that their articles are from Floramondo",
|
||||
"It is not possible to modify cloned sales": "It is not possible to modify cloned sales",
|
||||
"Valid priorities: 1,2,3": "Valid priorities: 1,2,3",
|
||||
"Warehouse inventory not set": "Almacén inventario no está establecido",
|
||||
"Component cost not set": "Componente coste no está estabecido",
|
||||
"Tickets with associated refunds can't be deleted. This ticket is associated with refund Nº 2": "Tickets with associated refunds can't be deleted. This ticket is associated with refund Nº 2",
|
||||
"Description cannot be blank": "Description cannot be blank",
|
||||
"company": "Company",
|
||||
"country": "Country",
|
||||
|
@ -178,5 +176,6 @@
|
|||
"Failed to upload delivery note": "Error to upload delivery note {{id}}",
|
||||
"Mail not sent": "There has been an error sending the invoice to the client [{{clientId}}]({{{clientUrl}}}), please check the email address",
|
||||
"The renew period has not been exceeded": "The renew period has not been exceeded",
|
||||
"You can not use the same password": "You can not use the same password"
|
||||
"You can not use the same password": "You can not use the same password",
|
||||
"Valid priorities": "Valid priorities: %d"
|
||||
}
|
||||
|
|
|
@ -268,7 +268,7 @@
|
|||
"Invoice date can't be less than max date": "La fecha de factura no puede ser inferior a la fecha límite",
|
||||
"Warehouse inventory not set": "El almacén inventario no está establecido",
|
||||
"This locker has already been assigned": "Esta taquilla ya ha sido asignada",
|
||||
"Tickets with associated refunds": "No se pueden borrar tickets con abonos asociados. Este ticket está asociado al abono Nº {{id}}",
|
||||
"Tickets with associated refunds": "No se pueden borrar tickets con abonos asociados. Este ticket está asociado al abono Nº %d",
|
||||
"Not exist this branch": "La rama no existe",
|
||||
"This ticket cannot be signed because it has not been boxed": "Este ticket no puede firmarse porque no ha sido encajado",
|
||||
"Collection does not exist": "La colección no existe",
|
||||
|
@ -301,6 +301,7 @@
|
|||
"Fecha fuera de rango": "Fecha fuera de rango",
|
||||
"Error while generating PDF": "Error al generar PDF",
|
||||
"Error when sending mail to client": "Error al enviar el correo al cliente",
|
||||
"Mail not sent": "Se ha producido un fallo al enviar la factura al cliente [{{clientId}}]({{{clientUrl}}}), por favor revisa la dirección de correo electrónico",
|
||||
"The renew period has not been exceeded": "El periodo de renovación no ha sido superado"
|
||||
"Mail not sent": "Se ha producido un fallo al enviar la factura al cliente [{{clientId}}]({{{clientUrl}}}), por favor revisa la dirección de correo electrónico",
|
||||
"The renew period has not been exceeded": "El periodo de renovación no ha sido superado",
|
||||
"Valid priorities": "Prioridades válidas: %d"
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
let UserError = require('vn-loopback/util/user-error');
|
||||
const UserError = require('vn-loopback/util/user-error');
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethodCtx('new', {
|
||||
|
@ -49,7 +49,7 @@ module.exports = Self => {
|
|||
try {
|
||||
const itemConfig = await models.ItemConfig.findOne({fields: ['validPriorities']}, myOptions);
|
||||
if (!itemConfig.validPriorities.includes(params.priority))
|
||||
throw new UserError(`Valid priorities: ${[...itemConfig.validPriorities]}`);
|
||||
throw new UserError('Valid priorities', 'VALID_PRIORITIES', [...itemConfig.validPriorities]);
|
||||
|
||||
const provisionalName = params.provisionalName;
|
||||
delete params.provisionalName;
|
||||
|
|
|
@ -50,7 +50,7 @@ module.exports = Self => {
|
|||
fields: ['id']}
|
||||
, myOptions);
|
||||
if (ticketRefunds.length > 0)
|
||||
throw new UserError($t('Tickets with associated refunds', {id: ticketRefunds[0].id}));
|
||||
throw new UserError('Tickets with associated refunds', 'TICKET_REFUND', ticketRefunds[0].id);
|
||||
|
||||
// Check if has sales with shelving
|
||||
const canDeleteTicketWithPartPrepared =
|
||||
|
|
|
@ -33,7 +33,6 @@ module.exports = Self => {
|
|||
map.set(node.parentFk, []);
|
||||
map.get(node.parentFk).push(node);
|
||||
}
|
||||
|
||||
function setLeaves(nodes) {
|
||||
if (!nodes) return;
|
||||
for (let node of nodes) {
|
||||
|
@ -43,6 +42,7 @@ module.exports = Self => {
|
|||
}
|
||||
|
||||
let leaves = map.get(parentId);
|
||||
|
||||
setLeaves(leaves);
|
||||
|
||||
return leaves || [];
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
const models = require('vn-loopback/server/server').models;
|
||||
|
||||
describe('department getLeaves()', () => {
|
||||
const ctx = {req: {accessToken: {userId: 9}}};
|
||||
it('should return the department and the childs containing the search value', async() => {
|
||||
let result = await models.Department.getLeaves(ctx, null, 'INFORMATICA');
|
||||
|
||||
expect(result.length).toEqual(1);
|
||||
});
|
||||
});
|
|
@ -171,7 +171,7 @@ module.exports = Self => {
|
|||
throw new UserError(`That payment method requires an IBAN`);
|
||||
|
||||
await models.Worker.rawSql(
|
||||
'CALL vn.clientCreate(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
|
||||
'CALL vn.client_create(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
|
||||
[
|
||||
args.firstName,
|
||||
args.lastNames,
|
||||
|
|
|
@ -8,8 +8,9 @@
|
|||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "number",
|
||||
"id": true,
|
||||
"type": "number"
|
||||
"description": "Identifier"
|
||||
},
|
||||
"code": {
|
||||
"type": "string"
|
||||
|
@ -37,6 +38,30 @@
|
|||
},
|
||||
"hasToMistake": {
|
||||
"type": "number"
|
||||
},
|
||||
"isTeleworking": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"hasToRefill": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"hasToSendMail": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"isProduction": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
"client": {
|
||||
"type": "belongsTo",
|
||||
"model": "Client",
|
||||
"foreignKey": "clientFk"
|
||||
},
|
||||
"worker": {
|
||||
"type": "belongsTo",
|
||||
"model": "Worker",
|
||||
"foreignKey": "workerFk"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@
|
|||
"user": {
|
||||
"type": "belongsTo",
|
||||
"model": "VnUser",
|
||||
"foreignKey": "userFk"
|
||||
"foreignKey": "id"
|
||||
},
|
||||
"boss": {
|
||||
"type": "belongsTo",
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
<vn-watcher
|
||||
vn-id="watcher"
|
||||
data="$ctrl.department"
|
||||
form="form"
|
||||
url="Departments">
|
||||
</vn-watcher>
|
||||
<vn-portal slot="topbar">
|
||||
<vn-searchbar
|
||||
vn-focus
|
||||
info="Search departments by id, name or code"
|
||||
on-search="$ctrl.onSearch($params)"
|
||||
base-state="worker.department">
|
||||
</vn-searchbar>
|
||||
</vn-portal>
|
||||
<form name="form" ng-submit="watcher.submit()" class="vn-w-md">
|
||||
<vn-card class="vn-pa-lg">
|
||||
<vn-vertical>
|
||||
<vn-horizontal>
|
||||
<vn-textfield
|
||||
vn-one
|
||||
label="Name"
|
||||
ng-model="$ctrl.department.name"
|
||||
vn-name="Name">
|
||||
</vn-textfield>
|
||||
<vn-textfield
|
||||
vn-one
|
||||
label="Code"
|
||||
ng-model="$ctrl.department.code"
|
||||
vn-name="Code">
|
||||
</vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-textfield
|
||||
vn-one
|
||||
label="Chat"
|
||||
ng-model="$ctrl.department.chatName"
|
||||
vn-name="Chat">
|
||||
</vn-textfield>
|
||||
<vn-textfield type="Email"
|
||||
vn-one
|
||||
label="Email"
|
||||
ng-model="$ctrl.department.notificationEmail"
|
||||
vn-name="Email">
|
||||
</vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-autocomplete
|
||||
ng-model="$ctrl.department.workerFk"
|
||||
url="Workers/activeWithInheritedRole"
|
||||
show-field="nickname"
|
||||
search-function="{firstName: $search}"
|
||||
label="Boss department">
|
||||
</vn-autocomplete>
|
||||
<vn-autocomplete
|
||||
ng-model="$ctrl.department.clientFk"
|
||||
url="Clients/"
|
||||
show-field="name"
|
||||
search-function="{firstName: $search}"
|
||||
label="Self-consumption customer">
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-check
|
||||
label="Telework"
|
||||
ng-model="$ctrl.department.isTeleworking">
|
||||
</vn-check>
|
||||
<vn-check
|
||||
label="Notify on errors"
|
||||
ng-model="$ctrl.department.hasToMistake">
|
||||
</vn-check>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-check
|
||||
label="worksInProduction"
|
||||
ng-model="$ctrl.department.isProduction">
|
||||
</vn-check>
|
||||
<vn-check
|
||||
label="Fill in days without physical check-ins"
|
||||
ng-model="$ctrl.department.hasToRefill">
|
||||
</vn-check>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-check
|
||||
label="Send check-ins by email"
|
||||
ng-model="$ctrl.department.hasToSendMail">
|
||||
</vn-check>
|
||||
</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>
|
|
@ -0,0 +1,10 @@
|
|||
import ngModule from '../../module';
|
||||
import Section from 'salix/components/section';
|
||||
|
||||
ngModule.vnComponent('vnWorkerDepartmentBasicData', {
|
||||
template: require('./index.html'),
|
||||
controller: Section,
|
||||
bindings: {
|
||||
department: '<'
|
||||
}
|
||||
});
|
|
@ -0,0 +1,13 @@
|
|||
Name: Nombre
|
||||
Code: Código
|
||||
Chat: Chat
|
||||
Email: Email
|
||||
Boss department: Jefe del departamento
|
||||
Self-consumption customer: Cliente autoconsumo
|
||||
Telecommutes: Teletrabaja
|
||||
Notify on errors: Notificar errores
|
||||
worksInProduction: Pertenece a producción
|
||||
Fill in days without physical check-ins: Completar días sin registros físicos
|
||||
Send check-ins by email: Enviar fichadas por email
|
||||
Save: Guardar
|
||||
Undo changes: Deshacer cambios
|
|
@ -0,0 +1,5 @@
|
|||
<vn-portal slot="menu">
|
||||
<vn-worker-department-descriptor department="$ctrl.department"></vn-worker-department-descriptor>
|
||||
<vn-left-menu source="department"></vn-left-menu>
|
||||
</vn-portal>
|
||||
<ui-view></ui-view>
|
|
@ -0,0 +1,39 @@
|
|||
import ngModule from '../../module';
|
||||
import ModuleCard from 'salix/components/module-card';
|
||||
|
||||
class Controller extends ModuleCard {
|
||||
reload() {
|
||||
const filter = {
|
||||
fields: ['id', 'name', 'code', 'workerFk', 'isProduction', 'chatName',
|
||||
'isTeleworking', 'notificationEmail', 'hasToRefill', 'hasToSendMail', 'hasToMistake', 'clientFk'],
|
||||
include: [
|
||||
{
|
||||
relation: 'client',
|
||||
scope: {
|
||||
fields: ['id', 'name']
|
||||
}
|
||||
}, {
|
||||
relation: 'worker',
|
||||
scope: {
|
||||
fields: ['id', 'firstName', 'lastName'],
|
||||
include: {
|
||||
relation: 'user',
|
||||
scope: {
|
||||
fields: ['name']
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
};
|
||||
|
||||
this.$http.get(`Departments/${this.$params.id}`, {filter})
|
||||
.then(res => this.department = res.data);
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.vnComponent('vnWorkerDepartmentCard', {
|
||||
template: require('./index.html'),
|
||||
controller: Controller
|
||||
});
|
|
@ -0,0 +1,4 @@
|
|||
<slot-descriptor>
|
||||
<vn-worker-department-descriptor>
|
||||
</vn-worker-department-descriptor>
|
||||
</slot-descriptor>
|
|
@ -0,0 +1,9 @@
|
|||
import ngModule from '../../module';
|
||||
import DescriptorPopover from 'salix/components/descriptor-popover';
|
||||
|
||||
class Controller extends DescriptorPopover {}
|
||||
|
||||
ngModule.vnComponent('vnWorkerDepartmentDescriptorPopover', {
|
||||
slotTemplate: require('./index.html'),
|
||||
controller: Controller
|
||||
});
|
|
@ -0,0 +1,49 @@
|
|||
<vn-descriptor-content
|
||||
module="worker"
|
||||
description="$ctrl.department.name"
|
||||
base-state="worker.department">
|
||||
<slot-menu>
|
||||
<vn-item
|
||||
ng-click="deleteConfirmation.show()"
|
||||
name="deleteDepartment"
|
||||
translate>
|
||||
Delete
|
||||
</vn-item>
|
||||
</slot-menu>
|
||||
<slot-body>
|
||||
<div class="attributes">
|
||||
<vn-label-value
|
||||
label="Chat"
|
||||
value="{{$ctrl.department.chatName}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value
|
||||
label="Email"
|
||||
value="{{$ctrl.department.emailNotification}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value
|
||||
label="Self-consumption customer"
|
||||
value="{{$ctrl.department.client.name}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value
|
||||
label="Boss department"
|
||||
value="{{$ctrl.department.worker.firstName}}">
|
||||
</vn-label-value>
|
||||
</div>
|
||||
<div class="quicklinks">
|
||||
<div ng-transclude="btnOne">
|
||||
<vn-quick-link vn-anchor="{state: 'worker.index', params: {q: {departmentFk: $ctrl.$params.id} } }"
|
||||
vn-tooltip="Department workers"
|
||||
icon="icon-worker">
|
||||
</vn-quick-link>
|
||||
</div>
|
||||
</div>
|
||||
</slot-body>
|
||||
</vn-descriptor-content>
|
||||
<vn-popup vn-id="summary">
|
||||
<vn-worker-summary worker="$ctrl.worker"></vn-worker-summary>
|
||||
</vn-popup>
|
||||
<vn-confirm
|
||||
vn-id="deleteConfirmation"
|
||||
on-accept="$ctrl.deleteDepartment()"
|
||||
question="Are you sure you want to delete this department?">
|
||||
</vn-confirm>
|
|
@ -0,0 +1,45 @@
|
|||
import ngModule from '../../module';
|
||||
import Descriptor from 'salix/components/descriptor';
|
||||
|
||||
class Controller extends Descriptor {
|
||||
constructor($element, $, $rootScope) {
|
||||
super($element, $);
|
||||
this.$rootScope = $rootScope;
|
||||
}
|
||||
|
||||
get department() {
|
||||
return this.entity;
|
||||
}
|
||||
|
||||
set department(value) {
|
||||
this.entity = value;
|
||||
}
|
||||
|
||||
filterDepartments(department, event) {
|
||||
if (event.defaultPrevented) return;
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
this.$state.go(`worker.index`,
|
||||
{q: JSON.stringify({departmentFk: department.id})});
|
||||
}
|
||||
|
||||
deleteDepartment() {
|
||||
return this.$http.delete(`Departments/${this.id}`)
|
||||
.then(() => {
|
||||
this.$state.go('worker.department');
|
||||
|
||||
this.vnApp.showSuccess(this.$t('Department deleted.'));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Controller.$inject = ['$element', '$scope', '$rootScope'];
|
||||
|
||||
ngModule.vnComponent('vnWorkerDepartmentDescriptor', {
|
||||
template: require('./index.html'),
|
||||
controller: Controller,
|
||||
bindings: {
|
||||
department: '<'
|
||||
}
|
||||
});
|
|
@ -1,83 +1,7 @@
|
|||
import ngModule from '../module';
|
||||
import Section from 'salix/components/section';
|
||||
|
||||
class Controller extends Section {
|
||||
$postLink() {
|
||||
this.$.treeview.fetch();
|
||||
}
|
||||
|
||||
onFetch(item) {
|
||||
const params = item ? {parentId: item.id} : null;
|
||||
return this.$.model.applyFilter({}, params).then(() => {
|
||||
return this.$.model.data;
|
||||
});
|
||||
}
|
||||
|
||||
onSort(a, b) {
|
||||
return a.name.localeCompare(b.name);
|
||||
}
|
||||
|
||||
onDrop(dropped, dragged) {
|
||||
const params = dropped ? {parentId: dropped.id} : null;
|
||||
const query = `departments/${dragged.id}/moveChild`;
|
||||
this.$http.post(query, params).then(() => {
|
||||
this.$.treeview.move(dragged, dropped);
|
||||
});
|
||||
}
|
||||
|
||||
onCreate(parent) {
|
||||
this.newChild = {
|
||||
parent: parent,
|
||||
name: ''
|
||||
};
|
||||
|
||||
this.$.createNode.show();
|
||||
}
|
||||
|
||||
onCreateDialogOpen() {
|
||||
this.newChild.name = '';
|
||||
}
|
||||
|
||||
onCreateResponse() {
|
||||
try {
|
||||
if (!this.newChild.name)
|
||||
throw new Error(`Name can't be empty`);
|
||||
|
||||
const params = {name: this.newChild.name};
|
||||
const parent = this.newChild.parent;
|
||||
|
||||
if (parent && parent.id)
|
||||
params.parentId = parent.id;
|
||||
|
||||
const query = `departments/createChild`;
|
||||
this.$http.post(query, params).then(res => {
|
||||
const item = res.data;
|
||||
item.parent = parent;
|
||||
|
||||
this.$.treeview.create(item);
|
||||
});
|
||||
} catch (e) {
|
||||
this.vnApp.showError(this.$t(e.message));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
onRemove(item) {
|
||||
this.removedChild = item;
|
||||
this.$.deleteNode.show();
|
||||
}
|
||||
|
||||
onRemoveResponse() {
|
||||
const childId = this.removedChild.id;
|
||||
const path = `departments/${childId}/removeChild`;
|
||||
this.$http.post(path).then(() => {
|
||||
this.$.treeview.remove(this.removedChild);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.vnComponent('vnWorkerDepartment', {
|
||||
template: require('./index.html'),
|
||||
controller: Controller
|
||||
});
|
||||
import './main';
|
||||
import './index/';
|
||||
import './summary';
|
||||
import './card';
|
||||
import './descriptor';
|
||||
import './basic-data';
|
||||
import './descriptor-popover';
|
||||
|
|
|
@ -3,6 +3,14 @@
|
|||
url="departments/getLeaves"
|
||||
auto-load="false">
|
||||
</vn-crud-model>
|
||||
<vn-portal slot="topbar">
|
||||
<vn-searchbar
|
||||
vn-focus
|
||||
info="Search departments by id, name or code"
|
||||
on-search="$ctrl.onSearch($params)"
|
||||
base-state="worker.department">
|
||||
</vn-searchbar>
|
||||
</vn-portal>
|
||||
<form name="form" class="vn-w-md">
|
||||
<vn-card class="vn-pa-md">
|
||||
<vn-treeview vn-id="treeview" root-label="Departments" read-only="false"
|
||||
|
@ -13,7 +21,12 @@
|
|||
on-drop="$ctrl.onDrop($dropped, $dragged)"
|
||||
on-drag-start="$ctrl.onDragStart(item)"
|
||||
on-drag-end="$ctrl.onDragEnd(item)">
|
||||
{{::item.name}}
|
||||
<a
|
||||
style="display: block; color: inherit;"
|
||||
ui-sref="worker.department.card.summary({id: item.id})"
|
||||
translate>
|
||||
{{::item.name}}
|
||||
</a>
|
||||
</vn-treeview>
|
||||
</vn-card>
|
||||
</form>
|
|
@ -0,0 +1,94 @@
|
|||
import ngModule from '../../module';
|
||||
import Section from 'salix/components/section';
|
||||
|
||||
class Controller extends Section {
|
||||
$postLink() {
|
||||
this.$.treeview.fetch();
|
||||
if (this.$params.q) {
|
||||
const search = JSON.parse(this.$params.q);
|
||||
this.onSearch(search);
|
||||
}
|
||||
}
|
||||
|
||||
onSearch(params) {
|
||||
this.$.model.applyFilter({}, params).then(() => {
|
||||
const data = this.$.model.data;
|
||||
this.$.treeview.data = data;
|
||||
});
|
||||
}
|
||||
|
||||
onFetch(item) {
|
||||
const params = item ? {parentId: item.id} : null;
|
||||
return this.$.model.applyFilter({}, params).then(() => {
|
||||
return this.$.model.data;
|
||||
});
|
||||
}
|
||||
|
||||
onSort(a, b) {
|
||||
return a.name.localeCompare(b.name);
|
||||
}
|
||||
|
||||
onDrop(dropped, dragged) {
|
||||
const params = dropped ? {parentId: dropped.id} : null;
|
||||
const query = `departments/${dragged.id}/moveChild`;
|
||||
this.$http.post(query, params).then(() => {
|
||||
this.$.treeview.move(dragged, dropped);
|
||||
});
|
||||
}
|
||||
|
||||
onCreate(parent) {
|
||||
this.newChild = {
|
||||
parent: parent,
|
||||
name: ''
|
||||
};
|
||||
|
||||
this.$.createNode.show();
|
||||
}
|
||||
|
||||
onCreateDialogOpen() {
|
||||
this.newChild.name = '';
|
||||
}
|
||||
|
||||
onCreateResponse() {
|
||||
try {
|
||||
if (!this.newChild.name)
|
||||
throw new Error(`Name can't be empty`);
|
||||
|
||||
const params = {name: this.newChild.name};
|
||||
const parent = this.newChild.parent;
|
||||
|
||||
if (parent && parent.id)
|
||||
params.parentId = parent.id;
|
||||
|
||||
const query = `departments/createChild`;
|
||||
this.$http.post(query, params).then(res => {
|
||||
const item = res.data;
|
||||
item.parent = parent;
|
||||
|
||||
this.$.treeview.create(item);
|
||||
});
|
||||
} catch (e) {
|
||||
this.vnApp.showError(this.$t(e.message));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
onRemove(item) {
|
||||
this.removedChild = item;
|
||||
this.$.deleteNode.show();
|
||||
}
|
||||
|
||||
onRemoveResponse() {
|
||||
const childId = this.removedChild.id;
|
||||
const path = `departments/${childId}/removeChild`;
|
||||
this.$http.post(path).then(() => {
|
||||
this.$.treeview.remove(this.removedChild);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.vnComponent('vnWorkerDepartmentIndex', {
|
||||
template: require('./index.html'),
|
||||
controller: Controller
|
||||
});
|
|
@ -2,3 +2,4 @@ New department: Nuevo departamento
|
|||
Delete department: Eliminar departamento
|
||||
Are you sure you want to delete it?: ¿Seguro que quieres eliminarlo?
|
||||
Name can't be empty: El nombre esta vacio
|
||||
Department workers: Trabajadores del departamento
|
|
@ -0,0 +1,9 @@
|
|||
<vn-crud-model
|
||||
vn-id="model"
|
||||
url="Departments/filter"
|
||||
limit="20"
|
||||
order="id">
|
||||
</vn-crud-model>
|
||||
<ui-view>
|
||||
<vn-worker-department-index></vn-worker-department-index>
|
||||
</ui-view>
|
|
@ -0,0 +1,7 @@
|
|||
import ngModule from '../../module';
|
||||
import ModuleMain from 'salix/components/module-main';
|
||||
|
||||
ngModule.vnComponent('vnWorkerDepartment', {
|
||||
controller: ModuleMain,
|
||||
template: require('./index.html')
|
||||
});
|
|
@ -0,0 +1,91 @@
|
|||
<vn-portal slot="topbar">
|
||||
<vn-searchbar
|
||||
vn-focus
|
||||
info="Search departments by id, name or code"
|
||||
on-search="$ctrl.onSearch($params)"
|
||||
base-state="worker.department">
|
||||
</vn-searchbar>
|
||||
</vn-portal>
|
||||
<vn-card class="summary">
|
||||
<h5>
|
||||
<span>{{summary.name}}</span>
|
||||
</h5>
|
||||
<vn-horizontal class="vn-pa-md">
|
||||
<vn-one class="expand">
|
||||
<h4 ng-show="$ctrl.isHr">
|
||||
<a
|
||||
ui-sref="worker.department.card.basicData({id:summary.id})">
|
||||
<span translate vn-tooltip="Go to">Basic data</span>
|
||||
</a>
|
||||
</h4>
|
||||
<h4
|
||||
translates
|
||||
ng-show="!$ctrl.isHr">
|
||||
Basic data
|
||||
</h4>
|
||||
</vn-one>
|
||||
<vn-one>
|
||||
<vn-vertical>
|
||||
<vn-label-value label="Nombre"
|
||||
value="{{summary.name}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value label="Code"
|
||||
value="{{summary.code}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value label="Chat"
|
||||
value="{{summary.chatName}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value
|
||||
label="Boss department">
|
||||
<span
|
||||
ng-click="workerDescriptor.show($event, summary.worker.id)"
|
||||
class="link">
|
||||
{{summary.worker.user.name}}
|
||||
</span>
|
||||
</vn-label-value>
|
||||
<vn-label-value
|
||||
label="Email"
|
||||
value="{{summary.notificationEmail}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value label="Self-consumption customer"
|
||||
value="{{summary.client.name}}">
|
||||
</vn-label-value>
|
||||
</vn-vertical>
|
||||
</vn-one>
|
||||
<vn-one>
|
||||
<vn-vertical>
|
||||
<vn-check
|
||||
label="Telework"
|
||||
ng-model="summary.isTeleworking"
|
||||
disabled="true">
|
||||
</vn-check>
|
||||
<vn-check
|
||||
label="Notify on errors"
|
||||
ng-model="summary.hasToMistake"
|
||||
disabled="true">
|
||||
</vn-check>
|
||||
<vn-check
|
||||
label="worksInProduction"
|
||||
ng-model="summary.isProduction"
|
||||
disabled="true">
|
||||
</vn-check>
|
||||
<vn-check
|
||||
label="Fill in days without physical check-ins"
|
||||
ng-model="summary.hasToRefill"
|
||||
disabled="true">
|
||||
</vn-check>
|
||||
<vn-check
|
||||
label="Send check-ins by email"
|
||||
ng-model="summary.hasToSendMail"
|
||||
disabled="true">
|
||||
</vn-check>
|
||||
</vn-vertical>
|
||||
</vn-one>
|
||||
</vn-horizontal>
|
||||
</vn-card>
|
||||
<vn-worker-descriptor-popover
|
||||
vn-id="workerDescriptor">
|
||||
</vn-worker-descriptor-popover>
|
||||
<vn-worker-department-descriptor-popover
|
||||
vn-id="workerDepartmentDescriptor">
|
||||
</vn-worker-department-descriptor-popover>
|
|
@ -0,0 +1,27 @@
|
|||
import ngModule from '../../module';
|
||||
import Component from 'core/lib/component';
|
||||
import './style.scss';
|
||||
|
||||
class Controller extends Component {
|
||||
set department(value) {
|
||||
this._department = value;
|
||||
this.$.summary = null;
|
||||
if (!value) return;
|
||||
this.$.summary = this.department;
|
||||
}
|
||||
get department() {
|
||||
return this._department;
|
||||
}
|
||||
|
||||
get isHr() {
|
||||
return this.aclService.hasAny(['hr']);
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.component('vnWorkerDepartmentSummary', {
|
||||
template: require('./index.html'),
|
||||
controller: Controller,
|
||||
bindings: {
|
||||
department: '<'
|
||||
}
|
||||
});
|
|
@ -0,0 +1,12 @@
|
|||
Name: Nombre
|
||||
Code: Código
|
||||
Chat: Chat
|
||||
Boss department: Jefe de departamento
|
||||
Email: Email
|
||||
Self-consumption customer: Cliente autoconsumo
|
||||
Telework: Teletrabaja
|
||||
Notify on errors: Notificar errores
|
||||
worksInProduction: Pertenece a producción
|
||||
Fill in days without physical check-ins: Completar días sin registros físicos
|
||||
Send check-ins by email: Enviar fichadas por mail
|
||||
Are you sure you want to delete this department?: ¿Estás seguro de que quieres eliminar este departamento?
|
|
@ -0,0 +1,8 @@
|
|||
@import "./variables";
|
||||
|
||||
vn-worker-department-summary {
|
||||
.expand {
|
||||
min-width: 100%;
|
||||
}
|
||||
}
|
||||
|
|
@ -24,6 +24,9 @@
|
|||
"description": "Wikipedia"
|
||||
},
|
||||
{"state": "worker.card.workerLog", "icon": "history"}
|
||||
],
|
||||
"department": [
|
||||
{"state": "worker.department.card.basicData", "icon": "settings"}
|
||||
]
|
||||
},
|
||||
"keybindings": [
|
||||
|
@ -118,12 +121,35 @@
|
|||
"worker": "$ctrl.worker"
|
||||
}
|
||||
}, {
|
||||
"url" : "/department",
|
||||
"url": "/department?q",
|
||||
"state": "worker.department",
|
||||
"component": "vn-worker-department",
|
||||
"description": "Departments",
|
||||
"acl": ["hr"]
|
||||
"description":"Departments"
|
||||
}, {
|
||||
"url": "/:id",
|
||||
"state": "worker.department.card",
|
||||
"component": "vn-worker-department-card",
|
||||
"abstract": true,
|
||||
"description": "Detail"
|
||||
}, {
|
||||
"url" : "/summary",
|
||||
"state": "worker.department.card.summary",
|
||||
"component": "vn-worker-department-summary",
|
||||
"description": "Summary",
|
||||
"params": {
|
||||
"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,
|
||||
|
|
|
@ -27,15 +27,19 @@
|
|||
<vn-label-value label="Email" no-ellipsize
|
||||
value="{{worker.user.emailUser.email}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value label="Department"
|
||||
value="{{worker.department.department.name}}">
|
||||
<vn-label-value label="Department">
|
||||
<span
|
||||
ng-click="workerDepartmentDescriptor.show($event, worker.department.department.id)"
|
||||
class="link">
|
||||
{{worker.department.department.name}}
|
||||
</span>
|
||||
</vn-label-value>
|
||||
<vn-label-value
|
||||
label="Boss">
|
||||
<span
|
||||
ng-click="workerDescriptor.show($event, worker.boss.id)"
|
||||
class="link">
|
||||
{{::worker.boss.nickname}}
|
||||
{{::worker.boss.name}}
|
||||
</span>
|
||||
</vn-label-value>
|
||||
<vn-label-value label="Mobile extension"
|
||||
|
@ -71,3 +75,6 @@
|
|||
<vn-worker-descriptor-popover
|
||||
vn-id="workerDescriptor">
|
||||
</vn-worker-descriptor-popover>
|
||||
<vn-worker-department-descriptor-popover
|
||||
vn-id="workerDepartmentDescriptor">
|
||||
</vn-worker-department-descriptor-popover>
|
||||
|
|
|
@ -38,7 +38,7 @@ class Controller extends Summary {
|
|||
},
|
||||
{
|
||||
relation: 'boss',
|
||||
scope: {fields: ['id', 'nickname']}
|
||||
scope: {fields: ['id', 'name']}
|
||||
},
|
||||
{
|
||||
relation: 'sip',
|
||||
|
@ -48,7 +48,8 @@ class Controller extends Summary {
|
|||
relation: 'department',
|
||||
scope: {
|
||||
include: {
|
||||
relation: 'department'
|
||||
relation: 'department',
|
||||
scope: {fields: ['id', 'code', 'name']}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue