This commit is contained in:
Juan Ferrer Toribio 2018-01-30 16:34:32 +01:00
commit 109f04c517
14 changed files with 272 additions and 31 deletions

View File

@ -46,6 +46,47 @@
<vn-textfield vn-one label="Phone" field="$ctrl.address.phone"></vn-textfield> <vn-textfield vn-one label="Phone" field="$ctrl.address.phone"></vn-textfield>
<vn-textfield vn-one label="Mobile" field="$ctrl.address.mobile"></vn-textfield> <vn-textfield vn-one label="Mobile" field="$ctrl.address.mobile"></vn-textfield>
</vn-horizontal> </vn-horizontal>
<vn-one margin-medium-top>
<vn-title>Notes</vn-title>
<mg-ajax path="/client/api/ObservationTypes" options="mgIndex as observationsTypes"></mg-ajax>
<vn-horizontal ng-repeat="note in $ctrl.notes track by note.id">
<vn-autocomplete
vn-one
initial-data = "note.observationType"
field = "note.observationTypeFk"
data = "observationsTypes.model"
show-field = "description"
label = "Observation type"
order = "description ASC"
filter-search="{where: {description: {regexp: 'search'}} }"
>
<tpl-item>{{$parent.$parent.item.description}}</tpl-item>
</vn-autocomplete>
<vn-textfield vn-three label="Description" model="note.description"></vn-textfield>
<vn-one pad-medium-top>
<vn-icon
pointer
medium-grey
icon="remove_circle_outline"
ng-if = "note.showRemoveIcon"
ng-click="$ctrl.removeNote(note.id)"
>
</vn-icon>
<vn-icon
pointer
margin-medium-left
orange
icon="add_circle"
ng-if = "note.showAddIcon"
ng-click="$ctrl.addNote()"
></vn-icon>
</vn-one>
</vn-horizontal>
</vn-one>
</vn-vertical> </vn-vertical>
</vn-card> </vn-card>
<vn-button-bar> <vn-button-bar>

View File

