Merge branch 'dev' into 3734-item_diary_scroll
gitea/salix/pipeline/head This commit looks good Details

This commit is contained in:
Carlos Jimenez Ruiz 2022-03-29 08:34:35 +00:00
commit e2aaa616af
31 changed files with 598 additions and 142 deletions

View File

@ -1,2 +0,0 @@
INSERT INTO salix.ACL (id, model, property, accessType, permission, principalType, principalId)
VALUES(301, 'Agency', '*', 'READ', 'ALLOW', 'ROLE', 'employee');

View File

@ -0,0 +1,2 @@
INSERT INTO `salix`.`ACL` (`id`, `model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
VALUES(304, 'Agency', '*', '*', 'ALLOW', 'ROLE', 'employee');

View File

@ -0,0 +1,3 @@
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
VALUES
('SupplierAgencyTerm', '*', '*', 'ALLOW', 'ROLE', 'administrative');

View File

@ -0,0 +1,48 @@
ALTER TABLE `vn`.`agencyTerm` ADD `supplierFk` INT NULL;
ALTER TABLE `vn`.`agencyTerm` CHANGE `supplierFk` `supplierFk` INT NULL AFTER `agencyFk`;
UPDATE `vn`.`agencyTerm` `at`
JOIN `vn`.`agency` `a` ON `a`.`id` = `at`.`agencyFk`
SET `at`.`supplierFk` = `a`.`supplierFk`;
ALTER TABLE `vn`.`agencyTerm` ADD CONSTRAINT `agencyTerm_FK` FOREIGN KEY (`agencyFk`) REFERENCES `vn`.`agency`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
ALTER TABLE `vn`.`agencyTerm` ADD CONSTRAINT `agencyTerm_FK_1` FOREIGN KEY (`supplierFk`) REFERENCES `vn`.`supplier`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
RENAME TABLE `vn`.`agencyTerm` TO `vn`.`supplierAgencyTerm`;
CREATE OR REPLACE
ALGORITHM = UNDEFINED
DEFINER=`root`@`localhost`
VIEW `vn`.`agencyTerm` AS
SELECT
`sat`.`agencyFk` AS `agencyFk`,
`sat`.`minimumPackages` AS `minimumPackages`,
`sat`.`kmPrice` AS `kmPrice`,
`sat`.`packagePrice` AS `packagePrice`,
`sat`.`routePrice` AS `routePrice`,
`sat`.`minimumKm` AS `minimumKm`,
`sat`.`minimumM3` AS `minimumM3`,
`sat`.`m3Price` AS `m3Price`
FROM
`vn`.`supplierAgencyTerm` `sat`;
ALTER TABLE `vn`.`agency` DROP FOREIGN KEY `agency_ibfk_4`;
ALTER TABLE `vn`.`agency` CHANGE `supplierFk` `supplierFk__` int(11) DEFAULT NULL NULL;
CREATE OR REPLACE
ALGORITHM = UNDEFINED
DEFINER=`root`@`localhost`
VIEW `vn2008`.`agency` AS
SELECT
`a`.`id` AS `agency_id`,
`a`.`name` AS `name`,
`a`.`warehouseFk` AS `warehouse_id`,
`a`.`isVolumetric` AS `por_volumen`,
`a`.`bankFk` AS `Id_Banco`,
`a`.`warehouseAliasFk` AS `warehouse_alias_id`,
`a`.`isOwn` AS `propios`,
`a`.`labelZone` AS `zone_label`,
`a`.`workCenterFk` AS `workCenterFk`,
`a`.`supplierFk__` AS `supplierFk__`
FROM
`vn`.`agency` `a`;

View File

@ -0,0 +1,3 @@
ALTER TABLE `postgresql`.`business_labour_payroll` DROP FOREIGN KEY `business_labour_payroll_cod_contrato`;
ALTER TABLE `vn`.`workerBusinessType` MODIFY COLUMN `id` int(11) NOT NULL;
ALTER TABLE `postgresql`.`business_labour_payroll` ADD CONSTRAINT `business_labour_payroll_FK` FOREIGN KEY (cod_contrato) REFERENCES `vn`.`workerBusinessType`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;

View File

@ -1902,14 +1902,29 @@ INSERT INTO `vn`.`workCenterHoliday` (`workCenterFk`, `days`, `year`)
('1', '24.5', YEAR(DATE_ADD(CURDATE(), INTERVAL -1 YEAR))),
('5', '23', YEAR(DATE_ADD(CURDATE(), INTERVAL -1 YEAR)));
INSERT INTO `postgresql`.`calendar_state` (`calendar_state_id`, `type`, `rgb`, `code`, `holidayEntitlementRate`)
INSERT INTO `postgresql`.`calendar_state` (`calendar_state_id`, `type`, `rgb`, `code`, `holidayEntitlementRate`, `discountRate`)
VALUES
(1, 'Holidays', '#FF4444', 'holiday', 0),
(2, 'Leave of absence', '#C71585', 'absence', 0),
(6, 'Half holiday', '#E65F00', 'halfHoliday', 0),
(15, 'Half Paid Leave', '#5151c0', 'halfPaidLeave', 0),
(20, 'Furlough', '#97B92F', 'furlough', 1),
(21, 'Furlough half day', '#778899', 'halfFurlough', 0.5);
(1, 'Holidays', '#FF4444', 'holiday', 0, 0),
(2, 'Leave of absence', '#C71585', 'absence', 0, 1),
(6, 'Half holiday', '#E65F00', 'halfHoliday', 0, 0.5),
(15, 'Half Paid Leave', '#5151c0', 'halfPaidLeave', 0, 1),
(20, 'Furlough', '#97B92F', 'furlough', 1, 1),
(21, 'Furlough half day', '#778899', 'halfFurlough', 0.5, 1);
ALTER TABLE `postgresql`.`business_labour_payroll` DROP FOREIGN KEY `business_labour_payroll_cod_categoria`;
INSERT INTO `vn`.`workerBusinessType` (`id`, `name`, `isFullTime`, `isPermanent`, `hasHolidayEntitlement`)
VALUES
(1, 'CONTRATO HOLANDA', 1, 0, 1),
(100, 'INDEFINIDO A TIEMPO COMPLETO', 1, 1, 1),
(109, 'CONVERSION DE TEMPORAL EN INDEFINIDO T.COMPLETO', 1, 1, 1);
INSERT INTO `postgresql`.`business_labour_payroll` (`business_id`, `cod_tarifa`, `cod_categoria`, `cod_contrato`, `importepactado`)
VALUES
(1, 7, 12, 100, 900.50),
(1106, 7, 12, 100, 1263.03),
(1107, 7, 12, 100, 2000),
(1108, 7, 12, 100, 1500);
INSERT INTO `postgresql`.`calendar_employee` (`business_id`, `calendar_state_id`, `date`)
VALUES
@ -2462,28 +2477,25 @@ INSERT INTO `bs`.`defaulter` (`clientFk`, `amount`, `created`, `defaulterSinced`
(1107, 500, CURDATE(), CURDATE()),
(1109, 500, CURDATE(), CURDATE());
INSERT INTO `vn`.`agencyTerm` (`agencyFk`, `minimumPackages`, `kmPrice`, `packagePrice`, `routePrice`, `minimumKm`, `minimumM3`, `m3Price`)
VALUES
(1, 0, 0.00, 0.00, NULL, 0, 0.00, 0),
(3, 0, 0.00, 3.05, NULL, 0, 0.00, 0),
(2, 60, 0.00, 0.00, NULL, 0, 5.00, 33);
UPDATE `vn`.`agency`
SET `supplierFk`=1
WHERE `id`=1;
UPDATE `vn`.`agency`
SET `supplierFk`=1
WHERE `id`=1;
SET `supplierFk`=1
WHERE `id`=2;
UPDATE `vn`.`agency`
SET `supplierFk`=1
WHERE `id`=2;
UPDATE `vn`.`agency`
SET `supplierFk`=2
WHERE `id`=3;
SET `supplierFk`=2
WHERE `id`=3;
UPDATE `vn`.`route`
SET `invoiceInFk`=1
WHERE `id`=1;
SET `invoiceInFk`=1
WHERE `id`=1;
UPDATE `vn`.`route`
SET `invoiceInFk`=2
WHERE `id`=2;
SET `invoiceInFk`=2
WHERE `id`=2;
INSERT INTO `bs`.`salesPerson` (`workerFk`, `year`, `month`, `portfolioWeight`)
VALUES
(18, YEAR(CURDATE()), MONTH(CURDATE()), 807.23),
@ -2496,6 +2508,7 @@ INSERT INTO `bs`.`sale` (`saleFk`, `amount`, `dated`, `typeFk`, `clientFk`)
(3, 200.78, CURDATE(), 2, 1101),
(4, 33.8, CURDATE(), 1, 1101),
(30, 34.4, CURDATE(), 1, 1108);
INSERT INTO `vn`.`docuware` (`code`, `fileCabinetName`, `dialogName` , `find`)
VALUES
('deliveryClientTest', 'deliveryClientTest', 'findTest', 'word');
@ -2503,3 +2516,23 @@ INSERT INTO `vn`.`docuware` (`code`, `fileCabinetName`, `dialogName` , `find`)
INSERT INTO `vn`.`docuwareConfig` (`url`)
VALUES
('https://verdnatura.docuware.cloud/docuware/platform');
INSERT INTO `vn`.`calendarHolidaysName` (`id`, `name`)
VALUES
(1, 'dayOfIT');
INSERT INTO `vn`.`calendarHolidaysType` (`id`, `name`, `hexColour`)
VALUES
(1, 'National', '#4169E1');
INSERT INTO `vn`.`calendarHolidays` (`id`, `calendarHolidaysTypeFk`, `dated`, `calendarHolidaysNameFk`, `workCenterFk`)
VALUES
(1, 1, CONCAT(YEAR(CURDATE()), '-12-09'), 1, 1);
INSERT INTO `vn`.`supplierAgencyTerm` (`agencyFk`, `supplierFk`, `minimumPackages`, `kmPrice`, `packagePrice`, `routePrice`, `minimumKm`, `minimumM3`, `m3Price`)
VALUES
(1, 1, 0, 0.00, 0.00, NULL, 0, 0.00, 23),
(2, 1, 60, 0.00, 0.00, NULL, 0, 5.00, 33),
(3, 2, 0, 15.00, 0.00, NULL, 0, 0.00, 0),
(4, 2, 0, 20.00, 0.00, NULL, 0, 0.00, 0),
(5, 442, 0, 0.00, 3.05, NULL, 0, 0.00, 0);

View File

@ -221,6 +221,7 @@
"Can't transfer claimed sales": "No puedes transferir lineas reclamadas",
"You don't have privileges to create pay back": "No tienes permisos para crear un abono",
"The item is required": "El artículo es requerido",
"The agency is already assigned to another autonomous": "La agencia ya está asignada a otro autónomo",
"date in the future": "Fecha en el futuro",
"reference duplicated": "Referencia duplicada"
}

View File

@ -87,21 +87,21 @@ module.exports = Self => {
SUM(t.packages) packages,
r.m3,
r.kmEnd - r.kmStart kmTotal,
CAST(IFNULL(ate.routePrice,
(ate.kmPrice * (GREATEST(r.kmEnd - r.kmStart , ate.minimumKm))
+ GREATEST(r.m3 , ate.minimumM3) * ate.m3Price)
+ ate.packagePrice * SUM(t.packages) )
CAST(IFNULL(sat.routePrice,
(sat.kmPrice * (GREATEST(r.kmEnd - r.kmStart , sat.minimumKm))
+ GREATEST(r.m3 , sat.minimumM3) * sat.m3Price)
+ sat.packagePrice * SUM(t.packages) )
AS DECIMAL(10,2)) price,
r.invoiceInFk,
a.supplierFk,
sat.supplierFk,
s.name supplierName
FROM vn.route r
LEFT JOIN vn.agencyMode am ON r.agencyModeFk = am.id
LEFT JOIN vn.agency a ON am.agencyFk = a.id
LEFT JOIN vn.ticket t ON t.routeFk = r.id
LEFT JOIN vn.agencyTerm ate ON ate.agencyFk = a.id
LEFT JOIN vn.supplier s ON s.id = a.supplierFk
WHERE r.created > DATE_ADD(CURDATE(), INTERVAL -2 MONTH) AND a.supplierFk IS NOT NULL
LEFT JOIN vn.supplierAgencyTerm sat ON sat.agencyFk = a.id
LEFT JOIN vn.supplier s ON s.id = sat.supplierFk
WHERE r.created > DATE_ADD(CURDATE(), INTERVAL -2 MONTH) AND sat.supplierFk IS NOT NULL
GROUP BY r.id
) a`
);

