diff --git a/Jenkinsfile b/Jenkinsfile index 62248b0fe..4cc6d74f4 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -43,11 +43,13 @@ node stage ("Stopping/Removing Docker") { + env.TAG = "${env.BUILD_NUMBER}" - 1; sh "docker-compose down --rmi 'all'" } stage ("Generar dockers") { + env.TAG = "${env.BUILD_NUMBER}" + 1; sh "docker-compose up -d --build" } } diff --git a/client/client/routes.json b/client/client/routes.json index c938dd8a6..99c083ff3 100644 --- a/client/client/routes.json +++ b/client/client/routes.json @@ -26,7 +26,7 @@ "client": "$ctrl.client" }, "menu": { - "description": "Datos básicos", + "description": "Basic data", "icon": "person" } }, { @@ -37,7 +37,7 @@ "client": "$ctrl.client" }, "menu": { - "description": "Datos fiscales", + "description": "Fiscal data", "icon": "account_balance" } }, { @@ -64,7 +64,7 @@ "client": "$ctrl.client" }, "menu": { - "description": "Consignatarios", + "description": "Addresses", "icon": "local_shipping" } }, { @@ -83,7 +83,7 @@ "client": "$ctrl.client" }, "menu": { - "description": "Acceso web", + "description": "Web access", "icon": "language" } }, { @@ -99,13 +99,59 @@ "client": "$ctrl.client" }, "menu": { - "description": "Notas", + "description": "Notes", "icon": "insert_drive_file" } }, { "url": "/create", "state": "clientCard.notes.create", "component": "vn-note-create" + }, { + "url": "/credit", + "abstract": true, + "state": "clientCard.credit", + "component": "ui-view" + }, { + "url": "/list", + "state": "clientCard.credit.list", + "component": "vn-client-credit-list", + "params": { + "client": "$ctrl.client" + }, + "menu": { + "description": "Credit", + "icon": "credit_card" + } + }, { + "url": "/create", + "state": "clientCard.credit.create", + "component": "vn-client-credit-create", + "params": { + "client": "$ctrl.client" + } + }, { + "url": "/greuge", + "abstract": true, + "state": "clientCard.greuge", + "component": "ui-view" + }, { + "url": "/list", + "state": "clientCard.greuge.list", + "component": "vn-client-greuge-list", + "params": { + "client": "$ctrl.client" + }, + "menu": { + "description": "Greuge", + "icon": "work" + } + }, { + "url": "/create", + "state": "clientCard.greuge.create", + "component": "vn-client-greuge-create", + "params": { + "client": "$ctrl.client" + } } ] } diff --git a/client/client/src/addresses/locale/es.json b/client/client/src/addresses/locale/es.json index dc7a13c4a..ab0c0e4ca 100644 --- a/client/client/src/addresses/locale/es.json +++ b/client/client/src/addresses/locale/es.json @@ -1,4 +1,3 @@ { - "Addresses": "Consignatarios", "Set as default": "Establecer como predeterminado" } \ No newline at end of file diff --git a/client/client/src/basic-data/locale/es.json b/client/client/src/basic-data/locale/es.json index d0e654979..4594d683e 100644 --- a/client/client/src/basic-data/locale/es.json +++ b/client/client/src/basic-data/locale/es.json @@ -1,5 +1,4 @@ { - "Basic data": "Datos básicos", "Comercial Name": "Nombre comercial", "Tax number": "NIF/CIF", "Social name": "Razón social", diff --git a/client/client/src/client.js b/client/client/src/client.js index 6dc0de725..15bd2d8ec 100644 --- a/client/client/src/client.js +++ b/client/client/src/client.js @@ -14,3 +14,7 @@ import './address-edit/address-edit'; import './notes/notes'; import './note-create/note-create'; import './web-access/web-access'; +import './credit-list/credit-list'; +import './credit-create/credit-create'; +import './greuge-list/greuge-list'; +import './greuge-create/greuge-create'; diff --git a/client/client/src/credit-create/credit-create.html b/client/client/src/credit-create/credit-create.html new file mode 100644 index 000000000..c02ff7167 --- /dev/null +++ b/client/client/src/credit-create/credit-create.html @@ -0,0 +1,23 @@ + + + +
+ + + Add credit + + + + + + + + + + + +
diff --git a/client/client/src/credit-create/credit-create.js b/client/client/src/credit-create/credit-create.js new file mode 100644 index 000000000..2d0bccf56 --- /dev/null +++ b/client/client/src/credit-create/credit-create.js @@ -0,0 +1,8 @@ +import ngModule from '../module'; + +ngModule.component('vnClientCreditCreate', { + template: require('./credit-create.html'), + bindings: { + client: '<' + } +}); diff --git a/client/client/src/credit-create/locale/es.json b/client/client/src/credit-create/locale/es.json new file mode 100644 index 000000000..7b0a22a1f --- /dev/null +++ b/client/client/src/credit-create/locale/es.json @@ -0,0 +1,3 @@ +{ + "Add credit": "Añadir crédito" +} \ No newline at end of file diff --git a/client/client/src/credit-list/credit-list.html b/client/client/src/credit-list/credit-list.html new file mode 100644 index 000000000..d6523fe1d --- /dev/null +++ b/client/client/src/credit-list/credit-list.html @@ -0,0 +1,29 @@ + + + + Credit + + + + + + + + + {{::credit.amount | number:2}} € + {{::credit.created | date:'dd/MM/yyyy HH:mm' }} + {{::credit.employee.name}} + + + No results + + + + + + + \ No newline at end of file diff --git a/client/client/src/credit-list/credit-list.js b/client/client/src/credit-list/credit-list.js new file mode 100644 index 000000000..8cf7a449f --- /dev/null +++ b/client/client/src/credit-list/credit-list.js @@ -0,0 +1,45 @@ +import ngModule from '../module'; + +class ClientCreditList { + constructor($scope, $timeout) { + this.$ = $scope; + this.$timeout = $timeout; + + this.waitingMgCrud = 0; + } + onOrder(field, order) { + this.filter(`${field} ${order}`); + } + filter(order) { + if (this.$.index && this.client && this.client.id) { + this.waitingMgCrud = 0; + this.$.index.filter = { + page: 1, + size: 10, + clientFk: this.client.id + }; + + if (order) { + this.$.index.filter.order = order; + } + + this.$.index.accept(); + } else if (this.waitingMgCrud > 0) { + throw new Error('Magic Crud is not loaded'); + } else { + this.waitingMgCrud++; + this.$timeout(() => { + this.filter(order); + }, 250); + } + } +} +ClientCreditList.$inject = ['$scope', '$timeout']; + +ngModule.component('vnClientCreditList', { + template: require('./credit-list.html'), + controller: ClientCreditList, + bindings: { + client: '<' + } +}); diff --git a/client/client/src/credit-list/locale/es.json b/client/client/src/credit-list/locale/es.json new file mode 100644 index 000000000..2c99e8b73 --- /dev/null +++ b/client/client/src/credit-list/locale/es.json @@ -0,0 +1,5 @@ +{ + "Since" : "Desde", + "Employee" : "Empleado", + "No results": "Sin resultados" +} \ No newline at end of file diff --git a/client/client/src/greuge-create/greuge-create.html b/client/client/src/greuge-create/greuge-create.html new file mode 100644 index 000000000..65e71cad3 --- /dev/null +++ b/client/client/src/greuge-create/greuge-create.html @@ -0,0 +1,17 @@ + + + Add Greuge + + + + + + + + + + + diff --git a/client/client/src/greuge-create/greuge-create.js b/client/client/src/greuge-create/greuge-create.js new file mode 100644 index 000000000..8036b687b --- /dev/null +++ b/client/client/src/greuge-create/greuge-create.js @@ -0,0 +1,8 @@ +import ngModule from '../module'; + +ngModule.component('vnClientGreugeCreate', { + template: require('./greuge-create.html'), + bindings: { + client: '<' + } +}); diff --git a/client/client/src/greuge-list/greuge-list.html b/client/client/src/greuge-list/greuge-list.html new file mode 100644 index 000000000..2a0a3b9bd --- /dev/null +++ b/client/client/src/greuge-list/greuge-list.html @@ -0,0 +1,38 @@ + + + + + Greuge + + + + + + + + + + {{::greuge.shipped | date:'dd/MM/yyyy HH:mm' }} + {{::greuge.description}} + {{::greuge.amount | number:2}} € + {{::greuge.greugeType.name}} + + + + No results + + + + {{edit.model.sumAmount | number:2}} € + + + + + + + + \ No newline at end of file diff --git a/client/client/src/greuge-list/greuge-list.js b/client/client/src/greuge-list/greuge-list.js new file mode 100644 index 000000000..0574a321c --- /dev/null +++ b/client/client/src/greuge-list/greuge-list.js @@ -0,0 +1,45 @@ +import ngModule from '../module'; + +class ClientGreugeList { + constructor($scope, $timeout) { + this.$ = $scope; + this.$timeout = $timeout; + + this.waitingMgCrud = 0; + } + onOrder(field, order) { + this.filter(`${field} ${order}`); + } + filter(order) { + if (this.$.index && this.client && this.client.id) { + this.waitingMgCrud = 0; + this.$.index.filter = { + page: 1, + size: 10, + clientFk: this.client.id + }; + + if (order) { + this.$.index.filter.order = order; + } + + this.$.index.accept(); + } else if (this.waitingMgCrud > 3) { + throw new Error('Magic Crud is not loaded'); + } else { + this.waitingMgCrud++; + this.$timeout(() => { + this.filter(order); + }, 250); + } + } +} +ClientGreugeList.$inject = ['$scope', '$timeout']; + +ngModule.component('vnClientGreugeList', { + template: require('./greuge-list.html'), + controller: ClientGreugeList, + bindings: { + client: '<' + } +}); diff --git a/client/client/src/greuge-list/locale/es.json b/client/client/src/greuge-list/locale/es.json new file mode 100644 index 000000000..7aa276bd0 --- /dev/null +++ b/client/client/src/greuge-list/locale/es.json @@ -0,0 +1,7 @@ +{ + "Date" : "Fecha", + "Comment" : "Comentario", + "Amount" : "Importe", + "Type": "Tipo", + "Add Greuge": "Añadir Greuge" +} \ No newline at end of file diff --git a/client/client/src/locale/es.json b/client/client/src/locale/es.json index ae0e1a52a..6ff1bec95 100644 --- a/client/client/src/locale/es.json +++ b/client/client/src/locale/es.json @@ -2,7 +2,11 @@ "Active": "Activo", "Client": "Cliente", "Clients": "Clientes", + "Basic data": "Datos básicos", "Fiscal data": "Datos Fiscales", + "Addresses": "Consignatarios", + "Web access": "Acceso web", + "Notes": "Notas", "Has to invoice": "Factura", "Invoice by mail": "Factura impresa", "Country": "País", @@ -12,5 +16,6 @@ "Province": "Provincia", "Save": "Guardar", "Pay method" : "Forma de pago", - "Address": "Consignatario" + "Address": "Consignatario", + "Credit" : "Crédito" } diff --git a/client/client/src/notes/locale/es.json b/client/client/src/notes/locale/es.json deleted file mode 100644 index 28b37f5a8..000000000 --- a/client/client/src/notes/locale/es.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "Notes": "Notas" -} \ No newline at end of file diff --git a/client/client/src/web-access/locale/es.json b/client/client/src/web-access/locale/es.json index 82652f89f..dd42d1c3a 100644 --- a/client/client/src/web-access/locale/es.json +++ b/client/client/src/web-access/locale/es.json @@ -1,7 +1,6 @@ { "User": "Usuario", "Enable web access": "Habilitar acceso web", - "Web access": "Acceso web", "New password": "Nueva contraseña", "Repeat password": "Repetir contraseña", "Change password": "Cambiar contraseña" diff --git a/client/core/src/column-header/column-header.html b/client/core/src/column-header/column-header.html index 435057a19..d5747fcfe 100644 --- a/client/core/src/column-header/column-header.html +++ b/client/core/src/column-header/column-header.html @@ -1,5 +1,5 @@
- + {{::$ctrl.text}} diff --git a/client/core/src/column-header/column-header.js b/client/core/src/column-header/column-header.js index 2f5f4d3c3..4c52e7e3d 100644 --- a/client/core/src/column-header/column-header.js +++ b/client/core/src/column-header/column-header.js @@ -1,19 +1,25 @@ import {module} from '../module'; export default class ColumnHeader { - constructor() { + constructor($attrs) { this.order = undefined; this.mouseIsOver = false; + this.orderLocked = ($attrs.orderLocked !== undefined); } onClick() { - if (this.order === 'ASC') { - this.order = 'DESC'; - } else { - this.order = 'ASC'; + if (!this.orderLocked) { + if (this.order === 'ASC') { + this.order = 'DESC'; + } else { + this.order = 'ASC'; + } + this.gridHeader.selectColum(this); } - this.gridHeader.selectColum(this); } showArrow(type) { + if (this.orderLocked) + return false; + let showArrow = (this.gridHeader && this.gridHeader.currentColumn && this.gridHeader.currentColumn.field === this.field && this.order === type); let showOther = (this.gridHeader && this.gridHeader.currentColumn && this.gridHeader.currentColumn.field === this.field && this.order !== type); if (type === 'DESC' && this.mouseIsOver && !showOther) { @@ -22,13 +28,13 @@ export default class ColumnHeader { return showArrow; } $onInit() { - if (this.defaultOrder) { + if (this.defaultOrder && !this.orderLocked) { this.order = this.defaultOrder; this.onClick(); } } } -ColumnHeader.$inject = []; +ColumnHeader.$inject = ['$attrs']; module.component('vnColumnHeader', { template: require('./column-header.html'), diff --git a/client/core/src/grid-header/style.scss b/client/core/src/grid-header/style.scss index cc983dcf1..324e488d1 100644 --- a/client/core/src/grid-header/style.scss +++ b/client/core/src/grid-header/style.scss @@ -2,7 +2,6 @@ vn-grid-header { border-bottom: 3px solid #9D9D9D; font-weight: bold; .orderly{ - cursor: pointer; text-align: center; white-space: nowrap; justify-content: center; diff --git a/client/production/src/production-table/production-table.js b/client/production/src/production-table/production-table.js index 91c24314f..288118a0d 100644 --- a/client/production/src/production-table/production-table.js +++ b/client/production/src/production-table/production-table.js @@ -13,6 +13,8 @@ export class ProductionTable { }, model: [] }; + this.filteredField = null; + this.filteredReverse = null; } get checkAll() { return this._checkAll; @@ -21,7 +23,7 @@ export class ProductionTable { this._checkAll = value; } set tickets(value) { - this._tickets = value; + this._tickets = this.filteredField ? this.$filter('orderBy')(value, this.filteredField, this.filteredReverse) : value; this.totalFilter = this._tickets.length; this.pageTable.filter.page = 1; this.pageTickets(); @@ -30,8 +32,9 @@ export class ProductionTable { return this._tickets; } onOrder(field, order) { - let reverse = order === 'DESC'; - this.tickets = this.$filter('orderBy')(this.tickets, field, reverse); + this.filteredField = field; + this.filteredReverse = order === 'DESC'; + this.tickets = this.tickets; // call tickets setter } pageTickets() { let init = (this.pageTable.filter.page - 1) * this.itemsDisplayedInList; diff --git a/client/salix/src/components/left-menu/actions.js b/client/salix/src/components/left-menu/actions.js index 4d4d6ee6d..30d379df1 100644 --- a/client/salix/src/components/left-menu/actions.js +++ b/client/salix/src/components/left-menu/actions.js @@ -9,7 +9,7 @@ export default class MenuActions { switchItem() { if (!this.items || !this.items.length) return; - let stateName = this.$state.current.name.replace('create', 'list').replace('edit', 'list'); + let stateName = this.$state.current.name.replace('.create', '.list').replace('.edit', '.list'); for (let i = 0; i < this.items.length; i++) { this.items[i].active = (this.items[i].href === stateName); diff --git a/services/client/common/methods/client/before-save.js b/services/client/common/methods/client/before-save.js index 470b7ba3f..b761a71f1 100644 --- a/services/client/common/methods/client/before-save.js +++ b/services/client/common/methods/client/before-save.js @@ -116,12 +116,7 @@ module.exports = function(Client) { } function maxCb(_, instances) { - if (!instances) { - done(generateErrorCredit()); - return; - } - - if (instances.length !== 1 || instances[0].employeeFk == userId || instances[0].amount > 0) { + if (!instances || instances.length !== 1 || instances[0].employeeFk == userId || instances[0].amount > 0) { done(); return; } diff --git a/services/client/common/methods/greuge/filter.js b/services/client/common/methods/greuge/filter.js new file mode 100644 index 000000000..dba4e8ef6 --- /dev/null +++ b/services/client/common/methods/greuge/filter.js @@ -0,0 +1,20 @@ +module.exports = Self => { + Self.installMethod('filter', filterParams); + + function filterParams(params) { + return { + where: { + clientFk: params.clientFk + }, + skip: (params.page - 1) * params.size, + limit: params.size, + order: params.order || 'shipped DESC', + include: { + relation: "greugeType", + scope: { + fields: ["id", "name"] + } + } + }; + } +}; diff --git a/services/client/common/methods/greuge/totalGreuge.js b/services/client/common/methods/greuge/totalGreuge.js new file mode 100644 index 000000000..849746493 --- /dev/null +++ b/services/client/common/methods/greuge/totalGreuge.js @@ -0,0 +1,34 @@ +module.exports = Self => { + Self.remoteMethod('sumAmount', { + description: 'returns sum greuge.ammount from client', + accessType: 'READ', + accepts: [{ + arg: 'id', + type: 'number', + required: true, + description: 'clientFk', + http: {source: 'path'} + }], + returns: { + arg: 'sumAmount' + }, + http: { + path: `/:id/sumAmount`, + verb: 'get' + } + }); + + Self.sumAmount = (clientFk, callback) => { + let query = `SELECT sum(amount) as sumAmount FROM vn.greuge WHERE clientFk = ?`; + Self.rawSql(query, [clientFk], callback).then(response => { + if (response.length) { + callback(null, response[0].sumAmount); + } else { + callback(null, 0); + } + }) + .catch(reject => { + callback(reject, null); + }); + }; +}; diff --git a/services/client/common/models/client-credit.js b/services/client/common/models/client-credit.js new file mode 100644 index 000000000..7205be03e --- /dev/null +++ b/services/client/common/models/client-credit.js @@ -0,0 +1,31 @@ +module.exports = function(Self) { + Self.installMethod('filter', filterParams, filterResults); + + function filterParams(params) { + return { + where: { + clientFk: params.clientFk + }, + skip: (params.page - 1) * params.size, + limit: params.size, + order: params.order || 'created DESC', + include: { + relation: "employee", + scope: { + fields: ["id", "name", "surname"] + } + } + }; + } + + function filterResults(instances) { + let result = JSON.parse(JSON.stringify(instances)); + if (result && result.instances && result.instances.length) { + result.instances.forEach((element, i) => { + result.instances[i].employee.name = `${element.employee.name} ${element.employee.surname}`; + delete result.instances[i].employee.surname; + }); + } + return result; + } +}; diff --git a/services/client/common/models/client-credit.json b/services/client/common/models/client-credit.json index f6512bfc7..26a1733ad 100644 --- a/services/client/common/models/client-credit.json +++ b/services/client/common/models/client-credit.json @@ -1,5 +1,5 @@ { - "name": "ClientCredit", + "name": "clientCredit", "base": "VnModel", "validateUpsert": true, "properties": { diff --git a/services/client/common/models/greuge-type.json b/services/client/common/models/greuge-type.json new file mode 100644 index 000000000..151aea5a6 --- /dev/null +++ b/services/client/common/models/greuge-type.json @@ -0,0 +1,14 @@ +{ + "name": "greugeType", + "base": "VnModel", + "properties": { + "id": { + "id": true, + "type": "Number", + "description": "Identifier" + }, + "name": { + "type": "String" + } + } + } \ No newline at end of file diff --git a/services/client/common/models/greuge.js b/services/client/common/models/greuge.js new file mode 100644 index 000000000..7bacecc4e --- /dev/null +++ b/services/client/common/models/greuge.js @@ -0,0 +1,4 @@ +module.exports = function(Self) { + require('../methods/greuge/filter.js')(Self); + require('../methods/greuge/totalGreuge.js')(Self); +}; diff --git a/services/client/common/models/greuge.json b/services/client/common/models/greuge.json new file mode 100644 index 000000000..2c00f9f73 --- /dev/null +++ b/services/client/common/models/greuge.json @@ -0,0 +1,35 @@ +{ + "name": "greuge", + "base": "VnModel", + "properties": { + "id": { + "id": true, + "type": "Number", + "description": "Identifier" + }, + "description": { + "type": "String" + }, + "amount": { + "type": "Number" + }, + "shipped": { + "type": "date" + }, + "created": { + "type": "date" + } + }, + "relations": { + "client": { + "type": "belongsTo", + "model": "Client", + "foreignKey": "clientFk" + }, + "greugeType": { + "type": "belongsTo", + "model": "greugeType", + "foreignKey": "greugeTypeFk" + } + } + } \ No newline at end of file diff --git a/services/client/common/validations/validateDni.js b/services/client/common/validations/validateDni.js index ab9008605..94b595f09 100644 --- a/services/client/common/validations/validateDni.js +++ b/services/client/common/validations/validateDni.js @@ -1,4 +1,7 @@ module.exports = fi => { + if (fi === undefined || fi === null) { + return true; + } let dni = fi; let getLetterDni = dni => { const regExpDni = 'TRWAGMYFPDXBNJZSQVHLCKE'; diff --git a/services/client/server/model-config.json b/services/client/server/model-config.json index 3c9c2199d..c95fb15c7 100644 --- a/services/client/server/model-config.json +++ b/services/client/server/model-config.json @@ -27,8 +27,8 @@ "Client": { "dataSource": "vn" }, - "ClientCredit": { - "dataSource": "salix" + "clientCredit": { + "dataSource": "vn" }, "ClientCreditLimit": { "dataSource": "salix" @@ -59,5 +59,11 @@ }, "CreditClassification": { "dataSource": "salix" + }, + "greuge": { + "dataSource": "vn" + }, + "greugeType": { + "dataSource": "vn" } } diff --git a/services/loopback/common/models/vn-model.js b/services/loopback/common/models/vn-model.js index 3305cb67d..30f358204 100644 --- a/services/loopback/common/models/vn-model.js +++ b/services/loopback/common/models/vn-model.js @@ -130,7 +130,7 @@ module.exports = function(Self) { }; }; - Self.installMethod = function(methodName, filterCb) { + Self.installMethod = function(methodName, filterCb, filterResult) { this.remoteMethod(methodName, { description: 'List items using a filter', accessType: 'READ', @@ -161,8 +161,12 @@ module.exports = function(Self) { var response = {}; function returnValues() { - if (response.instances !== undefined && response.count !== undefined) - cb(null, response); + if (response.instances !== undefined && response.count !== undefined) { + if (filterResult) + cb(null, filterResult(response)); + else + cb(null, response); + } } function error() {