@ -1,13 +1,76 @@
import ngModule from '../module'; import ngModule from '../module';
export default class Controller { export default class Controller {
constructor($state) { constructor($state, $http) {
this.address = { this.address = {
id: parseInt($state.params.addressId) id: parseInt($state.params.addressId)
}; };
this.$http = $http;
this.notes = [];
}
_setIconAdd() {
if (this.notes.length) {
this.notes.forEach(element => {
element.showAddIcon = false;
});
this.notes[this.notes.length - 1].showAddIcon = true;
}
}
_setRemoveAdd() {
if (this.notes.length) {
this.notes.forEach(element => {
element.showRemoveIcon = true;
});
} else {
this.notes = [this._createEmptyNote()];
}
}
_createEmptyNote() {
return {id: this._createFakeId(), observationTypeFk: null, description: null, showRemoveIcon: true, showAddIcon: true};
}
_createFakeId() {
let now = Date.now();
let random = Math.ceil((Math.random() * 100000) + 1);
return `fakeId${now}${random}`;
}
addNote() {
this.notes.push(this._createEmptyNote());
this._setIconAdd();
this._setRemoveAdd();
}
removeNote(id) {
let found = false;
for (let i = 0; i < this.notes.length; i++) {
if (this.notes[i].id === id) {
this.notes.splice(i, 1);
found = true;
break;
}
}
if (found) {
this._setIconAdd();
this._setRemoveAdd();
}
}
$onInit() {
let filter = {
where: {
addressFk: this.address.id
},
include: [
{relation: 'observationType'}
]
};
this.$http.get(`/client/api/AddressObservations?filter=${JSON.stringify(filter)}`).then(res => {
this.notes = (res.data && res.data.length) ? res.data : [this._createEmptyNote()];
this._setIconAdd();
this._setRemoveAdd();
});
} }
} }
Controller.$inject = ['$state']; Controller.$inject = ['$state', '$http'];
ngModule.component('vnAddressEdit', { ngModule.component('vnAddressEdit', {
template: require('./address-edit.html'), template: require('./address-edit.html'),

View File

@ -5,21 +5,27 @@
<vn-horizontal> <vn-horizontal>
<vn-title vn-one>Addresses</vn-title> <vn-title vn-one>Addresses</vn-title>
</vn-horizontal> </vn-horizontal>
<vn-horizontal ng-repeat="i in index.model.items track by i.id" class="pad-medium-top" style="align-items: center;"> <vn-horizontal ng-repeat="address in index.model.items track by address.id" class="pad-medium-top" style="align-items: center;">
<vn-one border-radius class="pad-small border-solid" <vn-one border-radius class="pad-small border-solid"
ng-class="{'bg-dark-item': i.isDefaultAddress,'bg-opacity-item': !i.isActive && !i.isDefaultAddress}"> ng-class="{'bg-dark-item': address.isDefaultAddress,'bg-opacity-item': !address.isEnabled && !address.isDefaultAddress}">
<vn-horizontal style="align-items: center;"> <vn-horizontal style="align-items: center;">
<vn-none pad-medium-h style="color:#FFA410;"> <vn-none pad-medium-h style="color:#FFA410;">
<i class="material-icons" ng-if="i.isDefaultAddress">star</i> <i class="material-icons" ng-if="address.isDefaultAddress">star</i>
<i class="material-icons pointer" ng-if="!i.isDefaultAddress" vn-tooltip="Set as default" tooltip-position="left" ng-click="$ctrl.setDefault(i.id)">star_border</i> <i class="material-icons pointer" ng-if="!address.isDefaultAddress" vn-tooltip="Set as default" tooltip-position="left" ng-click="$ctrl.setDefault(address.id)">star_border</i>
</vn-none> </vn-none>
<vn-one> <vn-one border-solid-right>
<div><b>{{::i.nickname}}</b></div> <div><b>{{::address.nickname}}</b></div>
<div>{{::i.street}}</div> <div>{{::address.street}}</div>
<div>{{::i.city}}, {{::i.province}}</div> <div>{{::address.city}}, {{::address.province}}</div>
<div>{{::i.phone}}, {{::i.mobile}}</div> <div>{{::address.phone}}, {{::address.mobile}}</div>
</vn-one> </vn-one>
<a vn-auto ui-sref="clientCard.addresses.edit({addressId: {{i.id}}})"> <vn-vertical vn-one pad-medium-h>
<vn-one ng-repeat="observation in address.observations track by $index" ng-class="{'pad-small-top': $index}">
<b margin-medium-right>{{::observation.observationType.description}}:</b>
<span>{{::observation.description}}</span>
</vn-one>
</vn-vertical>
<a vn-auto ui-sref="clientCard.addresses.edit({addressId: {{address.id}}})">
<vn-icon-button icon="edit"></vn-icon-button> <vn-icon-button icon="edit"></vn-icon-button>
</a> </a>
</vn-horizontal> </vn-horizontal>

View File

@ -14,7 +14,9 @@ class ItemCard {
{relation: "origin"}, {relation: "origin"},
{relation: "ink"}, {relation: "ink"},
{relation: "producer"}, {relation: "producer"},
{relation: "intrastat"} {relation: "intrastat"},
{relation: "expence"},
{relation: "taxClass"}
] ]
}; };
this.$http.get(`/item/api/Items/${this.$state.params.id}?filter=${JSON.stringify(filter)}`).then( this.$http.get(`/item/api/Items/${this.$state.params.id}?filter=${JSON.stringify(filter)}`).then(

View File

@ -23,6 +23,7 @@
show-field="name" show-field="name"
value-field="id" value-field="id"
field="$ctrl.item.typeFk" field="$ctrl.item.typeFk"
initial-data="$ctrl.item.itemType"
> >
</vn-autocomplete> </vn-autocomplete>
</vn-horizontal> </vn-horizontal>
@ -35,6 +36,7 @@
field="$ctrl.item.intrastatFk" field="$ctrl.item.intrastatFk"
order="description ASC" order="description ASC"
filter-search="{where: {description: {regexp: 'search'}} }" filter-search="{where: {description: {regexp: 'search'}} }"
initial-data="$ctrl.item.intrastat"
> >
<tpl-item>{{$parent.$parent.item.description}}</tpl-item> <tpl-item>{{$parent.$parent.item.description}}</tpl-item>
</vn-autocomplete> </vn-autocomplete>
@ -49,13 +51,28 @@
show-field="name" show-field="name"
value-field="id" value-field="id"
field="$ctrl.item.originFk" field="$ctrl.item.originFk"
initial-data="$ctrl.item.origin"
></vn-autocomplete> ></vn-autocomplete>
<vn-autocomplete vn-one <vn-autocomplete vn-one
url="/item/api/Expences" url="/item/api/Expences"
label="Expence" label="Expence"
field="$ctrl.item.expenceFk" field="$ctrl.item.expenceFk"
initial-data="$ctrl.item.expence"
></vn-autocomplete> ></vn-autocomplete>
</vn-horizontal> </vn-horizontal>
<vn-horizontal>
<vn-autocomplete vn-one
url="/item/api/TaxClasses"
label="TaxClass"
show-field="description"
value-field="id"
order="description ASC"
filter-search="{where: {description: {regexp: 'search'}} }"
field="$ctrl.item.taxClassFk"
initial-data="$ctrl.item.taxClass"
><tpl-item>{{$parent.$parent.item.description}}</tpl-item></vn-autocomplete>
<vn-one></vn-one>
</vn-horizontal>
</vn-vertical> </vn-vertical>
</vn-card> </vn-card>
<vn-button-bar> <vn-button-bar>

View File

@ -9,4 +9,16 @@ body {
} }
html [uppercase], .uppercase { html [uppercase], .uppercase {
text-transform: uppercase; text-transform: uppercase;
} }
html [green], .green{color: $color-green}
html [orange], .orange{color: $color-orange}
html [white], .white{color: $color-white}
html [dark], .dark{color: $color-dark}
html [dark-grey], .dark-grey{color: $color-dark-grey}
html [light-grey], .light-grey{color: $color-light-grey}
html [medium-grey], .medium-grey{color: $color-medium-grey}
html [medium-green], .medium-green{color: $color-medium-green}
html [medium-orange], .medium-orange{color: $color-medium-orange}
html [light-green], .light-green{color: $color-light-green}
html [light-orange], .light-orange{color: $color-light-orange}

View File

@ -8,7 +8,7 @@ webpackConfig.plugins = [];
// Generated on Tue Aug 22 2017 13:37:43 GMT+0200 (CEST) // Generated on Tue Aug 22 2017 13:37:43 GMT+0200 (CEST)
module.exports = function(config) { module.exports = function(config) {
let myConfig = { let baseConfig = {
// base path that will be used to resolve all patterns (eg. files, exclude) // base path that will be used to resolve all patterns (eg. files, exclude)
basePath: '', basePath: '',
@ -82,8 +82,17 @@ module.exports = function(config) {
let browserConfig; let browserConfig;
// TODO: Detect the browser if (process.env.FIREFOX_BIN) {
if (true) { browserConfig = {
browsers: ['FirefoxHeadless'],
customLaunchers: {
FirefoxHeadless: {
base: 'Firefox',
flags: ['--headless']
}
}
};
} else {
browserConfig = { browserConfig = {
browsers: ['ChromeNoSandboxHeadless'], browsers: ['ChromeNoSandboxHeadless'],
customLaunchers: { customLaunchers: {
@ -100,19 +109,8 @@ module.exports = function(config) {
} }
} }
}; };
} else {
browserConfig = {
browsers: ['FirefoxHeadless'],
customLaunchers: {
FirefoxHeadless: {
base: 'Firefox',
flags: [
'--headless'
]
}
}
};
} }
config.set(Object.assign(myConfig, browserConfig)); Object.assign(baseConfig, browserConfig);
config.set(baseConfig);
}; };

View File

@ -1,7 +1,22 @@
import app from '../../../server/server'; import app from '../../../server/server';
import routes from '../routes'; import routes from '../routes';
import restoreFixtures from '../../../../../services/db/testing_fixtures';
describe('Auth routes', () => { describe('Auth routes', () => {
let fixturesToApply = {tables: ['`salix`.`user`'], inserts: [
`INSERT INTO salix.user(id,username,password,email)
VALUES
(10, 'JessicaJones', 'ac754a330530832ba1bf7687f577da91', 'JessicaJones@verdnatura.es');`
]};
beforeEach(done => {
restoreFixtures(fixturesToApply, done);
});
afterAll(done => {
restoreFixtures(fixturesToApply, done);
});
let User = app.models.User; let User = app.models.User;
let loginFunction; let loginFunction;
let logoutFunction; let logoutFunction;
@ -29,6 +44,20 @@ describe('Auth routes', () => {
loginFunction(req, res); loginFunction(req, res);
}); });
describe('when the user doesnt exist but the client does and the password is correct', () => {
it('should create the user login and return the token', done => {
spyOn(User, 'upsertWithWhere').and.callThrough();
req.body.user = 'PetterParker';
req.body.password = 'nightmare';
res.json = response => {
expect(User.upsertWithWhere).toHaveBeenCalledWith(jasmine.any(Object), jasmine.any(Object), jasmine.any(Function));
expect(response.token).toBeDefined();
done();
};
loginFunction(req, res);
});
});
it('should define the url to continue upon login', done => { it('should define the url to continue upon login', done => {
req.body.user = 'JessicaJones'; req.body.user = 'JessicaJones';
req.body.password = 'nightmare'; req.body.password = 'nightmare';

View File

@ -38,7 +38,8 @@ module.exports = function(Client) {
}, },
skip: (params.page - 1) * params.size, skip: (params.page - 1) * params.size,
limit: params.size, limit: params.size,
order: ['isDefaultAddress DESC', 'isEnabled DESC'] order: ['isDefaultAddress DESC', 'isEnabled DESC'],
include: {observations: 'observationType'}
}; };
let total = null; let total = null;

View File

@ -0,0 +1,34 @@
{
"name": "AddressObservation",
"base": "VnModel",
"options": {
"mysql": {
"table": "addressObservation",
"database": "vn"
}
},
"properties": {
"id": {
"type": "Number",
"id": true,
"description": "Identifier"
},
"description": {
"type": "string",
"required": true
}
},
"relations": {
"address": {
"type": "belongsTo",
"model": "Address",
"foreignKey": "addressFk"
},
"observationType": {
"type": "belongsTo",
"model": "ObservationType",
"foreignKey": "observationTypeFk"
}
}
}

View File

@ -0,0 +1,22 @@
{
"name": "ObservationType",
"base": "VnModel",
"options": {
"mysql": {
"table": "observationType",
"database": "vn"
}
},
"properties": {
"id": {
"type": "Number",
"id": true,
"description": "Identifier"
},
"description": {
"type": "string",
"required": true
}
}
}

View File

@ -1,4 +1,7 @@
{ {
"AddressObservation": {
"dataSource": "vn"
},
"AgencyMode": { "AgencyMode": {
"dataSource": "vn" "dataSource": "vn"
}, },
@ -22,5 +25,8 @@
}, },
"MandateType": { "MandateType": {
"dataSource": "vn" "dataSource": "vn"
},
"ObservationType": {
"dataSource": "vn"
} }
} }

View File

@ -74,6 +74,11 @@
"type": "belongsTo", "type": "belongsTo",
"model": "Expence", "model": "Expence",
"foreignKey": "expenceFk" "foreignKey": "expenceFk"
},
"taxClass": {
"type": "belongsTo",
"model": "TaxClass",
"foreignKey": "taxClassFk"
} }
} }
} }

View File

@ -66,6 +66,11 @@
"type": "belongsTo", "type": "belongsTo",
"model": "AgencyMode", "model": "AgencyMode",
"foreignKey": "agencyFk" "foreignKey": "agencyFk"
},
"observations": {
"type": "hasMany",
"model": "AddressObservation",
"foreignKey": "addressFk"
} }
} }
} }