View File

@ -18,7 +18,7 @@ describe('AgencyTerm filter()', () => {
const firstAgencyTerm = agencyTerms[0];
expect(firstAgencyTerm.routeFk).toEqual(1);
expect(agencyTerms.length).toEqual(3);
expect(agencyTerms.length).toEqual(5);
await tx.rollback();
} catch (e) {
@ -72,7 +72,7 @@ describe('AgencyTerm filter()', () => {
const results = await models.AgencyTerm.filter(ctx, options);
expect(results.length).toBe(3);
expect(results.length).toBe(5);
await tx.rollback();
} catch (e) {

View File

@ -0,0 +1,42 @@
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
const mergeFilters = require('vn-loopback/util/filter').mergeFilters;
module.exports = Self => {
Self.remoteMethod('freeAgencies', {
description: 'Returns a list of agencies without a supplier assigned',
accepts: [{
arg: 'filter',
type: 'object',
description: `Filter defining where, order, offset, and limit - must be a JSON-encoded string`
}],
returns: {
type: ['object'],
root: true
},
http: {
path: `/freeAgencies`,
verb: 'GET'
}
});
Self.freeAgencies = async(filter, options) => {
const conn = Self.dataSource.connector;
const where = {'sat.supplierFk': null};
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
filter = mergeFilters(filter, {where});
let stmt = new ParameterizedSQL(
`SELECT a.name, a.id
FROM agency a
LEFT JOIN supplierAgencyTerm sat ON sat.agencyFk = a.id`,
null, myOptions);
stmt.merge(conn.makeSuffix(filter));
return conn.executeStmt(stmt);
};
};

View File

@ -11,6 +11,9 @@
"SupplierAccount": {
"dataSource": "vn"
},
"SupplierAgencyTerm": {
"dataSource": "vn"
},
"SupplierLog": {
"dataSource": "vn"
},

View File

@ -0,0 +1,9 @@
const UserError = require('vn-loopback/util/user-error');
module.exports = Self => {
Self.rewriteDbError(function(err) {
if (err.code === 'ER_DUP_ENTRY')
return new UserError(`The agency is already assigned to another autonomous`);
return err;
});
};

View File

@ -0,0 +1,46 @@
{
"name": "SupplierAgencyTerm",
"base": "VnModel",
"options": {
"mysql": {
"table": "supplierAgencyTerm"
}
},
"properties": {
"agencyFk": {
"type": "number",
"id": true
},
"supplierFk": {
"type": "number"
},
"minimumPackages": {
"type": "number"
},
"kmPrice": {
"type": "number"
},
"packagePrice": {
"type": "number"
},
"routePrice": {
"type": "number"
},
"minimumKm": {
"type": "number"
},
"minimumM3": {
"type": "number"
},
"m3Price": {
"type": "number"
}
},
"relations": {
"agency": {
"type": "belongsTo",
"model": "Agency",
"foreignKey": "agencyFk"
}
}
}

View File

@ -7,6 +7,7 @@ module.exports = Self => {
require('../methods/supplier/getSummary')(Self);
require('../methods/supplier/updateFiscalData')(Self);
require('../methods/supplier/consumption')(Self);
require('../methods/supplier/freeAgencies')(Self);
Self.validatesPresenceOf('name', {
message: 'The social name cannot be empty'

View File

@ -0,0 +1,74 @@
<vn-watcher
vn-id="watcher"
url="SupplierAgencyTerms"
primary-key="agencyFk"
data="$ctrl.supplierAgencyTerm"
insert-mode="true"
form="form">
</vn-watcher>
<vn-crud-model
auto-load="true"
url="Suppliers/freeAgencies"
data="$ctrl.agencies">
</vn-crud-model>
<form name="form" ng-submit="$ctrl.onSubmit()" class="vn-w-md">
<vn-card class="vn-pa-lg">
<vn-horizontal>
<vn-autocomplete vn-one
label="Agency"
ng-model="$ctrl.supplierAgencyTerm.agencyFk"
data="$ctrl.agencies"
show-field="name"
value-field="id"
rule>
</vn-autocomplete>
<vn-input-number
type="number"
label="Minimum M3"
ng-model="$ctrl.supplierAgencyTerm.minimumM3"
rule>
</vn-input-number>
</vn-horizontal>
<vn-horizontal>
<vn-input-number
type="number"
label="Package Price"
ng-model="$ctrl.supplierAgencyTerm.packagePrice"
rule>
</vn-input-number>
<vn-input-number
type="number"
label="Km Price"
ng-model="$ctrl.supplierAgencyTerm.kmPrice"
rule>
</vn-input-number>
<vn-input-number
type="number"
label="M3 Price"
ng-model="$ctrl.supplierAgencyTerm.m3Price"
rule>
</vn-input-number>
</vn-horizontal>
<vn-horizontal>
<vn-input-number
type="number"
label="Route Price"
ng-model="$ctrl.supplierAgencyTerm.routePrice"
rule>
</vn-input-number>
<vn-input-number
type="number"
label="Minimum Km"
ng-model="$ctrl.supplierAgencyTerm.minimumKm"
rule>
</vn-input-number>
</vn-horizontal>
</vn-card>
<vn-button-bar>
<vn-submit label="Save"></vn-submit>
<vn-button
label="Cancel"
ui-sref="supplier.card.agencyTerm.index">
</vn-button>
</vn-button-bar>
</form>

View File

@ -0,0 +1,26 @@
import ngModule from '../../module';
import Section from 'salix/components/section';
export default class Controller extends Section {
constructor($element, $) {
super($element, $);
this.supplierAgencyTerm = {
supplierFk: this.$params.id
};
}
onSubmit() {
this.$.watcher.submit().then(res => {
this.$state.go('supplier.card.agencyTerm.index');
});
}
}
ngModule.vnComponent('vnSupplierAgencyTermCreate', {
template: require('./index.html'),
controller: Controller,
bindings: {
supplier: '<'
}
});

View File

@ -0,0 +1,28 @@
import './index';
import watcher from 'core/mocks/watcher';
describe('Supplier', () => {
describe('Component vnSupplierAddressCreate', () => {
let $scope;
let controller;
let $element;
beforeEach(ngModule('supplier'));
beforeEach(inject(($componentController, $rootScope, _$state_) => {
$scope = $rootScope.$new();
$scope.watcher = watcher;
$element = angular.element('<vn-supplier-agency-term-create></vn-supplier-agency-term-create>');
controller = $componentController('vnSupplierAgencyTermCreate', {$element, $scope});
}));
describe('onSubmit()', () => {
it(`should redirect to 'supplier.card.agencyTerm.index' state`, () => {
jest.spyOn(controller.$state, 'go');
controller.onSubmit();
expect(controller.$state.go).toHaveBeenCalledWith('supplier.card.agencyTerm.index');
});
});
});
});

View File

@ -0,0 +1,85 @@
<vn-crud-model
vn-id="model"
url="SupplierAgencyTerms"
link="{supplierFk: $ctrl.$params.id}"
primary-key="agencyFk"
filter="$ctrl.filter"
data="$ctrl.supplierAgencyTerms"
auto-load="true">
</vn-crud-model>
<vn-watcher
vn-id="watcher"
data="$ctrl.supplierAgencyTerms"
form="form">
</vn-watcher>
<form name="form" ng-submit="$ctrl.onSubmit()" class="vn-w-lg">
<vn-card class="vn-pa-lg">
<vn-horizontal ng-repeat="supplierAgencyTerm in $ctrl.supplierAgencyTerms">
<vn-textfield
disabled="true"
vn-id="agency"
label="Agency"
ng-model="supplierAgencyTerm.agency.name"
rule>
</vn-textfield>
<vn-input-number
type="number"
label="Minimum M3"
ng-model="supplierAgencyTerm.minimumM3"
rule>
</vn-input-number>
<vn-input-number
type="number"
label="Package Price"
ng-model="supplierAgencyTerm.packagePrice"
rule>
</vn-input-number>
<vn-input-number
type="number"
label="Km Price"
ng-model="supplierAgencyTerm.kmPrice"
rule>
</vn-input-number>
<vn-input-number
type="number"
label="M3 Price"
ng-model="supplierAgencyTerm.m3Price"
rule>
</vn-input-number>
<vn-input-number
type="number"
label="Route Price"
ng-model="supplierAgencyTerm.routePrice"
rule>
</vn-input-number>
<vn-input-number
type="number"
label="Minimum Km"
ng-model="supplierAgencyTerm.minimumKm"
rule>
</vn-input-number>
<vn-none>
<vn-icon-button
vn-tooltip="Remove row"
icon="delete"
ng-click="model.remove($index)"
tabindex="-1">
</vn-icon-button>
</vn-none>
</vn-horizontal>
</vn-card>
<vn-button-bar>
<vn-submit
disabled="!watcher.dataChanged()"
label="Save">
</vn-submit>
</vn-button-bar>
</form>
<vn-float-button
vn-bind="+"
fixed-bottom-right
vn-tooltip="New row"
ui-sref="supplier.card.agencyTerm.create"
icon="add"
label="Add">
</vn-float-button>

View File

@ -0,0 +1,36 @@
import ngModule from '../../module';
import Section from 'salix/components/section';
class Controller extends Section {
constructor($element, $) {
super($element, $);
this.filter = {
include:
{relation: 'agency',
scope: {
fields: ['id', 'name']
}
}
};
}
add() {
this.$.model.insert({});
}
onSubmit() {
this.$.watcher.check();
this.$.model.save().then(() => {
this.$.watcher.notifySaved();
this.$.watcher.updateOriginalData();
});
}
}
ngModule.vnComponent('vnSupplierAgencyTermIndex', {
template: require('./index.html'),
controller: Controller,
bindings: {
supplier: '<'
}
});

View File

@ -0,0 +1,37 @@
import './index';
import watcher from 'core/mocks/watcher';
import crudModel from 'core/mocks/crud-model';
describe('Supplier', () => {
describe('Component vnSupplierAddressCreate', () => {
let $scope;
let controller;
let $element;
beforeEach(ngModule('supplier'));
beforeEach(inject(($componentController, $rootScope, _$state_) => {
$scope = $rootScope.$new();
$scope.model = crudModel;
$scope.watcher = watcher;
$element = angular.element('<vn-supplier-agency-term-index></vn-supplier-agency-term-index>');
controller = $componentController('vnSupplierAgencyTermIndex', {$element, $scope});
}));
describe('onSubmit()', () => {
it('should make HTTP POST request to save values', () => {
jest.spyOn($scope.watcher, 'check');
jest.spyOn($scope.watcher, 'notifySaved');
jest.spyOn($scope.watcher, 'updateOriginalData');
jest.spyOn($scope.model, 'save');
controller.onSubmit();
expect($scope.model.save).toHaveBeenCalledWith();
expect($scope.watcher.updateOriginalData).toHaveBeenCalledWith();
expect($scope.watcher.check).toHaveBeenCalledWith();
expect($scope.watcher.notifySaved).toHaveBeenCalledWith();
});
});
});
});

View File

@ -0,0 +1,8 @@
Minimum M3: M3 minimos
Package Price: Precio bulto
Km Price: Precio Km
M3 Price: Precio M3
Route Price: Precio ruta
Minimum Km: Km minimos
Remove row: Eliminar fila
Add row: Añadir fila

View File

@ -18,3 +18,5 @@ import './billing-data';
import './address/index';
import './address/create';
import './address/edit';
import './agency-term/index';
import './agency-term/create';

View File

@ -15,6 +15,7 @@
{"state": "supplier.card.address.index", "icon": "icon-delivery"},
{"state": "supplier.card.account", "icon": "icon-account"},
{"state": "supplier.card.contact", "icon": "contact_phone"},
{"state": "supplier.card.agencyTerm.index", "icon": "contact_support"},
{"state": "supplier.card.log", "icon": "history"},
{"state": "supplier.card.consumption", "icon": "show_chart"}
]
@ -86,6 +87,30 @@
"supplier": "$ctrl.supplier"
}
},
{
"url": "/agency-term",
"state": "supplier.card.agencyTerm",
"component": "ui-view",
"abstract": true
},
{
"url": "/index",
"state": "supplier.card.agencyTerm.index",
"component": "vn-supplier-agency-term-index",
"description": "Autonomous",
"params": {
"supplier": "$ctrl.supplier"
}
},
{
"url": "/create",
"state": "supplier.card.agencyTerm.create",
"component": "vn-supplier-agency-term-create",
"description": "New autonomous",
"params": {
"supplier": "$ctrl.supplier"
}
},
{
"url": "/consumption?q",
"state": "supplier.card.consumption",

View File

@ -1,4 +1,5 @@
const UserError = require('vn-loopback/util/user-error');
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
module.exports = Self => {
Self.remoteMethodCtx('holidays', {
@ -33,7 +34,8 @@ module.exports = Self => {
Self.holidays = async(ctx, id, options) => {
const models = Self.app.models;
const args = ctx.args;
const conn = Self.dataSource.connector;
const stmts = [];
const myOptions = {};
if (typeof options == 'object')
@ -56,42 +58,6 @@ module.exports = Self => {
ended.setHours(23, 59, 59, 59);
const filter = {
include: [{
relation: 'holidays',
scope: {
where: {year: args.year}
}
},
{
relation: 'absences',
scope: {
include: {
relation: 'absenceType',
},
where: {
dated: {between: [started, ended]}
}
}
},
{
relation: 'workCenter',
scope: {
include: {
relation: 'holidays',
scope: {
include: [{
relation: 'detail'
},
{
relation: 'type'
}],
where: {
dated: {between: [started, ended]}
}
}
}
}
}],
where: {
and: [
{workerFk: id},
@ -107,76 +73,32 @@ module.exports = Self => {
}
};
if (args.businessFk)
filter.where.and.push({businessFk: args.businessFk});
const contracts = await models.WorkerLabour.find(filter, myOptions);
let [firstContract] = contracts;
let payedHolidays;
const payedHolidays = firstContract.payedHolidays;
if (firstContract.payedHolidays)
payedHolidays = firstContract.payedHolidays;
else payedHolidays = 0;
let totalHolidays = 0;
let holidaysEnjoyed = 0;
for (let contract of contracts) {
const contractStarted = contract.started;
contractStarted.setHours(0, 0, 0, 0);
const contractEnded = contract.ended;
if (contractEnded)
contractEnded.setHours(23, 59, 59, 59);
let startedTime;
if (contractStarted < started)
startedTime = started.getTime();
else startedTime = contractStarted.getTime();
let endedTime;
if (!contractEnded || (contractEnded && contractEnded > ended))
endedTime = ended.getTime();
else endedTime = contractEnded.getTime();
const dayTimestamp = 1000 * 60 * 60 * 24;
// Get number of worked days between dates
let workedDays = Math.floor((endedTime - startedTime) / dayTimestamp);
workedDays += 1; // 1 day inclusion
// Calculates absences
let entitlementRate = 0;
for (let absence of contract.absences()) {
const absenceType = absence.absenceType();
const isHoliday = absenceType.code === 'holiday';
const isHalfHoliday = absenceType.code === 'halfHoliday';
if (isHoliday) holidaysEnjoyed += 1;
if (isHalfHoliday) holidaysEnjoyed += 0.5;
entitlementRate += absenceType.holidayEntitlementRate;
}
workedDays -= entitlementRate;
// Max holidays for the selected year
const maxHolidays = contract.holidays() && contract.holidays().days;
if (workedDays < daysInYear())
totalHolidays += Math.round(2 * maxHolidays * (workedDays) / daysInYear()) / 2;
else totalHolidays = maxHolidays;
}
function daysInYear() {
let queryIndex;
const year = started.getFullYear();
return isLeapYear(year) ? 366 : 365;
if (args.businessFk) {
stmts.push(new ParameterizedSQL('CALL vn.workerCalendar_calculateBusiness(?,?)', [year, args.businessFk]));
queryIndex = stmts.push('SELECT * FROM tmp.workerCalendarCalculateBusiness') - 1;
stmts.push('DROP TEMPORARY TABLE tmp.workerCalendarCalculateBusiness');
} else {
stmts.push(new ParameterizedSQL('CALL vn.workerCalendar_calculateYear(?,?)', [year, id]));
queryIndex = stmts.push('SELECT * FROM tmp.workerCalendarCalculateYear') - 1;
stmts.push('DROP TEMPORARY TABLE tmp.workerCalendarCalculateYear');
}
return {totalHolidays, holidaysEnjoyed, payedHolidays};
};
function isLeapYear(year) {
return year % 400 === 0 || (year % 100 !== 0 && year % 4 === 0);
}
const sql = ParameterizedSQL.join(stmts, ';');
const result = await conn.executeStmt(sql, myOptions);
const [holidays] = result[queryIndex];
const totalHolidays = holidays.days;
const holidaysEnjoyed = holidays.daysEnjoyed;
const totalHours = holidays.hours;
const hoursEnjoyed = holidays.hoursEnjoyed;
return {totalHolidays, holidaysEnjoyed, totalHours, hoursEnjoyed, payedHolidays};
};
};

View File

@ -34,6 +34,9 @@
},
"notificationEmail": {
"type": "string"
},
"hasToMistake": {
"type": "number"
}
}
}

View File

@ -25,20 +25,28 @@
<div class="totalBox vn-mb-sm" style="text-align: center;">
<h6>{{'Contract' | translate}} #{{$ctrl.businessId}}</h6>
<div>
{{'Used' | translate}} {{$ctrl.contractHolidays.holidaysEnjoyed}}
{{'Used' | translate}} {{$ctrl.contractHolidays.holidaysEnjoyed || 0}}
{{'of' | translate}} {{$ctrl.contractHolidays.totalHolidays || 0}} {{'days' | translate}}
</div>
<div>
{{'Paid holidays' | translate}} {{$ctrl.contractHolidays.payedHolidays}} {{'days' | translate}}
{{'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}}
{{'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">

View File

@ -198,7 +198,7 @@ class Controller extends Section {
const event = this.events[stamp];
const calendar = $event.target.closest('vn-calendar').$ctrl;
if (event) {
if (event && event.absenceId) {
if (event.type == this.absenceType.code)
this.delete(calendar, day, event);
else
@ -230,6 +230,7 @@ class Controller extends Section {
.then(calendar.repaint())
.then(() => this.getContractHolidays())
.then(() => this.getYearHolidays())
.then(() => this.repaint())
);
});
}
@ -266,6 +267,7 @@ class Controller extends Section {
.then(calendar.repaint())
.then(() => this.getContractHolidays())
.then(() => this.getYearHolidays())
.then(() => this.repaint())
);
});
}

View File

@ -191,7 +191,8 @@ describe('Worker', () => {
const selectedDay = new Date();
const expectedEvent = {
dated: selectedDay,
type: 'holiday'
type: 'holiday',
absenceId: 1
};
const $event = {
target: {
@ -214,7 +215,8 @@ describe('Worker', () => {
const selectedDay = new Date();
const expectedEvent = {
dated: selectedDay,
type: 'leaveOfAbsence'
type: 'leaveOfAbsence',
absenceId: 1
};
const $event = {
target: {

View File

@ -2,9 +2,11 @@ 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

View File

@ -16,5 +16,12 @@
"type": "string",
"required": false
}
},
"relations": {
"supplierAgencyTerm": {
"type": "hasOne",
"model": "SupplierAgencyTerm",
"foreignKey": "agencyFk"
}
}
}