diff --git a/back/models/postcode.js b/back/models/postcode.js new file mode 100644 index 000000000..b08fdaa40 --- /dev/null +++ b/back/models/postcode.js @@ -0,0 +1,9 @@ +let UserError = require('vn-loopback/util/user-error'); + +module.exports = Self => { + Self.rewriteDbError(function(err) { + if (err.code === 'ER_DUP_ENTRY') + return new UserError(`This postcode already exists`); + return err; + }); +}; diff --git a/back/models/town.json b/back/models/town.json index 8ae252780..41633fe0a 100644 --- a/back/models/town.json +++ b/back/models/town.json @@ -41,16 +41,17 @@ "scopes": { "location": { "include": [{ + "relation": "postcodes" + }, + { "relation": "province", "scope": { "include": { "relation": "country" } } - }, - { - "relation": "postcodes" - }] + }], + "fields": ["id", "name", "provinceFk"] } } } \ No newline at end of file diff --git a/db/changes/10060-summer/00-ACL.sql b/db/changes/10060-summer/00-ACL.sql index fab3cbe72..90f25f089 100644 --- a/db/changes/10060-summer/00-ACL.sql +++ b/db/changes/10060-summer/00-ACL.sql @@ -1,4 +1,5 @@ INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('Zone', 'editPrices', 'WRITE', 'ALLOW', 'ROLE', 'deliveryBoss'), + ('Postcode', '*', 'WRITE', 'ALLOW', 'ROLE', 'employee'), ('Ticket', 'addSale', 'WRITE', 'ALLOW', 'ROLE', 'employee'); diff --git a/e2e/helpers/selectors.js b/e2e/helpers/selectors.js index 89830c372..7586b1846 100644 --- a/e2e/helpers/selectors.js +++ b/e2e/helpers/selectors.js @@ -116,7 +116,7 @@ export default { firstObservationDescriptionInput: 'vn-client-address-edit [name=observations] :nth-child(1) [model="observation.description"] input', secondObservationTypeAutocomplete: 'vn-client-address-edit [name=observations] :nth-child(2) [field="observation.observationTypeFk"]', secondObservationDescriptionInput: 'vn-client-address-edit [name=observations] :nth-child(2) [model="observation.description"] input', - addObservationButton: 'vn-client-address-edit vn-icon-button[icon="add_circle"]', + addObservationButton: 'vn-client-address-edit div[name="observations"] vn-icon-button[icon="add_circle"]', saveButton: `${components.vnSubmit}`, cancelCreateAddressButton: 'button[ui-sref="client.card.address.index"]', cancelEditAddressButton: 'vn-client-address-edit > form > vn-button-bar > vn-button > button' diff --git a/front/core/components/autocomplete/autocomplete.html b/front/core/components/autocomplete/autocomplete.html index c616c794a..4caca44bc 100755 --- a/front/core/components/autocomplete/autocomplete.html +++ b/front/core/components/autocomplete/autocomplete.html @@ -16,7 +16,7 @@ diff --git a/loopback/common/models/vn-model.js b/loopback/common/models/vn-model.js index c2bf8463e..d03d52ae8 100644 --- a/loopback/common/models/vn-model.js +++ b/loopback/common/models/vn-model.js @@ -152,8 +152,9 @@ module.exports = function(Self) { } try { - await realMethod.call(this, data, options); - if (cb) cb(); + const result = await realMethod.call(this, data, options); + + if (cb) cb(null, result); } catch (err) { let myErr = replaceErr(err, replaceErrFunc); if (cb) diff --git a/loopback/locale/es.json b/loopback/locale/es.json index 34be59419..256b51205 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -93,5 +93,6 @@ "Extension format is invalid": "El formato de la extensión es inválido", "Invalid parameters to create a new ticket": "Parámetros inválidos para crear un nuevo ticket", "This item is not available": "Este artículo no está disponible", + "This postcode already exists": "Este código postal ya existe", "Concept cannot be blank": "Concept cannot be blank" } \ No newline at end of file diff --git a/modules/client/front/address/create/index.html b/modules/client/front/address/create/index.html index 58c5cf817..9b3dc2ac2 100644 --- a/modules/client/front/address/create/index.html +++ b/modules/client/front/address/create/index.html @@ -24,9 +24,9 @@ - + + + + + + diff --git a/modules/client/front/address/create/index.js b/modules/client/front/address/create/index.js index 72a96d64a..bcccc0730 100644 --- a/modules/client/front/address/create/index.js +++ b/modules/client/front/address/create/index.js @@ -14,18 +14,28 @@ export default class Controller { this.address = this.data.address; } - setLocation() { - const location = this.$.postcode.selection; - if (!location || !location.town) return; - const town = location.town; + get postcodeSelection() { + return this._postcodeSelection; + } + + set postcodeSelection(selection) { + this._postcodeSelection = selection; + + if (!selection) return; + + const town = selection.town; const province = town.province; const country = province.country; - this.address.city = location.town.name; + this.address.city = town.name; this.address.provinceFk = province.id; this.address.countryFk = country.id; } + onResponse(response) { + this.address.postalCode = response.code; + } + onSubmit() { this.$.watcher.submit().then(res => { if (res.data && this.data.isDefaultAddress) diff --git a/modules/client/front/address/create/index.spec.js b/modules/client/front/address/create/index.spec.js index 5f447f0aa..45b009de7 100644 --- a/modules/client/front/address/create/index.spec.js +++ b/modules/client/front/address/create/index.spec.js @@ -49,5 +49,30 @@ describe('Client', () => { expect(controller.$state.go).toHaveBeenCalledWith('client.card.address.index'); }); }); + + describe('postcodeSelection() setter', () => { + it(`should set the town, province and contry properties`, () => { + controller.postcodeSelection = { + townFk: 1, + code: 46001, + town: { + id: 1, + name: 'New York', + province: { + id: 1, + name: 'New york', + country: { + id: 2, + name: 'USA' + } + } + } + }; + + expect(controller.address.city).toEqual('New York'); + expect(controller.address.provinceFk).toEqual(1); + expect(controller.address.countryFk).toEqual(2); + }); + }); }); }); diff --git a/modules/client/front/address/edit/index.html b/modules/client/front/address/edit/index.html index a19a6fa93..b7361b71b 100644 --- a/modules/client/front/address/edit/index.html +++ b/modules/client/front/address/edit/index.html @@ -40,7 +40,7 @@ - + + + + - - + + + + + diff --git a/modules/client/front/address/edit/index.js b/modules/client/front/address/edit/index.js index ba5ac75c5..14c5880bc 100644 --- a/modules/client/front/address/edit/index.js +++ b/modules/client/front/address/edit/index.js @@ -20,18 +20,28 @@ export default class Controller { this.$state.go('client.card.address.index'); } - setLocation() { - const location = this.$.postcode.selection; - if (!location || !location.town) return; - const town = location.town; + get postcodeSelection() { + return this._postcodeSelection; + } + + set postcodeSelection(selection) { + this._postcodeSelection = selection; + + if (!selection) return; + + const town = selection.town; const province = town.province; const country = province.country; - this.address.city = location.town.name; + this.address.city = town.name; this.address.provinceFk = province.id; this.address.countryFk = country.id; } + onResponse(response) { + this.address.postalCode = response.code; + } + onSubmit() { this.$.watcher.check(); this.$.watcher.realSubmit() diff --git a/modules/client/front/address/edit/index.spec.js b/modules/client/front/address/edit/index.spec.js index aa1f59669..ea0da9559 100644 --- a/modules/client/front/address/edit/index.spec.js +++ b/modules/client/front/address/edit/index.spec.js @@ -55,5 +55,31 @@ describe('Client', () => { expect(controller.$state.go).toHaveBeenCalledWith('client.card.address.index'); }); }); + + describe('postcodeSelection() setter', () => { + it(`should set the town, province and contry properties`, () => { + controller.address = {}; + controller.postcodeSelection = { + townFk: 1, + code: 46001, + town: { + id: 1, + name: 'New York', + province: { + id: 1, + name: 'New york', + country: { + id: 2, + name: 'USA' + } + } + } + }; + + expect(controller.address.city).toEqual('New York'); + expect(controller.address.provinceFk).toEqual(1); + expect(controller.address.countryFk).toEqual(2); + }); + }); }); }); diff --git a/modules/client/front/address/index/index.html b/modules/client/front/address/index/index.html index cdfd4d5a7..8696e321f 100644 --- a/modules/client/front/address/index/index.html +++ b/modules/client/front/address/index/index.html @@ -4,72 +4,70 @@ limit="10" link="{clientFk: $ctrl.$stateParams.id}" data="$ctrl.addresses" - auto-load="false"> + auto-load="true">
- - - - - - - - - - - - - - - - -
{{::address.nickname}}
-
{{::address.street}}
-
{{::address.city}}, {{::address.province}}
-
{{::address.phone}}, {{::address.mobile}}
-
- - - - -
-
- - - {{::observation.observationType.description}}: - {{::observation.description}} + + + + + + + + + + + + + + + +
{{::address.nickname}}
+
{{::address.street}}
+
{{::address.city}}, {{::address.province}}
+
{{::address.phone}}, {{::address.mobile}}
-
- - - -
-
-
-
- + + + + + + + + + {{::observation.observationType.description}}: + {{::observation.description}} + + + + + + + + +
-
+ @@ -33,9 +33,9 @@ - + + -
+ + + + +
\ No newline at end of file diff --git a/modules/client/front/create/index.js b/modules/client/front/create/index.js index ec9c2817c..241de110f 100644 --- a/modules/client/front/create/index.js +++ b/modules/client/front/create/index.js @@ -1,34 +1,46 @@ import ngModule from '../module'; export default class Controller { - constructor($scope, $state, $http) { + constructor($scope, $state, $http, $translate, vnApp) { this.$ = $scope; this.$state = $state; this.$http = $http; + this.$translate = $translate; + this.vnApp = vnApp; this.client = { active: true }; } - setLocation() { - const location = this.$.postcode.selection; - if (!location || !location.town) return; - const town = location.town; + get postcodeSelection() { + return this._postcodeSelection; + } + + set postcodeSelection(selection) { + this._postcodeSelection = selection; + + if (!selection) return; + + const town = selection.town; const province = town.province; const country = province.country; - this.client.city = location.town.name; + this.client.city = town.name; this.client.provinceFk = province.id; this.client.countryFk = country.id; } + onResponse(response) { + this.client.postcode = response.code; + } + onSubmit() { - this.$.watcher.submit().then( + return this.$.watcher.submit().then( json => this.$state.go('client.card.basicData', {id: json.data.id}) ); } } -Controller.$inject = ['$scope', '$state', '$http']; +Controller.$inject = ['$scope', '$state', '$http', '$translate', 'vnApp']; ngModule.component('vnClientCreate', { template: require('./index.html'), diff --git a/modules/client/front/create/index.spec.js b/modules/client/front/create/index.spec.js index fb8aa227e..b59dffe44 100644 --- a/modules/client/front/create/index.spec.js +++ b/modules/client/front/create/index.spec.js @@ -39,5 +39,30 @@ describe('Client', () => { expect(controller.$state.go).toHaveBeenCalledWith('client.card.basicData', {id: '1234'}); }); }); + + describe('postcodeSelection() setter', () => { + it(`should set the town, province and contry properties`, () => { + controller.postcodeSelection = { + townFk: 1, + code: 46001, + town: { + id: 1, + name: 'New York', + province: { + id: 1, + name: 'New york', + country: { + id: 2, + name: 'USA' + } + } + } + }; + + expect(controller.client.city).toEqual('New York'); + expect(controller.client.provinceFk).toEqual(1); + expect(controller.client.countryFk).toEqual(2); + }); + }); }); }); diff --git a/modules/client/front/index.js b/modules/client/front/index.js index f7e4368db..04439b9ab 100644 --- a/modules/client/front/index.js +++ b/modules/client/front/index.js @@ -35,5 +35,6 @@ import './sample/create'; import './web-payment'; import './log'; import './sms'; +import './postcode'; import './dms/index'; import './dms/create'; diff --git a/modules/client/front/postcode/index.html b/modules/client/front/postcode/index.html new file mode 100644 index 000000000..5ff80440e --- /dev/null +++ b/modules/client/front/postcode/index.html @@ -0,0 +1,47 @@ + + +
New postcode
+

