From a5e833af2c56720825f460e5b59116bb5850fc89 Mon Sep 17 00:00:00 2001 From: joan Date: Tue, 31 May 2022 07:56:17 +0200 Subject: [PATCH 1/6] feat(client): detail section with smart-table --- .../10470-family/00-defaultViewConfig.sql | 3 + .../back/methods/client/detailFilter.js | 202 +++++++++++ modules/client/back/models/client.js | 1 + modules/client/front/detail/index.html | 335 ++++++++++++++++++ modules/client/front/detail/index.js | 113 ++++++ modules/client/front/detail/index.spec.js | 30 ++ modules/client/front/detail/locale/es.yml | 2 + modules/client/front/detail/style.scss | 32 ++ modules/client/front/index.js | 1 + modules/client/front/routes.json | 7 + 10 files changed, 726 insertions(+) create mode 100644 db/changes/10470-family/00-defaultViewConfig.sql create mode 100644 modules/client/back/methods/client/detailFilter.js create mode 100644 modules/client/front/detail/index.html create mode 100644 modules/client/front/detail/index.js create mode 100644 modules/client/front/detail/index.spec.js create mode 100644 modules/client/front/detail/locale/es.yml create mode 100644 modules/client/front/detail/style.scss diff --git a/db/changes/10470-family/00-defaultViewConfig.sql b/db/changes/10470-family/00-defaultViewConfig.sql new file mode 100644 index 000000000..5290f5a98 --- /dev/null +++ b/db/changes/10470-family/00-defaultViewConfig.sql @@ -0,0 +1,3 @@ +INSERT INTO salix.defaultViewConfig (tableCode, columns) +VALUES ('clientsDetail', '{"id":true,"phone":true,"city":true,"socialName":true,"salesPersonFk":true,"email":true}'); + diff --git a/modules/client/back/methods/client/detailFilter.js b/modules/client/back/methods/client/detailFilter.js new file mode 100644 index 000000000..91cb7e411 --- /dev/null +++ b/modules/client/back/methods/client/detailFilter.js @@ -0,0 +1,202 @@ + +const ParameterizedSQL = require('loopback-connector').ParameterizedSQL; +const buildFilter = require('vn-loopback/util/filter').buildFilter; +const mergeFilters = require('vn-loopback/util/filter').mergeFilters; + +module.exports = Self => { + Self.remoteMethodCtx('detailFilter', { + description: 'Find all instances of the model matched by filter from the data source.', + accessType: 'READ', + accepts: [ + { + arg: 'filter', + type: 'object', + description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string', + }, + { + arg: 'tags', + type: ['object'], + description: 'List of tags to filter with', + }, + { + arg: 'search', + type: 'string', + description: `If it's and integer searchs by id, otherwise it searchs by name`, + }, + { + arg: 'id', + type: 'integer', + description: 'Item id', + }, + { + arg: 'categoryFk', + type: 'integer', + description: 'Category id', + }, + { + arg: 'typeFk', + type: 'integer', + description: 'Type id', + }, + { + arg: 'isActive', + type: 'boolean', + description: 'Whether the item is or not active', + }, + { + arg: 'buyerFk', + type: 'integer', + description: 'The buyer of the item', + }, + { + arg: 'supplierFk', + type: 'integer', + description: 'The supplier of the item', + }, + { + arg: 'description', + type: 'string', + description: 'The item description', + }, + { + arg: 'stemMultiplier', + type: 'integer', + description: 'The item multiplier', + }, + { + arg: 'landed', + type: 'date', + description: 'The item last buy landed date', + }, + { + arg: 'isFloramondo', + type: 'boolean', + description: 'Whether the the item is or not floramondo', + } + ], + returns: { + type: ['object'], + root: true + }, + http: { + path: `/detailFilter`, + verb: 'GET' + } + }); + + Self.detailFilter = async(ctx, filter, options) => { + const conn = Self.dataSource.connector; + const myOptions = {}; + + if (typeof options == 'object') + Object.assign(myOptions, options); + + let codeWhere; + + if (ctx.args.search) { + const items = await Self.app.models.ItemBarcode.find({ + where: {code: ctx.args.search}, + fields: ['itemFk'] + }, myOptions); + + const itemIds = []; + + for (const item of items) + itemIds.push(item.itemFk); + + codeWhere = {'i.id': {inq: itemIds}}; + } + + const where = buildFilter(ctx.args, (param, value) => { + switch (param) { + case 'search': + return /^\d+$/.test(value) + ? {or: [{'i.id': value}, codeWhere]} + : {or: [ + {'i.name': {like: `%${value}%`}}, + {'i.longName': {like: `%${value}%`}}, + codeWhere]}; + case 'id': + case 'isActive': + case 'typeFk': + case 'isFloramondo': + return {[`i.${param}`]: value}; + case 'multiplier': + return {'i.stemMultiplier': value}; + case 'categoryFk': + return {'ic.id': value}; + case 'buyerFk': + return {'it.workerFk': value}; + case 'supplierFk': + return {'s.id': value}; + case 'origin': + return {'ori.code': value}; + case 'intrastat': + return {'intr.description': value}; + case 'landed': + return {'lb.landed': value}; + } + }); + + filter = mergeFilters(filter, {where}); + + const stmts = []; + const stmt = new ParameterizedSQL( + `SELECT + c.id, + c.name, + c.socialName, + c.fi, + c.credit, + c.creditInsurance, + c.phone, + c.mobile, + c.street, + c.city, + c.postcode, + c.email, + c.created, + c.isActive, + c.isVies, + c.isTaxDataChecked, + c.isEqualizated, + c.isFreezed, + c.hasToInvoice, + c.hasToInvoiceByAddress, + c.isToBeMailed, + c.hasSepaVnl, + c.hasLcr, + c.hasCoreVnl, + ct.id AS countryFk, + ct.country, + p.id AS provinceFk, + p.name AS province, + u.id AS salesPersonFk, + u.name AS salesPerson, + bt.code AS businessTypeFk, + bt.description AS businessType, + sti.CodigoIva AS sageTaxTypeFk, + sti.Iva AS sageTaxType, + stt.CodigoTransaccion AS sageTransactionTypeFk, + stt.Transaccion AS sageTransactionType + FROM client c + LEFT JOIN account.user u ON u.id = c.salesPersonFk + LEFT JOIN country ct ON ct.id = c.countryFk + LEFT JOIN province p ON p.id = c.provinceFk + LEFT JOIN businessType bt ON bt.code = c.businessTypeFk + LEFT JOIN sage.TiposIva sti ON sti.CodigoIva = c.taxTypeSageFk + LEFT JOIN sage.TiposTransacciones stt ON stt.CodigoTransaccion = c.transactionTypeSageFk + + ` + ); + + stmt.merge(conn.makeWhere(filter.where)); + stmt.merge(conn.makePagination(filter)); + + const clientsIndex = stmts.push(stmt) - 1; + const sql = ParameterizedSQL.join(stmts, ';'); + const result = await conn.executeStmt(sql, myOptions); + + return clientsIndex === 0 ? result : result[clientsIndex]; + }; +}; diff --git a/modules/client/back/models/client.js b/modules/client/back/models/client.js index 5ed777ab5..d71279bd0 100644 --- a/modules/client/back/models/client.js +++ b/modules/client/back/models/client.js @@ -31,6 +31,7 @@ module.exports = Self => { require('../methods/client/createReceipt')(Self); require('../methods/client/updatePortfolio')(Self); require('../methods/client/checkDuplicated')(Self); + require('../methods/client/detailFilter')(Self); // Validations diff --git a/modules/client/front/detail/index.html b/modules/client/front/detail/index.html new file mode 100644 index 000000000..66028efc0 --- /dev/null +++ b/modules/client/front/detail/index.html @@ -0,0 +1,335 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Identifier + + Name + + Social name + + Fiscal ID + + Salesperson + + Credit + + Credit insurance + + Phone + + Mobile + + Street + + Country + + Province + + City + + Postcode + + Email + + Created + + Business type + + Sage tax type + + Sage tr. type + + Active + + Vies + + Tax data checked + + Tax equalized + + Freezed + + Invoice + + Invoice by address + + Mailing + + Received LCR + + Received core VNL + + Received B2B VNL +
+ + + + + + + {{::client.id}} + + {{::client.name}}{{::client.socialName}}{{::client.fi}} + + {{::client.salesPerson | dashIfEmpty}} + + {{::client.credit}}{{::client.creditInsurance | dashIfEmpty}}{{::client.phone | dashIfEmpty}}{{::client.mobile | dashIfEmpty}}{{::client.street | dashIfEmpty}}{{::client.country | dashIfEmpty}}{{::client.province | dashIfEmpty}}{{::client.city | dashIfEmpty}}{{::client.postcode | dashIfEmpty}}{{::client.email | dashIfEmpty}}{{::client.created | date:'dd/MM/yyyy'}}{{::client.businessType | dashIfEmpty}}{{::client.sageTaxType | dashIfEmpty}}{{::client.sageTransactionType | dashIfEmpty}} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ + + + + + + + + + + + + + + + Filter by selection + + + Exclude selection + + + Remove filter + + + Remove all filters + + + \ No newline at end of file diff --git a/modules/client/front/detail/index.js b/modules/client/front/detail/index.js new file mode 100644 index 000000000..cca19622a --- /dev/null +++ b/modules/client/front/detail/index.js @@ -0,0 +1,113 @@ +import ngModule from '../module'; +import Section from 'salix/components/section'; +import './style.scss'; + +class Controller extends Section { + constructor($element, $) { + super($element, $); + + this.smartTableOptions = { + activeButtons: { + search: true, + shownColumns: true, + }, + columns: [ + { + field: 'category', + autocomplete: { + url: 'ItemCategories', + valueField: 'name', + } + }, + { + field: 'origin', + autocomplete: { + url: 'Origins', + showField: 'code', + valueField: 'code' + } + }, + { + field: 'typeFk', + autocomplete: { + url: 'ItemTypes', + } + }, + { + field: 'intrastat', + autocomplete: { + url: 'Intrastats', + showField: 'description', + valueField: 'description' + } + }, + { + field: 'buyerFk', + autocomplete: { + url: 'Workers/activeWithRole', + where: `{role: {inq: ['logistic', 'buyer']}}`, + searchFunction: '{firstName: $search}', + showField: 'nickname', + valueField: 'id', + } + }, + { + field: 'active', + searchable: false + }, + { + field: 'landed', + searchable: false + }, + ] + }; + } + + exprBuilder(param, value) { + switch (param) { + case 'category': + return {'ic.name': value}; + case 'buyerFk': + return {'it.workerFk': value}; + case 'grouping': + return {'b.grouping': value}; + case 'packing': + return {'b.packing': value}; + case 'origin': + return {'ori.code': value}; + case 'typeFk': + return {'i.typeFk': value}; + case 'intrastat': + return {'intr.description': value}; + case 'name': + return {'i.name': {like: `%${value}%`}}; + case 'producer': + return {'pr.name': {like: `%${value}%`}}; + case 'id': + case 'size': + case 'subname': + case 'isActive': + case 'density': + case 'stemMultiplier': + case 'stems': + return {[`i.${param}`]: value}; + } + } + + onCloneAccept(itemFk) { + return this.$http.post(`Items/${itemFk}/clone`) + .then(res => { + this.$state.go('item.card.tags', {id: res.data.id}); + }); + } + + preview(client) { + this.clientSelected = client; + this.$.preview.show(); + } +} + +ngModule.vnComponent('vnClientDetail', { + template: require('./index.html'), + controller: Controller +}); diff --git a/modules/client/front/detail/index.spec.js b/modules/client/front/detail/index.spec.js new file mode 100644 index 000000000..18abde581 --- /dev/null +++ b/modules/client/front/detail/index.spec.js @@ -0,0 +1,30 @@ +import './index.js'; + +describe('Item', () => { + describe('Component vnItemIndex', () => { + let controller; + let $httpBackend; + let $scope; + + beforeEach(ngModule('item')); + + beforeEach(inject(($componentController, _$httpBackend_, $rootScope) => { + $httpBackend = _$httpBackend_; + $scope = $rootScope.$new(); + const $element = angular.element(''); + controller = $componentController('vnItemIndex', {$element, $scope}); + })); + + describe('onCloneAccept()', () => { + it('should perform a post query and then call go() then update itemSelected in the controller', () => { + jest.spyOn(controller.$state, 'go'); + + $httpBackend.expectRoute('POST', `Items/:id/clone`).respond({id: 99}); + controller.onCloneAccept(1); + $httpBackend.flush(); + + expect(controller.$state.go).toHaveBeenCalledWith('item.card.tags', {id: 99}); + }); + }); + }); +}); diff --git a/modules/client/front/detail/locale/es.yml b/modules/client/front/detail/locale/es.yml new file mode 100644 index 000000000..0d72edd28 --- /dev/null +++ b/modules/client/front/detail/locale/es.yml @@ -0,0 +1,2 @@ +picture: Foto +Buy requests: Peticiones de compra \ No newline at end of file diff --git a/modules/client/front/detail/style.scss b/modules/client/front/detail/style.scss new file mode 100644 index 000000000..eaa1a16ed --- /dev/null +++ b/modules/client/front/detail/style.scss @@ -0,0 +1,32 @@ +@import "variables"; + +vn-item-product { + display: block; + + .id { + background-color: $color-main; + color: $color-font-dark; + margin-bottom: 0; + } + .image { + height: 112px; + width: 112px; + + & > img { + max-height: 100%; + max-width: 100%; + border-radius: 3px; + } + } + vn-label-value:first-of-type section{ + margin-top: 9px; + } +} + +table { + img { + border-radius: 50%; + width: 50px; + height: 50px; + } +} \ No newline at end of file diff --git a/modules/client/front/index.js b/modules/client/front/index.js index ea732beea..5985966d1 100644 --- a/modules/client/front/index.js +++ b/modules/client/front/index.js @@ -47,3 +47,4 @@ import './consumption-search-panel'; import './defaulter'; import './notification'; import './unpaid'; +import './detail'; diff --git a/modules/client/front/routes.json b/modules/client/front/routes.json index 293243470..2073cb200 100644 --- a/modules/client/front/routes.json +++ b/modules/client/front/routes.json @@ -7,6 +7,7 @@ "menus": { "main": [ {"state": "client.index", "icon": "person"}, + {"state": "client.detail", "icon": "person"}, {"state": "client.notification", "icon": "campaign"}, {"state": "client.defaulter", "icon": "icon-defaulter"} ], @@ -381,6 +382,12 @@ "component": "vn-client-unpaid", "acl": ["administrative"], "description": "Unpaid" + }, + { + "url": "/detail", + "state": "client.detail", + "component": "vn-client-detail", + "description": "Detail" } ] } From c369453bfc25cb24b1a6851e15c42f2651e8c469 Mon Sep 17 00:00:00 2001 From: joan Date: Tue, 31 May 2022 13:36:27 +0200 Subject: [PATCH 2/6] Added model fields --- .../10470-family/00-defaultViewConfig.sql | 2 +- front/core/components/smart-table/index.js | 22 +- loopback/locale/es.json | 4 +- ...{detailFilter.js => extendedListFilter.js} | 139 ++++------- modules/client/back/models/client.js | 2 +- modules/client/front/detail/index.js | 113 --------- modules/client/front/detail/locale/es.yml | 2 - modules/client/front/detail/style.scss | 32 --- .../{detail => extended-list}/index.html | 217 ++++++++---------- modules/client/front/extended-list/index.js | 184 +++++++++++++++ .../{detail => extended-list}/index.spec.js | 0 .../client/front/extended-list/locale/es.yml | 3 + modules/client/front/extended-list/style.scss | 6 + modules/client/front/index.js | 2 +- modules/client/front/locale/es.yml | 1 + modules/client/front/routes.json | 10 +- .../client/front/search-panel/locale/es.yml | 2 +- modules/monitor/front/index/tickets/index.js | 2 +- 18 files changed, 377 insertions(+), 366 deletions(-) rename modules/client/back/methods/client/{detailFilter.js => extendedListFilter.js} (58%) delete mode 100644 modules/client/front/detail/index.js delete mode 100644 modules/client/front/detail/locale/es.yml delete mode 100644 modules/client/front/detail/style.scss rename modules/client/front/{detail => extended-list}/index.html (61%) create mode 100644 modules/client/front/extended-list/index.js rename modules/client/front/{detail => extended-list}/index.spec.js (100%) create mode 100644 modules/client/front/extended-list/locale/es.yml create mode 100644 modules/client/front/extended-list/style.scss diff --git a/db/changes/10470-family/00-defaultViewConfig.sql b/db/changes/10470-family/00-defaultViewConfig.sql index 5290f5a98..0a394e5bc 100644 --- a/db/changes/10470-family/00-defaultViewConfig.sql +++ b/db/changes/10470-family/00-defaultViewConfig.sql @@ -1,3 +1,3 @@ INSERT INTO salix.defaultViewConfig (tableCode, columns) -VALUES ('clientsDetail', '{"id":true,"phone":true,"city":true,"socialName":true,"salesPersonFk":true,"email":true}'); +VALUES ('clientsDetail', '{"id":true,"phone":true,"city":true,"socialName":true,"salesPersonFk":true,"email":true,"name":false,"fi":false,"credit":false,"creditInsurance":false,"mobile":false,"street":false,"countryFk":false,"provinceFk":false,"postcode":false,"created":false,"businessTypeFk":false,"payMethodFk":false,"sageTaxTypeFk":false,"sageTransactionTypeFk":false,"isActive":false,"isVies":false,"isTaxDataChecked":false,"isEqualizated":false,"isFreezed":false,"hasToInvoice":false,"hasToInvoiceByAddress":false,"isToBeMailed":false,"hasLcr":false,"hasCoreVnl":false,"hasSepaVnl":false}'); diff --git a/front/core/components/smart-table/index.js b/front/core/components/smart-table/index.js index 81d8d103e..9f913071e 100644 --- a/front/core/components/smart-table/index.js +++ b/front/core/components/smart-table/index.js @@ -318,6 +318,8 @@ export default class SmartTable extends Component { for (let column of columns) { const field = column.getAttribute('field'); const cell = document.createElement('td'); + cell.setAttribute('centered', ''); + if (field) { let input; let options; @@ -346,6 +348,23 @@ export default class SmartTable extends Component { on-change="$ctrl.searchByColumn('${field}')" clear-disabled="true" />`)(this.$inputsScope); + } else if (options && options.checkbox) { + input = this.$compile(` + `)(this.$inputsScope); + } else if (options && options.datepicker) { + input = this.$compile(` + `)(this.$inputsScope); } else { input = this.$compile(` { - Self.remoteMethodCtx('detailFilter', { + Self.remoteMethodCtx('extendedListFilter', { description: 'Find all instances of the model matched by filter from the data source.', accessType: 'READ', accepts: [ @@ -13,128 +13,84 @@ module.exports = Self => { type: 'object', description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string', }, - { - arg: 'tags', - type: ['object'], - description: 'List of tags to filter with', - }, { arg: 'search', type: 'string', description: `If it's and integer searchs by id, otherwise it searchs by name`, }, { - arg: 'id', - type: 'integer', - description: 'Item id', - }, - { - arg: 'categoryFk', - type: 'integer', - description: 'Category id', - }, - { - arg: 'typeFk', - type: 'integer', - description: 'Type id', - }, - { - arg: 'isActive', - type: 'boolean', - description: 'Whether the item is or not active', - }, - { - arg: 'buyerFk', - type: 'integer', - description: 'The buyer of the item', - }, - { - arg: 'supplierFk', - type: 'integer', - description: 'The supplier of the item', - }, - { - arg: 'description', + arg: 'name', type: 'string', - description: 'The item description', + description: 'The client name', }, { - arg: 'stemMultiplier', - type: 'integer', - description: 'The item multiplier', + arg: 'salesPersonFk', + type: 'number', }, { - arg: 'landed', - type: 'date', - description: 'The item last buy landed date', + arg: 'fi', + type: 'string', + description: 'The client fiscal id', }, { - arg: 'isFloramondo', - type: 'boolean', - description: 'Whether the the item is or not floramondo', - } + arg: 'socialName', + type: 'string', + }, + { + arg: 'city', + type: 'string', + }, + { + arg: 'postcode', + type: 'string', + }, + { + arg: 'provinceFk', + type: 'number', + }, + { + arg: 'email', + type: 'string', + }, + { + arg: 'phone', + type: 'string', + }, ], returns: { type: ['object'], root: true }, http: { - path: `/detailFilter`, + path: `/extendedListFilter`, verb: 'GET' } }); - Self.detailFilter = async(ctx, filter, options) => { + Self.extendedListFilter = async(ctx, filter, options) => { const conn = Self.dataSource.connector; const myOptions = {}; if (typeof options == 'object') Object.assign(myOptions, options); - let codeWhere; - - if (ctx.args.search) { - const items = await Self.app.models.ItemBarcode.find({ - where: {code: ctx.args.search}, - fields: ['itemFk'] - }, myOptions); - - const itemIds = []; - - for (const item of items) - itemIds.push(item.itemFk); - - codeWhere = {'i.id': {inq: itemIds}}; - } - const where = buildFilter(ctx.args, (param, value) => { switch (param) { case 'search': return /^\d+$/.test(value) - ? {or: [{'i.id': value}, codeWhere]} - : {or: [ - {'i.name': {like: `%${value}%`}}, - {'i.longName': {like: `%${value}%`}}, - codeWhere]}; - case 'id': - case 'isActive': - case 'typeFk': - case 'isFloramondo': - return {[`i.${param}`]: value}; - case 'multiplier': - return {'i.stemMultiplier': value}; - case 'categoryFk': - return {'ic.id': value}; - case 'buyerFk': - return {'it.workerFk': value}; - case 'supplierFk': - return {'s.id': value}; - case 'origin': - return {'ori.code': value}; - case 'intrastat': - return {'intr.description': value}; - case 'landed': - return {'lb.landed': value}; + ? {'c.id': {inq: value}} + : {'c.name': {like: `%${value}%`}}; + case 'name': + case 'salesPersonFk': + case 'fi': + case 'socialName': + case 'city': + case 'postcode': + case 'provinceFk': + case 'email': + case 'phone': + param = `c.${param}`; + return {[param]: value}; } }); @@ -175,6 +131,8 @@ module.exports = Self => { u.name AS salesPerson, bt.code AS businessTypeFk, bt.description AS businessType, + pm.id AS payMethodFk, + pm.name AS payMethod, sti.CodigoIva AS sageTaxTypeFk, sti.Iva AS sageTaxType, stt.CodigoTransaccion AS sageTransactionTypeFk, @@ -184,6 +142,7 @@ module.exports = Self => { LEFT JOIN country ct ON ct.id = c.countryFk LEFT JOIN province p ON p.id = c.provinceFk LEFT JOIN businessType bt ON bt.code = c.businessTypeFk + LEFT JOIN payMethod pm ON pm.id = c.payMethodFk LEFT JOIN sage.TiposIva sti ON sti.CodigoIva = c.taxTypeSageFk LEFT JOIN sage.TiposTransacciones stt ON stt.CodigoTransaccion = c.transactionTypeSageFk diff --git a/modules/client/back/models/client.js b/modules/client/back/models/client.js index d71279bd0..03ad90285 100644 --- a/modules/client/back/models/client.js +++ b/modules/client/back/models/client.js @@ -31,7 +31,7 @@ module.exports = Self => { require('../methods/client/createReceipt')(Self); require('../methods/client/updatePortfolio')(Self); require('../methods/client/checkDuplicated')(Self); - require('../methods/client/detailFilter')(Self); + require('../methods/client/extendedListFilter')(Self); // Validations diff --git a/modules/client/front/detail/index.js b/modules/client/front/detail/index.js deleted file mode 100644 index cca19622a..000000000 --- a/modules/client/front/detail/index.js +++ /dev/null @@ -1,113 +0,0 @@ -import ngModule from '../module'; -import Section from 'salix/components/section'; -import './style.scss'; - -class Controller extends Section { - constructor($element, $) { - super($element, $); - - this.smartTableOptions = { - activeButtons: { - search: true, - shownColumns: true, - }, - columns: [ - { - field: 'category', - autocomplete: { - url: 'ItemCategories', - valueField: 'name', - } - }, - { - field: 'origin', - autocomplete: { - url: 'Origins', - showField: 'code', - valueField: 'code' - } - }, - { - field: 'typeFk', - autocomplete: { - url: 'ItemTypes', - } - }, - { - field: 'intrastat', - autocomplete: { - url: 'Intrastats', - showField: 'description', - valueField: 'description' - } - }, - { - field: 'buyerFk', - autocomplete: { - url: 'Workers/activeWithRole', - where: `{role: {inq: ['logistic', 'buyer']}}`, - searchFunction: '{firstName: $search}', - showField: 'nickname', - valueField: 'id', - } - }, - { - field: 'active', - searchable: false - }, - { - field: 'landed', - searchable: false - }, - ] - }; - } - - exprBuilder(param, value) { - switch (param) { - case 'category': - return {'ic.name': value}; - case 'buyerFk': - return {'it.workerFk': value}; - case 'grouping': - return {'b.grouping': value}; - case 'packing': - return {'b.packing': value}; - case 'origin': - return {'ori.code': value}; - case 'typeFk': - return {'i.typeFk': value}; - case 'intrastat': - return {'intr.description': value}; - case 'name': - return {'i.name': {like: `%${value}%`}}; - case 'producer': - return {'pr.name': {like: `%${value}%`}}; - case 'id': - case 'size': - case 'subname': - case 'isActive': - case 'density': - case 'stemMultiplier': - case 'stems': - return {[`i.${param}`]: value}; - } - } - - onCloneAccept(itemFk) { - return this.$http.post(`Items/${itemFk}/clone`) - .then(res => { - this.$state.go('item.card.tags', {id: res.data.id}); - }); - } - - preview(client) { - this.clientSelected = client; - this.$.preview.show(); - } -} - -ngModule.vnComponent('vnClientDetail', { - template: require('./index.html'), - controller: Controller -}); diff --git a/modules/client/front/detail/locale/es.yml b/modules/client/front/detail/locale/es.yml deleted file mode 100644 index 0d72edd28..000000000 --- a/modules/client/front/detail/locale/es.yml +++ /dev/null @@ -1,2 +0,0 @@ -picture: Foto -Buy requests: Peticiones de compra \ No newline at end of file diff --git a/modules/client/front/detail/style.scss b/modules/client/front/detail/style.scss deleted file mode 100644 index eaa1a16ed..000000000 --- a/modules/client/front/detail/style.scss +++ /dev/null @@ -1,32 +0,0 @@ -@import "variables"; - -vn-item-product { - display: block; - - .id { - background-color: $color-main; - color: $color-font-dark; - margin-bottom: 0; - } - .image { - height: 112px; - width: 112px; - - & > img { - max-height: 100%; - max-width: 100%; - border-radius: 3px; - } - } - vn-label-value:first-of-type section{ - margin-top: 9px; - } -} - -table { - img { - border-radius: 50%; - width: 50px; - height: 50px; - } -} \ No newline at end of file diff --git a/modules/client/front/detail/index.html b/modules/client/front/extended-list/index.html similarity index 61% rename from modules/client/front/detail/index.html rename to modules/client/front/extended-list/index.html index 66028efc0..23c331915 100644 --- a/modules/client/front/detail/index.html +++ b/modules/client/front/extended-list/index.html @@ -1,12 +1,13 @@ Social name - Fiscal ID + Tax number Salesperson @@ -75,43 +76,46 @@ Business type - + + Billing data + + Sage tax type Sage tr. type - + Active - + Vies - - Tax data checked + + Verified data - - Tax equalized + + Is equalizated - + Freezed - + Invoice - + Invoice by address - + Mailing - + Received LCR - + Received core VNL - + Received B2B VNL @@ -124,11 +128,11 @@ params: {id: client.id} }"> - - @@ -162,116 +166,97 @@ {{::client.email | dashIfEmpty}} {{::client.created | date:'dd/MM/yyyy'}} {{::client.businessType | dashIfEmpty}} + {{::client.payMethod | dashIfEmpty}} {{::client.sageTaxType | dashIfEmpty}} {{::client.sageTransactionType | dashIfEmpty}} - - - + + + {{ ::client.isActive ? 'Yes' : 'No' | translate}} + - - - + + + {{ ::client.isVies ? 'Yes' : 'No' | translate}} + - - - + + + {{ ::client.isTaxDataChecked ? 'Yes' : 'No' | translate}} + - - - + + + {{ ::client.isEqualizated ? 'Yes' : 'No' | translate}} + - - - + + + {{ ::client.isFreezed ? 'Yes' : 'No' | translate}} + - - - + + + {{ ::client.hasToInvoice ? 'Yes' : 'No' | translate}} + - - - + + + {{ ::client.hasToInvoiceByAddress ? 'Yes' : 'No' | translate}} + - - - + + + {{ ::client.isToBeMailed ? 'Yes' : 'No' | translate}} + - - - + + + {{ ::client.hasLcr ? 'Yes' : 'No' | translate}} + - - - + + + {{ ::client.hasCoreVnl ? 'Yes' : 'No' | translate}} + - - - + + + {{ ::client.hasSepaVnl ? 'Yes' : 'No' | translate}} + - - + Date: Wed, 1 Jun 2022 13:07:28 +0200 Subject: [PATCH 3/6] Added back unit tests --- .../back/methods/client/extendedListFilter.js | 3 +- .../client/specs/extendedListFilter.spec.js | 180 ++++++++++++++++++ 2 files changed, 181 insertions(+), 2 deletions(-) create mode 100644 modules/client/back/methods/client/specs/extendedListFilter.spec.js diff --git a/modules/client/back/methods/client/extendedListFilter.js b/modules/client/back/methods/client/extendedListFilter.js index f5514c673..19e08fb7d 100644 --- a/modules/client/back/methods/client/extendedListFilter.js +++ b/modules/client/back/methods/client/extendedListFilter.js @@ -5,13 +5,12 @@ const mergeFilters = require('vn-loopback/util/filter').mergeFilters; module.exports = Self => { Self.remoteMethodCtx('extendedListFilter', { - description: 'Find all instances of the model matched by filter from the data source.', + description: 'Find all clients matched by the filter', accessType: 'READ', accepts: [ { arg: 'filter', type: 'object', - description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string', }, { arg: 'search', diff --git a/modules/client/back/methods/client/specs/extendedListFilter.spec.js b/modules/client/back/methods/client/specs/extendedListFilter.spec.js new file mode 100644 index 000000000..6a0ba1f64 --- /dev/null +++ b/modules/client/back/methods/client/specs/extendedListFilter.spec.js @@ -0,0 +1,180 @@ +const { models } = require('vn-loopback/server/server'); + +fdescribe('client extendedListFilter()', () => { + it('should return the clients matching the filter with a limit of 20 rows', async() => { + const tx = await models.Client.beginTransaction({}); + + try { + const options = {transaction: tx}; + + const ctx = {req: {accessToken: {userId: 1}}, args: {}}; + const filter = {limit: '20'}; + const result = await models.Client.extendedListFilter(ctx, filter, options); + + expect(result.length).toEqual(20); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); + + it('should return the client "Bruce Wayne" matching the search argument with his name', async() => { + const tx = await models.Client.beginTransaction({}); + + try { + const options = {transaction: tx}; + + const ctx = {req: {accessToken: {userId: 1}}, args: {search: 'Bruce Wayne'}}; + const filter = {}; + const result = await models.Client.extendedListFilter(ctx, filter, options); + + const firstResult = result[0]; + + expect(result.length).toEqual(1); + expect(firstResult.name).toEqual('Bruce Wayne'); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); + + it('should return the client "Bruce Wayne" matching the search argument with his id', async() => { + const tx = await models.Client.beginTransaction({}); + + try { + const options = {transaction: tx}; + + const ctx = {req: {accessToken: {userId: 1}}, args: {search: '1101'}}; + const filter = {}; + const result = await models.Client.extendedListFilter(ctx, filter, options); + + const firstResult = result[0]; + + expect(result.length).toEqual(1); + expect(firstResult.name).toEqual('Bruce Wayne'); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); + + it('should return the client "Bruce Wayne" matching the name argument', async() => { + const tx = await models.Client.beginTransaction({}); + + try { + const options = {transaction: tx}; + + const ctx = {req: {accessToken: {userId: 1}}, args: {name: 'Bruce Wayne'}}; + const filter = {}; + const result = await models.Client.extendedListFilter(ctx, filter, options); + + const firstResult = result[0]; + + expect(result.length).toEqual(1); + expect(firstResult.name).toEqual('Bruce Wayne'); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); + + it('should return the clients matching the "salesPersonFk" argument', async() => { + const tx = await models.Client.beginTransaction({}); + const salesPersonId = 18; + + try { + const options = {transaction: tx}; + + const ctx = {req: {accessToken: {userId: 1}}, args: {salesPersonFk: salesPersonId}}; + const filter = {}; + const result = await models.Client.extendedListFilter(ctx, filter, options); + + const randomIndex = Math.floor(Math.random() * result.length); + const randomResultClient = result[randomIndex]; + + expect(result.length).toBeGreaterThanOrEqual(5); + expect(randomResultClient.salesPersonFk).toEqual(salesPersonId); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); + + it('should return the clients matching the "fi" argument', async() => { + const tx = await models.Client.beginTransaction({}); + + try { + const options = {transaction: tx}; + + const ctx = {req: {accessToken: {userId: 1}}, args: {fi: '251628698'}}; + const filter = {}; + const result = await models.Client.extendedListFilter(ctx, filter, options); + + const firstClient = result[0]; + + expect(result.length).toEqual(1); + expect(firstClient.name).toEqual('Max Eisenhardt'); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); + + it('should return the clients matching the "city" argument', async() => { + const tx = await models.Client.beginTransaction({}); + + try { + const options = {transaction: tx}; + + const ctx = {req: {accessToken: {userId: 1}}, args: {city: 'Silla'}}; + const filter = {}; + const result = await models.Client.extendedListFilter(ctx, filter, options); + + const randomIndex = Math.floor(Math.random() * result.length); + const randomResultClient = result[randomIndex]; + + expect(result.length).toBeGreaterThanOrEqual(20); + expect(randomResultClient.city.toLowerCase()).toEqual('silla'); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); + + it('should return the clients matching the "postcode" argument', async() => { + const tx = await models.Client.beginTransaction({}); + + try { + const options = {transaction: tx}; + + const ctx = {req: {accessToken: {userId: 1}}, args: {postcode: '46460'}}; + const filter = {}; + const result = await models.Client.extendedListFilter(ctx, filter, options); + + const randomIndex = Math.floor(Math.random() * result.length); + const randomResultClient = result[randomIndex]; + + expect(result.length).toBeGreaterThanOrEqual(20); + expect(randomResultClient.postcode).toEqual('46460'); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); +}); From 571e2f03d3613b7ed6297b0a9efc4efd92effc3c Mon Sep 17 00:00:00 2001 From: joan Date: Wed, 1 Jun 2022 13:07:47 +0200 Subject: [PATCH 4/6] Removed focus --- .../client/back/methods/client/specs/extendedListFilter.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/client/back/methods/client/specs/extendedListFilter.spec.js b/modules/client/back/methods/client/specs/extendedListFilter.spec.js index 6a0ba1f64..907c03ef9 100644 --- a/modules/client/back/methods/client/specs/extendedListFilter.spec.js +++ b/modules/client/back/methods/client/specs/extendedListFilter.spec.js @@ -1,6 +1,6 @@ const { models } = require('vn-loopback/server/server'); -fdescribe('client extendedListFilter()', () => { +describe('client extendedListFilter()', () => { it('should return the clients matching the filter with a limit of 20 rows', async() => { const tx = await models.Client.beginTransaction({}); From a4a9ea45b71e6e8cfc9049206ace9d94770016c6 Mon Sep 17 00:00:00 2001 From: joan Date: Wed, 1 Jun 2022 13:44:07 +0200 Subject: [PATCH 5/6] Removed front unit test --- .../client/front/extended-list/index.spec.js | 30 ------------------- 1 file changed, 30 deletions(-) delete mode 100644 modules/client/front/extended-list/index.spec.js diff --git a/modules/client/front/extended-list/index.spec.js b/modules/client/front/extended-list/index.spec.js deleted file mode 100644 index 18abde581..000000000 --- a/modules/client/front/extended-list/index.spec.js +++ /dev/null @@ -1,30 +0,0 @@ -import './index.js'; - -describe('Item', () => { - describe('Component vnItemIndex', () => { - let controller; - let $httpBackend; - let $scope; - - beforeEach(ngModule('item')); - - beforeEach(inject(($componentController, _$httpBackend_, $rootScope) => { - $httpBackend = _$httpBackend_; - $scope = $rootScope.$new(); - const $element = angular.element(''); - controller = $componentController('vnItemIndex', {$element, $scope}); - })); - - describe('onCloneAccept()', () => { - it('should perform a post query and then call go() then update itemSelected in the controller', () => { - jest.spyOn(controller.$state, 'go'); - - $httpBackend.expectRoute('POST', `Items/:id/clone`).respond({id: 99}); - controller.onCloneAccept(1); - $httpBackend.flush(); - - expect(controller.$state.go).toHaveBeenCalledWith('item.card.tags', {id: 99}); - }); - }); - }); -}); From c92f4447765b8dcfd31a905f56fbed267064ae56 Mon Sep 17 00:00:00 2001 From: joan Date: Tue, 7 Jun 2022 14:59:18 +0200 Subject: [PATCH 6/6] Ammends --- .../10470-family/00-defaultViewConfig.sql | 2 +- front/core/components/smart-table/index.js | 27 +++++++++++-------- .../back/methods/client/extendedListFilter.js | 1 - modules/client/front/extended-list/index.html | 3 +-- 4 files changed, 18 insertions(+), 15 deletions(-) diff --git a/db/changes/10470-family/00-defaultViewConfig.sql b/db/changes/10470-family/00-defaultViewConfig.sql index 0a394e5bc..d423599b1 100644 --- a/db/changes/10470-family/00-defaultViewConfig.sql +++ b/db/changes/10470-family/00-defaultViewConfig.sql @@ -1,3 +1,3 @@ -INSERT INTO salix.defaultViewConfig (tableCode, columns) +INSERT INTO `salix`.`defaultViewConfig` (tableCode, columns) VALUES ('clientsDetail', '{"id":true,"phone":true,"city":true,"socialName":true,"salesPersonFk":true,"email":true,"name":false,"fi":false,"credit":false,"creditInsurance":false,"mobile":false,"street":false,"countryFk":false,"provinceFk":false,"postcode":false,"created":false,"businessTypeFk":false,"payMethodFk":false,"sageTaxTypeFk":false,"sageTransactionTypeFk":false,"isActive":false,"isVies":false,"isTaxDataChecked":false,"isEqualizated":false,"isFreezed":false,"hasToInvoice":false,"hasToInvoiceByAddress":false,"isToBeMailed":false,"hasLcr":false,"hasCoreVnl":false,"hasSepaVnl":false}'); diff --git a/front/core/components/smart-table/index.js b/front/core/components/smart-table/index.js index 9f913071e..401541c2c 100644 --- a/front/core/components/smart-table/index.js +++ b/front/core/components/smart-table/index.js @@ -333,6 +333,15 @@ export default class SmartTable extends Component { continue; } + input = this.$compile(` + `)(this.$inputsScope); + if (options && options.autocomplete) { let props = ``; @@ -348,7 +357,9 @@ export default class SmartTable extends Component { on-change="$ctrl.searchByColumn('${field}')" clear-disabled="true" />`)(this.$inputsScope); - } else if (options && options.checkbox) { + } + + if (options && options.checkbox) { input = this.$compile(` `)(this.$inputsScope); - } else if (options && options.datepicker) { + } + + if (options && options.datepicker) { input = this.$compile(` `)(this.$inputsScope); - } else { - input = this.$compile(` - `)(this.$inputsScope); } + cell.appendChild(input[0]); } searchRow.appendChild(cell); diff --git a/modules/client/back/methods/client/extendedListFilter.js b/modules/client/back/methods/client/extendedListFilter.js index 19e08fb7d..8e02cd413 100644 --- a/modules/client/back/methods/client/extendedListFilter.js +++ b/modules/client/back/methods/client/extendedListFilter.js @@ -144,7 +144,6 @@ module.exports = Self => { LEFT JOIN payMethod pm ON pm.id = c.payMethodFk LEFT JOIN sage.TiposIva sti ON sti.CodigoIva = c.taxTypeSageFk LEFT JOIN sage.TiposTransacciones stt ON stt.CodigoTransaccion = c.transactionTypeSageFk - ` ); diff --git a/modules/client/front/extended-list/index.html b/modules/client/front/extended-list/index.html index 23c331915..b45a0bc5f 100644 --- a/modules/client/front/extended-list/index.html +++ b/modules/client/front/extended-list/index.html @@ -1,8 +1,7 @@ + limit="20">