Autocomplete geolocation from postcode #1519 and #1531
gitea/salix/dev This commit looks good Details

This commit is contained in:
Joan Sanchez 2019-06-13 13:08:11 +02:00
parent 03205e01ae
commit 9c00e7e67c
26 changed files with 390 additions and 101 deletions

View File

@ -11,6 +11,9 @@
"Company": {
"dataSource": "vn"
},
"Container": {
"dataSource": "storage"
},
"Delivery": {
"dataSource": "vn"
},
@ -44,8 +47,11 @@
"DmsType": {
"dataSource": "vn"
},
"Container": {
"dataSource": "storage"
"Town": {
"dataSource": "vn"
},
"Postcode": {
"dataSource": "vn"
}
}

50
back/models/postcode.json Normal file
View File

@ -0,0 +1,50 @@
{
"name": "Postcode",
"base": "VnModel",
"options": {
"mysql": {
"table": "postCode"
}
},
"properties": {
"code": {
"id": true,
"type": "String"
}
},
"relations": {
"town": {
"type": "belongsTo",
"model": "Town",
"foreignKey": "townFk"
},
"geo": {
"type": "belongsTo",
"model": "ZoneGeo",
"foreignKey": "geoFk"
}
},
"acls": [{
"accessType": "READ",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW"
}],
"scopes": {
"location": {
"include": {
"relation": "town",
"scope": {
"include": {
"relation": "province",
"scope": {
"include": {
"relation": "country"
}
}
}
}
}
}
}
}

56
back/models/town.json Normal file
View File

@ -0,0 +1,56 @@
{
"name": "Town",
"base": "VnModel",
"options": {
"mysql": {
"table": "town"
}
},
"properties": {
"id": {
"id": true,
"type": "Number"
},
"name": {
"type": "String"
}
},
"relations": {
"province": {
"type": "belongsTo",
"model": "Province",
"foreignKey": "provinceFk"
},
"postcodes": {
"type": "hasMany",
"model": "Postcode",
"foreignKey": "townFk"
},
"geo": {
"type": "belongsTo",
"model": "ZoneGeo",
"foreignKey": "geoFk"
}
},
"acls": [{
"accessType": "READ",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW"
}],
"scopes": {
"location": {
"include": [{
"relation": "province",
"scope": {
"include": {
"relation": "country"
}
}
},
{
"relation": "postcodes"
}]
}
}
}

View File

@ -5,7 +5,7 @@ export MYSQL_PWD=root
mysql_import() {
FILE=$1
echo "[INFO] -> Imported $FILE"
mysql -u root --comments -f < "$FILE"
mysql -u root --default-character-set=utf8 --comments -f < "$FILE"
}
mysql_import dump/structure.sql

View File

@ -147,6 +147,20 @@ INSERT INTO `vn`.`province`(`id`, `name`, `countryFk`, `warehouseFk`, `zoneFk`)
(4, 'Province four', 1, NULL, 2),
(5, 'Province five', 1, NULL, 1);
INSERT INTO `vn`.`town`(`id`, `name`, `provinceFk`)
VALUES
(1, 'Valencia', 1),
(2, 'Silla', 1),
(3, 'Algemesi', 1),
(4, 'Alzira', 1);
INSERT INTO `vn`.`postCode`(`code`, `townFk`)
VALUES
('46000', 1),
('46460', 2),
('46680', 3),
('46600', 4);
INSERT INTO `vn`.`clientType`(`id`, `code`, `type`)
VALUES
(1, 'normal', 'Normal'),

View File