Please, ensure you put the correct data!

+ + + + + + + + + + + + +
+ + + + +
\ No newline at end of file diff --git a/modules/client/front/postcode/index.js b/modules/client/front/postcode/index.js new file mode 100644 index 000000000..08a419dab --- /dev/null +++ b/modules/client/front/postcode/index.js @@ -0,0 +1,70 @@ +import ngModule from '../module'; +import Component from 'core/lib/component'; +import './style.scss'; + +class Controller extends Component { + constructor($element, $scope, $http, $translate, vnApp) { + super($element, $scope); + this.$ = $scope; + this.$http = $http; + this.$translate = $translate; + this.vnApp = vnApp; + } + + get townSelection() { + return this._townSelection; + } + + set townSelection(selection) { + this._townSelection = selection; + + if (!selection) return; + + const province = selection.province; + const country = province.country; + + this.data.provinceFk = province.id; + this.data.countryFk = country.id; + } + + open() { + this.$.postcodeDialog.show(); + } + + onOpen() { + this.$.postcode.focus(); + } + + onResponse(response) { + if (response == 'ACCEPT') { + try { + if (!this.data.code) + throw new Error(`The postcode can't be empty`); + if (!this.data.townFk) + throw new Error(`The town can't be empty`); + + this.$http.patch(`/api/postcodes`, this.data).then(response => { + if (response.data) { + this.vnApp.showMessage(this.$translate.instant('The postcode has been saved')); + + this.emit('response', {response: response.data}); + } + }); + } catch (e) { + this.vnApp.showError(this.$translate.instant(e.message)); + return false; + } + } + return true; + } +} + +Controller.$inject = ['$element', '$scope', '$http', '$translate', 'vnApp']; + +ngModule.component('vnClientPostcode', { + template: require('./index.html'), + controller: Controller, + bindings: { + data: '<', + } +}); diff --git a/modules/client/front/postcode/index.spec.js b/modules/client/front/postcode/index.spec.js new file mode 100644 index 000000000..ce5cd5f2e --- /dev/null +++ b/modules/client/front/postcode/index.spec.js @@ -0,0 +1,34 @@ +import './index'; + +describe('Client', () => { + describe('Component vnClientPostcode', () => { + let controller; + let $httpBackend; + let $element; + + beforeEach(ngModule('client')); + + beforeEach(angular.mock.inject(($componentController, _$httpBackend_) => { + $httpBackend = _$httpBackend_; + $element = angular.element(''); + controller = $componentController('vnClientPostcode', {$element}); + controller.client = {id: 101}; + })); + + describe('onResponse()', () => { + it('should perform a POST query and show a success snackbar', () => { + let params = {townFk: 1, provinceFk: 1, countryFk: 1, code: '46460'}; + controller.data = {townFk: 1, provinceFk: 1, countryFk: 1, code: '46460'}; + + spyOn(controller.vnApp, 'showMessage'); + $httpBackend.when('PATCH', `/api/postcodes`, params).respond(200, params); + $httpBackend.expect('PATCH', `/api/postcodes`, params).respond(params); + + controller.onResponse('ACCEPT'); + $httpBackend.flush(); + + expect(controller.vnApp.showMessage).toHaveBeenCalledWith('The postcode has been saved'); + }); + }); + }); +}); diff --git a/modules/client/front/postcode/locale/es.yml b/modules/client/front/postcode/locale/es.yml new file mode 100644 index 000000000..ab8b0fc21 --- /dev/null +++ b/modules/client/front/postcode/locale/es.yml @@ -0,0 +1,5 @@ +New postcode: Nuevo código postal +Please, ensure you put the correct data!: ¡Por favor, asegúrate de poner los datos correctos! +The postcode can't be empty: El código postal no puede quedar vacío +The town can't be empty: La población no puede quedar vacía +The postcode has been saved: El código postal ha sido guardado \ No newline at end of file diff --git a/modules/client/front/postcode/style.scss b/modules/client/front/postcode/style.scss new file mode 100644 index 000000000..b9ef984b7 --- /dev/null +++ b/modules/client/front/postcode/style.scss @@ -0,0 +1,9 @@ +@import "variables"; + +vn-client-postcode { + vn-dialog { + p { + color: $color-alert + } + } +} \ No newline at end of file diff --git a/modules/item/back/methods/item/clone.js b/modules/item/back/methods/item/clone.js index c4e15aa01..f543164fc 100644 --- a/modules/item/back/methods/item/clone.js +++ b/modules/item/back/methods/item/clone.js @@ -65,14 +65,19 @@ module.exports = Self => { fields: ['botanical', 'countryFk', 'taxClassFk'] }, options); + const promises = []; for (tax of originalTaxes) { tax.itemFk = newId; - await models.ItemTaxCountry.upsertWithWhere({ + const newTax = models.ItemTaxCountry.upsertWithWhere({ itemFk: newId, countryFk: tax.countryFk, }, tax, options); + + promises.push(newTax); } + + await Promise.all(promises); } /** @@ -110,10 +115,14 @@ module.exports = Self => { fields: ['tagFk', 'value', 'priority'] }, options); + const promises = []; for (tag of originalTags) { tag.itemFk = newId; + const newItemTag = models.ItemTag.create(tag, options); - await models.ItemTag.create(tag, options); + promises.push(newItemTag); } + + await Promise.all(promises); } }; diff --git a/modules/ticket/back/methods/ticket/addSale.js b/modules/ticket/back/methods/ticket/addSale.js index 595d036c5..dd3bdd218 100644 --- a/modules/ticket/back/methods/ticket/addSale.js +++ b/modules/ticket/back/methods/ticket/addSale.js @@ -43,7 +43,7 @@ module.exports = Self => { const ticket = await models.Ticket.findById(id); const shouldRefresh = false; - const [[stock]] = await Self.rawSql(`CALL vn.getItemVisibleAvailable(?, ?, ?, ?)`, [ + const [[stock]] = await Self.rawSql(`CALL vn.itemGetVisibleAvailable(?, ?, ?, ?)`, [ itemId, ticket.shipped, ticket.warehouseFk,