Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix into 1788-remove_autoload_vnTable
gitea/salix/pipeline/head This commit looks good
Details
gitea/salix/pipeline/head This commit looks good
Details
This commit is contained in:
commit
59e43ea17f
|
@ -11,4 +11,5 @@ npm-debug.log
|
|||
datasources.*.json
|
||||
print.*.json
|
||||
db.json
|
||||
junit.xml
|
||||
junit.xml
|
||||
.DS_Store
|
|
@ -69,13 +69,13 @@ pipeline {
|
|||
}
|
||||
}
|
||||
}
|
||||
stage('Backend') {
|
||||
/* stage('Backend') {
|
||||
steps {
|
||||
nodejs('node-lts') {
|
||||
sh 'gulp backTestOnce --ci'
|
||||
}
|
||||
}
|
||||
}
|
||||
} */
|
||||
}
|
||||
}
|
||||
stage('Build') {
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -26,6 +26,15 @@
|
|||
"Delivery": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"Image": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"ImageCollection": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"ImageCollectionSize": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"Province": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
{
|
||||
"name": "ImageCollectionSize",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "hedera.imageCollectionSize"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "Number",
|
||||
"id": true,
|
||||
"description": "Identifier"
|
||||
},
|
||||
"width": {
|
||||
"type": "Number",
|
||||
"required": true
|
||||
},
|
||||
"height": {
|
||||
"type": "Number",
|
||||
"required": true
|
||||
},
|
||||
"crop": {
|
||||
"type": "Boolean",
|
||||
"required": true
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
"collection": {
|
||||
"type": "belongsTo",
|
||||
"model": "ImageCollection",
|
||||
"foreignKey": "collectionFk"
|
||||
}
|
||||
},
|
||||
"acls": [
|
||||
{
|
||||
"accessType": "READ",
|
||||
"principalType": "ROLE",
|
||||
"principalId": "employee",
|
||||
"permission": "ALLOW"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
{
|
||||
"name": "ImageCollection",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "hedera.imageCollection"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "Number",
|
||||
"id": true,
|
||||
"description": "Identifier"
|
||||
},
|
||||
"name": {
|
||||
"type": "String",
|
||||
"required": true
|
||||
},
|
||||
"desc": {
|
||||
"type": "String",
|
||||
"required": true
|
||||
},
|
||||
"maxWidth": {
|
||||
"type": "Number",
|
||||
"required": true
|
||||
},
|
||||
"maxHeight": {
|
||||
"type": "Number",
|
||||
"required": true
|
||||
},
|
||||
"model": {
|
||||
"type": "String",
|
||||
"required": true
|
||||
},
|
||||
"property": {
|
||||
"type": "String",
|
||||
"required": true
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
"sizes": {
|
||||
"type": "hasMany",
|
||||
"model": "ImageCollectionSize",
|
||||
"foreignKey": "collectionFk",
|
||||
"property": "id"
|
||||
}
|
||||
},
|
||||
"acls": [
|
||||
{
|
||||
"accessType": "READ",
|
||||
"principalType": "ROLE",
|
||||
"principalId": "employee",
|
||||
"permission": "ALLOW"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
const fs = require('fs-extra');
|
||||
const sharp = require('sharp');
|
||||
const path = require('path');
|
||||
|
||||
module.exports = Self => {
|
||||
Self.getPath = function() {
|
||||
return '/var/lib/salix/image';
|
||||
};
|
||||
|
||||
Self.registerImage = async(collectionName, file, srcFilePath) => {
|
||||
const models = Self.app.models;
|
||||
const tx = await Self.beginTransaction({});
|
||||
const myOptions = {transaction: tx};
|
||||
|
||||
try {
|
||||
const collection = await models.ImageCollection.findOne({
|
||||
fields: [
|
||||
'id',
|
||||
'name',
|
||||
'maxWidth',
|
||||
'maxHeight',
|
||||
'model',
|
||||
'property'
|
||||
],
|
||||
where: {name: collectionName},
|
||||
include: {
|
||||
relation: 'sizes',
|
||||
scope: {
|
||||
fields: ['width', 'height', 'crop']
|
||||
}
|
||||
}
|
||||
}, myOptions);
|
||||
|
||||
const fileName = file.split('.')[0];
|
||||
const rootPath = Self.getPath();
|
||||
const data = {
|
||||
name: fileName,
|
||||
collectionFk: collectionName
|
||||
};
|
||||
|
||||
const newImage = await Self.upsertWithWhere(data, {
|
||||
name: fileName,
|
||||
collectionFk: collectionName,
|
||||
updated: (new Date).getTime()
|
||||
}, myOptions);
|
||||
|
||||
// Resizes and saves the image
|
||||
const collectionDir = path.join(rootPath, collectionName);
|
||||
const dstDir = path.join(collectionDir, 'full');
|
||||
const dstFile = path.join(dstDir, file);
|
||||
|
||||
const resizeOpts = {
|
||||
withoutEnlargement: true,
|
||||
fit: 'inside'
|
||||
};
|
||||
|
||||
await fs.mkdir(dstDir, {recursive: true});
|
||||
await sharp(srcFilePath)
|
||||
.resize(collection.maxWidth, collection.maxHeight, resizeOpts)
|
||||
.toFile(dstFile);
|
||||
|
||||
const sizes = collection.sizes();
|
||||
for (let size of sizes) {
|
||||
const dstDir = path.join(collectionDir, `${size.width}x${size.height}`);
|
||||
const dstFile = path.join(dstDir, file);
|
||||
const resizeOpts = {
|
||||
withoutEnlargement: true,
|
||||
fit: size.crop ? 'cover' : 'inside'
|
||||
};
|
||||
|
||||
await fs.mkdir(dstDir, {recursive: true});
|
||||
await sharp(srcFilePath)
|
||||
.resize(size.width, size.height, resizeOpts)
|
||||
.toFile(dstFile);
|
||||
}
|
||||
|
||||
const model = models[collection.model];
|
||||
|
||||
if (!model)
|
||||
throw new Error('Matching model not found');
|
||||
|
||||
const item = await model.findById(fileName, null, myOptions);
|
||||
if (item) {
|
||||
await item.updateAttribute(
|
||||
collection.property,
|
||||
fileName,
|
||||
myOptions
|
||||
);
|
||||
}
|
||||
|
||||
await fs.unlink(srcFilePath);
|
||||
await tx.commit();
|
||||
return newImage;
|
||||
} catch (e) {
|
||||
await tx.rollback();
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
};
|
|
@ -0,0 +1,41 @@
|
|||
{
|
||||
"name": "Image",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "hedera.image"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "Number",
|
||||
"id": true,
|
||||
"description": "The id"
|
||||
},
|
||||
"name": {
|
||||
"type": "String",
|
||||
"required": true
|
||||
},
|
||||
"collectionFk": {
|
||||
"type": "String",
|
||||
"required": true
|
||||
},
|
||||
"updated": {
|
||||
"type": "Number"
|
||||
},
|
||||
"nRefs": {
|
||||
"type": "Number",
|
||||
"required": true,
|
||||
"default": 0
|
||||
}
|
||||
},
|
||||
"acls": [
|
||||
{
|
||||
"accessType": "READ",
|
||||
"principalType": "ROLE",
|
||||
"principalId": "employee",
|
||||
"permission": "ALLOW"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
UPDATE `salix`.`ACL` SET `accessType`='WRITE' WHERE `id`='213';
|
||||
UPDATE `salix`.`ACL` SET `property` = 'deleteSales' WHERE (`id` = '80');
|
||||
|
||||
INSERT IGNORE INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('CustomsAgent', '*', '*', 'ALLOW', 'ROLE', 'employee');
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
ALTER TABLE `postgresql`.`calendar_employee`
|
||||
ADD COLUMN `id` INT NULL AUTO_INCREMENT FIRST,
|
||||
ADD UNIQUE INDEX `id_UNIQUE` (`id` ASC) VISIBLE,
|
||||
ADD INDEX `id_index` (`id` ASC) VISIBLE;
|
||||
;
|
|
@ -0,0 +1,12 @@
|
|||
USE `vn`;
|
||||
CREATE
|
||||
OR REPLACE ALGORITHM = UNDEFINED
|
||||
DEFINER = `root`@`%`
|
||||
SQL SECURITY DEFINER
|
||||
VIEW `workerCalendar2` AS
|
||||
SELECT
|
||||
`ce`.`id` AS `id`,
|
||||
`ce`.`business_id` AS `businessFk`,
|
||||
`ce`.`calendar_state_id` AS `absenceTypeFk`,
|
||||
`ce`.`date` AS `dated`
|
||||
FROM `postgresql`.`calendar_employee` `ce`;
|
|
@ -0,0 +1,47 @@
|
|||
USE `vn`;
|
||||
CREATE
|
||||
OR REPLACE ALGORITHM = UNDEFINED
|
||||
DEFINER = `root`@`%`
|
||||
SQL SECURITY DEFINER
|
||||
VIEW `vn`.`zoneEstimatedDelivery` AS
|
||||
SELECT
|
||||
`t`.`zoneFk` AS `zoneFk`,
|
||||
CAST((CURDATE() + INTERVAL ((HOUR(`zc`.`hour`) * 60) + MINUTE(`zc`.`hour`)) MINUTE)
|
||||
AS TIME) AS `hourTheoretical`,
|
||||
CAST(SUM(`sv`.`volume`) AS DECIMAL (5 , 1 )) AS `totalVolume`,
|
||||
CAST(SUM(IF((`s`.`alertLevel` < 2),
|
||||
`sv`.`volume`,
|
||||
0))
|
||||
AS DECIMAL (5 , 1 )) AS `remainingVolume`,
|
||||
GREATEST(IFNULL(`lhp`.`m3`, 0),
|
||||
IFNULL(`dl`.`minSpeed`, 0)) AS `speed`,
|
||||
CAST((`zc`.`hour` + INTERVAL ((-(SUM(IF((`s`.`alertLevel` < 2),
|
||||
`sv`.`volume`,
|
||||
0))) * 60) / GREATEST(IFNULL(`lhp`.`m3`, 0),
|
||||
IFNULL(`dl`.`minSpeed`, 0))) MINUTE)
|
||||
AS TIME) AS `hourEffective`,
|
||||
FLOOR(((-(SUM(IF((`s`.`alertLevel` < 2),
|
||||
`sv`.`volume`,
|
||||
0))) * 60) / GREATEST(IFNULL(`lhp`.`m3`, 0),
|
||||
IFNULL(`dl`.`minSpeed`, 0)))) AS `minutesLess`,
|
||||
CAST((`zc`.`hour` + INTERVAL ((-(SUM(IF((`s`.`alertLevel` < 2),
|
||||
`sv`.`volume`,
|
||||
0))) * 60) / GREATEST(IFNULL(`lhp`.`m3`, 0),
|
||||
IFNULL(`dl`.`minSpeed`, 0))) MINUTE)
|
||||
AS TIME) AS `etc`
|
||||
FROM
|
||||
((((((((`ticket` `t`
|
||||
JOIN `ticketStateToday` `tst` ON ((`tst`.`ticket` = `t`.`id`)))
|
||||
JOIN `state` `s` ON ((`s`.`id` = `tst`.`state`)))
|
||||
JOIN `saleVolume` `sv` ON ((`sv`.`ticketFk` = `t`.`id`)))
|
||||
LEFT JOIN `lastHourProduction` `lhp` ON ((`lhp`.`warehouseFk` = `t`.`warehouseFk`)))
|
||||
JOIN `warehouse` `w` ON ((`w`.`id` = `t`.`warehouseFk`)))
|
||||
JOIN `warehouseAlias` `wa` ON ((`wa`.`id` = `w`.`aliasFk`)))
|
||||
LEFT JOIN `zoneClosure` `zc` ON (((`zc`.`zoneFk` = `t`.`zoneFk`)
|
||||
AND (`zc`.`dated` = CURDATE()))))
|
||||
LEFT JOIN `cache`.`departure_limit` `dl` ON (((`dl`.`warehouse_id` = `t`.`warehouseFk`)
|
||||
AND (`dl`.`fecha` = CURDATE()))))
|
||||
WHERE
|
||||
((`wa`.`name` = 'Silla')
|
||||
AND (CAST(`t`.`shipped` AS DATE) = CURDATE()))
|
||||
GROUP BY `t`.`zoneFk`;
|
|
@ -0,0 +1,16 @@
|
|||
CREATE
|
||||
OR REPLACE ALGORITHM = UNDEFINED
|
||||
DEFINER = `root`@`%`
|
||||
SQL SECURITY DEFINER
|
||||
VIEW `vn`.`zone_ETD` AS
|
||||
SELECT
|
||||
`zed`.`zoneFk` AS `zoneFk`,
|
||||
`zed`.`hourTheoretical` AS `HoraTeórica`,
|
||||
`zed`.`totalVolume` AS `volumenTotal`,
|
||||
`zed`.`remainingVolume` AS `volumenPendiente`,
|
||||
`zed`.`speed` AS `velocidad`,
|
||||
`zed`.`hourEffective` AS `HoraPráctica`,
|
||||
`zed`.`minutesLess` AS `minutesLess`,
|
||||
`zed`.`etc` AS `etc`
|
||||
FROM
|
||||
`vn`.`zoneEstimatedDelivery` `zed`
|
File diff suppressed because one or more lines are too long
|
@ -88,13 +88,18 @@ INSERT INTO `vn`.`country`(`id`, `country`, `isUeeMember`, `code`, `currencyFk`,
|
|||
(19,'Francia', 1, 'FR', 1, 27),
|
||||
(30,'Canarias', 1, 'IC', 1, 24);
|
||||
|
||||
INSERT INTO `vn`.`warehouse`(`id`, `name`, `isComparative`, `isInventory`, `hasAvailable`, `isManaged`, `hasStowaway`, `hasDms`, `hasComission`)
|
||||
INSERT INTO `vn`.`warehouseAlias`(`id`, `name`)
|
||||
VALUES
|
||||
(1, 'Warehouse One', 1, 1, 1, 1, 1, 1, 1),
|
||||
(2, 'Warehouse Two', 1, 1, 1, 1, 0, 0, 1),
|
||||
(3, 'Warehouse Three', 1, 1, 1, 1, 0, 0, 0),
|
||||
(4, 'Warehouse Four', 1, 1, 1, 1, 0, 0, 0),
|
||||
(5, 'Warehouse Five', 1, 1, 1, 1, 0, 0, 0);
|
||||
(1, 'Main Warehouse'),
|
||||
(2, 'Silla');
|
||||
|
||||
INSERT INTO `vn`.`warehouse`(`id`, `name`, `isComparative`, `isInventory`, `hasAvailable`, `isManaged`, `hasStowaway`, `hasDms`, `hasComission`, `aliasFk`)
|
||||
VALUES
|
||||
(1, 'Warehouse One', 1, 1, 1, 1, 1, 1, 1, 2),
|
||||
(2, 'Warehouse Two', 1, 1, 1, 1, 0, 0, 1, 2),
|
||||
(3, 'Warehouse Three', 1, 1, 1, 1, 0, 0, 0, 2),
|
||||
(4, 'Warehouse Four', 1, 1, 1, 1, 0, 0, 0, 2),
|
||||
(5, 'Warehouse Five', 1, 1, 1, 1, 0, 0, 0, 2);
|
||||
|
||||
INSERT INTO `vn`.`sector`(`id`, `description`, `warehouseFk`, `isPreviousPreparedByPacking`, `code`, `pickingPlacement`, `path`)
|
||||
VALUES
|
||||
|
@ -111,10 +116,6 @@ INSERT INTO `vn`.`shelving` (`code`, `parkingFk`, `isPrinted`, `priority`, `park
|
|||
('GVC', '1', '0', '1', '0', '106'),
|
||||
('HEJ', '2', '0', '1', '0', '106');
|
||||
|
||||
INSERT INTO `vn`.`warehouseAlias`(`id`, `name`)
|
||||
VALUES
|
||||
(1, 'Main Warehouse');
|
||||
|
||||
INSERT INTO `vn`.`accountingType`(`id`, `description`)
|
||||
VALUES
|
||||
(1, 'Digital money'),
|
||||
|
@ -510,7 +511,23 @@ INSERT INTO `vn`.`zoneWarehouse` (`id`, `zoneFk`, `warehouseFk`)
|
|||
(11, 11, 5),
|
||||
(12, 12, 4),
|
||||
(13, 13, 5);
|
||||
|
||||
|
||||
INSERT INTO `vn`.`zoneClosure` (`zoneFk`, `dated`, `hour`)
|
||||
VALUES
|
||||
(1, CURDATE(), '23:59'),
|
||||
(2, CURDATE(), '23:59'),
|
||||
(3, CURDATE(), '23:59'),
|
||||
(4, CURDATE(), '23:59'),
|
||||
(5, CURDATE(), '23:59'),
|
||||
(6, CURDATE(), '23:59'),
|
||||
(7, CURDATE(), '23:59'),
|
||||
(8, CURDATE(), '23:59'),
|
||||
(9, CURDATE(), '23:59'),
|
||||
(10, CURDATE(), '23:59'),
|
||||
(11, CURDATE(), '23:59'),
|
||||
(12, CURDATE(), '23:59'),
|
||||
(13, CURDATE(), '23:59');
|
||||
|
||||
INSERT INTO `vn`.`zoneConfig` (`scope`) VALUES ('1');
|
||||
|
||||
INSERT INTO `vn`.`route`(`id`, `time`, `workerFk`, `created`, `vehicleFk`, `agencyModeFk`, `description`, `m3`, `cost`, `started`, `finished`, `zoneFk`)
|
||||
|
@ -588,7 +605,7 @@ INSERT INTO `vn`.`ticketTracking`(`ticketFk`, `stateFk`, `workerFk`, `created`)
|
|||
(16, 3, 19, NOW()),
|
||||
(17, 3, 19, NOW()),
|
||||
(18, 3, 19, NOW()),
|
||||
(19, 17, 19, NOW()),
|
||||
(19, 3, 19, NOW()),
|
||||
(20, 1, 19, DATE_ADD(NOW(), INTERVAL +1 MONTH)),
|
||||
(21, 1, 19, DATE_ADD(NOW(), INTERVAL +1 MONTH)),
|
||||
(22, 1, 19, DATE_ADD(NOW(), INTERVAL +1 MONTH)),
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -80,7 +80,6 @@ IGNORETABLES=(
|
|||
--ignore-table=vn.ticketRequest__
|
||||
--ignore-table=vn.ticketToPrepare
|
||||
--ignore-table=vn.till__
|
||||
--ignore-table=vn.time
|
||||
--ignore-table=vn.travelThermograph__
|
||||
--ignore-table=vn.travel_cloneWeekly
|
||||
--ignore-table=vn.unary
|
||||
|
|
|
@ -28,6 +28,7 @@ services:
|
|||
volumes:
|
||||
- /mnt/storage/pdfs:/var/lib/salix/pdfs
|
||||
- /mnt/storage/dms:/var/lib/salix/dms
|
||||
- /mnt/storage/image:/var/lib/salix/image
|
||||
deploy:
|
||||
replicas: 6
|
||||
configs:
|
||||
|
|
|
@ -631,7 +631,7 @@ export default {
|
|||
},
|
||||
ordersIndex: {
|
||||
searchResult: 'vn-order-index vn-card > vn-table > div > vn-tbody > a.vn-tr',
|
||||
firstSearchResultTotal: 'vn-order-index vn-card > vn-table > div > vn-tbody vn-tr vn-td:nth-child(7)',
|
||||
secondSearchResultTotal: 'vn-order-index vn-card > vn-table > div > vn-tbody vn-tr:nth-child(2) vn-td:nth-child(9)',
|
||||
searchResultDate: 'vn-order-index vn-table vn-tbody > a:nth-child(1) > vn-td:nth-child(4)',
|
||||
searchResultAddress: 'vn-order-index vn-table vn-tbody > a:nth-child(1) > vn-td:nth-child(6)',
|
||||
searchButton: 'vn-searchbar vn-icon[icon="search"]',
|
||||
|
|
|
@ -211,12 +211,16 @@ describe('Ticket Edit sale path', () => {
|
|||
it('should search for a ticket then access to the sales section', async() => {
|
||||
await page.accessToSearchResult('16');
|
||||
await page.accessToSection('ticket.card.sale');
|
||||
await page.wait(2000);
|
||||
});
|
||||
|
||||
it('should select the third sale and delete it', async() => {
|
||||
await page.waitToClick(selectors.ticketSales.thirdSaleCheckbox);
|
||||
await page.wait(2000);
|
||||
await page.waitToClick(selectors.ticketSales.deleteSaleButton);
|
||||
await page.wait(2000);
|
||||
await page.waitToClick(selectors.ticketSales.acceptDeleteLineButton);
|
||||
await page.wait(2000);
|
||||
await page.waitForSpinnerLoad();
|
||||
const message = await page.waitForSnackbar();
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ describe('Order summary path', () => {
|
|||
browser = await getBrowser();
|
||||
page = browser.page;
|
||||
await page.loginAndModule('employee', 'order');
|
||||
await page.waitFor(2000);
|
||||
await page.accessToSearchResult('16');
|
||||
});
|
||||
|
||||
|
|
|
@ -15,9 +15,9 @@ describe('Order Index', () => {
|
|||
await browser.close();
|
||||
});
|
||||
|
||||
it(`should check the first search result doesn't contain a total of 0€`, async() => {
|
||||
it(`should check the second search result doesn't contain a total of 0€`, async() => {
|
||||
await page.waitToClick(selectors.ordersIndex.searchButton);
|
||||
const result = await page.waitToGetProperty(selectors.ordersIndex.firstSearchResultTotal, 'innerText');
|
||||
const result = await page.waitToGetProperty(selectors.ordersIndex.secondSearchResultTotal, 'innerText');
|
||||
|
||||
expect(result).not.toContain('0.00');
|
||||
});
|
||||
|
@ -26,8 +26,8 @@ describe('Order Index', () => {
|
|||
await page.waitToClick(selectors.ordersIndex.openAdvancedSearch);
|
||||
await page.waitToClick(selectors.ordersIndex.advancedSearchShowEmptyCheckbox);
|
||||
await page.waitToClick(selectors.ordersIndex.advancedSearchButton);
|
||||
await page.waitForTextInElement(selectors.ordersIndex.firstSearchResultTotal, '0.00');
|
||||
const result = await page.waitToGetProperty(selectors.ordersIndex.firstSearchResultTotal, 'innerText');
|
||||
await page.waitForTextInElement(selectors.ordersIndex.secondSearchResultTotal, '0.00');
|
||||
const result = await page.waitToGetProperty(selectors.ordersIndex.secondSearchResultTotal, 'innerText');
|
||||
|
||||
expect(result).toContain('0.00');
|
||||
});
|
||||
|
|
|
@ -135,7 +135,7 @@ export default class Calendar extends FormInput {
|
|||
$days: [day],
|
||||
$type: 'day'
|
||||
});
|
||||
this.repaint();
|
||||
// this.repaint();
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Binary file not shown.
|
@ -249,7 +249,6 @@ module.exports = function(Self) {
|
|||
let newInstance = {};
|
||||
if (ctx.hookState.newInstance)
|
||||
Object.assign(newInstance, ctx.hookState.newInstance);
|
||||
|
||||
let userFk;
|
||||
if (loopBackContext)
|
||||
userFk = loopBackContext.active.accessToken.userId;
|
||||
|
|
|
@ -133,5 +133,6 @@
|
|||
"Distance must be lesser than 1000": "La distancia debe ser inferior a 1000",
|
||||
"This ticket is deleted": "Este ticket está eliminado",
|
||||
"A travel with this data already exists": "Ya existe un travel con estos datos",
|
||||
"This thermograph id already exists": "La id del termógrafo ya existe"
|
||||
"This thermograph id already exists": "La id del termógrafo ya existe",
|
||||
"ORDER_ALREADY_CONFIRMED": "ORDER_ALREADY_CONFIRMED"
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
|
||||
// #2304
|
||||
xdescribe('regularizeClaim()', () => {
|
||||
describe('regularizeClaim()', () => {
|
||||
const claimFk = 1;
|
||||
const pendentState = 1;
|
||||
const resolvedState = 3;
|
||||
|
|
|
@ -27,11 +27,11 @@ module.exports = function(Self) {
|
|||
{
|
||||
relation: 'salesPerson',
|
||||
scope: {
|
||||
fields: ['userFk'],
|
||||
fields: ['userFk', 'firstName'],
|
||||
include: {
|
||||
relation: 'user',
|
||||
scope: {
|
||||
fields: ['nickname']
|
||||
fields: ['name', 'nickname']
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -45,6 +45,12 @@ module.exports = function(Self) {
|
|||
scope: {
|
||||
fields: ['id', 'name']
|
||||
}
|
||||
}, {
|
||||
}, {
|
||||
relation: 'salesPersonUser',
|
||||
scope: {
|
||||
fields: ['id', 'name']
|
||||
}
|
||||
}, {
|
||||
relation: 'country',
|
||||
scope: {
|
||||
|
|
|
@ -17,7 +17,7 @@ describe('Client activeWorkersWithRole', () => {
|
|||
|
||||
let isBuyer = await app.models.Account.hasRole(result[0].id, 'buyer');
|
||||
|
||||
expect(result.length).toEqual(13);
|
||||
expect(result.length).toEqual(15);
|
||||
expect(isBuyer).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -136,6 +136,11 @@
|
|||
"model": "Worker",
|
||||
"foreignKey": "salesPersonFk"
|
||||
},
|
||||
"salesPersonUser": {
|
||||
"type": "belongsTo",
|
||||
"model": "Account",
|
||||
"foreignKey": "salesPersonFk"
|
||||
},
|
||||
"province": {
|
||||
"type": "belongsTo",
|
||||
"model": "Province",
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
const https = require('https');
|
||||
const fs = require('fs-extra');
|
||||
const path = require('path');
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethod('downloadImages', {
|
||||
description: 'Returns last entries',
|
||||
accessType: 'WRITE',
|
||||
returns: {
|
||||
type: ['Object'],
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/downloadImages`,
|
||||
verb: 'POST'
|
||||
}
|
||||
});
|
||||
|
||||
Self.downloadImages = async() => {
|
||||
const models = Self.app.models;
|
||||
|
||||
try {
|
||||
const imageQueue = await Self.find({limit: 25});
|
||||
const rootPath = models.Image.getPath();
|
||||
const tempPath = path.join(rootPath, 'temp');
|
||||
|
||||
// Create temporary path
|
||||
await fs.mkdir(tempPath, {recursive: true});
|
||||
|
||||
for (let image of imageQueue) {
|
||||
const fileName = `${image.itemFk}.png`;
|
||||
const filePath = path.join(tempPath, fileName);
|
||||
const file = fs.createWriteStream(filePath);
|
||||
|
||||
https.get(image.url, async response => {
|
||||
response.pipe(file);
|
||||
});
|
||||
|
||||
file.on('finish', async function() {
|
||||
await models.Image.registerImage('catalog', fileName, filePath);
|
||||
await image.destroy();
|
||||
});
|
||||
|
||||
file.on('error', err => {
|
||||
fs.unlink(filePath);
|
||||
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
|
||||
return imageQueue;
|
||||
} catch (e) {
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
};
|
|
@ -50,6 +50,9 @@
|
|||
"ItemShelvingSale": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"ItemImageQueue": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"Origin": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
module.exports = Self => {
|
||||
require('../methods/item-image-queue/downloadImages')(Self);
|
||||
};
|
|
@ -0,0 +1,36 @@
|
|||
{
|
||||
"name": "ItemImageQueue",
|
||||
"description": "Image download queue",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "itemImageQueue"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"itemFk": {
|
||||
"type": "Number",
|
||||
"id": true,
|
||||
"description": "Identifier"
|
||||
},
|
||||
"url": {
|
||||
"type": "String",
|
||||
"required": true
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
"item": {
|
||||
"type": "belongsTo",
|
||||
"model": "Item",
|
||||
"foreignKey": "itemFk"
|
||||
}
|
||||
},
|
||||
"acls": [
|
||||
{
|
||||
"accessType": "*",
|
||||
"principalType": "ROLE",
|
||||
"principalId": "employee",
|
||||
"permission": "ALLOW"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -133,7 +133,6 @@ module.exports = Self => {
|
|||
});
|
||||
|
||||
filter = mergeFilters(filter, {where});
|
||||
|
||||
let stmts = [];
|
||||
let stmt;
|
||||
|
||||
|
@ -157,14 +156,20 @@ module.exports = Self => {
|
|||
c.salesPersonFk,
|
||||
u.nickname workerNickname,
|
||||
u.name name,
|
||||
co.code companyCode
|
||||
co.code companyCode,
|
||||
zed.zoneFk,
|
||||
zed.hourTheoretical,
|
||||
zed.hourEffective
|
||||
FROM hedera.order o
|
||||
LEFT JOIN address a ON a.id = o.address_id
|
||||
LEFT JOIN agencyMode am ON am.id = o.agency_id
|
||||
LEFT JOIN client c ON c.id = o.customer_id
|
||||
LEFT JOIN worker wk ON wk.id = c.salesPersonFk
|
||||
LEFT JOIN account.user u ON u.id = wk.userFk
|
||||
LEFT JOIN company co ON co.id = o.company_id`);
|
||||
LEFT JOIN company co ON co.id = o.company_id
|
||||
LEFT JOIN orderTicket ot ON ot.orderFk = o.id
|
||||
LEFT JOIN ticket t ON t.id = ot.ticketFk
|
||||
LEFT JOIN zoneEstimatedDelivery zed ON zed.zoneFk = t.zoneFk`);
|
||||
|
||||
if (args && args.ticketFk) {
|
||||
stmt.merge({
|
||||
|
@ -172,7 +177,11 @@ module.exports = Self => {
|
|||
});
|
||||
}
|
||||
|
||||
stmt.merge(conn.makeSuffix(filter));
|
||||
stmt.merge(conn.makeWhere(filter.where));
|
||||
stmt.merge({
|
||||
sql: `GROUP BY o.id`
|
||||
});
|
||||
stmt.merge(conn.makePagination(filter));
|
||||
stmts.push(stmt);
|
||||
|
||||
stmts.push(`
|
||||
|
|
|
@ -10,11 +10,13 @@
|
|||
<vn-thead>
|
||||
<vn-tr>
|
||||
<vn-th field="id" number>Id</vn-th>
|
||||
<vn-th field="clientFk">Client</vn-th>
|
||||
<vn-th field="salesPersonFk">Sales person</vn-th>
|
||||
<vn-th field="clientFk">Client</vn-th>
|
||||
<vn-th field="isConfirmed" center>Confirmed</vn-th>
|
||||
<vn-th field="created" center>Created</vn-th>
|
||||
<vn-th field="landed" default-order="DESC" center>Landed</vn-th>
|
||||
<vn-th field="created" center title ="Theoretical hour" >T. Hour</vn-th>
|
||||
<vn-th field="created" center>Real hour </vn-th>
|
||||
<vn-th center>Total</vn-th>
|
||||
</vn-tr>
|
||||
</vn-thead>
|
||||
|
@ -24,13 +26,6 @@
|
|||
class="clickable search-result"
|
||||
ui-sref="order.card.summary({id: {{::order.id}}})">
|
||||
<vn-td number>{{::order.id}}</vn-td>
|
||||
<vn-td expand>
|
||||
<span
|
||||
vn-click-stop="clientDescriptor.show($event, order.clientFk)"
|
||||
class="link">
|
||||
{{::order.clientName}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td expand>
|
||||
<span
|
||||
vn-click-stop="workerDescriptor.show($event, order.salesPersonFk)"
|
||||
|
@ -38,14 +33,27 @@
|
|||
{{::order.name | dashIfEmpty}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td center>
|
||||
<vn-td expand>
|
||||
<span
|
||||
vn-click-stop="clientDescriptor.show($event, order.clientFk)"
|
||||
class="link">
|
||||
{{::order.clientName}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td center>
|
||||
<vn-check
|
||||
ng-model="order.isConfirmed"
|
||||
disabled="true">
|
||||
</vn-check>
|
||||
</vn-td>
|
||||
<vn-td center>{{::order.created | date: 'dd/MM/yyyy HH:mm'}}</vn-td>
|
||||
<vn-td center>{{::order.landed | date:'dd/MM/yyyy'}}</vn-td>
|
||||
<vn-td center>
|
||||
<span class="chip {{$ctrl.compareDate(order.landed)}}">
|
||||
{{::order.landed | date:'dd/MM/yyyy'}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td shrink>{{::order.hourTheoretical | date: 'HH:mm'}}</vn-td>
|
||||
<vn-td shrink>{{::ticket.hourEffective | date: 'HH:mm'}}</vn-td>
|
||||
<vn-td number>{{::order.total | currency: 'EUR': 2 | dashIfEmpty}}</vn-td>
|
||||
<vn-td shrink>
|
||||
<vn-icon-button
|
||||
|
|
|
@ -6,6 +6,20 @@ export default class Controller extends Section {
|
|||
this.selectedOrder = order;
|
||||
this.$.summary.show();
|
||||
}
|
||||
|
||||
compareDate(date) {
|
||||
let today = new Date();
|
||||
today.setHours(0, 0, 0, 0);
|
||||
let timeTicket = new Date(date);
|
||||
timeTicket.setHours(0, 0, 0, 0);
|
||||
|
||||
let comparation = today - timeTicket;
|
||||
|
||||
if (comparation == 0)
|
||||
return 'warning';
|
||||
if (comparation < 0)
|
||||
return 'success';
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.component('vnOrderIndex', {
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
import './index.js';
|
||||
describe('Component vnOrderIndex', () => {
|
||||
let controller;
|
||||
let $window;
|
||||
let orders = [{
|
||||
id: 1,
|
||||
clientFk: 1,
|
||||
isConfirmed: false
|
||||
}, {
|
||||
id: 2,
|
||||
clientFk: 1,
|
||||
isConfirmed: false
|
||||
}, {
|
||||
id: 3,
|
||||
clientFk: 1,
|
||||
isConfirmed: true
|
||||
}];
|
||||
|
||||
beforeEach(ngModule('order'));
|
||||
|
||||
beforeEach(inject(($componentController, _$window_,) => {
|
||||
$window = _$window_;
|
||||
const $element = angular.element('<vn-order-index></vn-order-index>');
|
||||
controller = $componentController('vnOrderIndex', {$element});
|
||||
}));
|
||||
|
||||
describe('compareDate()', () => {
|
||||
it('should return warning when the date is the present', () => {
|
||||
let curDate = new Date();
|
||||
let result = controller.compareDate(curDate);
|
||||
|
||||
expect(result).toEqual('warning');
|
||||
});
|
||||
|
||||
it('should return sucess when the date is in the future', () => {
|
||||
let futureDate = new Date();
|
||||
futureDate = futureDate.setDate(futureDate.getDate() + 10);
|
||||
let result = controller.compareDate(futureDate);
|
||||
|
||||
expect(result).toEqual('success');
|
||||
});
|
||||
|
||||
it('should return undefined when the date is in the past', () => {
|
||||
let pastDate = new Date();
|
||||
pastDate = pastDate.setDate(pastDate.getDate() - 10);
|
||||
let result = controller.compareDate(pastDate);
|
||||
|
||||
expect(result).toEqual(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
describe('preview()', () => {
|
||||
it('should show the dialog summary', () => {
|
||||
controller.$.summary = {show: () => {}};
|
||||
jest.spyOn(controller.$.summary, 'show');
|
||||
|
||||
let event = new MouseEvent('click', {
|
||||
view: $window,
|
||||
bubbles: true,
|
||||
cancelable: true
|
||||
});
|
||||
controller.preview(event, orders[0]);
|
||||
|
||||
expect(controller.$.summary.show).toHaveBeenCalledWith();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -21,4 +21,6 @@ Ascendant: Ascendente
|
|||
Descendant: Descendente
|
||||
Created from: Creado desde
|
||||
Search order by id: Buscar el pedido por identificador
|
||||
order: pedido
|
||||
order: pedido
|
||||
Confirm lines: Confirmar las lineas
|
||||
Confirm: Confirmar
|
|
@ -1,5 +1,14 @@
|
|||
<vn-card class="summary">
|
||||
<h5>{{$ctrl.summary.id}} - {{$ctrl.summary.client.name}} - {{$ctrl.summary.client.salesPerson.id}}</h5>
|
||||
<h5>{{$ctrl.summary.id}} - {{$ctrl.summary.client.name}} - {{$ctrl.summary.client.salesPerson.id}}
|
||||
<vn-button
|
||||
disabled="$ctrl.order.isConfirmed"
|
||||
class="flat"
|
||||
style="color: inherit;"
|
||||
label="Confirm"
|
||||
ng-click="$ctrl.save()"
|
||||
vn-tooltip="Confirm lines">
|
||||
</vn-button>
|
||||
</h5>
|
||||
<vn-horizontal class="ticketSummary__data">
|
||||
<vn-one>
|
||||
<vn-label-value label="Id"
|
||||
|
|
|
@ -21,6 +21,15 @@ class Controller extends Section {
|
|||
if (this.order && this.order.id)
|
||||
this.setSummary();
|
||||
}
|
||||
|
||||
save() {
|
||||
this.$http.post(`Orders/${this.order.id}/confirm`).then(() => {
|
||||
this.vnApp.showSuccess(this.$t('Order confirmed'));
|
||||
this.$state.go(`ticket.index`, {
|
||||
q: JSON.stringify({clientFk: this.order.clientFk})
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.component('vnOrderSummary', {
|
||||
|
|
|
@ -3,6 +3,21 @@
|
|||
vn-order-summary .summary{
|
||||
max-width: $width-lg;
|
||||
|
||||
h5 {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
align-content: center;
|
||||
|
||||
|
||||
span {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
vn-button {
|
||||
flex: none
|
||||
}
|
||||
}
|
||||
& > div > vn-horizontal > vn-one {
|
||||
min-width: 160px !important;
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ describe('ticket filter()', () => {
|
|||
const secondRow = result[1];
|
||||
const thirdRow = result[2];
|
||||
|
||||
expect(result.length).toEqual(13);
|
||||
expect(result.length).toEqual(12);
|
||||
expect(firstRow.state).toEqual('Entregado');
|
||||
expect(secondRow.state).toEqual('Entregado');
|
||||
expect(thirdRow.state).toEqual('Entregado');
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
const UserError = require('vn-loopback/util/user-error');
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethodCtx('createAbsence', {
|
||||
description: 'Creates a new worker absence',
|
||||
accepts: [{
|
||||
arg: 'id',
|
||||
type: 'Number',
|
||||
description: 'The worker id',
|
||||
http: {source: 'path'}
|
||||
},
|
||||
{
|
||||
arg: 'absenceTypeId',
|
||||
type: 'Number',
|
||||
required: true
|
||||
},
|
||||
{
|
||||
arg: 'dated',
|
||||
type: 'Date',
|
||||
required: false
|
||||
}],
|
||||
returns: {
|
||||
type: 'Object',
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/:id/createAbsence`,
|
||||
verb: 'POST'
|
||||
}
|
||||
});
|
||||
|
||||
Self.createAbsence = async(ctx, id, absenceTypeId, dated) => {
|
||||
const models = Self.app.models;
|
||||
const userId = ctx.req.accessToken.userId;
|
||||
const isSubordinate = await models.Worker.isSubordinate(ctx, id);
|
||||
const isTeamBoss = await models.Account.hasRole(userId, 'teamBoss');
|
||||
|
||||
if (!isSubordinate || (isSubordinate && userId == id && !isTeamBoss))
|
||||
throw new UserError(`You don't have enough privileges`);
|
||||
|
||||
const labour = await models.WorkerLabour.findOne({
|
||||
where: {
|
||||
and: [
|
||||
{workerFk: id},
|
||||
{or: [{
|
||||
ended: {gte: [dated]}
|
||||
}, {ended: null}]}
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
return models.WorkerCalendar.create({
|
||||
businessFk: labour.businessFk,
|
||||
absenceTypeFk: absenceTypeId,
|
||||
dated: dated
|
||||
});
|
||||
};
|
||||
};
|
|
@ -0,0 +1,37 @@
|
|||
const UserError = require('vn-loopback/util/user-error');
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethodCtx('deleteAbsence', {
|
||||
description: 'Deletes a worker absence',
|
||||
accepts: [{
|
||||
arg: 'id',
|
||||
type: 'Number',
|
||||
description: 'The worker id',
|
||||
http: {source: 'path'}
|
||||
},
|
||||
{
|
||||
arg: 'absenceId',
|
||||
type: 'Number',
|
||||
required: true
|
||||
}],
|
||||
returns: 'Object',
|
||||
http: {
|
||||
path: `/:id/deleteAbsence`,
|
||||
verb: 'DELETE'
|
||||
}
|
||||
});
|
||||
|
||||
Self.deleteAbsence = async(ctx, id, absenceId) => {
|
||||
const models = Self.app.models;
|
||||
const userId = ctx.req.accessToken.userId;
|
||||
const isSubordinate = await models.Worker.isSubordinate(ctx, id);
|
||||
const isTeamBoss = await models.Account.hasRole(userId, 'teamBoss');
|
||||
|
||||
if (!isSubordinate || (isSubordinate && userId == id && !isTeamBoss))
|
||||
throw new UserError(`You don't have enough privileges`);
|
||||
|
||||
const absence = await models.WorkerCalendar.findById(absenceId);
|
||||
|
||||
return absence.destroy();
|
||||
};
|
||||
};
|
|
@ -0,0 +1,39 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
|
||||
describe('Worker createAbsence()', () => {
|
||||
const workerId = 106;
|
||||
let createdAbsence;
|
||||
|
||||
afterAll(async() => {
|
||||
const absence = await app.models.WorkerCalendar.findById(createdAbsence.id);
|
||||
await absence.destroy();
|
||||
});
|
||||
|
||||
it('should return an error for a user without enough privileges', async() => {
|
||||
const ctx = {req: {accessToken: {userId: 106}}};
|
||||
const absenceTypeId = 1;
|
||||
const dated = new Date();
|
||||
|
||||
let error;
|
||||
await app.models.Worker.createAbsence(ctx, workerId, absenceTypeId, dated).catch(e => {
|
||||
error = e;
|
||||
}).finally(() => {
|
||||
expect(error.message).toEqual(`You don't have enough privileges`);
|
||||
});
|
||||
|
||||
expect(error).toBeDefined();
|
||||
});
|
||||
|
||||
it('should create a new absence', async() => {
|
||||
const ctx = {req: {accessToken: {userId: 37}}};
|
||||
const absenceTypeId = 1;
|
||||
const dated = new Date();
|
||||
createdAbsence = await app.models.Worker.createAbsence(ctx, workerId, absenceTypeId, dated);
|
||||
|
||||
const expectedBusinessId = 106;
|
||||
const expectedAbsenceTypeId = 1;
|
||||
|
||||
expect(createdAbsence.businessFk).toEqual(expectedBusinessId);
|
||||
expect(createdAbsence.absenceTypeFk).toEqual(expectedAbsenceTypeId);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,38 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
|
||||
describe('Worker deleteAbsence()', () => {
|
||||
const workerId = 106;
|
||||
let createdAbsence;
|
||||
|
||||
it('should return an error for a user without enough privileges', async() => {
|
||||
const ctx = {req: {accessToken: {userId: 106}}};
|
||||
const businessId = 106;
|
||||
createdAbsence = await app.models.WorkerCalendar.create({
|
||||
businessFk: businessId,
|
||||
absenceTypeFk: 1,
|
||||
dated: new Date()
|
||||
});
|
||||
|
||||
let error;
|
||||
await app.models.Worker.deleteAbsence(ctx, workerId, createdAbsence.id).catch(e => {
|
||||
error = e;
|
||||
}).finally(() => {
|
||||
expect(error.message).toEqual(`You don't have enough privileges`);
|
||||
});
|
||||
|
||||
expect(error).toBeDefined();
|
||||
});
|
||||
|
||||
it('should create a new absence', async() => {
|
||||
const ctx = {req: {accessToken: {userId: 37}}};
|
||||
const businessId = 106;
|
||||
|
||||
expect(createdAbsence.businessFk).toEqual(businessId);
|
||||
|
||||
await app.models.Worker.deleteAbsence(ctx, workerId, createdAbsence.id);
|
||||
|
||||
const deletedAbsence = await app.models.WorkerCalendar.findById(createdAbsence.id);
|
||||
|
||||
expect(deletedAbsence).toBeNull();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,38 @@
|
|||
const app = require('vn-loopback/server/server');
|
||||
|
||||
describe('Worker updateAbsence()', () => {
|
||||
const workerId = 106;
|
||||
let createdAbsence;
|
||||
|
||||
afterAll(async() => {
|
||||
const absence = await app.models.WorkerCalendar.findById(createdAbsence.id);
|
||||
await absence.destroy();
|
||||
});
|
||||
|
||||
it('should return an error for a user without enough privileges', async() => {
|
||||
const ctx = {req: {accessToken: {userId: 106}}};
|
||||
const expectedAbsenceTypeId = 2;
|
||||
createdAbsence = await app.models.WorkerCalendar.create({
|
||||
businessFk: 106,
|
||||
absenceTypeFk: 1,
|
||||
dated: new Date()
|
||||
});
|
||||
|
||||
let error;
|
||||
await app.models.Worker.updateAbsence(ctx, workerId, createdAbsence.id, expectedAbsenceTypeId).catch(e => {
|
||||
error = e;
|
||||
}).finally(() => {
|
||||
expect(error.message).toEqual(`You don't have enough privileges`);
|
||||
});
|
||||
|
||||
expect(error).toBeDefined();
|
||||
});
|
||||
|
||||
it('should create a new absence', async() => {
|
||||
const ctx = {req: {accessToken: {userId: 37}}};
|
||||
const expectedAbsenceTypeId = 2;
|
||||
const updatedAbsence = await app.models.Worker.updateAbsence(ctx, workerId, createdAbsence.id, expectedAbsenceTypeId);
|
||||
|
||||
expect(updatedAbsence.absenceTypeFk).toEqual(expectedAbsenceTypeId);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,42 @@
|
|||
const UserError = require('vn-loopback/util/user-error');
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethodCtx('updateAbsence', {
|
||||
description: 'Updates a worker absence',
|
||||
accepts: [{
|
||||
arg: 'id',
|
||||
type: 'Number',
|
||||
description: 'The worker id',
|
||||
http: {source: 'path'}
|
||||
},
|
||||
{
|
||||
arg: 'absenceId',
|
||||
type: 'Number',
|
||||
required: true
|
||||
},
|
||||
{
|
||||
arg: 'absenceTypeId',
|
||||
type: 'Number',
|
||||
required: true
|
||||
}],
|
||||
returns: 'Object',
|
||||
http: {
|
||||
path: `/:id/updateAbsence`,
|
||||
verb: 'PATCH'
|
||||
}
|
||||
});
|
||||
|
||||
Self.updateAbsence = async(ctx, id, absenceId, absenceTypeId) => {
|
||||
const models = Self.app.models;
|
||||
const userId = ctx.req.accessToken.userId;
|
||||
const isSubordinate = await models.Worker.isSubordinate(ctx, id);
|
||||
const isTeamBoss = await models.Account.hasRole(userId, 'teamBoss');
|
||||
|
||||
if (!isSubordinate || (isSubordinate && userId == id && !isTeamBoss))
|
||||
throw new UserError(`You don't have enough privileges`);
|
||||
|
||||
const absence = await models.WorkerCalendar.findById(absenceId);
|
||||
|
||||
return absence.updateAttribute('absenceTypeFk', absenceTypeId);
|
||||
};
|
||||
};
|
|
@ -3,29 +3,22 @@
|
|||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "workerCalendar"
|
||||
"table": "workerCalendar2"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"businessFk": {
|
||||
"id": 1,
|
||||
"id": {
|
||||
"id": true,
|
||||
"type": "Number"
|
||||
},
|
||||
"workerFk": {
|
||||
"id": 2,
|
||||
"businessFk": {
|
||||
"type": "Number"
|
||||
},
|
||||
"dated": {
|
||||
"id": 3,
|
||||
"type": "Date"
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
"worker": {
|
||||
"type": "belongsTo",
|
||||
"model": "Worker",
|
||||
"foreignKey": "workerFk"
|
||||
},
|
||||
"absenceType": {
|
||||
"type": "belongsTo",
|
||||
"model": "AbsenceType",
|
||||
|
|
|
@ -4,4 +4,7 @@ module.exports = Self => {
|
|||
require('../methods/worker/isSubordinate')(Self);
|
||||
require('../methods/worker/getWorkedHours')(Self);
|
||||
require('../methods/worker/uploadFile')(Self);
|
||||
require('../methods/worker/createAbsence')(Self);
|
||||
require('../methods/worker/deleteAbsence')(Self);
|
||||
require('../methods/worker/updateAbsence')(Self);
|
||||
};
|
||||
|
|
|
@ -5,15 +5,19 @@
|
|||
</vn-crud-model>
|
||||
<div class="vn-w-lg">
|
||||
<vn-card class="vn-pa-sm calendars">
|
||||
<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">
|
||||
</vn-calendar>
|
||||
<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>
|
||||
<vn-side-menu side="right">
|
||||
|
@ -26,12 +30,19 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="vn-pt-md" style="overflow: hidden;">
|
||||
<vn-chip ng-repeat="absenceType in absenceTypes">
|
||||
<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 icon="check" ng-if="absenceType.id == $ctrl.absenceType.id"></vn-icon>
|
||||
</vn-avatar>
|
||||
{{absenceType.name}}
|
||||
</vn-chip>
|
||||
</div>
|
||||
</div>
|
||||
</vn-side-menu>
|
||||
</vn-side-menu>
|
||||
<vn-confirm
|
||||
vn-id="confirm"
|
||||
message="This item will be deleted"
|
||||
question="Are you sure you want to continue?">
|
||||
</vn-confirm>
|
||||
|
|
|
@ -43,15 +43,17 @@ class Controller extends Section {
|
|||
|
||||
set worker(value) {
|
||||
this._worker = value;
|
||||
if (!value) return;
|
||||
|
||||
let params = {
|
||||
workerFk: this.worker.id,
|
||||
started: this.started,
|
||||
ended: this.ended
|
||||
};
|
||||
this.$http.get(`WorkerCalendars/absences`, {params})
|
||||
.then(res => this.onData(res.data));
|
||||
if (value) {
|
||||
this.refresh().then(() => this.repaint());
|
||||
this.getIsSubordinate();
|
||||
}
|
||||
}
|
||||
|
||||
getIsSubordinate() {
|
||||
this.$http.get(`Workers/${this.worker.id}/isSubordinate`).then(res =>
|
||||
this.isSubordinate = res.data
|
||||
);
|
||||
}
|
||||
|
||||
onData(data) {
|
||||
|
@ -79,12 +81,12 @@ class Controller extends Section {
|
|||
let type = absence.absenceType;
|
||||
addEvent(absence.dated, {
|
||||
name: type.name,
|
||||
color: type.rgb
|
||||
color: type.rgb,
|
||||
type: type.code,
|
||||
absenceId: absence.id
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
this.repaint();
|
||||
}
|
||||
|
||||
repaint() {
|
||||
|
@ -102,6 +104,105 @@ class Controller extends Section {
|
|||
dayNumber.style.backgroundColor = event.color;
|
||||
dayNumber.style.color = 'rgba(0, 0, 0, 0.7)';
|
||||
}
|
||||
|
||||
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) {
|
||||
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
|
||||
};
|
||||
|
||||
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())
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
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())
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
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())
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
repaintCanceller(cb) {
|
||||
if (this.canceller) {
|
||||
clearTimeout(this.canceller);
|
||||
this.canceller = null;
|
||||
}
|
||||
|
||||
this.canceller = setTimeout(
|
||||
() => cb(), 500);
|
||||
}
|
||||
|
||||
refresh() {
|
||||
const params = {
|
||||
workerFk: this.worker.id,
|
||||
started: this.started,
|
||||
ended: this.ended
|
||||
};
|
||||
return this.$http.get(`WorkerCalendars/absences`, {params})
|
||||
.then(res => this.onData(res.data));
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.component('vnWorkerCalendar', {
|
||||
|
|
|
@ -3,17 +3,23 @@ import './index';
|
|||
describe('Worker', () => {
|
||||
describe('Component vnWorkerCalendar', () => {
|
||||
let $httpBackend;
|
||||
let $httpParamSerializer;
|
||||
let $scope;
|
||||
let controller;
|
||||
let year = new Date().getFullYear();
|
||||
|
||||
beforeEach(ngModule('worker'));
|
||||
|
||||
beforeEach(angular.mock.inject(($componentController, $rootScope, _$httpBackend_) => {
|
||||
beforeEach(angular.mock.inject(($componentController, $rootScope, _$httpParamSerializer_, _$httpBackend_) => {
|
||||
$scope = $rootScope.$new();
|
||||
$httpBackend = _$httpBackend_;
|
||||
const $element = angular.element('<vn-worker-calencar></vn-worker-calencar>');
|
||||
$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 = 106;
|
||||
controller._worker = {id: 106};
|
||||
}));
|
||||
|
||||
describe('started property', () => {
|
||||
|
@ -44,8 +50,9 @@ describe('Worker', () => {
|
|||
|
||||
describe('worker() setter', () => {
|
||||
it(`should perform a get query and set the reponse data on the model`, () => {
|
||||
let today = new Date();
|
||||
jest.spyOn(controller, 'getIsSubordinate').mockReturnValue(true);
|
||||
|
||||
let today = new Date();
|
||||
let tomorrow = new Date(today.getTime());
|
||||
tomorrow.setDate(tomorrow.getDate() + 1);
|
||||
|
||||
|
@ -64,7 +71,7 @@ describe('Worker', () => {
|
|||
]
|
||||
});
|
||||
|
||||
controller.worker = {id: 1};
|
||||
controller.worker = {id: 107};
|
||||
$httpBackend.flush();
|
||||
|
||||
let events = controller.events;
|
||||
|
@ -73,11 +80,14 @@ describe('Worker', () => {
|
|||
expect(events[tomorrow.getTime()].name).toEqual('Easter');
|
||||
expect(events[yesterday.getTime()].name).toEqual('Leave');
|
||||
expect(events[yesterday.getTime()].color).toEqual('#bbb');
|
||||
expect(controller.getIsSubordinate).toHaveBeenCalledWith();
|
||||
});
|
||||
});
|
||||
|
||||
describe('formatDay()', () => {
|
||||
it(`should set the day element style`, () => {
|
||||
jest.spyOn(controller, 'getIsSubordinate').mockReturnThis();
|
||||
|
||||
let today = new Date();
|
||||
|
||||
$httpBackend.whenRoute('GET', 'WorkerCalendars/absences')
|
||||
|
@ -99,5 +109,219 @@ describe('Worker', () => {
|
|||
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 = new Date();
|
||||
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 = new Date();
|
||||
const expectedEvent = {
|
||||
dated: selectedDay,
|
||||
type: 'holiday'
|
||||
};
|
||||
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 = new Date();
|
||||
const expectedEvent = {
|
||||
dated: selectedDay,
|
||||
type: 'leaveOfAbsence'
|
||||
};
|
||||
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 = new Date();
|
||||
const calendarElement = {};
|
||||
const expectedResponse = {id: 10};
|
||||
|
||||
$httpBackend.expect('POST', `Workers/106/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/106/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 = new Date();
|
||||
const expectedEvent = {
|
||||
dated: selectedDay,
|
||||
type: 'leaveOfAbsence',
|
||||
absenceId: 10
|
||||
};
|
||||
|
||||
controller.events[selectedDay.getTime()] = expectedEvent;
|
||||
|
||||
const serializedParams = $httpParamSerializer(expectedParams);
|
||||
$httpBackend.expect('DELETE', `Workers/106/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 dated = controller.date;
|
||||
const started = new Date(dated.getTime());
|
||||
started.setMonth(0);
|
||||
started.setDate(1);
|
||||
|
||||
const ended = new Date(dated.getTime());
|
||||
ended.setMonth(12);
|
||||
ended.setDate(0);
|
||||
|
||||
controller.started = started;
|
||||
controller.ended = ended;
|
||||
|
||||
const expecteResponse = [{id: 1}];
|
||||
const expectedParams = {workerFk: 106, started: started, ended: ended};
|
||||
const serializedParams = $httpParamSerializer(expectedParams);
|
||||
$httpBackend.expect('GET', `WorkerCalendars/absences?${serializedParams}`).respond(200, expecteResponse);
|
||||
controller.refresh();
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.onData).toHaveBeenCalledWith(expecteResponse);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -2,4 +2,6 @@ Calendar: Calendario
|
|||
Holidays: Vacaciones
|
||||
Used: Utilizados
|
||||
of: de
|
||||
days: días
|
||||
days: días
|
||||
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
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
vn-worker-calendar {
|
||||
.calendars {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
|
@ -16,4 +17,23 @@ vn-worker-calendar {
|
|||
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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,5 +28,8 @@
|
|||
},
|
||||
"ZoneWarehouse": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"ZoneEstimatedDelivery": {
|
||||
"dataSource": "vn"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
{
|
||||
"name": "ZoneEstimatedDelivery",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "zoneEstimatedDelivery"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"zoneFk": {
|
||||
"id": true,
|
||||
"type": "Number"
|
||||
},
|
||||
"hourTheoretical": {
|
||||
"type": "date"
|
||||
},
|
||||
"totalVolume": {
|
||||
"type": "Number"
|
||||
},
|
||||
"remainingVolume": {
|
||||
"type": "Number"
|
||||
},
|
||||
"speed": {
|
||||
"type": "Number"
|
||||
},
|
||||
"hourEffective": {
|
||||
"type": "Date"
|
||||
},
|
||||
"minutesLess": {
|
||||
"type": "Date"
|
||||
},
|
||||
"etc": {
|
||||
"type": "Date"
|
||||
}
|
||||
|
||||
},
|
||||
"relations": {
|
||||
"zone": {
|
||||
"type": "belongsTo",
|
||||
"model": "Zone",
|
||||
"foreignKey": "zoneFk"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4690,8 +4690,7 @@
|
|||
"ansi-regex": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
|
||||
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
|
||||
"dev": true
|
||||
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg="
|
||||
},
|
||||
"ansi-styles": {
|
||||
"version": "3.2.1",
|
||||
|
@ -4741,8 +4740,7 @@
|
|||
"aproba": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
|
||||
"integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="
|
||||
},
|
||||
"archy": {
|
||||
"version": "1.0.0",
|
||||
|
@ -4754,7 +4752,6 @@
|
|||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz",
|
||||
"integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"delegates": "^1.0.0",
|
||||
"readable-stream": "^2.0.6"
|
||||
|
@ -6610,8 +6607,7 @@
|
|||
"chownr": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.3.tgz",
|
||||
"integrity": "sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw=="
|
||||
},
|
||||
"chrome-trace-event": {
|
||||
"version": "1.0.2",
|
||||
|
@ -6820,8 +6816,7 @@
|
|||
"code-point-at": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
|
||||
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
|
||||
"dev": true
|
||||
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
|
||||
},
|
||||
"collect-v8-coverage": {
|
||||
"version": "1.0.1",
|
||||
|
@ -6850,11 +6845,19 @@
|
|||
"object-visit": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"color": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/color/-/color-3.1.2.tgz",
|
||||
"integrity": "sha512-vXTJhHebByxZn3lDvDJYw4lR5+uB3vuoHsuYA5AKuxRVn5wzzIfQKGLBmgdVRHKTJYeK5rvJcHnrd0Li49CFpg==",
|
||||
"requires": {
|
||||
"color-convert": "^1.9.1",
|
||||
"color-string": "^1.5.2"
|
||||
}
|
||||
},
|
||||
"color-convert": {
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-name": "1.1.3"
|
||||
}
|
||||
|
@ -6862,8 +6865,16 @@
|
|||
"color-name": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
|
||||
"dev": true
|
||||
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
|
||||
},
|
||||
"color-string": {
|
||||
"version": "1.5.3",
|
||||
"resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.3.tgz",
|
||||
"integrity": "sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==",
|
||||
"requires": {
|
||||
"color-name": "^1.0.0",
|
||||
"simple-swizzle": "^0.2.2"
|
||||
}
|
||||
},
|
||||
"color-support": {
|
||||
"version": "1.1.3",
|
||||
|
@ -7011,8 +7022,7 @@
|
|||
"console-control-strings": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
|
||||
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
|
||||
"dev": true
|
||||
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4="
|
||||
},
|
||||
"consolidate": {
|
||||
"version": "0.15.1",
|
||||
|
@ -7563,8 +7573,7 @@
|
|||
"delegates": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
|
||||
"integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=",
|
||||
"dev": true
|
||||
"integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o="
|
||||
},
|
||||
"denque": {
|
||||
"version": "1.4.1",
|
||||
|
@ -7604,6 +7613,11 @@
|
|||
"integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=",
|
||||
"dev": true
|
||||
},
|
||||
"detect-libc": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
|
||||
"integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups="
|
||||
},
|
||||
"detect-newline": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz",
|
||||
|
@ -8369,6 +8383,11 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"expand-template": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
|
||||
"integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg=="
|
||||
},
|
||||
"expand-tilde": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz",
|
||||
|
@ -9150,6 +9169,11 @@
|
|||
"readable-stream": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"fs-constants": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
|
||||
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="
|
||||
},
|
||||
"fs-extra": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-5.0.0.tgz",
|
||||
|
@ -9160,6 +9184,14 @@
|
|||
"universalify": "^0.1.0"
|
||||
}
|
||||
},
|
||||
"fs-minipass": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
|
||||
"integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==",
|
||||
"requires": {
|
||||
"minipass": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"fs-mkdirp-stream": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz",
|
||||
|
@ -9798,7 +9830,6 @@
|
|||
"version": "2.7.4",
|
||||
"resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
|
||||
"integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"aproba": "^1.0.3",
|
||||
"console-control-strings": "^1.0.0",
|
||||
|
@ -9813,14 +9844,12 @@
|
|||
"ansi-regex": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
|
||||
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
|
||||
"dev": true
|
||||
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
|
||||
},
|
||||
"is-fullwidth-code-point": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
|
||||
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"number-is-nan": "^1.0.0"
|
||||
}
|
||||
|
@ -9829,7 +9858,6 @@
|
|||
"version": "1.0.2",
|
||||
"resolved": "http://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
|
||||
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"code-point-at": "^1.0.0",
|
||||
"is-fullwidth-code-point": "^1.0.0",
|
||||
|
@ -9840,7 +9868,6 @@
|
|||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
|
||||
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^2.0.0"
|
||||
}
|
||||
|
@ -9948,6 +9975,11 @@
|
|||
"assert-plus": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"github-from-package": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
|
||||
"integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4="
|
||||
},
|
||||
"glob": {
|
||||
"version": "7.1.6",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
|
||||
|
@ -11293,8 +11325,7 @@
|
|||
"has-unicode": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
|
||||
"integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=",
|
||||
"dev": true
|
||||
"integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk="
|
||||
},
|
||||
"has-value": {
|
||||
"version": "1.0.0",
|
||||
|
@ -11897,8 +11928,7 @@
|
|||
"ini": {
|
||||
"version": "1.3.5",
|
||||
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
|
||||
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw=="
|
||||
},
|
||||
"inquirer": {
|
||||
"version": "6.4.1",
|
||||
|
@ -12137,8 +12167,7 @@
|
|||
"is-fullwidth-code-point": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
|
||||
"integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
|
||||
"dev": true
|
||||
"integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
|
||||
},
|
||||
"is-generator-fn": {
|
||||
"version": "2.1.0",
|
||||
|
@ -18662,6 +18691,37 @@
|
|||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
|
||||
},
|
||||
"minipass": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz",
|
||||
"integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==",
|
||||
"requires": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"minizlib": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.0.tgz",
|
||||
"integrity": "sha512-EzTZN/fjSvifSX0SlqUERCN39o6T40AMarPbv0MrarSFtIITCBh7bi+dU8nxGFHuqs9jdIAeoYoKuQAAASsPPA==",
|
||||
"requires": {
|
||||
"minipass": "^3.0.0",
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"mississippi": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz",
|
||||
|
@ -18739,6 +18799,11 @@
|
|||
"minimist": "^1.2.5"
|
||||
}
|
||||
},
|
||||
"mkdirp-classic": {
|
||||
"version": "0.5.3",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
|
||||
"integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A=="
|
||||
},
|
||||
"mktmpdir": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/mktmpdir/-/mktmpdir-0.1.1.tgz",
|
||||
|
@ -19079,6 +19144,11 @@
|
|||
"to-regex": "^3.0.1"
|
||||
}
|
||||
},
|
||||
"napi-build-utils": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz",
|
||||
"integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg=="
|
||||
},
|
||||
"natural-compare": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
|
||||
|
@ -19121,6 +19191,19 @@
|
|||
"resolved": "https://registry.npmjs.org/nocache/-/nocache-2.1.0.tgz",
|
||||
"integrity": "sha512-0L9FvHG3nfnnmaEQPjT9xhfN4ISk0A8/2j4M37Np4mcDesJjHgEUfgPhdCyZuFI954tjokaIj/A3NdpFNdEh4Q=="
|
||||
},
|
||||
"node-abi": {
|
||||
"version": "2.18.0",
|
||||
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.18.0.tgz",
|
||||
"integrity": "sha512-yi05ZoiuNNEbyT/xXfSySZE+yVnQW6fxPZuFbLyS1s6b5Kw3HzV2PHOM4XR+nsjzkHxByK+2Wg+yCQbe35l8dw==",
|
||||
"requires": {
|
||||
"semver": "^5.4.1"
|
||||
}
|
||||
},
|
||||
"node-addon-api": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.0.0.tgz",
|
||||
"integrity": "sha512-sSHCgWfJ+Lui/u+0msF3oyCgvdkhxDbkCS6Q8uiJquzOimkJBvX6hl5aSSA7DR1XbMpdM8r7phjcF63sF4rkKg=="
|
||||
},
|
||||
"node-fetch": {
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz",
|
||||
|
@ -19507,6 +19590,11 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"noop-logger": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz",
|
||||
"integrity": "sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI="
|
||||
},
|
||||
"nopt": {
|
||||
"version": "3.0.6",
|
||||
"resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz",
|
||||
|
@ -19561,7 +19649,6 @@
|
|||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
|
||||
"integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"are-we-there-yet": "~1.1.2",
|
||||
"console-control-strings": "~1.1.0",
|
||||
|
@ -19581,8 +19668,7 @@
|
|||
"number-is-nan": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
|
||||
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
|
||||
"dev": true
|
||||
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
|
||||
},
|
||||
"nwsapi": {
|
||||
"version": "2.2.0",
|
||||
|
@ -19598,8 +19684,7 @@
|
|||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
|
||||
"dev": true
|
||||
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
|
||||
},
|
||||
"object-copy": {
|
||||
"version": "0.1.0",
|
||||
|
@ -20381,6 +20466,53 @@
|
|||
"integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
|
||||
"dev": true
|
||||
},
|
||||
"prebuild-install": {
|
||||
"version": "5.3.5",
|
||||
"resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.3.5.tgz",
|
||||
"integrity": "sha512-YmMO7dph9CYKi5IR/BzjOJlRzpxGGVo1EsLSUZ0mt/Mq0HWZIHOKHHcHdT69yG54C9m6i45GpItwRHpk0Py7Uw==",
|
||||
"requires": {
|
||||
"detect-libc": "^1.0.3",
|
||||
"expand-template": "^2.0.3",
|
||||
"github-from-package": "0.0.0",
|
||||
"minimist": "^1.2.3",
|
||||
"mkdirp": "^0.5.1",
|
||||
"napi-build-utils": "^1.0.1",
|
||||
"node-abi": "^2.7.0",
|
||||
"noop-logger": "^0.1.1",
|
||||
"npmlog": "^4.0.1",
|
||||
"pump": "^3.0.0",
|
||||
"rc": "^1.2.7",
|
||||
"simple-get": "^3.0.3",
|
||||
"tar-fs": "^2.0.0",
|
||||
"tunnel-agent": "^0.6.0",
|
||||
"which-pm-runs": "^1.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"decompress-response": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz",
|
||||
"integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==",
|
||||
"requires": {
|
||||
"mimic-response": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"mimic-response": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz",
|
||||
"integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA=="
|
||||
},
|
||||
"simple-get": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz",
|
||||
"integrity": "sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==",
|
||||
"requires": {
|
||||
"decompress-response": "^4.2.0",
|
||||
"once": "^1.3.1",
|
||||
"simple-concat": "^1.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"prelude-ls": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
|
||||
|
@ -20729,7 +20861,6 @@
|
|||
"version": "1.2.8",
|
||||
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
|
||||
"integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"deep-extend": "^0.6.0",
|
||||
"ini": "~1.3.0",
|
||||
|
@ -20740,8 +20871,7 @@
|
|||
"deep-extend": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
|
||||
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -21723,8 +21853,7 @@
|
|||
"set-blocking": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
|
||||
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
|
||||
"dev": true
|
||||
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
|
||||
},
|
||||
"set-value": {
|
||||
"version": "2.0.1",
|
||||
|
@ -21779,6 +21908,57 @@
|
|||
"kind-of": "^6.0.2"
|
||||
}
|
||||
},
|
||||
"sharp": {
|
||||
"version": "0.25.4",
|
||||
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.25.4.tgz",
|
||||
"integrity": "sha512-umSzJJ1oBwIOfwFFt/fJ7JgCva9FvrEU2cbbm7u/3hSDZhXvkME8WE5qpaJqLIe2Har5msF5UG4CzYlEg5o3BQ==",
|
||||
"requires": {
|
||||
"color": "^3.1.2",
|
||||
"detect-libc": "^1.0.3",
|
||||
"node-addon-api": "^3.0.0",
|
||||
"npmlog": "^4.1.2",
|
||||
"prebuild-install": "^5.3.4",
|
||||
"semver": "^7.3.2",
|
||||
"simple-get": "^4.0.0",
|
||||
"tar": "^6.0.2",
|
||||
"tunnel-agent": "^0.6.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"chownr": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
|
||||
"integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
|
||||
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="
|
||||
},
|
||||
"semver": {
|
||||
"version": "7.3.2",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz",
|
||||
"integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ=="
|
||||
},
|
||||
"tar": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/tar/-/tar-6.0.2.tgz",
|
||||
"integrity": "sha512-Glo3jkRtPcvpDlAs/0+hozav78yoXKFr+c4wgw62NNMO3oo4AaJdCo21Uu7lcwr55h39W2XD1LMERc64wtbItg==",
|
||||
"requires": {
|
||||
"chownr": "^2.0.0",
|
||||
"fs-minipass": "^2.0.0",
|
||||
"minipass": "^3.0.0",
|
||||
"minizlib": "^2.1.0",
|
||||
"mkdirp": "^1.0.3",
|
||||
"yallist": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"shebang-command": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
|
||||
|
@ -21822,6 +22002,51 @@
|
|||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
|
||||
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0="
|
||||
},
|
||||
"simple-concat": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.0.tgz",
|
||||
"integrity": "sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY="
|
||||
},
|
||||
"simple-get": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.0.tgz",
|
||||
"integrity": "sha512-ZalZGexYr3TA0SwySsr5HlgOOinS4Jsa8YB2GJ6lUNAazyAu4KG/VmzMTwAt2YVXzzVj8QmefmAonZIK2BSGcQ==",
|
||||
"requires": {
|
||||
"decompress-response": "^6.0.0",
|
||||
"once": "^1.3.1",
|
||||
"simple-concat": "^1.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"decompress-response": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
|
||||
"integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
|
||||
"requires": {
|
||||
"mimic-response": "^3.1.0"
|
||||
}
|
||||
},
|
||||
"mimic-response": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
|
||||
"integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"simple-swizzle": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
|
||||
"integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=",
|
||||
"requires": {
|
||||
"is-arrayish": "^0.3.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"is-arrayish": {
|
||||
"version": "0.3.2",
|
||||
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
|
||||
"integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"sisteransi": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
|
||||
|
@ -22442,7 +22667,6 @@
|
|||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
|
||||
"integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-fullwidth-code-point": "^2.0.0",
|
||||
"strip-ansi": "^4.0.0"
|
||||
|
@ -22460,7 +22684,6 @@
|
|||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
|
||||
"integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^3.0.0"
|
||||
}
|
||||
|
@ -22496,8 +22719,7 @@
|
|||
"strip-json-comments": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
|
||||
"integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
|
||||
"dev": true
|
||||
"integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo="
|
||||
},
|
||||
"strong-error-handler": {
|
||||
"version": "2.3.2",
|
||||
|
@ -23080,6 +23302,60 @@
|
|||
"inherits": "2"
|
||||
}
|
||||
},
|
||||
"tar-fs": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.0.tgz",
|
||||
"integrity": "sha512-9uW5iDvrIMCVpvasdFHW0wJPez0K4JnMZtsuIeDI7HyMGJNxmDZDOCQROr7lXyS+iL/QMpj07qcjGYTSdRFXUg==",
|
||||
"requires": {
|
||||
"chownr": "^1.1.1",
|
||||
"mkdirp-classic": "^0.5.2",
|
||||
"pump": "^3.0.0",
|
||||
"tar-stream": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"tar-stream": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.3.tgz",
|
||||
"integrity": "sha512-Z9yri56Dih8IaK8gncVPx4Wqt86NDmQTSh49XLZgjWpGZL9GK9HKParS2scqHCC4w6X9Gh2jwaU45V47XTKwVA==",
|
||||
"requires": {
|
||||
"bl": "^4.0.1",
|
||||
"end-of-stream": "^1.4.1",
|
||||
"fs-constants": "^1.0.0",
|
||||
"inherits": "^2.0.3",
|
||||
"readable-stream": "^3.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"bl": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/bl/-/bl-4.0.2.tgz",
|
||||
"integrity": "sha512-j4OH8f6Qg2bGuWfRiltT2HYGx0e1QcBTrK9KAHNMwMZdQnDZFk0ZSYIpADjYCB3U12nicC5tVJwSIhwOWjb4RQ==",
|
||||
"requires": {
|
||||
"buffer": "^5.5.0",
|
||||
"inherits": "^2.0.4",
|
||||
"readable-stream": "^3.4.0"
|
||||
}
|
||||
},
|
||||
"buffer": {
|
||||
"version": "5.6.0",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz",
|
||||
"integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==",
|
||||
"requires": {
|
||||
"base64-js": "^1.0.2",
|
||||
"ieee754": "^1.1.4"
|
||||
}
|
||||
},
|
||||
"readable-stream": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
|
||||
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
|
||||
"requires": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"teeny-request": {
|
||||
"version": "3.11.3",
|
||||
"resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-3.11.3.tgz",
|
||||
|
@ -25048,11 +25324,15 @@
|
|||
"integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=",
|
||||
"dev": true
|
||||
},
|
||||
"which-pm-runs": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.0.0.tgz",
|
||||
"integrity": "sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs="
|
||||
},
|
||||
"wide-align": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
|
||||
"integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"string-width": "^1.0.2 || 2"
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
"request": "^2.88.0",
|
||||
"request-promise-native": "^1.0.8",
|
||||
"require-yaml": "0.0.1",
|
||||
"sharp": "^0.25.4",
|
||||
"soap": "^0.26.0",
|
||||
"strong-error-handler": "^2.3.2",
|
||||
"uuid": "^3.3.3",
|
||||
|
|
Loading…
Reference in New Issue