diff --git a/Dockerfile b/Dockerfile
index 5a65b9b18..a574e61fd 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -8,7 +8,7 @@ RUN apt-get update \
ca-certificates \
gnupg2 \
libfontconfig \
- && curl -sL https://deb.nodesource.com/setup_10.x | bash - \
+ && curl -sL https://deb.nodesource.com/setup_12.x | bash - \
&& apt-get install -y --no-install-recommends \
nodejs \
&& apt-get purge -y --auto-remove \
diff --git a/README.md b/README.md
index 8960c8d00..52f854b6e 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@ Salix is also the scientific name of a beautifull tree! :)
Required applications.
* Visual Studio Code
-* Node.js = 10.15.3 LTS
+* Node.js = 12.17.0 LTS
* Docker
In Visual Studio Code we use the ESLint extension. Open Visual Studio Code, press Ctrl+P and paste the following command.
diff --git a/db/changes/10180-holyWeek/00-ACL.sql b/db/changes/10180-holyWeek/00-ACL.sql
new file mode 100644
index 000000000..b0ab68a97
--- /dev/null
+++ b/db/changes/10180-holyWeek/00-ACL.sql
@@ -0,0 +1 @@
+INSERT IGNORE INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('WorkerLog', '*', 'READ', 'ALLOW', 'ROLE', 'hr');
\ No newline at end of file
diff --git a/db/changes/10190-PostErte/00-ACL.sql b/db/changes/10190-PostErte/00-ACL.sql
new file mode 100644
index 000000000..2a2673fcc
--- /dev/null
+++ b/db/changes/10190-PostErte/00-ACL.sql
@@ -0,0 +1,4 @@
+UPDATE `salix`.`ACL` SET `accessType`='WRITE' WHERE `id`='213';
+
+INSERT IGNORE INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('CustomsAgent', '*', '*', 'ALLOW', 'ROLE', 'employee');
+
diff --git a/e2e/helpers/selectors.js b/e2e/helpers/selectors.js
index ecf0d37e3..b12c470f5 100644
--- a/e2e/helpers/selectors.js
+++ b/e2e/helpers/selectors.js
@@ -122,6 +122,12 @@ export default {
mobileInput: 'vn-textfield[ng-model="$ctrl.address.mobile"]',
defaultAddress: 'vn-client-address-index div:nth-child(1) div[name="street"]',
incoterms: 'vn-autocomplete[ng-model="$ctrl.address.incotermsId"]',
+ addNewCustomsAgent: 'vn-client-address-create vn-autocomplete[ng-model="$ctrl.address.customsAgentId"] vn-icon-button[icon="add_circle"]',
+ newCustomsAgentFiscalID: 'vn-textfield[ng-model="$ctrl.newCustomsAgent.nif"]',
+ newCustomsAgentFiscalName: 'vn-textfield[ng-model="$ctrl.newCustomsAgent.fiscalName"]',
+ newCustomsAgentStreet: 'vn-textfield[ng-model="$ctrl.newCustomsAgent.street"]',
+ newCustomsAgentPhone: 'vn-textfield[ng-model="$ctrl.newCustomsAgent.phone"]',
+ saveNewCustomsAgentButton: 'button[response="accept"]',
customsAgent: 'vn-autocomplete[ng-model="$ctrl.address.customsAgentId"]',
secondMakeDefaultStar: 'vn-client-address-index vn-card div:nth-child(2) vn-icon-button[icon="star_border"]',
firstEditAddress: 'vn-client-address-index div:nth-child(1) > a',
@@ -828,6 +834,12 @@ export default {
},
travelThermograph: {
add: 'vn-travel-thermograph-index vn-float-button[icon="add"]',
+ addThermographIcon: 'vn-travel-thermograph-create vn-autocomplete vn-icon[icon="add_circle"]',
+ newThermographId: 'vn-textfield[ng-model="$ctrl.newThermograph.thermographId"]',
+ newThermographModel: 'vn-autocomplete[ng-model="$ctrl.newThermograph.model"]',
+ newThermographWarehouse: 'vn-autocomplete[ng-model="$ctrl.newThermograph.warehouseId"]',
+ newThermographTemperature: 'vn-autocomplete[ng-model="$ctrl.newThermograph.temperature"]',
+ createThermographButton: 'form button[response="accept"]',
thermographID: 'vn-travel-thermograph-create vn-autocomplete[ng-model="$ctrl.dms.thermographId"]',
uploadIcon: 'vn-travel-thermograph-create vn-icon[icon="icon-attach"]',
createdThermograph: 'vn-travel-thermograph-index vn-tbody > vn-tr',
diff --git a/e2e/paths/02-client/05_add_address.spec.js b/e2e/paths/02-client/05_add_address.spec.js
index 2fe238fea..f16408b34 100644
--- a/e2e/paths/02-client/05_add_address.spec.js
+++ b/e2e/paths/02-client/05_add_address.spec.js
@@ -61,12 +61,18 @@ describe('Client Add address path', () => {
expect(message.text).toBe('Customs agent is required for a non UEE member');
});
- it(`should create a new address with all it's data`, async() => {
- await page.autocompleteSearch(selectors.clientAddresses.customsAgent, 'Agent one');
+ it(`should create a new custom agent and then save the address`, async() => {
+ await page.waitToClick(selectors.clientAddresses.addNewCustomsAgent);
+ await page.write(selectors.clientAddresses.newCustomsAgentFiscalID, 'ID');
+ await page.write(selectors.clientAddresses.newCustomsAgentFiscalName, 'name');
+ await page.write(selectors.clientAddresses.newCustomsAgentStreet, 'street');
+ await page.write(selectors.clientAddresses.newCustomsAgentPhone, '555555555');
+ await page.waitToClick(selectors.clientAddresses.saveNewCustomsAgentButton);
+
await page.waitToClick(selectors.clientAddresses.saveButton);
const message = await page.waitForSnackbar();
- expect(message.type).toBe('success');
+ expect(message.text).toBe('Data saved!');
});
it(`should navigate back to the addresses index`, async() => {
diff --git a/e2e/paths/10-travel/01_thermograph.spec.js b/e2e/paths/10-travel/01_thermograph.spec.js
index 67a62381a..e7f1e234d 100644
--- a/e2e/paths/10-travel/01_thermograph.spec.js
+++ b/e2e/paths/10-travel/01_thermograph.spec.js
@@ -2,6 +2,7 @@ import selectors from '../../helpers/selectors.js';
import getBrowser from '../../helpers/puppeteer';
describe('Travel thermograph path', () => {
+ const thermographName = '7H3-37H3RN4L-FL4M3';
let browser;
let page;
@@ -26,10 +27,18 @@ describe('Travel thermograph path', () => {
await page.waitForState('travel.card.thermograph.create');
});
- it('should select the thermograph and then the file to upload', async() => {
+ it('should click on the add thermograph icon of the thermograph autocomplete', async() => {
+ await page.waitToClick(selectors.travelThermograph.addThermographIcon);
+ await page.write(selectors.travelThermograph.newThermographId, thermographName);
+ await page.autocompleteSearch(selectors.travelThermograph.newThermographModel, 'TEMPMATE');
+ await page.autocompleteSearch(selectors.travelThermograph.newThermographWarehouse, 'Warehouse Two');
+ await page.autocompleteSearch(selectors.travelThermograph.newThermographTemperature, 'WARM');
+ await page.waitToClick(selectors.travelThermograph.createThermographButton);
+ });
+
+ it('should select the file to upload', async() => {
let currentDir = process.cwd();
let filePath = `${currentDir}/e2e/dms/ecc/3.jpeg`;
- await page.autocompleteSearch(selectors.travelThermograph.thermographID, '138350-0');
const [fileChooser] = await Promise.all([
page.waitForFileChooser(),
@@ -38,11 +47,17 @@ describe('Travel thermograph path', () => {
await fileChooser.accept([filePath]);
await page.waitToClick(selectors.travelThermograph.upload);
+
+ const message = await page.waitForSnackbar();
+ const state = await page.getState();
+
+ expect(message.type).toBe('success');
+ expect(state).toBe('travel.card.thermograph.index');
});
- it('should reload the section and check everything was saved', async() => {
- let createdThermograph = await page.waitToGetProperty(selectors.travelThermograph.createdThermograph, 'innerText');
+ it('should check everything was saved correctly', async() => {
+ const result = await page.waitToGetProperty(selectors.travelThermograph.createdThermograph, 'innerText');
- expect(createdThermograph).toContain('138350-0');
+ expect(result).toContain(thermographName);
});
});
diff --git a/loopback/common/methods/vn-model/getEnumValues.js b/loopback/common/methods/vn-model/getEnumValues.js
new file mode 100644
index 000000000..0bc8f8eb6
--- /dev/null
+++ b/loopback/common/methods/vn-model/getEnumValues.js
@@ -0,0 +1,55 @@
+const UserError = require('vn-loopback/util/user-error');
+
+module.exports = Self => {
+ /**
+ * Returns a set of allowed values defined on table scheme
+ * @param {String} column - Model or Table column name
+ * @return {Array} - Array of set values
+ */
+ Self.getEnumValues = async function(column) {
+ let model = this.app.models[this.modelName].definition;
+ let properties = model.properties;
+ let tableName = this.modelName;
+ let schema = null;
+
+ if (model.settings && model.settings.mysql) {
+ let tableSplit = model.settings.mysql.table.split('.');
+ tableName = tableSplit.pop();
+ schema = tableSplit.pop() || null;
+ }
+
+ let property = properties[column];
+
+ if (!property)
+ throw new UserError(`Column does not exist`);
+
+ let columnName = property.mysql
+ ? property.mysql.columnName
+ : column;
+
+ let columnInfo = await this.rawSql(
+ `SELECT column_type columnType
+ FROM information_schema.columns
+ WHERE table_name = ?
+ AND table_schema = IFNULL(?, DATABASE())
+ AND column_name = ?`,
+ [tableName, schema, columnName]
+ );
+
+ if (!columnInfo || !columnInfo[0])
+ throw new UserError(`Cannot fetch column values`);
+
+ let setValues;
+ setValues = columnInfo[0].columnType
+ .replace(/^enum\((.*)\)$/i, '$1')
+ .replace(/'/g, '')
+ .match(new RegExp(/(\w+)+/, 'ig'));
+
+ let values = [];
+ setValues.forEach(setValue => {
+ values.push({value: setValue});
+ });
+
+ return values;
+ };
+};
diff --git a/loopback/common/methods/vn-model/specs/getEnumValues.spec.js b/loopback/common/methods/vn-model/specs/getEnumValues.spec.js
new file mode 100644
index 000000000..b49a952e4
--- /dev/null
+++ b/loopback/common/methods/vn-model/specs/getEnumValues.spec.js
@@ -0,0 +1,18 @@
+const app = require('vn-loopback/server/server');
+
+describe('Model getEnumValues()', () => {
+ it('should extend getEnumValues properties to any model passed', () => {
+ let exampleModel = app.models.TravelThermograph;
+
+ expect(exampleModel.getEnumValues).toBeDefined();
+ });
+
+ it('should return an array of enum values from a given column', async() => {
+ let result = await app.models.TravelThermograph.getSetValues('temperature');
+
+ expect(result.length).toEqual(3);
+ expect(result[0].value).toEqual('enum');
+ expect(result[1].value).toEqual('COOL');
+ expect(result[2].value).toEqual('WARM');
+ });
+});
diff --git a/loopback/common/models/loggable.js b/loopback/common/models/loggable.js
index d9116a0de..ec6989717 100644
--- a/loopback/common/models/loggable.js
+++ b/loopback/common/models/loggable.js
@@ -12,23 +12,34 @@ module.exports = function(Self) {
});
Self.observe('before save', async function(ctx) {
- let options = {};
+ const appModels = ctx.Model.app.models;
+ const definition = ctx.Model.definition;
+ const options = {};
+
+ // Check for transactions
if (ctx.options && ctx.options.transaction)
options.transaction = ctx.options.transaction;
let oldInstance;
- let oldInstanceFk;
let newInstance;
if (ctx.data) {
- oldInstanceFk = pick(ctx.currentInstance, Object.keys(ctx.data));
+ const changes = pick(ctx.currentInstance, Object.keys(ctx.data));
newInstance = await fkToValue(ctx.data, ctx);
- oldInstance = await fkToValue(oldInstanceFk, ctx);
+ oldInstance = await fkToValue(changes, ctx);
+
if (ctx.where && !ctx.currentInstance) {
- let fields = Object.keys(ctx.data);
- ctx.oldInstances = await ctx.Model.app.models[ctx.Model.definition.name].find({where: ctx.where, fields: fields}, options);
+ const fields = Object.keys(ctx.data);
+ const modelName = definition.name;
+
+ ctx.oldInstances = await appModels[modelName].find({
+ where: ctx.where,
+ fields: fields
+ }, options);
}
}
+
+ // Get changes from created instance
if (ctx.isNewInstance)
newInstance = await fkToValue(ctx.instance.__data, ctx);
@@ -37,18 +48,24 @@ module.exports = function(Self) {
});
Self.observe('before delete', async function(ctx) {
+ const appModels = ctx.Model.app.models;
+ const definition = ctx.Model.definition;
+ const relations = ctx.Model.relations;
+
let options = {};
if (ctx.options && ctx.options.transaction)
options.transaction = ctx.options.transaction;
if (ctx.where) {
- let affectedModel = ctx.Model.definition.name;
- let definition = ctx.Model.definition;
- let deletedInstances = await ctx.Model.app.models[affectedModel].find({where: ctx.where}, options);
+ let affectedModel = definition.name;
+ let deletedInstances = await appModels[affectedModel].find({
+ where: ctx.where
+ }, options);
+
let relation = definition.settings.log.relation;
if (relation) {
- let primaryKey = ctx.Model.relations[relation].keyFrom;
+ let primaryKey = relations[relation].keyFrom;
let arrangedDeletedInstances = [];
for (let i = 0; i < deletedInstances.length; i++) {
@@ -69,6 +86,8 @@ module.exports = function(Self) {
});
async function logDeletedInstances(ctx, loopBackContext) {
+ const appModels = ctx.Model.app.models;
+ const definition = ctx.Model.definition;
let options = {};
if (ctx.options && ctx.options.transaction)
options.transaction = ctx.options.transaction;
@@ -78,14 +97,12 @@ module.exports = function(Self) {
if (loopBackContext)
userFk = loopBackContext.active.accessToken.userId;
- let definition = ctx.Model.definition;
-
let changedModelValue = definition.settings.log.changedModelValue;
let logRecord = {
originFk: instance.originFk,
userFk: userFk,
action: 'delete',
- changedModel: ctx.Model.definition.name,
+ changedModel: definition.name,
changedModelId: instance.id,
changedModelValue: instance[changedModelValue],
oldInstance: instance,
@@ -95,26 +112,44 @@ module.exports = function(Self) {
delete instance.originFk;
let logModel = definition.settings.log.model;
- await ctx.Model.app.models[logModel].create(logRecord, options);
+ await appModels[logModel].create(logRecord, options);
});
}
+ // Get log values from a foreign key
async function fkToValue(instance, ctx) {
+ const appModels = ctx.Model.app.models;
+ const relations = ctx.Model.relations;
let options = {};
+
+ // Check for transactions
if (ctx.options && ctx.options.transaction)
options.transaction = ctx.options.transaction;
- let cleanInstance = JSON.parse(JSON.stringify(instance));
- let result = {};
- for (let key in cleanInstance) {
- let val = cleanInstance[key];
- if (val === undefined || val === null) continue;
- for (let key1 in ctx.Model.relations) {
- let val1 = ctx.Model.relations[key1];
- if (val1.keyFrom == key && key != 'id') {
- let recordSet = await ctx.Model.app.models[val1.modelTo.modelName].findById(val, null, options);
+ const instanceCopy = JSON.parse(JSON.stringify(instance));
+ const result = {};
+ for (const key in instanceCopy) {
+ let value = instanceCopy[key];
+
+ if (value instanceof Object)
+ continue;
+
+ if (value === undefined || value === null) continue;
+
+ for (let relationName in relations) {
+ const relation = relations[relationName];
+ if (relation.keyFrom == key && key != 'id') {
+ const model = relation.modelTo;
+ const modelName = relation.modelTo.modelName;
+ const properties = model && model.definition.properties;
+ const settings = model && model.definition.settings;
+
+ const recordSet = await appModels[modelName].findById(value, null, options);
+
+ const hasShowField = settings.log && settings.log.showField;
+ let showField = hasShowField && recordSet
+ && recordSet[settings.log.showField];
- let showField = val1.modelTo && val1.modelTo.definition.settings.log && val1.modelTo.definition.settings.log.showField && recordSet && recordSet[val1.modelTo.definition.settings.log.showField];
if (!showField) {
const showFieldNames = [
'name',
@@ -122,7 +157,10 @@ module.exports = function(Self) {
'code'
];
for (field of showFieldNames) {
- if (val1.modelTo.definition.properties && val1.modelTo.definition.properties[field] && recordSet && recordSet[field]) {
+ const propField = properties && properties[field];
+ const recordField = recordSet && recordSet[field];
+
+ if (propField && recordField) {
showField = field;
break;
}
@@ -130,25 +168,29 @@ module.exports = function(Self) {
}
if (showField && recordSet && recordSet[showField]) {
- val = recordSet[showField];
+ value = recordSet[showField];
break;
}
- val = recordSet && recordSet.id || val;
+ value = recordSet && recordSet.id || value;
break;
}
}
- result[key] = val;
+ result[key] = value;
}
return result;
}
async function logInModel(ctx, loopBackContext) {
- let options = {};
+ const appModels = ctx.Model.app.models;
+ const definition = ctx.Model.definition;
+ const defSettings = ctx.Model.definition.settings;
+ const relations = ctx.Model.relations;
+
+ const options = {};
if (ctx.options && ctx.options.transaction)
options.transaction = ctx.options.transaction;
- let definition = ctx.Model.definition;
let primaryKey;
for (let property in definition.properties) {
if (definition.properties[property].id) {
@@ -163,11 +205,11 @@ module.exports = function(Self) {
// RELATIONS LOG
let changedModelId;
- if (ctx.instance && !definition.settings.log.relation) {
+ if (ctx.instance && !defSettings.log.relation) {
originId = ctx.instance.id;
changedModelId = ctx.instance.id;
- } else if (definition.settings.log.relation) {
- primaryKey = ctx.Model.relations[definition.settings.log.relation].keyFrom;
+ } else if (defSettings.log.relation) {
+ primaryKey = relations[defSettings.log.relation].keyFrom;
if (ctx.where && ctx.where[primaryKey])
originId = ctx.where[primaryKey];
@@ -181,12 +223,16 @@ module.exports = function(Self) {
}
// Sets the changedModelValue to save and the instances changed in case its an updateAll
- let showField = definition.settings.log.showField;
+ let showField = defSettings.log.showField;
let where;
if (showField && (!ctx.instance || !ctx.instance[showField]) && ctx.where) {
changedModelId = [];
where = [];
- let changedInstances = await ctx.Model.app.models[definition.name].find({where: ctx.where, fields: ['id', showField, primaryKey]}, options);
+ let changedInstances = await appModels[definition.name].find({
+ where: ctx.where,
+ fields: ['id', showField, primaryKey]
+ }, options);
+
changedInstances.forEach(element => {
where.push(element[showField]);
changedModelId.push(element.id);
@@ -195,7 +241,6 @@ module.exports = function(Self) {
} else if (ctx.hookState.oldInstance)
where = ctx.instance[showField];
-
// Set oldInstance, newInstance, userFk and action
let oldInstance = {};
if (ctx.hookState.oldInstance)
@@ -211,14 +256,14 @@ module.exports = function(Self) {
let action = setActionType(ctx);
- removeUnloggableProperties(definition, oldInstance);
- removeUnloggableProperties(definition, newInstance);
+ removeUnloggable(definition, oldInstance);
+ removeUnloggable(definition, newInstance);
let logRecord = {
originFk: originId,
userFk: userFk,
action: action,
- changedModel: ctx.Model.definition.name,
+ changedModel: definition.name,
changedModelId: changedModelId, // Model property with an different data type will throw a NaN error
changedModelValue: where,
oldInstance: oldInstance,
@@ -226,9 +271,9 @@ module.exports = function(Self) {
};
let logsToSave = setLogsToSave(where, changedModelId, logRecord, ctx);
- let logModel = definition.settings.log.model;
+ let logModel = defSettings.log.model;
- await ctx.Model.app.models[logModel].create(logsToSave, options);
+ await appModels[logModel].create(logsToSave, options);
}
/**
@@ -236,7 +281,7 @@ module.exports = function(Self) {
* @param {*} definition Model definition
* @param {*} properties Modified object properties
*/
- function removeUnloggableProperties(definition, properties) {
+ function removeUnloggable(definition, properties) {
const propList = Object.keys(properties);
const propDefs = new Map();
diff --git a/loopback/common/models/vn-model.js b/loopback/common/models/vn-model.js
index d65ca71df..f56183df2 100644
--- a/loopback/common/models/vn-model.js
+++ b/loopback/common/models/vn-model.js
@@ -6,6 +6,7 @@ module.exports = function(Self) {
Self.ParameterizedSQL = ParameterizedSQL;
require('../methods/vn-model/getSetValues')(Self);
+ require('../methods/vn-model/getEnumValues')(Self);
Object.assign(Self, {
setup() {
diff --git a/loopback/locale/es.json b/loopback/locale/es.json
index eeb18fb73..d77b6d290 100644
--- a/loopback/locale/es.json
+++ b/loopback/locale/es.json
@@ -132,5 +132,5 @@
"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",
- "AMOUNT_NOT_MATCH_GROUPING": "AMOUNT_NOT_MATCH_GROUPING"
+ "This thermograph id already exists": "La id del termógrafo ya existe"
}
\ No newline at end of file
diff --git a/modules/client/front/address/create/index.js b/modules/client/front/address/create/index.js
index b1629073d..79774cf93 100644
--- a/modules/client/front/address/create/index.js
+++ b/modules/client/front/address/create/index.js
@@ -29,7 +29,7 @@ export default class Controller extends Section {
onCustomAgentAccept() {
return this.$http.post(`CustomsAgents`, this.newCustomsAgent)
- .then(res => this.address.customsAgentFk = res.data.id);
+ .then(res => this.address.customsAgentId = res.data.id);
}
get town() {
diff --git a/modules/client/front/address/create/index.spec.js b/modules/client/front/address/create/index.spec.js
index fb6567dce..4f332e75e 100644
--- a/modules/client/front/address/create/index.spec.js
+++ b/modules/client/front/address/create/index.spec.js
@@ -123,7 +123,7 @@ describe('Client', () => {
controller.onCustomAgentAccept();
$httpBackend.flush();
- expect(controller.address.customsAgentFk).toEqual(1);
+ expect(controller.address.customsAgentId).toEqual(1);
});
});
});
diff --git a/modules/client/front/address/edit/index.spec.js b/modules/client/front/address/edit/index.spec.js
index b67138b6d..c4c1a78b5 100644
--- a/modules/client/front/address/edit/index.spec.js
+++ b/modules/client/front/address/edit/index.spec.js
@@ -64,7 +64,7 @@ describe('Client', () => {
});
describe('onCustomAgentAccept()', () => {
- it(`should create a new customs agent and then set the customsAgentFk property on the address`, () => {
+ it(`should now create a new customs agent and then set the customsAgentFk property on the address`, () => {
const expectedResult = {id: 1, fiscalName: 'Customs agent one'};
$httpBackend.when('POST', 'CustomsAgents').respond(200, expectedResult);
controller.onCustomAgentAccept();
diff --git a/modules/order/back/methods/order/getSourceValues.js b/modules/order/back/methods/order/getSourceValues.js
index da3685c62..5e9f0e6dc 100644
--- a/modules/order/back/methods/order/getSourceValues.js
+++ b/modules/order/back/methods/order/getSourceValues.js
@@ -12,7 +12,7 @@ module.exports = Self => {
}
});
- Self.getSourceValues = async () => {
+ Self.getSourceValues = async() => {
return Self.getSetValues('sourceApp');
};
};
diff --git a/modules/travel/back/methods/thermograph/createThermograph.js b/modules/travel/back/methods/thermograph/createThermograph.js
new file mode 100644
index 000000000..bfca208fe
--- /dev/null
+++ b/modules/travel/back/methods/thermograph/createThermograph.js
@@ -0,0 +1,60 @@
+module.exports = Self => {
+ Self.remoteMethod('createThermograph', {
+ description: 'Creates a new thermograph',
+ accessType: 'WRITE',
+ accepts: [{
+ arg: 'thermographId',
+ type: 'String',
+ description: 'The thermograph id',
+ required: true
+ }, {
+ arg: 'model',
+ type: 'String',
+ description: 'The thermograph model',
+ required: true
+ }, {
+ arg: 'temperature',
+ type: 'String',
+ description: 'The thermograph temperature',
+ required: true
+ }, {
+ arg: 'warehouseId',
+ type: 'Number',
+ description: 'The warehouse id',
+ required: true
+ }],
+ returns: {
+ type: 'Object',
+ root: true
+ },
+ http: {
+ path: `/createThermograph`,
+ verb: 'POST'
+ }
+ });
+
+ Self.createThermograph = async(thermographId, model, temperature, warehouseId) => {
+ const models = Self.app.models;
+ const tx = await Self.beginTransaction({});
+
+ try {
+ const options = {transaction: tx};
+ const thermograph = await models.Thermograph.create({
+ id: thermographId,
+ model: model
+ }, options);
+
+ await Self.rawSql(`
+ INSERT INTO travelThermograph(thermographFk, warehouseFk, temperature, created)
+ VALUES (?, ?,?, NOW())
+ `, [thermograph.id, warehouseId, temperature], options);
+
+ await tx.commit();
+
+ return thermograph;
+ } catch (err) {
+ await tx.rollback();
+ throw err;
+ }
+ };
+};
diff --git a/modules/travel/back/methods/thermograph/getThermographModels.js b/modules/travel/back/methods/thermograph/getThermographModels.js
new file mode 100644
index 000000000..188c3a530
--- /dev/null
+++ b/modules/travel/back/methods/thermograph/getThermographModels.js
@@ -0,0 +1,18 @@
+module.exports = Self => {
+ Self.remoteMethod('getThermographModels', {
+ description: 'Gets the thermograph models',
+ accessType: 'READ',
+ returns: {
+ type: ['String'],
+ root: true
+ },
+ http: {
+ path: `/getThermographModels`,
+ verb: 'GET'
+ }
+ });
+
+ Self.getThermographModels = async() => {
+ return Self.getEnumValues('model');
+ };
+};
diff --git a/modules/travel/back/methods/thermograph/specs/createThermograph.spec.js b/modules/travel/back/methods/thermograph/specs/createThermograph.spec.js
new file mode 100644
index 000000000..733b713f0
--- /dev/null
+++ b/modules/travel/back/methods/thermograph/specs/createThermograph.spec.js
@@ -0,0 +1,49 @@
+const app = require('vn-loopback/server/server');
+
+describe('Termograph createThermograph()', () => {
+ const models = app.models;
+ const thermographId = '99999-1';
+ const model = 'DISPOSABLE';
+ const temperature = 'COOL';
+ const warehouseId = 1;
+ let createdThermograph;
+
+ afterAll(async done => {
+ let travelThermograpToDelete = await models.TravelThermograph.findOne({where: {thermographFk: createdThermograph.id}});
+ let thermograpToDelete = await models.Thermograph.findById(createdThermograph.id);
+
+ await travelThermograpToDelete.destroy();
+ await thermograpToDelete.destroy();
+
+ done();
+ });
+
+ it(`should create a thermograph which is saved in both thermograph and travelThermograph`, async() => {
+ let createdTravelThermograpth = await models.TravelThermograph.findOne({where: {thermographFk: thermographId}});
+
+ expect(createdTravelThermograpth).toBeNull();
+
+ createdThermograph = await models.Thermograph.createThermograph(thermographId, model, temperature, warehouseId);
+
+ expect(createdThermograph.id).toEqual(thermographId);
+ expect(createdThermograph.model).toEqual(model);
+
+ createdTravelThermograpth = await models.TravelThermograph.findOne({where: {thermographFk: thermographId}});
+
+ expect(createdTravelThermograpth.warehouseFk).toEqual(warehouseId);
+ expect(createdTravelThermograpth.temperature).toEqual(temperature);
+ });
+
+ it(`should not be able to created duplicated entries`, async() => {
+ let error;
+
+ try {
+ await models.Thermograph.createThermograph(thermographId, model, temperature, warehouseId);
+ } catch (e) {
+ error = e;
+ }
+
+ expect(error).toBeDefined();
+ expect(error.message).toBe('This thermograph id already exists');
+ });
+});
diff --git a/modules/travel/back/methods/travel-thermograph/getThermographTemperatures.js b/modules/travel/back/methods/travel-thermograph/getThermographTemperatures.js
new file mode 100644
index 000000000..1d510b513
--- /dev/null
+++ b/modules/travel/back/methods/travel-thermograph/getThermographTemperatures.js
@@ -0,0 +1,18 @@
+module.exports = Self => {
+ Self.remoteMethod('getThermographTemperatures', {
+ description: 'Gets the thermograph temperatures',
+ accessType: 'READ',
+ returns: {
+ type: ['String'],
+ root: true
+ },
+ http: {
+ path: `/getThermographTemperatures`,
+ verb: 'GET'
+ }
+ });
+
+ Self.getThermographTemperatures = async() => {
+ return Self.getEnumValues('temperature');
+ };
+};
diff --git a/modules/travel/back/models/thermograph.js b/modules/travel/back/models/thermograph.js
new file mode 100644
index 000000000..3f95a0670
--- /dev/null
+++ b/modules/travel/back/models/thermograph.js
@@ -0,0 +1,12 @@
+let UserError = require('vn-loopback/util/user-error');
+
+module.exports = Self => {
+ require('../methods/thermograph/createThermograph')(Self);
+ require('../methods/thermograph/getThermographModels')(Self);
+
+ Self.rewriteDbError(function(err) {
+ if (err.code === 'ER_DUP_ENTRY')
+ return new UserError(`This thermograph id already exists`);
+ return err;
+ });
+};
diff --git a/modules/travel/back/models/thermograph.json b/modules/travel/back/models/thermograph.json
index 421ae4341..2519fffc4 100644
--- a/modules/travel/back/models/thermograph.json
+++ b/modules/travel/back/models/thermograph.json
@@ -10,10 +10,12 @@
"id": {
"type": "String",
"id": true,
- "description": "Identifier"
+ "description": "Identifier",
+ "required": true
},
"model": {
- "type": "String"
+ "type": "String",
+ "required": true
}
}
}
diff --git a/modules/travel/back/models/travel-thermograph.js b/modules/travel/back/models/travel-thermograph.js
index 0d70edd7e..a16e68b98 100644
--- a/modules/travel/back/models/travel-thermograph.js
+++ b/modules/travel/back/models/travel-thermograph.js
@@ -1,4 +1,5 @@
module.exports = Self => {
require('../methods/travel-thermograph/allowedContentTypes')(Self);
+ require('../methods/travel-thermograph/getThermographTemperatures')(Self);
};
diff --git a/modules/travel/back/models/travel-thermograph.json b/modules/travel/back/models/travel-thermograph.json
index b8f7fa41a..70ee0de07 100644
--- a/modules/travel/back/models/travel-thermograph.json
+++ b/modules/travel/back/models/travel-thermograph.json
@@ -21,10 +21,15 @@
"type": "Date"
},
"temperature": {
- "type": "String"
+ "type": "String",
+ "required": true
},
"result": {
"type": "String"
+ },
+ "warehouseFk": {
+ "type": "Number",
+ "required": true
}
},
"relations": {
diff --git a/modules/travel/front/thermograph/create/index.html b/modules/travel/front/thermograph/create/index.html
index 4b1fc8cf4..0232c1b12 100644
--- a/modules/travel/front/thermograph/create/index.html
+++ b/modules/travel/front/thermograph/create/index.html
@@ -17,6 +17,18 @@
where="{travelFk: null}"
show-field="thermographFk"
value-field="thermographFk">
+
+ {{thermographFk}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/modules/travel/front/thermograph/create/index.js b/modules/travel/front/thermograph/create/index.js
index 6c0464991..d398febf1 100644
--- a/modules/travel/front/thermograph/create/index.js
+++ b/modules/travel/front/thermograph/create/index.js
@@ -55,6 +55,28 @@ class Controller extends Section {
});
}
+ onAddThermographClick(event) {
+ const defaultTemperature = 'COOL';
+ const defaultModel = 'DISPOSABLE';
+
+ event.preventDefault();
+ this.newThermograph = {
+ thermographId: this.thermographId,
+ warehouseId: this.warehouseId,
+ temperature: defaultTemperature,
+ model: defaultModel
+ };
+
+ this.$.modelsModel.refresh();
+ this.$.temperaturesModel.refresh();
+ this.$.newThermographDialog.show();
+ }
+
+ onNewThermographAccept() {
+ return this.$http.post(`Thermographs/createThermograph`, this.newThermograph)
+ .then(res => this.dms.thermographId = res.data.id);
+ }
+
onSubmit() {
const query = `Travels/${this.travel.id}/createThermograph`;
const options = {
diff --git a/modules/travel/front/thermograph/create/index.spec.js b/modules/travel/front/thermograph/create/index.spec.js
index 58fbe3991..23976fc96 100644
--- a/modules/travel/front/thermograph/create/index.spec.js
+++ b/modules/travel/front/thermograph/create/index.spec.js
@@ -63,5 +63,32 @@ describe('Ticket', () => {
expect(controller.allowedContentTypes).toEqual('application/pdf, image/png, image/jpg');
});
});
+
+ describe('onAddThermographClick()', () => {
+ it('should call the show() function of the create thermograph dialog', () => {
+ controller.$.newThermographDialog = {show: jest.fn()};
+ controller.$.modelsModel = {refresh: jest.fn()};
+ controller.$.temperaturesModel = {refresh: jest.fn()};
+
+ const event = new Event('click');
+ jest.spyOn(event, 'preventDefault');
+
+ controller.onAddThermographClick(event);
+
+ expect(event.preventDefault).toHaveBeenCalledTimes(1);
+ expect(controller.$.newThermographDialog.show).toHaveBeenCalledTimes(1);
+ });
+ });
+
+ describe('onNewThermographAccept()', () => {
+ it('should set the created thermograph id on to the controller for the autocomplete to use it', () => {
+ const response = {id: 'the created id'};
+ $httpBackend.when('POST', `Thermographs/createThermograph`).respond(response);
+ controller.onNewThermographAccept();
+ $httpBackend.flush();
+
+ expect(controller.dms.thermographId).toEqual(response.id);
+ });
+ });
});
});
diff --git a/modules/travel/front/thermograph/locale/es.yml b/modules/travel/front/thermograph/locale/es.yml
index 9f9be564b..0e3bc99fc 100644
--- a/modules/travel/front/thermograph/locale/es.yml
+++ b/modules/travel/front/thermograph/locale/es.yml
@@ -15,4 +15,6 @@ Add thermograph: Añadir termógrafo
Edit thermograph: Editar termógrafo
Thermograph deleted: Termógrafo eliminado
Thermograph: Termógrafo
-Are you sure you want to remove the thermograph?: ¿Seguro que quieres quitar el termógrafo?
\ No newline at end of file
+New thermograph: Nuevo termógrafo
+Are you sure you want to remove the thermograph?: ¿Seguro que quieres quitar el termógrafo?
+Identifier: Identificador
\ No newline at end of file
diff --git a/modules/worker/front/log/locale/es.yml b/modules/worker/front/log/locale/es.yml
index d9c204e55..c48c571ac 100644
--- a/modules/worker/front/log/locale/es.yml
+++ b/modules/worker/front/log/locale/es.yml
@@ -1,3 +1,4 @@
+Date: Fecha
Model: Modelo
Action: Acción
Author: Autor
diff --git a/modules/worker/front/routes.json b/modules/worker/front/routes.json
index 8447ef9c4..7825e9735 100644
--- a/modules/worker/front/routes.json
+++ b/modules/worker/front/routes.json
@@ -62,7 +62,8 @@
"url" : "/log",
"state": "worker.card.workerLog",
"component": "vn-worker-log",
- "description": "Log"
+ "description": "Log",
+ "acl": ["hr"]
}, {
"url": "/pbx",
"state": "worker.card.pbx",