@ -33,7 +33,10 @@ export default {
taxNumber: `${components.vnTextfield}[name="fi"]`,
socialName: `${components.vnTextfield}[name="socialName"]`,
street: `${components.vnTextfield}[name="street"]`,
city: `${components.vnTextfield}[name="city"]`,
postcode: `vn-autocomplete[field="$ctrl.client.postcode"]`,
city: `vn-autocomplete[field="$ctrl.client.city"]`,
province: `vn-autocomplete[field="$ctrl.client.provinceFk"]`,
country: `vn-autocomplete[field="$ctrl.client.countryFk"]`,
userName: `${components.vnTextfield}[name="userName"]`,
email: `${components.vnTextfield}[name="email"]`,
salesPersonAutocomplete: `vn-autocomplete[field="$ctrl.client.salesPersonFk"]`,
@ -62,8 +65,8 @@ export default {
equalizationTaxCheckbox: 'vn-check[label="Is equalizated"] md-checkbox',
acceptPropagationButton: 'vn-client-fiscal-data > vn-confirm button[response=ACCEPT]',
addressInput: `${components.vnTextfield}[name="street"]`,
cityInput: `${components.vnTextfield}[name="city"]`,
postcodeInput: `${components.vnTextfield}[name="postcode"]`,
postcodeAutocomplete: `vn-autocomplete[field="$ctrl.client.postcode"]`,
cityAutocomplete: `vn-autocomplete[field="$ctrl.client.city"]`,
provinceAutocomplete: 'vn-autocomplete[field="$ctrl.client.provinceFk"]',
countryAutocomplete: 'vn-autocomplete[field="$ctrl.client.countryFk"]',
activeCheckbox: 'vn-check[label="Active"] md-checkbox',
@ -97,8 +100,8 @@ export default {
defaultCheckboxInput: 'vn-check[label="Default"] md-checkbox',
consigneeInput: `${components.vnTextfield}[name="nickname"]`,
streetAddressInput: `${components.vnTextfield}[name="street"]`,
postcodeInput: `${components.vnTextfield}[name="postalCode"]`,
cityInput: `${components.vnTextfield}[name="city"]`,
postcodeAutocomplete: `vn-autocomplete[field="$ctrl.address.postalCode"]`,
cityAutocomplete: `vn-autocomplete[field="$ctrl.address.city"]`,
provinceAutocomplete: 'vn-autocomplete[field="$ctrl.address.provinceFk"]',
agencyAutocomplete: 'vn-autocomplete[field="$ctrl.address.agencyModeFk"]',
phoneInput: `${components.vnTextfield}[name="phone"]`,

View File

@ -53,7 +53,7 @@ describe('Client create path', () => {
.write(selectors.createClientView.name, 'Carol Danvers')
.write(selectors.createClientView.socialName, 'AVG tax')
.write(selectors.createClientView.street, 'Many places')
.write(selectors.createClientView.city, 'Silla')
.autocompleteSearch(selectors.createClientView.postcode, '46000')
.clearInput(selectors.createClientView.email)
.write(selectors.createClientView.email, 'incorrect email format')
.waitToClick(selectors.createClientView.createButton)
@ -62,6 +62,21 @@ describe('Client create path', () => {
expect(result).toEqual('Some fields are invalid');
});
it(`should check for autocompleted city, province and country`, async() => {
const clientCity = await nightmare
.waitToGetProperty(`${selectors.createClientView.city} input`, 'value');
const clientProvince = await nightmare
.waitToGetProperty(`${selectors.createClientView.province} input`, 'value');
const clientCountry = await nightmare
.waitToGetProperty(`${selectors.createClientView.country} input`, 'value');
expect(clientCity).toEqual('Valencia');
expect(clientProvince).toEqual('Province one');
expect(clientCountry).toEqual('España');
});
it(`should create a new user with all correct data`, async() => {
const result = await nightmare
.clearInput(selectors.createClientView.email)

View File

@ -67,11 +67,7 @@ describe('Client Edit fiscalData path', () => {
.write(selectors.clientFiscalData.fiscalIdInput, 'INVALID!')
.clearInput(selectors.clientFiscalData.addressInput)
.write(selectors.clientFiscalData.addressInput, 'Somewhere edited')
.clearInput(selectors.clientFiscalData.postcodeInput)
.write(selectors.clientFiscalData.postcodeInput, '12345')
.clearInput(selectors.clientFiscalData.cityInput)
.write(selectors.clientFiscalData.cityInput, 'N/A')
.autocompleteSearch(selectors.clientFiscalData.provinceAutocomplete, 'Province two')
.autocompleteSearch(selectors.clientFiscalData.postcodeAutocomplete, '46000')
.waitToClick(selectors.clientFiscalData.activeCheckbox)
.waitToClick(selectors.clientFiscalData.frozenCheckbox)
.waitToClick(selectors.clientFiscalData.hasToInvoiceCheckbox)
@ -197,23 +193,31 @@ describe('Client Edit fiscalData path', () => {
it('should confirm the postcode have been edited', async() => {
const result = await nightmare
.waitToGetProperty(selectors.clientFiscalData.postcodeInput, 'value');
.waitToGetProperty(`${selectors.clientFiscalData.postcodeAutocomplete} input`, 'value');
expect(result).toEqual('12345');
expect(result).toContain('46000');
});
it('should confirm the city have been edited', async() => {
it('should confirm the city have been autocompleted', async() => {
const result = await nightmare
.waitToGetProperty(selectors.clientFiscalData.cityInput, 'value');
.waitToGetProperty(`${selectors.clientFiscalData.cityAutocomplete} input`, 'value');
expect(result).toEqual('N/A');
expect(result).toEqual('Valencia');
});
it(`should confirm the province have been selected`, async() => {
it(`should confirm the province have been autocompleted`, async() => {
const result = await nightmare
.waitToGetProperty(`${selectors.clientFiscalData.provinceAutocomplete} input`, 'value');
expect(result).toEqual('Province two');
expect(result).toEqual('Province one');
});
it('should confirm the country have been autocompleted', async() => {
const result = await nightmare
.waitToGetProperty(`${selectors.clientFiscalData.countryAutocomplete} input`, 'value');
expect(result).toEqual('España');
});
it('should confirm active checkbox is unchecked', async() => {

View File

@ -24,8 +24,7 @@ describe('Client Add address path', () => {
const result = await nightmare
.waitToClick(selectors.clientAddresses.defaultCheckboxInput)
.clearInput(selectors.clientAddresses.streetAddressInput)
.write(selectors.clientAddresses.postcodeInput, '10022')
.autocompleteSearch(selectors.clientAddresses.provinceAutocomplete, 'Province four')
.autocompleteSearch(selectors.clientAddresses.postcodeAutocomplete, '46000')
.autocompleteSearch(selectors.clientAddresses.agencyAutocomplete, 'Entanglement')
.write(selectors.clientAddresses.phoneInput, '999887744')
.write(selectors.clientAddresses.mobileInput, '999887744')
@ -35,11 +34,32 @@ describe('Client Add address path', () => {
expect(result).toEqual('Some fields are invalid');
});
it('should confirm the postcode have been edited', async() => {
const result = await nightmare
.waitToGetProperty(`${selectors.clientAddresses.postcodeAutocomplete} input`, 'value');
expect(result).toContain('46000');
});
it('should confirm the city have been autocompleted', async() => {
const result = await nightmare
.waitToGetProperty(`${selectors.clientAddresses.cityAutocomplete} input`, 'value');
expect(result).toEqual('Valencia');
});
it(`should confirm the province have been autocompleted`, async() => {
const result = await nightmare
.waitToGetProperty(`${selectors.clientAddresses.provinceAutocomplete} input`, 'value');
expect(result).toEqual('Province one');
});
it(`should create a new address with all it's data`, async() => {
const result = await nightmare
.write(selectors.clientAddresses.consigneeInput, 'Bruce Bunner')
.write(selectors.clientAddresses.streetAddressInput, '320 Park Avenue New York')
.write(selectors.clientAddresses.cityInput, 'New York')
.waitToClick(selectors.clientAddresses.saveButton)
.waitForLastSnackbar();

View File

@ -19,6 +19,6 @@
</div>
<vn-drop-down
vn-id="drop-down"
on-select="$ctrl.onDropDownSelect(value)"
on-select="$ctrl.onDropDownSelect(item)"
on-data-ready="$ctrl.onDataReady()">
</vn-drop-down>

View File

@ -79,10 +79,10 @@ export default class Autocomplete extends Input {
}
set field(value) {
if (angular.equals(value, this._field))
return;
this._field = value;
if (!value) return;
this.refreshSelection();
this.emit('change', {value});
}
@ -125,7 +125,9 @@ export default class Autocomplete extends Input {
|| this.selectionIsValid(this._selection))
return;
this.selection = this.fetchSelection();
const selection = this.fetchSelection();
if (!this.selection)
this.selection = selection;
}
fetchSelection() {
@ -217,7 +219,9 @@ export default class Autocomplete extends Input {
if (this.form) this.form.$setDirty();
}
onDropDownSelect(value) {
onDropDownSelect(item) {
const value = item[this.valueField];
this.selection = item;
this.setValue(value);
this.field = value;
}

View File

@ -7,7 +7,7 @@
</button>
<vn-drop-down
vn-id="drop-down"
on-select="$ctrl.onDropDownSelect(value)"
on-select="$ctrl.onDropDownSelect(item)"
ng-click="$ctrl.onDropDownClick($event)">
</vn-drop-down>
</div>

View File

@ -53,7 +53,8 @@ export default class ButtonMenu extends Input {
event.preventDefault();
}
onDropDownSelect(value) {
onDropDownSelect(item) {
const value = item[this.valueField];
this.field = value;
this.emit('change', {value});
}

View File

@ -7,6 +7,7 @@ describe('Component vnButtonMenu', () => {
beforeEach(inject(($compile, $rootScope) => {
$element = $compile(`<vn-icon-menu></vn-icon-menu>`)($rootScope);
controller = $element.controller('vnIconMenu');
controller.valueField = 'name';
}));
afterEach(() => {
@ -31,10 +32,10 @@ describe('Component vnButtonMenu', () => {
describe('onDropDownSelect(value)', () => {
it(`should set field to the given value and emit the change event`, () => {
spyOn(controller, 'emit');
controller.onDropDownSelect('mariano');
controller.onDropDownSelect({name: 'Item name'});
expect(controller.field).toBe('mariano');
expect(controller.emit).toHaveBeenCalledWith('change', {value: 'mariano'});
expect(controller.field).toBe('Item name');
expect(controller.emit).toHaveBeenCalledWith('change', {value: 'Item name'});
});
});
});

View File

@ -8,7 +8,7 @@
model="$ctrl.search"
class="search"
ng-blur="$ctrl.onFocusOut()"
label = "Search">
label="Search">
</vn-textfield>
</div>
<div class="list" tabindex="-1">

View File

@ -186,7 +186,7 @@ export default class DropDown extends Component {
this.field = value;
}
this.emit('select', {value: value});
this.emit('select', {item});
}
if (!this.multiple)

View File

@ -5,7 +5,7 @@
</vn-icon>
<vn-drop-down
vn-id="drop-down"
on-select="$ctrl.onDropDownSelect(value)"
on-select="$ctrl.onDropDownSelect(item)"
ng-click="$ctrl.onDropDownClick($event)">
</vn-drop-down>
</div>

View File

@ -6,6 +6,14 @@
save="post"
form="form">
</vn-watcher>
<vn-crud-model
vn-id="model"
url="/client/api/AddressObservations"
fields="['id', 'addressFk', 'observationTypeFk', 'description']"
link="{addressFk: $ctrl.$stateParams.addressId}"
data="observations"
auto-load="true">
</vn-crud-model>
<form name="form" ng-submit="$ctrl.onSubmit()" compact>
<vn-card pad-large>
<vn-horizontal pad-small-v>
@ -16,22 +24,40 @@
<vn-textfield vn-one label="Street address" field="$ctrl.address.street"></vn-textfield>
</vn-horizontal>
<vn-horizontal>
<vn-textfield vn-one label="Postcode" field="$ctrl.address.postalCode"></vn-textfield>
<vn-textfield vn-one label="Town/City" field="$ctrl.address.city"></vn-textfield>
<vn-autocomplete
vn-one
<vn-autocomplete vn-id="postcode" vn-one
field="$ctrl.address.postalCode"
on-change="$ctrl.setLocation()"
search-function="{code: $search}"
url="/api/Postcodes/location"
fields="['code', 'townFk']"
show-field="code"
value-field="code"
label="Postcode">
<tpl-item>
{{code}}, {{town.name}} - {{town.province.name}}
({{town.province.country.country}})
</tpl-item>
</vn-autocomplete>
<vn-autocomplete vn-one
label="City"
url="/api/Towns"
show-field="name"
value-field="name"
field="$ctrl.address.city">
</vn-autocomplete>
<vn-autocomplete vn-one
disabled="true"
field="$ctrl.address.provinceFk"
url="/client/api/Provinces"
url="/api/Provinces"
show-field="name"
value-field="id"
label="Province">
</vn-autocomplete>
</vn-horizontal>
</vn-horizontal>
<vn-horizontal>
<vn-autocomplete
vn-one
field="$ctrl.address.agencyModeFk"
url="/client/api/AgencyModes/isActive"
url="/api/AgencyModes/isActive"
show-field="name"
value-field="id"
label="Agency">

View File

@ -1,8 +1,8 @@
import ngModule from '../../module';
export default class Controller {
constructor($scope, $state) {
this.$scope = $scope;
constructor($, $state) {
this.$ = $;
this.$state = $state;
this.data = {
address: {
@ -14,8 +14,20 @@ export default class Controller {
this.address = this.data.address;
}
setLocation() {
const location = this.$.postcode.selection;
if (!location || !location.town) return;
const town = location.town;
const province = town.province;
const country = province.country;
this.address.city = location.town.name;
this.address.provinceFk = province.id;
this.address.countryFk = country.id;
}
onSubmit() {
this.$scope.watcher.submit().then(res => {
this.$.watcher.submit().then(res => {
if (res.data && this.data.isDefaultAddress)
this.client.defaultAddressFk = res.data.id;

View File

@ -14,8 +14,8 @@ describe('Client', () => {
$state = _$state_;
$state.params.id = '1234';
controller = $componentController('vnClientAddressCreate', {$state});
controller.$scope.watcher = watcher;
controller.$scope.watcher.submit = () => {
controller.$.watcher = watcher;
controller.$.watcher.submit = () => {
return {
then: callback => {
callback({data: {id: 124}});

View File

@ -25,7 +25,7 @@
data="types"
auto-load="true">
</vn-crud-model>
<form name="form" ng-submit="$ctrl.submit()" compact>
<form name="form" ng-submit="$ctrl.onSubmit()" compact>
<vn-card pad-large>
<vn-horizontal pad-small-v>
<vn-check vn-one label="Enabled" field="$ctrl.address.isActive"></vn-check>
@ -40,12 +40,31 @@
<vn-textfield vn-one label="Street" field="$ctrl.address.street"></vn-textfield>
</vn-horizontal>
<vn-horizontal>
<vn-textfield vn-one label="Postcode" field="$ctrl.address.postalCode"></vn-textfield>
<vn-textfield vn-one label="City" field="$ctrl.address.city"></vn-textfield>
<vn-autocomplete vn-id="postcode" vn-one
field="$ctrl.address.postalCode"
on-change="$ctrl.setLocation()"
search-function="{code: $search}"
url="/api/Postcodes/location"
fields="['code', 'townFk']"
show-field="code"
value-field="code"
label="Postcode">
<tpl-item>
{{code}}, {{town.name}} - {{town.province.name}}
({{town.province.country.country}})
</tpl-item>
</vn-autocomplete>
<vn-autocomplete vn-one
initial-data="$ctrl.address.province"
label="City"
url="/api/Towns"
show-field="name"
value-field="name"
field="$ctrl.address.city">
</vn-autocomplete>
<vn-autocomplete vn-one
disabled="true"
field="$ctrl.address.provinceFk"
url="/client/api/Provinces"
url="/api/Provinces"
show-field="name"
value-field="id"
label="Province">

View File

@ -20,7 +20,19 @@ export default class Controller {
this.$state.go('client.card.address.index');
}
submit() {
setLocation() {
const location = this.$.postcode.selection;
if (!location || !location.town) return;
const town = location.town;
const province = town.province;
const country = province.country;
this.address.city = location.town.name;
this.address.provinceFk = province.id;
this.address.countryFk = country.id;
}
onSubmit() {
this.$.watcher.check();
this.$.watcher.realSubmit()
.then(() => this.$.model.save(true))

View File

@ -33,34 +33,45 @@
</vn-textfield>
</vn-horizontal>
<vn-horizontal>
<vn-textfield
vn-one
label="Postcode"
field="$ctrl.client.postcode">
</vn-textfield>
<vn-textfield
vn-one
<vn-autocomplete vn-id="postcode" vn-one
field="$ctrl.client.postcode"
on-change="$ctrl.setLocation()"
search-function="{code: $search}"
url="/api/Postcodes/location"
fields="['code', 'townFk']"
show-field="code"
value-field="code"
label="Postcode">
<tpl-item>
{{code}}, {{town.name}} - {{town.province.name}}
({{town.province.country.country}})
</tpl-item>
</vn-autocomplete>
<vn-autocomplete vn-one
label="City"
url="/api/Towns"
show-field="name"
value-field="name"
field="$ctrl.client.city">
</vn-textfield>
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal>
<vn-autocomplete
vn-one
field="$ctrl.client.countryFk"
url="/client/api/Countries"
show-field="country"
value-field="id"
label="Country">
</vn-autocomplete>
<vn-autocomplete
vn-one
<vn-autocomplete vn-one
disabled="true"
field="$ctrl.client.provinceFk"
url="/client/api/Provinces"
url="/api/Provinces"
show-field="name"
value-field="id"
label="Province">
</vn-autocomplete>
<vn-autocomplete vn-one
disabled="true"
field="$ctrl.client.countryFk"
url="/api/Countries"
show-field="country"
value-field="id"
label="Country">
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal>
<vn-textfield

View File

@ -1,20 +1,34 @@
import ngModule from '../module';
export default class Controller {
constructor($scope, $state) {
constructor($scope, $state, $http) {
this.$ = $scope;
this.$state = $state;
this.$http = $http;
this.client = {
active: true
};
}
setLocation() {
const location = this.$.postcode.selection;
if (!location || !location.town) return;
const town = location.town;
const province = town.province;
const country = province.country;
this.client.city = location.town.name;
this.client.provinceFk = province.id;
this.client.countryFk = country.id;
}
onSubmit() {
this.$.watcher.submit().then(
json => this.$state.go('client.card.basicData', {id: json.data.id})
);
}
}
Controller.$inject = ['$scope', '$state'];
Controller.$inject = ['$scope', '$state', '$http'];
ngModule.component('vnClientCreate', {
template: require('./index.html'),

View File

@ -5,7 +5,7 @@
form="form"
save="patch">
</vn-watcher>
<form name="form" ng-submit="$ctrl.submit()" compact>
<form name="form" ng-submit="$ctrl.onSubmit()" compact>
<vn-card pad-large>
<vn-horizontal>
<vn-textfield
@ -28,36 +28,45 @@
</vn-textfield>
</vn-horizontal>
<vn-horizontal>
<vn-textfield
vn-one
label="Postcode"
field="$ctrl.client.postcode">
</vn-textfield>
<vn-textfield
vn-one
<vn-autocomplete vn-id="postcode" vn-one
field="$ctrl.client.postcode"
on-change="$ctrl.setLocation()"
search-function="{code: $search}"
url="/api/Postcodes/location"
fields="['code', 'townFk']"
show-field="code"
value-field="code"
label="Postcode">
<tpl-item>
{{code}}, {{town.name}} - {{town.province.name}}
({{town.province.country.country}})
</tpl-item>
</vn-autocomplete>
<vn-autocomplete vn-one
label="City"
url="/api/Towns"
show-field="name"
value-field="name"
field="$ctrl.client.city">
</vn-textfield>
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal>
<vn-autocomplete
vn-one
initial-data="$ctrl.client.country"
field="$ctrl.client.countryFk"
url="/client/api/Countries"
show-field="country"
value-field="id"
label="Country">
</vn-autocomplete>
<vn-autocomplete
vn-one
initial-data="$ctrl.client.province"
<vn-autocomplete vn-one
disabled="true"
field="$ctrl.client.provinceFk"
url="/client/api/Provinces"
url="/api/Provinces"
show-field="name"
value-field="id"
label="Province">
</vn-autocomplete>
<vn-autocomplete vn-one
disabled="true"
field="$ctrl.client.countryFk"
url="/api/Countries"
show-field="country"
value-field="id"
label="Country">
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal pad-small-v>
<vn-check

View File

@ -24,7 +24,7 @@ export default class Controller {
return !this.client.isTaxDataChecked;
}
submit() {
onSubmit() {
if (this.isEqualizated != this.client.isEqualizated) {
this.oldHasToInvoiceByAddress = this.client.hasToInvoiceByAddress;
this.client.hasToInvoiceByAddress = false;
@ -56,6 +56,18 @@ export default class Controller {
);
}
}
setLocation() {
const location = this.$.postcode.selection;
if (!location || !location.town) return;
const town = location.town;
const province = town.province;
const country = province.country;
this.client.city = location.town.name;
this.client.provinceFk = province.id;
this.client.countryFk = country.id;
}
}
Controller.$inject = ['$scope', '$http', 'vnApp', '$translate'];