Merge branch 'dev' of https://git.verdnatura.es:/salix into test
This commit is contained in:
commit
e1a565ae1f
|
@ -1,5 +1,6 @@
|
|||
extends: [eslint:recommended, google, plugin:jasmine/recommended]
|
||||
installedESLint: true
|
||||
parserOptions:
|
||||
ecmaVersion: 2017
|
||||
plugins:
|
||||
- jasmine
|
||||
env:
|
||||
|
@ -18,3 +19,4 @@ rules:
|
|||
no-eq-null: 0
|
||||
no-console: 0
|
||||
no-warning-comments: 0
|
||||
no-empty: [error, allowEmptyCatch: true]
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
.DS_Store
|
||||
node_modules
|
||||
build
|
||||
npm-debug.log
|
||||
debug.log
|
||||
datasources.development.json
|
||||
.idea
|
||||
docker-compose.yml
|
||||
|
|
|
@ -2,25 +2,10 @@
|
|||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Asociar",
|
||||
"type": "node",
|
||||
"request": "attach",
|
||||
"port": 5858,
|
||||
"address": "localhost",
|
||||
"restart": false,
|
||||
"sourceMaps": false,
|
||||
"outFiles": [],
|
||||
"localRoot": "${workspaceRoot}",
|
||||
"remoteRoot": null
|
||||
},
|
||||
{
|
||||
"name": "Asociar al proceso",
|
||||
"type": "node",
|
||||
"request": "attach",
|
||||
"processId": "${command:PickProcess}",
|
||||
"port": 5858,
|
||||
"sourceMaps": false,
|
||||
"outFiles": []
|
||||
"name": "Attach by Process ID",
|
||||
"processId": "${command:PickProcess}"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
FROM node:8.9.4
|
||||
|
||||
COPY . /app
|
||||
COPY ../loopback /loopback
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN npm install
|
||||
RUN npm -g install pm2
|
||||
|
||||
CMD ["pm2-docker", "./server/server.js"]
|
||||
|
||||
EXPOSE 3000
|
|
@ -0,0 +1,17 @@
|
|||
Copyright (C) 2018 - Verdnatura Levante S.L.
|
||||
|
||||
This package is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
On Debian systems, the complete text of the GNU General Public
|
||||
License can be found in "/usr/share/common-licenses/GPL-3".
|
87
README.md
87
README.md
|
@ -1,67 +1,64 @@
|
|||
# Project Title
|
||||
# Salix
|
||||
|
||||
Salix is an Enterprise resource planning (ERP) integrated management of core business processes, in real-time and mediated by software and technology developed with the stack listed below.
|
||||
This project is an Enterprise resource planning (ERP) integrated management of core business processes, in real-time and mediated by software and technology developed with the stack listed below.
|
||||
|
||||
Salix is also the scientific name of a beautifull tree! :)
|
||||
|
||||
### Prerequisites
|
||||
## Prerequisites
|
||||
|
||||
You will need to install globally the following items:
|
||||
$ npm install -g karma
|
||||
$ npm install -g karma-cli
|
||||
$ npm install -g gulp
|
||||
$ npm install -g webpack
|
||||
$ npm install -g nodemon
|
||||
Required applications.
|
||||
|
||||
install nginx globally.
|
||||
* Node.js = 8.9.4
|
||||
* NGINX
|
||||
* Docker
|
||||
|
||||
## Getting Started // ### Installing
|
||||
You will need to install globally the following items.
|
||||
```
|
||||
$ npm install -g karma-cli gulp webpack nodemon
|
||||
```
|
||||
|
||||
## Getting Started // Installing
|
||||
|
||||
Pull from repository.
|
||||
|
||||
install nodejs v6.
|
||||
|
||||
Ask a senior developer for the datasources.development.json files required to run the project.
|
||||
|
||||
on root run:
|
||||
Run this commands on project root directory to install Node dependencies.
|
||||
```
|
||||
$ npm install
|
||||
$ gulp install
|
||||
```
|
||||
|
||||
lauching nginx:
|
||||
$ ./dev.sh
|
||||
Launch application in developer environment.
|
||||
```
|
||||
$ gulp
|
||||
```
|
||||
|
||||
launching frontend:
|
||||
Also you can run backend and frontend as separately gulp tasks (including NGINX).
|
||||
```
|
||||
$ gulp client
|
||||
or start nginx before client on sequence
|
||||
$ gulp clientDev
|
||||
|
||||
launching backend:
|
||||
$ gulp services
|
||||
or start the local database before services on sequence
|
||||
$ gulp serivcesDev
|
||||
```
|
||||
|
||||
Manually reset local fixtures:
|
||||
Manually reset fixtures.
|
||||
```
|
||||
$ gulp docker
|
||||
```
|
||||
|
||||
to check docker images and containers status:
|
||||
$ docker images
|
||||
$ docker ps -a
|
||||
## Running the unit tests
|
||||
|
||||
## Running the tests
|
||||
|
||||
for client-side unit tests run from project's root:
|
||||
For client-side unit tests run from project's root.
|
||||
```
|
||||
$ karma start
|
||||
```
|
||||
|
||||
for server-side unit tests run from project's root:
|
||||
For server-side unit tests run from project's root.
|
||||
```
|
||||
$ npm run test
|
||||
```
|
||||
|
||||
### Break down into end to end tests
|
||||
|
||||
Run local database plus e2e paths:
|
||||
For end-to-end tests run from project's root.
|
||||
```
|
||||
$ gulp e2e
|
||||
|
||||
Just the e2e paths as the fixtures are untainted:
|
||||
$ npm run e2e
|
||||
```
|
||||
|
||||
## Built With
|
||||
|
||||
|
@ -71,12 +68,6 @@ $ npm run e2e
|
|||
* [loopback](https://loopback.io/)
|
||||
* [docker](https://www.docker.com/)
|
||||
* [gulp.js](https://gulpjs.com/)
|
||||
|
||||
## Versioning
|
||||
|
||||
We use [SourceTree](https://www.sourcetreeapp.com/) for versioning. For the versions available, see the [salix project](https://git.verdnatura.es).
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the MIT License
|
||||
|
||||
* [Karma](https://karma-runner.github.io/)
|
||||
* [Jasmine](https://jasmine.github.io/)
|
||||
* [Nightmare](http://www.nightmarejs.org/)
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"name": "@salix/auth",
|
||||
"version": "0.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://git.verdnatura.es/salix"
|
||||
}
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
{
|
||||
"User": "User",
|
||||
"Password": "Password",
|
||||
"Do not close session": "Do not close session",
|
||||
"Enter": "Enter"
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
User: User
|
||||
Password: Password
|
||||
Do not close session: Do not close session
|
||||
Enter: Enter
|
|
@ -1,6 +0,0 @@
|
|||
{
|
||||
"User": "Usuario",
|
||||
"Password": "Contraseña",
|
||||
"Do not close session": "No cerrar sesión",
|
||||
"Enter": "Entrar"
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
User: Usuario
|
||||
Password: Contraseña
|
||||
Do not close session: No cerrar sesión
|
||||
Enter: Entrar
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"name": "@salix/client",
|
||||
"version": "0.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://git.verdnatura.es/salix"
|
||||
}
|
||||
}
|
|
@ -121,7 +121,8 @@
|
|||
"menu": {
|
||||
"description": "Credit",
|
||||
"icon": "credit_card"
|
||||
}
|
||||
},
|
||||
"acl": ["manager", "salesAssistant", "teamBoss", "teamManager"]
|
||||
}, {
|
||||
"url": "/create",
|
||||
"state": "clientCard.credit.create",
|
||||
|
|
|
@ -3,9 +3,10 @@
|
|||
url="/client/api/Addresses"
|
||||
id-field="id"
|
||||
data="$ctrl.address"
|
||||
save="post"
|
||||
form="form">
|
||||
</vn-watcher>
|
||||
<form name="form" ng-submit="watcher.submitGo('clientCard.addresses')" pad-medium>
|
||||
<form name="form" ng-submit="watcher.submitGo('clientCard.addresses.list')" pad-medium>
|
||||
<vn-card >
|
||||
<vn-vertical pad-large>
|
||||
<vn-title>Address</vn-title>
|
||||
|
@ -13,7 +14,7 @@
|
|||
<vn-check vn-one label="Default" field="$ctrl.address.isDefaultAddress"></vn-check>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-one label="Consignee" field="$ctrl.address.consignee" vn-focus></vn-textfield>
|
||||
<vn-textfield vn-one label="Consignee" field="$ctrl.address.nickname" vn-focus></vn-textfield>
|
||||
<vn-textfield vn-one label="Street address" field="$ctrl.address.street"></vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
|
|
|
@ -4,7 +4,7 @@ export default class Controller {
|
|||
constructor($state) {
|
||||
this.address = {
|
||||
clientFk: parseInt($state.params.id),
|
||||
isEnabled: true
|
||||
isActive: true
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ describe('Client', () => {
|
|||
|
||||
it('should define and set address property', () => {
|
||||
expect(controller.address.clientFk).toBe(1234);
|
||||
expect(controller.address.isEnabled).toBe(true);
|
||||
expect(controller.address.isActive).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
{
|
||||
"Street address": "Dirección postal",
|
||||
"Default": "Predeterminado",
|
||||
"Consignee": "Consignatario",
|
||||
"Postcode": "Código postal",
|
||||
"Town/City": "Ciudad",
|
||||
"Province": "Provincia",
|
||||
"Agency": "Agencia",
|
||||
"Phone": "Teléfono",
|
||||
"Mobile": "Móvil"
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
Street address: Dirección postal
|
||||
Default: Predeterminado
|
||||
Consignee: Consignatario
|
||||
Postcode: Código postal
|
||||
Town/City: Ciudad
|
||||
Province: Provincia
|
||||
Agency: Agencia
|
||||
Phone: Teléfono
|
||||
Mobile: Móvil
|
|
@ -1,4 +1,4 @@
|
|||
<mg-ajax path="/client/api/Addresses/{{edit.params.addressId}}" actions="$ctrl.address=edit.model" options="mgEdit"></mg-ajax>
|
||||
<mg-ajax path="/client/api/Addresses/{{edit.params.addressId}}" actions="$ctrl.address=edit.model;$ctrl._setIconAdd();" options="mgEdit"></mg-ajax>
|
||||
<vn-watcher
|
||||
vn-id="watcher"
|
||||
url="/client/api/Addresses"
|
||||
|
@ -6,20 +6,20 @@
|
|||
data="$ctrl.address"
|
||||
form="form">
|
||||
</vn-watcher>
|
||||
<form name="form" ng-submit="watcher.submitBack()" pad-medium>
|
||||
<form name="form" ng-submit="$ctrl.submit()" pad-medium>
|
||||
<vn-card>
|
||||
<vn-vertical pad-large>
|
||||
<vn-title>Address</vn-title>
|
||||
<vn-horizontal>
|
||||
<vn-one>
|
||||
<vn-check label="Enabled" field="$ctrl.address.isEnabled"></vn-check>
|
||||
<vn-check label="Enabled" field="$ctrl.address.isActive"></vn-check>
|
||||
</vn-one>
|
||||
<vn-one>
|
||||
<vn-check label="Is equalizated" field="$ctrl.address.isEqualizated" vn-acl="administrative"></vn-check>
|
||||
</vn-one>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-one label="Consignee" field="$ctrl.address.consignee" vn-focus></vn-textfield>
|
||||
<vn-textfield vn-one label="Consignee" field="$ctrl.address.nickname" vn-focus></vn-textfield>
|
||||
<vn-textfield vn-one label="Street" field="$ctrl.address.street"></vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
|
@ -36,8 +36,8 @@
|
|||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-autocomplete vn-one
|
||||
initial-data="$ctrl.address.defaultAgency"
|
||||
field="$ctrl.address.defaultAgencyFk"
|
||||
initial-data="$ctrl.address.agency"
|
||||
field="$ctrl.address.agencyFk"
|
||||
url="/client/api/AgencyModes"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
|
@ -46,6 +46,46 @@
|
|||
<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-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="observation in $ctrl.observations track by $index">
|
||||
<vn-autocomplete
|
||||
vn-one
|
||||
initial-data = "observation.observationType"
|
||||
field = "observation.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="observation.description"></vn-textfield>
|
||||
<vn-one pad-medium-top>
|
||||
<vn-icon
|
||||
pointer
|
||||
medium-grey
|
||||
icon="remove_circle_outline"
|
||||
ng-click="$ctrl.removeObservation($index)"
|
||||
>
|
||||
</vn-icon>
|
||||
<vn-icon
|
||||
pointer
|
||||
margin-medium-left
|
||||
orange
|
||||
icon="add_circle"
|
||||
ng-if = "observation.showAddIcon && observationsTypes.model.length > $ctrl.observations.length"
|
||||
ng-click="$ctrl.addObservation()"
|
||||
></vn-icon>
|
||||
</vn-one>
|
||||
</vn-horizontal>
|
||||
|
||||
</vn-one>
|
||||
|
||||
|
||||
</vn-vertical>
|
||||
</vn-card>
|
||||
<vn-button-bar>
|
||||
|
|
|
@ -1,13 +1,139 @@
|
|||
import ngModule from '../module';
|
||||
|
||||
export default class Controller {
|
||||
constructor($state) {
|
||||
constructor($state, $scope, $http, $q, $translate, vnApp) {
|
||||
this.$state = $state;
|
||||
this.$scope = $scope;
|
||||
this.$http = $http;
|
||||
this.$q = $q;
|
||||
this.$translate = $translate;
|
||||
this.vnApp = vnApp;
|
||||
|
||||
this.address = {
|
||||
id: parseInt($state.params.addressId)
|
||||
};
|
||||
this.observations = [];
|
||||
this.observationsOld = {};
|
||||
this.observationsRemoved = [];
|
||||
}
|
||||
|
||||
_setIconAdd() {
|
||||
if (this.observations.length) {
|
||||
this.observations.map(element => {
|
||||
element.showAddIcon = false;
|
||||
return true;
|
||||
});
|
||||
this.observations[this.observations.length - 1].showAddIcon = true;
|
||||
} else {
|
||||
this.addObservation();
|
||||
}
|
||||
}
|
||||
|
||||
_setDirtyForm() {
|
||||
if (this.$scope.form) {
|
||||
this.$scope.form.$setDirty();
|
||||
}
|
||||
}
|
||||
_unsetDirtyForm() {
|
||||
if (this.$scope.form) {
|
||||
this.$scope.form.$setPristine();
|
||||
}
|
||||
}
|
||||
|
||||
addObservation() {
|
||||
this.observations.push({observationTypeFk: null, addressFk: this.address.id, description: null, showAddIcon: true});
|
||||
this._setIconAdd();
|
||||
}
|
||||
|
||||
removeObservation(index) {
|
||||
let item = this.observations[index];
|
||||
if (item) {
|
||||
this.observations.splice(index, 1);
|
||||
this._setIconAdd();
|
||||
if (item.id) {
|
||||
this.observationsRemoved.push(item.id);
|
||||
this._setDirtyForm();
|
||||
}
|
||||
}
|
||||
}
|
||||
_submitObservations(objectObservations) {
|
||||
return this.$http.post(`/client/api/AddressObservations/crudAddressObservations`, objectObservations);
|
||||
}
|
||||
|
||||
_observationsEquals(ob1, ob2) {
|
||||
return ob1.id === ob2.id && ob1.observationTypeFk === ob2.observationTypeFk && ob1.description === ob2.description;
|
||||
}
|
||||
|
||||
submit() {
|
||||
this._unsetDirtyForm();
|
||||
let submitWatcher = this.$scope.watcher.dataChanged();
|
||||
let submitObservations;
|
||||
let repeatedTypes = false;
|
||||
let types = [];
|
||||
let observationsObj = {
|
||||
delete: this.observationsRemoved,
|
||||
create: [],
|
||||
update: []
|
||||
};
|
||||
|
||||
for (let i = 0; i < this.observations.length; i++) {
|
||||
let observation = this.observations[i];
|
||||
let isNewObservation = observation.id === undefined;
|
||||
|
||||
if (observation.observationTypeFk && types.indexOf(observation.observationTypeFk) !== -1) {
|
||||
repeatedTypes = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (observation.observationTypeFk)
|
||||
types.push(observation.observationTypeFk);
|
||||
|
||||
if (isNewObservation && observation.observationTypeFk && observation.description) {
|
||||
observationsObj.create.push(observation);
|
||||
} else if (!isNewObservation && !this._observationsEquals(this.observationsOld[observation.id], observation)) {
|
||||
observationsObj.update.push(observation);
|
||||
}
|
||||
}
|
||||
|
||||
submitObservations = observationsObj.update.length > 0 || observationsObj.create.length > 0 || observationsObj.delete.length > 0;
|
||||
|
||||
if (repeatedTypes) {
|
||||
this.vnApp.showMessage(
|
||||
this.$translate.instant('The observation type must be unique')
|
||||
);
|
||||
} else if (submitWatcher && !submitObservations) {
|
||||
this.$scope.watcher.submit().then(() => {
|
||||
this.$state.go('clientCard.addresses.list', {id: this.$state.params.id});
|
||||
});
|
||||
} else if (!submitWatcher && submitObservations) {
|
||||
this._submitObservations(observationsObj).then(() => {
|
||||
this.$state.go('clientCard.addresses.list', {id: this.$state.params.id});
|
||||
});
|
||||
} else if (submitWatcher && submitObservations) {
|
||||
this.$q.all([this.$scope.watcher.submit(), this._submitObservations(observationsObj)]).then(() => {
|
||||
this.$state.go('clientCard.addresses.list', {id: this.$state.params.id});
|
||||
});
|
||||
} else {
|
||||
this.vnApp.showMessage(
|
||||
this.$translate.instant('No changes to save')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$onInit() {
|
||||
let filter = {
|
||||
where: {addressFk: this.address.id},
|
||||
include: {relation: 'observationType'}
|
||||
};
|
||||
this.$http.get(`/client/api/AddressObservations?filter=${JSON.stringify(filter)}`).then(res => {
|
||||
this.observations = res.data;
|
||||
res.data.forEach(item => {
|
||||
this.observationsOld[item.id] = Object.assign({}, item);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
Controller.$inject = ['$state'];
|
||||
Controller.$inject = ['$state', '$scope', '$http', '$q', '$translate', 'vnApp'];
|
||||
|
||||
ngModule.component('vnAddressEdit', {
|
||||
template: require('./address-edit.html'),
|
||||
|
|
|
@ -5,20 +5,101 @@ describe('Client', () => {
|
|||
let $componentController;
|
||||
let $state;
|
||||
let controller;
|
||||
let $httpBackend;
|
||||
|
||||
beforeEach(() => {
|
||||
angular.mock.module('client');
|
||||
});
|
||||
|
||||
beforeEach(angular.mock.inject((_$componentController_, _$state_) => {
|
||||
beforeEach(angular.mock.inject((_$componentController_, _$state_, _$httpBackend_) => {
|
||||
$componentController = _$componentController_;
|
||||
$state = _$state_;
|
||||
$state.params.addressId = '1234';
|
||||
$httpBackend = _$httpBackend_;
|
||||
$state.params.addressId = '1';
|
||||
controller = $componentController('vnAddressEdit', {$state: $state});
|
||||
}));
|
||||
|
||||
it('should define and set address property', () => {
|
||||
expect(controller.address.id).toBe(1234);
|
||||
expect(controller.address.id).toEqual(1);
|
||||
});
|
||||
|
||||
describe('_setIconAdd()', () => {
|
||||
it('should set the propertie sowAddIcon from all observations to false less last one that be true', () => {
|
||||
controller.observations = [
|
||||
{id: 1, description: 'Spiderman rocks', showAddIcon: true},
|
||||
{id: 2, description: 'Batman sucks', showAddIcon: true},
|
||||
{id: 3, description: 'Ironman rules', showAddIcon: false}
|
||||
];
|
||||
|
||||
controller._setIconAdd();
|
||||
|
||||
expect(controller.observations[0].showAddIcon).toBeFalsy();
|
||||
expect(controller.observations[1].showAddIcon).toBeFalsy();
|
||||
expect(controller.observations[2].showAddIcon).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('addObservation()', () => {
|
||||
it('should add one empty observation into controller observations collection and call _setIconAdd()', () => {
|
||||
controller.observations = [];
|
||||
spyOn(controller, '_setIconAdd').and.callThrough();
|
||||
controller.addObservation();
|
||||
|
||||
expect(controller._setIconAdd).toHaveBeenCalledWith();
|
||||
expect(controller.observations.length).toEqual(1);
|
||||
expect(controller.observations[0].id).toBe(undefined);
|
||||
expect(controller.observations[0].showAddIcon).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('removeObservation(index)', () => {
|
||||
it('should remove an observation that occupies the position in the index given and call _setIconAdd()', () => {
|
||||
let index = 2;
|
||||
controller.observations = [
|
||||
{id: 1, description: 'Spiderman rocks', showAddIcon: false},
|
||||
{id: 2, description: 'Batman sucks', showAddIcon: false},
|
||||
{id: 3, description: 'Ironman rules', showAddIcon: true}
|
||||
];
|
||||
|
||||
spyOn(controller, '_setIconAdd').and.callThrough();
|
||||
|
||||
controller.removeObservation(index);
|
||||
|
||||
expect(controller._setIconAdd).toHaveBeenCalledWith();
|
||||
expect(controller.observations.length).toEqual(2);
|
||||
expect(controller.observations[0].showAddIcon).toBeFalsy();
|
||||
expect(controller.observations[1].showAddIcon).toBeTruthy();
|
||||
expect(controller.observations[index]).toBe(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
describe('_observationsEquals', () => {
|
||||
it('should return true if two observations are equals independent of control attributes', () => {
|
||||
let ob1 = {id: 1, observationTypeFk: 1, description: 'Spiderman rocks', showAddIcon: true};
|
||||
let ob2 = {id: 1, observationTypeFk: 1, description: 'Spiderman rocks', showAddIcon: false};
|
||||
let equals = controller._observationsEquals(ob2, ob1);
|
||||
|
||||
expect(equals).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should return false if two observations are not equals independent of control attributes', () => {
|
||||
let ob1 = {id: 1, observationTypeFk: 1, description: 'Spiderman rocks', showAddIcon: true};
|
||||
let ob2 = {id: 1, observationTypeFk: 1, description: 'Spiderman sucks', showAddIcon: true};
|
||||
let equals = controller._observationsEquals(ob2, ob1);
|
||||
|
||||
expect(equals).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('$onInit()', () => {
|
||||
it('should perform a GET query to receive the address observations', () => {
|
||||
let filter = {where: {addressFk: 1}, include: {relation: 'observationType'}};
|
||||
let res = ['some notes'];
|
||||
$httpBackend.when('GET', `/client/api/AddressObservations?filter=${JSON.stringify(filter)}`).respond(res);
|
||||
$httpBackend.expectGET(`/client/api/AddressObservations?filter=${JSON.stringify(filter)}`);
|
||||
controller.$onInit();
|
||||
$httpBackend.flush();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"Enabled": "Activo",
|
||||
"Is equalizated": "Recargo de equivalencia"
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
Enabled: Activo
|
||||
Is equalizated: Recargo de equivalencia
|
||||
Observation type: Tipo de observación
|
||||
Description: Descripción
|
||||
The observation type must be unique: El tipo de observación ha de ser único
|
|
@ -1,25 +1,39 @@
|
|||
<mg-ajax path="/client/api/Clients/{{index.params.id}}/addressesList" options="mgIndex"></mg-ajax>
|
||||
<mg-ajax path="/client/api/Clients/{{index.params.id}}/listAddresses" options="mgIndex"></mg-ajax>
|
||||
<vn-vertical pad-medium>
|
||||
<vn-card>
|
||||
<vn-vertical pad-large>
|
||||
<vn-horizontal>
|
||||
<vn-title vn-one>Addresses</vn-title>
|
||||
</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"
|
||||
ng-class="{'bg-dark-item': i.isDefaultAddress,'bg-opacity-item': !i.isEnabled && !i.isDefaultAddress}">
|
||||
ng-class="{'bg-dark-item': address.isDefaultAddress,'bg-opacity-item': !address.isActive && !address.isDefaultAddress}">
|
||||
<vn-horizontal style="align-items: center;">
|
||||
<vn-none pad-medium-h style="color:#FFA410;">
|
||||
<i class="material-icons" ng-if="i.isDefaultAddress">star</i>
|
||||
<i class="material-icons pointer" ng-if="!i.isDefaultAddress&&i.isEnabled" vn-tooltip="Set as default" tooltip-position="left" ng-click="$ctrl.setDefault(i.id)">star_border</i>
|
||||
<i class="material-icons" ng-if="address.isDefaultAddress">star</i>
|
||||
<i class="material-icons"
|
||||
vn-tooltip="Active first to set as default"
|
||||
tooltip-position="left"
|
||||
ng-if="!address.isActive">star_border</i>
|
||||
<i class="material-icons pointer"
|
||||
ng-if="address.isActive && !address.isDefaultAddress"
|
||||
vn-tooltip="Set as default"
|
||||
tooltip-position="left"
|
||||
ng-click="$ctrl.setDefault(address)">star_border</i>
|
||||
</vn-none>
|
||||
<vn-one>
|
||||
<div><b>{{::i.consignee}}</b></div>
|
||||
<div>{{::i.street}}</div>
|
||||
<div>{{::i.city}}, {{::i.province}}</div>
|
||||
<div>{{::i.phone}}, {{::i.mobile}}</div>
|
||||
<vn-one border-solid-right>
|
||||
<div><b>{{::address.nickname}}</b></div>
|
||||
<div>{{::address.street}}</div>
|
||||
<div>{{::address.city}}, {{::address.province}}</div>
|
||||
<div>{{::address.phone}}, {{::address.mobile}}</div>
|
||||
</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>
|
||||
</a>
|
||||
</vn-horizontal>
|
||||
|
@ -27,9 +41,7 @@
|
|||
</vn-horizontal>
|
||||
</vn-vertical>
|
||||
</vn-card>
|
||||
|
||||
<vn-paging index="index" total="index.model.total"></vn-paging>
|
||||
|
||||
<vn-float-button
|
||||
fixed-bottom-right
|
||||
ui-sref="clientCard.addresses.create"
|
||||
|
|
|
@ -5,10 +5,13 @@ class ClientAddresses {
|
|||
this.$http = $http;
|
||||
this.$scope = $scope;
|
||||
}
|
||||
setDefault(id) {
|
||||
this.$http.patch(`/client/api/Addresses/${id}`, {id: id, isDefaultAddress: true}).then(() => {
|
||||
this.$scope.index.accept();
|
||||
});
|
||||
setDefault(address) {
|
||||
if (address.isActive) {
|
||||
let params = {isDefaultAddress: true};
|
||||
this.$http.patch(`/client/api/Addresses/${address.id}`, params).then(
|
||||
() => this.$scope.index.accept()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
ClientAddresses.$inject = ['$http', '$scope'];
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"Set as default": "Establecer como predeterminado"
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
Set as default: Establecer como predeterminado
|
||||
Active first to set as default: Active primero para marcar como predeterminado
|
|
@ -19,8 +19,7 @@
|
|||
<vn-textfield vn-one
|
||||
label="Email"
|
||||
field="$ctrl.client.email"
|
||||
info="You can save multiple emails by chaining them using comma without spaces, example: user@domain.com,user2@domain.com the first email will be considered as the main"
|
||||
>
|
||||
info="You can save multiple emails">
|
||||
</vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
|
@ -30,10 +29,9 @@
|
|||
url="/client/api/Clients/activeSalesPerson"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
select-fields="surname"
|
||||
select-fields="name"
|
||||
label="Salesperson"
|
||||
filter-search="{where: {or: [{name: {regexp: 'search'}}, {surname: {regexp: 'search'}}]}}"
|
||||
>
|
||||
filter-search="{where: {or: [{name: {regexp: 'search'}}, {name: {regexp: 'search'}}]}}">
|
||||
</vn-autocomplete>
|
||||
<vn-autocomplete vn-one
|
||||
initial-data="$ctrl.client.contactChannel"
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
{
|
||||
"Comercial Name": "Nombre comercial",
|
||||
"Tax number": "NIF/CIF",
|
||||
"Social name": "Razón social",
|
||||
"Phone": "Teléfono",
|
||||
"Mobile": "Móvil",
|
||||
"Fax": "Fax",
|
||||
"Email": "Correo electrónico",
|
||||
"Salesperson": "Comercial",
|
||||
"Channel": "Canal",
|
||||
"You can save multiple emails by chaining them using comma without spaces, example: user@domain.com,user2@domain.com the first email will be considered as the main": "Puede guardar varios correos electrónicos encadenándolos mediante comas sin espacios, ejemplo: user@dominio.com,user2@dominio.com siendo el primer correo electrónico el principal",
|
||||
"Contact": "Contacto"
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
Comercial Name: Nombre comercial
|
||||
Tax number: NIF/CIF
|
||||
Social name: Razón social
|
||||
Phone: Teléfono
|
||||
Mobile: Móvil
|
||||
Fax: Fax
|
||||
Email: Correo electrónico
|
||||
Salesperson: Comercial
|
||||
Channel: Canal
|
||||
You can save multiple emails: >-
|
||||
Puede guardar varios correos electrónicos encadenándolos mediante comas
|
||||
sin espacios, ejemplo: user@dominio.com, user2@dominio.com siendo el primer
|
||||
correo electrónico el principal
|
||||
Contact: Contacto
|
|
@ -41,9 +41,7 @@ export default class Controller {
|
|||
returnDialog(response) {
|
||||
if (response === 'ACCEPT') {
|
||||
this.$http.post(`/mailer/notification/payment-update/${this.client.id}`).then(
|
||||
() => {
|
||||
this.vnApp.showMessage(this.translate.instant('Notification sent!'));
|
||||
}
|
||||
() => this.vnApp.showMessage(this.translate.instant('Notification sent!'))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ describe('Client', () => {
|
|||
beforeEach(angular.mock.inject((_$componentController_, $rootScope, _$httpBackend_) => {
|
||||
$componentController = _$componentController_;
|
||||
$httpBackend = _$httpBackend_;
|
||||
$httpBackend.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
|
||||
$scope = $rootScope.$new();
|
||||
let submit = jasmine.createSpy('submit').and.returnValue(Promise.resolve());
|
||||
$scope.watcher = {submit};
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
{
|
||||
"Changed terms": "Has modificado las condiciones de pago",
|
||||
"Notify customer?" : "¿Deseas notificar al cliente de dichos cambios?",
|
||||
"No": "No",
|
||||
"Yes, notify": "Sí, notificar",
|
||||
"Notification sent!": "¡Notificación enviada!",
|
||||
"Notification error": "Error al enviar notificación",
|
||||
"You changes the equivalent tax": "Has cambiado el recargo de equivalencia",
|
||||
"Do you want to spread the change to their consignees?" : "¿Deseas propagar el cambio a sus consignatarios?",
|
||||
"Yes, propagate": "Si, propagar",
|
||||
"Equivalent tax spreaded": "Recargo de equivalencia propagado",
|
||||
"Invoice by address": "Facturar por consignatario",
|
||||
"Equalization tax": "Recargo de equivalencia",
|
||||
"Due day": "Vencimiento",
|
||||
"Received core VNH": "Recibido core VNH",
|
||||
"Received core VNL": "Recibido core VNL",
|
||||
"Received B2B VNL": "Recibido B2B VNL",
|
||||
"SAVE": "GUARDAR"
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
Changed terms: Has modificado las condiciones de pago
|
||||
Notify customer?: ¿Deseas notificar al cliente de dichos cambios?
|
||||
No: No
|
||||
Yes, notify: Sí, notificar
|
||||
Notification sent!: ¡Notificación enviada!
|
||||
Notification error: Error al enviar notificación
|
||||
You changes the equivalent tax: Has cambiado el recargo de equivalencia
|
||||
Do you want to spread the change to their consignees?: ¿Deseas propagar el cambio a sus consignatarios?
|
||||
Yes, propagate: Si, propagar
|
||||
Equivalent tax spreaded: Recargo de equivalencia propagado
|
||||
Invoice by address: Facturar por consignatario
|
||||
Equalization tax: Recargo de equivalencia
|
||||
Due day: Vencimiento
|
||||
Received core VNH: Recibido core VNH
|
||||
Received core VNL: Recibido core VNL
|
||||
Received B2B VNL: Recibido B2B VNL
|
||||
SAVE: GUARDAR
|
|
@ -1,4 +1,4 @@
|
|||
<mg-ajax path="/client/api/Clients/createUserProfile" options="vnPost"></mg-ajax>
|
||||
<mg-ajax path="/client/api/Clients/createWithUser" options="vnPost"></mg-ajax>
|
||||
<vn-watcher
|
||||
vn-id="watcher"
|
||||
data="$ctrl.client"
|
||||
|
@ -19,16 +19,16 @@
|
|||
<vn-textfield vn-one label="User name" field="$ctrl.client.userName"></vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-one label="Email" field="$ctrl.client.email" info="You can save multiple emails by chaining them using comma without spaces, example: user@domain.com,user2@domain.com the first email will be considered as the main"></vn-textfield>
|
||||
<vn-textfield vn-one label="Email" field="$ctrl.client.email" info="You can save multiple emails"></vn-textfield>
|
||||
<vn-autocomplete vn-one
|
||||
field="$ctrl.client.salesPersonFk"
|
||||
url="/client/api/Clients/activeSalesPerson"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
select-fields="surname"
|
||||
select-fields="name"
|
||||
label="Salesperson"
|
||||
filter-search="{where: {or: [{name: {regexp: 'search'}}, {surname: {regexp: 'search'}}]}}"
|
||||
></vn-autocomplete>
|
||||
filter-search="{where: {or: [{name: {regexp: 'search'}}, {name: {regexp: 'search'}}]}}">
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
</vn-vertical>
|
||||
</vn-card>
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"Name": "Nombre",
|
||||
"Tax number": "NIF/CIF",
|
||||
"Business name": "Razón social",
|
||||
"User name": "Nombre de usuario",
|
||||
"Email": "Correo electrónico",
|
||||
"Create and edit": "Crear y editar",
|
||||
"Create": "Crear",
|
||||
"You can save multiple emails by chaining them using comma without spaces, example: user@domain.com,user2@domain.com the first email will be considered as the main": "Puede guardar varios correos electrónicos encadenándolos mediante comas sin espacios, ejemplo: user@dominio.com,user2@dominio.com siendo el primer correo electrónico el principal"
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
Name: Nombre
|
||||
Tax number: NIF/CIF
|
||||
Business name: Razón social
|
||||
User name: Nombre de usuario
|
||||
Email: Correo electrónico
|
||||
Create and edit: Crear y editar
|
||||
Create: Crear
|
||||
You can save multiple emails: >-
|
||||
Puede guardar varios correos electrónicos encadenándolos mediante comas
|
||||
sin espacios, ejemplo: user@dominio.com, user2@dominio.com siendo el primer
|
||||
correo electrónico el principal
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"Add credit": "Añadir crédito"
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
Add credit: Añadir crédito
|
|
@ -5,7 +5,7 @@
|
|||
<vn-grid-header on-order="$ctrl.onOrder(field, order)">
|
||||
<vn-column-header vn-one pad-medium-h field="amount" text="Credit"></vn-column-header>
|
||||
<vn-column-header vn-two pad-medium-h field="created" text="Since" default-order="ASC"></vn-column-header>
|
||||
<vn-column-header vn-two pad-medium-h field="employee.name" text="Employee" order-locked></vn-column-header>
|
||||
<vn-column-header vn-two pad-medium-h field="worker.firstName" text="Employee" order-locked></vn-column-header>
|
||||
</vn-grid-header>
|
||||
<vn-one class="list list-content">
|
||||
<vn-horizontal
|
||||
|
@ -14,7 +14,7 @@
|
|||
ng-repeat="credit in index.model.instances track by credit.id">
|
||||
<vn-one pad-medium-h>{{::credit.amount | number:2}} €</vn-one>
|
||||
<vn-two pad-medium-h>{{::credit.created | date:'dd/MM/yyyy HH:mm' }}</vn-two>
|
||||
<vn-two pad-medium-h>{{::credit.employee.name}} {{::credit.employee.surname}}</vn-two>
|
||||
<vn-two pad-medium-h>{{::credit.worker.firstName}} {{::credit.worker.name}}</vn-two>
|
||||
</vn-horizontal>
|
||||
</vn-one>
|
||||
<vn-one class="text-center pad-small-v" ng-if="index.model.count === 0" translate>No results</vn-one>
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
import ngModule from '../module';
|
||||
import FilterClientList from '../filterClientList';
|
||||
|
||||
class ClientCreditList extends FilterClientList {}
|
||||
|
||||
ngModule.component('vnClientCreditList', {
|
||||
template: require('./credit-list.html'),
|
||||
controller: ClientCreditList
|
||||
controller: FilterClientList
|
||||
});
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
"Since" : "Desde",
|
||||
"Employee" : "Empleado",
|
||||
"No results": "Sin resultados"
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
Since : Desde
|
||||
Employee : Empleado
|
||||
No results: Sin resultados
|
|
@ -1,40 +1,8 @@
|
|||
// Generic object to list models, related to the client, with mgCrud
|
||||
export default class FilterClientList {
|
||||
import FilterList from '../../core/src/lib/filterList';
|
||||
export default class FilterClientList extends FilterList {
|
||||
constructor($scope, $timeout, $state) {
|
||||
this.$ = $scope;
|
||||
this.$timeout = $timeout;
|
||||
this.$state = $state;
|
||||
|
||||
this.waitingMgCrud = 0;
|
||||
this.clientFk = $state.params.id;
|
||||
}
|
||||
onOrder(field, order) {
|
||||
this.filter(`${field} ${order}`);
|
||||
}
|
||||
filter(order) {
|
||||
if (this.$.index && this.clientFk) {
|
||||
this.waitingMgCrud = 0;
|
||||
this.$.index.filter = {
|
||||
page: 1,
|
||||
size: 10,
|
||||
clientFk: this.clientFk
|
||||
};
|
||||
|
||||
if (order) {
|
||||
this.$.index.filter.order = order;
|
||||
}
|
||||
|
||||
this.$.index.accept();
|
||||
} else if (!this.clientFk) {
|
||||
throw new Error('Error: ClientFk not found');
|
||||
} else if (this.waitingMgCrud > 3) {
|
||||
throw new Error('Error: Magic Crud is not loaded');
|
||||
} else {
|
||||
this.waitingMgCrud++;
|
||||
this.$timeout(() => {
|
||||
this.filter(order);
|
||||
}, 250);
|
||||
}
|
||||
super($scope, $timeout, $state);
|
||||
this.modelName = 'clientFk';
|
||||
}
|
||||
}
|
||||
FilterClientList.$inject = ['$scope', '$timeout', '$state'];
|
||||
|
|
|
@ -10,9 +10,9 @@
|
|||
<vn-vertical pad-large>
|
||||
<vn-title>Fiscal data</vn-title>
|
||||
<vn-horizontal>
|
||||
<vn-textfield autofocus vn-two label="Social name" field="$ctrl.client.socialName" vn-acl="administrative"></vn-textfield>
|
||||
<vn-textfield vn-one label="Tax number" field="$ctrl.client.fi" vn-acl="administrative"></vn-textfield>
|
||||
<vn-check vn-one label="Is equalizated" field="$ctrl.client.isEqualizated" vn-acl="administrative"></vn-check>
|
||||
<vn-textfield autofocus vn-two label="Social name" field="$ctrl.client.socialName" vn-acl="administrative"></vn-textfield>
|
||||
<vn-textfield vn-one label="Tax number" field="$ctrl.client.fi" vn-acl="administrative"></vn-textfield>
|
||||
<vn-check vn-one label="Is equalizated" field="$ctrl.client.isEqualizated" vn-acl="administrative"></vn-check>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-two label="Street" field="$ctrl.client.street" vn-focus vn-acl="administrative"></vn-textfield>
|
||||
|
@ -27,18 +27,16 @@
|
|||
show-field="name"
|
||||
value-field="id"
|
||||
label="Province"
|
||||
vn-acl="administrative"
|
||||
>
|
||||
vn-acl="administrative">
|
||||
</vn-autocomplete>
|
||||
<vn-autocomplete vn-one
|
||||
initial-data="$ctrl.client.country"
|
||||
field="$ctrl.client.countryFk"
|
||||
url="/client/api/Countries"
|
||||
show-field="name"
|
||||
show-field="country"
|
||||
value-field="id"
|
||||
label="Country"
|
||||
vn-acl="administrative"
|
||||
>
|
||||
vn-acl="administrative">
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal margin-small-bottom>
|
||||
|
@ -64,17 +62,14 @@
|
|||
</vn-one>
|
||||
</vn-horizontal>
|
||||
</vn-vertical>
|
||||
|
||||
</vn-card>
|
||||
|
||||
<vn-button-bar>
|
||||
<vn-submit label="Save" vn-acl="administrative"></vn-submit>
|
||||
</vn-button-bar>
|
||||
</form>
|
||||
<vn-dialog
|
||||
vn-id="propagate-isEqualizated"
|
||||
on-response="$ctrl.returnDialogEt(response)"
|
||||
>
|
||||
on-response="$ctrl.returnDialogEt(response)">
|
||||
<tpl-body>
|
||||
<vn-vertical>
|
||||
<vn-one text-center translate>You changes the equivalen
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
import './fiscal-data.js';
|
||||
|
||||
describe('Client', () => {
|
||||
describe('Component vnClientFiscalData', () => {
|
||||
let $componentController;
|
||||
let $httpBackend;
|
||||
let $scope;
|
||||
let controller;
|
||||
|
||||
beforeEach(() => {
|
||||
angular.mock.module('client');
|
||||
});
|
||||
|
||||
beforeEach(angular.mock.inject((_$componentController_, $rootScope, _$httpBackend_) => {
|
||||
$componentController = _$componentController_;
|
||||
$httpBackend = _$httpBackend_;
|
||||
$scope = $rootScope.$new();
|
||||
controller = $componentController('vnClientFiscalData', {$scope: $scope});
|
||||
}));
|
||||
|
||||
describe('returnDialogEt()', () => {
|
||||
it('should request to patch the propagation of tax status', () => {
|
||||
controller.client = {id: 123, isEqualizated: false};
|
||||
$httpBackend.when('PATCH', `/client/api/Clients/${controller.client.id}/addressesPropagateRe`, {isEqualizated: controller.client.isEqualizated}).respond('done');
|
||||
$httpBackend.expectPATCH(`/client/api/Clients/${controller.client.id}/addressesPropagateRe`, {isEqualizated: controller.client.isEqualizated});
|
||||
controller.returnDialogEt('ACCEPT');
|
||||
$httpBackend.flush();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -9,20 +9,17 @@
|
|||
<vn-column-header vn-one pad-medium-h field="amount" text="Amount"></vn-column-header>
|
||||
<vn-column-header vn-one pad-medium-h field="greugeTypeFk" text="Type"></vn-column-header>
|
||||
</vn-grid-header>
|
||||
|
||||
<vn-one class="list list-content">
|
||||
<vn-horizontal
|
||||
class="list list-element text-center"
|
||||
pad-small-bottom
|
||||
ng-repeat="greuge in index.model.instances track by greuge.id"
|
||||
>
|
||||
<vn-one pad-medium-h>{{::greuge.shipped | date:'dd/MM/yyyy HH:mm' }}</vn-one>
|
||||
<vn-two pad-medium-h>{{::greuge.description}}</vn-two>
|
||||
<vn-one pad-medium-h>{{::greuge.amount | number:2}} €</vn-one>
|
||||
<vn-one pad-medium-h>{{::greuge.greugeType.name}}</vn-one>
|
||||
ng-repeat="greuge in index.model.instances track by greuge.id">
|
||||
<vn-one pad-medium-h>{{::greuge.shipped | date:'dd/MM/yyyy HH:mm' }}</vn-one>
|
||||
<vn-two pad-medium-h>{{::greuge.description}}</vn-two>
|
||||
<vn-one pad-medium-h>{{::greuge.amount | number:2}} €</vn-one>
|
||||
<vn-one pad-medium-h>{{::greuge.greugeType.name}}</vn-one>
|
||||
</vn-horizontal>
|
||||
</vn-one>
|
||||
|
||||
<vn-one class="text-center pad-small-v" ng-if="index.model.count === 0" translate>No results</vn-one>
|
||||
<vn-horizontal vn-one class="list list-footer text-center">
|
||||
<vn-one pad-medium-h></vn-one>
|
||||
|
@ -36,3 +33,4 @@
|
|||
<a ui-sref="clientCard.greuge.create" fixed-bottom-right>
|
||||
<vn-float-button icon="add"></vn-float-button>
|
||||
</a>
|
||||
|
|
@ -1,9 +1,7 @@
|
|||
import ngModule from '../module';
|
||||
import FilterClientList from '../filterClientList';
|
||||
|
||||
class ClientGreugeList extends FilterClientList {}
|
||||
|
||||
ngModule.component('vnClientGreugeList', {
|
||||
template: require('./greuge-list.html'),
|
||||
controller: ClientGreugeList
|
||||
controller: FilterClientList
|
||||
});
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
{
|
||||
"Date" : "Fecha",
|
||||
"Comment" : "Comentario",
|
||||
"Amount" : "Importe",
|
||||
"Type": "Tipo",
|
||||
"Add Greuge": "Añadir Greuge"
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
Date: Fecha
|
||||
Comment: Comentario
|
||||
Amount: Importe
|
||||
Type: Tipo
|
||||
Add Greuge: Añadir Greuge
|
|
@ -1,7 +1,7 @@
|
|||
<a ui-sref="clientCard.basicData({ id: {{$ctrl.client.id}} })" pad-medium border-solid-bottom>
|
||||
<div class="vn-item-client-name">{{$ctrl.client.name}}</div>
|
||||
<div><span translate>Client id</span>: <b>{{$ctrl.client.id}}</b></div>
|
||||
<div><span translate>Phone</span>: <b>{{$ctrl.client.phone | phone}}</b></div>
|
||||
<div><span translate>Town/City</span>: <b>{{$ctrl.client.city}}</b></div>
|
||||
<div><span translate>Email</span>: <b>{{$ctrl.client.email}}</b></div>
|
||||
<a ui-sref="clientCard.basicData({ id: {{::$ctrl.client.id}} })" pad-medium border-solid-bottom>
|
||||
<div class="vn-item-client-name">{{::$ctrl.client.name}}</div>
|
||||
<div><span translate>Client id</span>: <b>{{::$ctrl.client.id}}</b></div>
|
||||
<div><span translate>Phone</span>: <b>{{::$ctrl.client.phone | phone}}</b></div>
|
||||
<div><span translate>Town/City</span>: <b>{{::$ctrl.client.city}}</b></div>
|
||||
<div><span translate>Email</span>: <b>{{::$ctrl.client.email}}</b></div>
|
||||
</a>
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
{
|
||||
"Client id": "Id cliente",
|
||||
"Phone": "Teléfono",
|
||||
"Town/City": "Ciudad",
|
||||
"Email": "Correo electrónico",
|
||||
"Create client": "Crear cliente"
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
Client id: Id cliente
|
||||
Phone: Teléfono
|
||||
Town/City: Ciudad
|
||||
Email: Correo electrónico
|
||||
Create client: Crear cliente
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"Client": "Client",
|
||||
"Clients": "Clients"
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
Client: Client
|
||||
Clients: Clients
|
|
@ -1,25 +0,0 @@
|
|||
{
|
||||
"Active": "Activo",
|
||||
"Client": "Cliente",
|
||||
"Clients": "Clientes",
|
||||
"Basic data": "Datos básicos",
|
||||
"Fiscal data": "Datos Fiscales",
|
||||
"Addresses": "Consignatarios",
|
||||
"Web access": "Acceso web",
|
||||
"Notes": "Notas",
|
||||
"Has to invoice": "Factura",
|
||||
"Invoice by mail": "Factura impresa",
|
||||
"Country": "País",
|
||||
"Street": "Domicilio fiscal",
|
||||
"City": "Municipio",
|
||||
"Postcode": "Código postal",
|
||||
"Province": "Provincia",
|
||||
"Save": "Guardar",
|
||||
"Pay method" : "Forma de pago",
|
||||
"Address": "Consignatario",
|
||||
"Credit" : "Crédito",
|
||||
"Secured credit": "Crédito asegurado",
|
||||
"Verified data": "Datos comprobados",
|
||||
"Mandate": "Mandato",
|
||||
"Amount": "Importe"
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
Active: Activo
|
||||
Client: Cliente
|
||||
Clients: Clientes
|
||||
Basic data: Datos básicos
|
||||
Fiscal data: Datos Fiscales
|
||||
Addresses: Consignatarios
|
||||
Web access: Acceso web
|
||||
Notes: Notas
|
||||
Has to invoice: Factura
|
||||
Invoice by mail: Factura impresa
|
||||
Country: País
|
||||
Street: Domicilio fiscal
|
||||
City: Municipio
|
||||
Postcode: Código postal
|
||||
Province: Provincia
|
||||
Save: Guardar
|
||||
Pay method : Forma de pago
|
||||
Address: Consignatario
|
||||
Credit : Crédito
|
||||
Secured credit: Crédito asegurado
|
||||
Verified data: Datos comprobados
|
||||
Mandate: Mandato
|
||||
Amount: Importe
|
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
"Company": "Empresa",
|
||||
"Register date": "Fecha alta",
|
||||
"End date": "Fecha baja"
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
Company: Empresa
|
||||
Register date: Fecha alta
|
||||
End date: Fecha baja
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"New note": "Nueva nota",
|
||||
"Note": "Nota"
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
New note: Nueva nota
|
||||
Note: Nota
|
|
@ -3,6 +3,7 @@
|
|||
url="/client/api/ClientObservations"
|
||||
id-field="id"
|
||||
data="$ctrl.note"
|
||||
save="post"
|
||||
form="form">
|
||||
</vn-watcher>
|
||||
<form name="form" ng-submit="watcher.submitGo('clientCard.notes.list')" pad-medium>
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
<vn-vertical pad-large>
|
||||
<vn-title>Notes</vn-title>
|
||||
<vn-one
|
||||
ng-repeat="n in $ctrl.observations"
|
||||
pad-small border-solid
|
||||
border-radius
|
||||
margin-small-bottom style="align-items: center;">
|
||||
ng-repeat="n in $ctrl.observations"
|
||||
pad-small border-solid
|
||||
border-radius
|
||||
margin-small-bottom style="align-items: center;">
|
||||
<vn-horizontal>
|
||||
<vn-one >{{::n.employee.name}} {{::n.employee.surname}}</vn-one>
|
||||
<vn-one >{{::n.worker.firstName}} {{::n.worker.name}}</vn-one>
|
||||
<vn-auto>{{::n.created | date:'dd/MM/yyyy HH:mm'}}</vn-auto>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
|
|
|
@ -15,7 +15,8 @@ describe('Client', () => {
|
|||
$componentController = _$componentController_;
|
||||
$state = _$state_;
|
||||
$httpBackend = _$httpBackend_;
|
||||
controller = $componentController('vnClientNotes', {$httpBackend: $httpBackend, $state: $state});
|
||||
$httpBackend.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
|
||||
controller = $componentController('vnClientNotes', {$state: $state});
|
||||
}));
|
||||
|
||||
describe('$onChanges()', () => {
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"Client id": "Id cliente",
|
||||
"Tax number": "NIF/CIF",
|
||||
"Name": "Nombre",
|
||||
"Social name": "Razon social",
|
||||
"Town/City": "Ciudad",
|
||||
"Postcode": "Código postal",
|
||||
"Email": "Correo electrónico",
|
||||
"Phone": "Teléfono"
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
Client id: Id cliente
|
||||
Tax number: NIF/CIF
|
||||
Name: Nombre
|
||||
Social name: Razon social
|
||||
Town/City: Ciudad
|
||||
Postcode: Código postal
|
||||
Email: Correo electrónico
|
||||
Phone: Teléfono
|
|
@ -1,41 +0,0 @@
|
|||
import './search-panel.js';
|
||||
|
||||
describe('Client', () => {
|
||||
describe('Component vnClientSearchPanel', () => {
|
||||
let $componentController;
|
||||
let sessionStorage;
|
||||
let controller;
|
||||
|
||||
beforeEach(() => {
|
||||
angular.mock.module('client');
|
||||
});
|
||||
|
||||
beforeEach(angular.mock.inject((_$componentController_, _sessionStorage_) => {
|
||||
$componentController = _$componentController_;
|
||||
sessionStorage = _sessionStorage_;
|
||||
controller = $componentController('vnClientSearchPanel', {sessionStorage: sessionStorage});
|
||||
}));
|
||||
|
||||
// describe('onSearch()', () => {
|
||||
// it('should call setStorageValue() and onSubmit()', () => {
|
||||
// spyOn(controller, 'setStorageValue');
|
||||
// spyOn(controller, 'onSubmit');
|
||||
// controller.setStorageValue();
|
||||
// controller.onSubmit();
|
||||
|
||||
// expect(controller.setStorageValue).toHaveBeenCalledWith();
|
||||
// expect(controller.onSubmit).toHaveBeenCalledWith();
|
||||
// });
|
||||
// });
|
||||
|
||||
// describe('$onChanges()', () => {
|
||||
// it('should set filter properties using the search values', () => {
|
||||
// expect(controller.filter).not.toBeDefined();
|
||||
// spyOn(sessionStorage, 'get').and.returnValue({data: 'data'});
|
||||
// controller.$onChanges();
|
||||
|
||||
// expect(controller.filter).toBe(sessionStorage.get({data: 'data'}));
|
||||
// });
|
||||
// });
|
||||
});
|
||||
});
|
|
@ -1,7 +0,0 @@
|
|||
{
|
||||
"User": "Usuario",
|
||||
"Enable web access": "Habilitar acceso web",
|
||||
"New password": "Nueva contraseña",
|
||||
"Repeat password": "Repetir contraseña",
|
||||
"Change password": "Cambiar contraseña"
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
User: Usuario
|
||||
Enable web access: Habilitar acceso web
|
||||
New password: Nueva contraseña
|
||||
Repeat password: Repetir contraseña
|
||||
Change password: Cambiar contraseña
|
|
@ -16,7 +16,7 @@ export default class Controller {
|
|||
|
||||
isCustomer() {
|
||||
if (this.client && this.client.id) {
|
||||
this.$http.get(`/client/api/Clients/${this.client.id}/getRoleCustomer`).then(res => {
|
||||
this.$http.get(`/client/api/Clients/${this.client.id}/hasCustomerRole`).then(res => {
|
||||
this.canChangePassword = (res.data) ? res.data.isCustomer : false;
|
||||
});
|
||||
} else {
|
||||
|
|
|
@ -15,6 +15,7 @@ describe('Component VnClientWebAccess', () => {
|
|||
$componentController = _$componentController_;
|
||||
$scope = $rootScope.$new();
|
||||
$httpBackend = _$httpBackend_;
|
||||
$httpBackend.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
|
||||
vnApp = _vnApp_;
|
||||
spyOn(vnApp, 'showError');
|
||||
controller = $componentController('vnClientWebAccess', {$scope: $scope});
|
||||
|
@ -37,8 +38,8 @@ describe('Component VnClientWebAccess', () => {
|
|||
controller.client = {id: '1234'};
|
||||
controller.isCustomer();
|
||||
|
||||
$httpBackend.when('GET', `/client/api/Clients/${controller.client.id}/getRoleCustomer`).respond('ok');
|
||||
$httpBackend.expectGET(`/client/api/Clients/${controller.client.id}/getRoleCustomer`);
|
||||
$httpBackend.when('GET', `/client/api/Clients/${controller.client.id}/hasCustomerRole`).respond('ok');
|
||||
$httpBackend.expectGET(`/client/api/Clients/${controller.client.id}/hasCustomerRole`);
|
||||
$httpBackend.flush();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"name": "@salix/core",
|
||||
"version": "0.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://git.verdnatura.es/salix"
|
||||
}
|
||||
}
|
|
@ -18,5 +18,5 @@
|
|||
item-width="$ctrl.width"
|
||||
multiple="$ctrl.multiple"
|
||||
parent = "$ctrl.element"
|
||||
><vn-item ng-transclude="tplItem">{{$parent.item.name}}</vn-item></vn-drop-down>
|
||||
><vn-item ng-transclude="tplItem">{{$parent.item[$ctrl.showField]}}</vn-item></vn-drop-down>
|
||||
</vn-vertical>
|
|
@ -2,7 +2,6 @@ import {module} from '../module';
|
|||
import Component from '../lib/component';
|
||||
import copyObject from '../lib/copy';
|
||||
import './style.scss';
|
||||
import { log } from 'util';
|
||||
|
||||
class Autocomplete extends Component {
|
||||
constructor($element, $scope, $http, $timeout, $filter) {
|
||||
|
@ -20,9 +19,8 @@ class Autocomplete extends Component {
|
|||
this._field = null;
|
||||
this._preLoad = false;
|
||||
this.maxRow = 10;
|
||||
this.showField = this.showField || 'name';
|
||||
this.valueField = this.valueField || 'id';
|
||||
this.order = this.order || 'name ASC';
|
||||
this.showField = 'name';
|
||||
this.valueField = 'id';
|
||||
this.items = copyObject(this.data) || [];
|
||||
this.displayValueMultiCheck = [];
|
||||
this._multiField = [];
|
||||
|
@ -195,6 +193,10 @@ class Autocomplete extends Component {
|
|||
return fields;
|
||||
}
|
||||
|
||||
getOrder() {
|
||||
return this.order ? this.order : `${this.showField} ASC`;
|
||||
}
|
||||
|
||||
findItems(search) {
|
||||
if (this.url && search && !this.finding) {
|
||||
this.maxRow = false;
|
||||
|
@ -208,7 +210,7 @@ class Autocomplete extends Component {
|
|||
Object.assign(filter.where, this.filter.where);
|
||||
}
|
||||
}
|
||||
filter.order = this.order;
|
||||
filter.order = this.getOrder();
|
||||
let json = JSON.stringify(filter);
|
||||
this.finding = true;
|
||||
this.$http.get(`${this.url}?filter=${json}`).then(
|
||||
|
@ -252,7 +254,7 @@ class Autocomplete extends Component {
|
|||
filter.skip = this.items.length;
|
||||
}
|
||||
filter.limit = this.maxRow;
|
||||
filter.order = this.order;
|
||||
filter.order = this.getOrder();
|
||||
}
|
||||
if (this.filter) {
|
||||
Object.assign(filter, this.filter);
|
||||
|
|
|
@ -16,6 +16,7 @@ describe('Component vnAutocomplete', () => {
|
|||
$componentController = _$componentController_;
|
||||
$scope = $rootScope.$new();
|
||||
$httpBackend = _$httpBackend_;
|
||||
$httpBackend.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
|
||||
$timeout = _$timeout_;
|
||||
$element = angular.element('<div></div>');
|
||||
controller = $componentController('vnAutocomplete', {$scope, $element, $httpBackend, $timeout});
|
||||
|
@ -120,7 +121,6 @@ describe('Component vnAutocomplete', () => {
|
|||
|
||||
it(`should perform a query if the item id isn't present in the controller.items property`, () => {
|
||||
controller.url = 'test.com';
|
||||
$httpBackend.whenGET(`${controller.url}?filter={"fields":{"id":true,"name":true},"where":{"id":3}}`).respond();
|
||||
$httpBackend.expectGET(`${controller.url}?filter={"fields":{"id":true,"name":true},"where":{"id":3}}`);
|
||||
controller.items = [{id: 1, name: 'test1'}, {id: 2, name: 'Bruce Wayne'}];
|
||||
controller.field = 3;
|
||||
|
@ -136,7 +136,6 @@ describe('Component vnAutocomplete', () => {
|
|||
|
||||
it(`should set field performing a query as the item id isn't present in the controller.items property`, () => {
|
||||
controller.url = 'test.com';
|
||||
$httpBackend.whenGET(`${controller.url}?filter={"fields":{"id":true,"name":true},"where":{"id":3}}`).respond();
|
||||
$httpBackend.expectGET(`${controller.url}?filter={"fields":{"id":true,"name":true},"where":{"id":3}}`);
|
||||
controller.items = [{id: 1, name: 'test1'}, {id: 2, name: 'Bruce Wayne'}];
|
||||
controller.field = 3;
|
||||
|
@ -150,7 +149,7 @@ describe('Component vnAutocomplete', () => {
|
|||
let controller = $componentController('vnAutocomplete', {$scope, $element, $httpBackend, $timeout});
|
||||
controller.url = 'test.com';
|
||||
let search = 'The Joker';
|
||||
let json = JSON.stringify({where: {name: {regexp: search}}, order: controller.order});
|
||||
let json = JSON.stringify({where: {name: {regexp: search}}, order: controller.getOrder()});
|
||||
$httpBackend.whenGET(`${controller.url}?filter=${json}`).respond([{id: 3, name: 'The Joker'}]);
|
||||
$httpBackend.expectGET(`${controller.url}?filter=${json}`);
|
||||
controller.findItems(search);
|
||||
|
@ -163,8 +162,8 @@ describe('Component vnAutocomplete', () => {
|
|||
let controller = $componentController('vnAutocomplete', {$scope, $element, $httpBackend, $timeout});
|
||||
controller.url = 'test.com';
|
||||
let search = 'The Joker';
|
||||
controller.filterSearch = "{where: {surname: {regexp: 'search'}}}";
|
||||
let json = JSON.stringify({where: {surname: {regexp: search}}, order: controller.order});
|
||||
controller.filterSearch = "{where: {name: {regexp: 'search'}}}";
|
||||
let json = JSON.stringify({where: {name: {regexp: search}}, order: controller.getOrder()});
|
||||
$httpBackend.whenGET(`${controller.url}?filter=${json}`).respond([{id: 3, name: 'The Joker'}]);
|
||||
$httpBackend.expectGET(`${controller.url}?filter=${json}`);
|
||||
controller.findItems(search);
|
||||
|
@ -177,7 +176,7 @@ describe('Component vnAutocomplete', () => {
|
|||
controller.url = 'test.com';
|
||||
let search = 'Joker';
|
||||
controller.multiple = true;
|
||||
let json = JSON.stringify({where: {name: {regexp: search}}, order: controller.order});
|
||||
let json = JSON.stringify({where: {name: {regexp: search}}, order: controller.getOrder()});
|
||||
$httpBackend.whenGET(`${controller.url}?filter=${json}`).respond([{id: 3, name: 'The Joker'}, {id: 4, name: 'Joker'}]);
|
||||
$httpBackend.expectGET(`${controller.url}?filter=${json}`);
|
||||
controller.findItems(search);
|
||||
|
|
|
@ -9,7 +9,8 @@ describe('Directive acl', () => {
|
|||
});
|
||||
|
||||
compile = (hasPermissions, _element) => {
|
||||
inject(($compile, $rootScope, aclService, _$timeout_) => {
|
||||
inject(($compile, $rootScope, aclService, _$timeout_, _$httpBackend_) => {
|
||||
_$httpBackend_.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
|
||||
spyOn(aclService, 'aclPermission').and.returnValue(hasPermissions);
|
||||
scope = $rootScope.$new();
|
||||
$timeout = _$timeout_;
|
||||
|
|
|
@ -20,8 +20,9 @@ describe('Directive dialog', () => {
|
|||
});
|
||||
};
|
||||
|
||||
beforeEach(angular.mock.inject(_$componentController_ => {
|
||||
beforeEach(angular.mock.inject((_$componentController_, _$httpBackend_) => {
|
||||
$componentController = _$componentController_;
|
||||
_$httpBackend_.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
|
||||
$element = angular.element('<div></div>');
|
||||
controller = $componentController('vnDialog', {$element});
|
||||
}));
|
||||
|
|
|
@ -8,12 +8,11 @@ describe('Directive focus', () => {
|
|||
});
|
||||
|
||||
compile = (_element, _childElement) => {
|
||||
inject(($compile, $rootScope) => {
|
||||
inject(($compile, $rootScope, _$httpBackend_) => {
|
||||
$scope = $rootScope.$new();
|
||||
_$httpBackend_.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
|
||||
$element = angular.element(_element);
|
||||
if (_childElement) {
|
||||
let childElement = angular.element(_childElement);
|
||||
$element[0] < childElement;
|
||||
$element[0].firstChild.focus = jasmine.createSpy(focus);
|
||||
}
|
||||
$element[0].focus = jasmine.createSpy('focus');
|
||||
|
|
|
@ -8,8 +8,9 @@ describe('Directive vnId', () => {
|
|||
});
|
||||
|
||||
compile = _element => {
|
||||
inject(($compile, $rootScope) => {
|
||||
inject(($compile, $rootScope, _$httpBackend_) => {
|
||||
$scope = $rootScope.$new();
|
||||
_$httpBackend_.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
|
||||
$element = angular.element(_element);
|
||||
$compile($element)($scope);
|
||||
$scope.$digest();
|
||||
|
|
|
@ -8,8 +8,9 @@ describe('Directive validation', () => {
|
|||
});
|
||||
|
||||
compile = (_element, validations, value) => {
|
||||
inject(($compile, $rootScope, aclService, _$timeout_, $window) => {
|
||||
inject(($compile, $rootScope, aclService, _$timeout_, $window, _$httpBackend_) => {
|
||||
$window.validations = validations;
|
||||
_$httpBackend_.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
|
||||
scope = $rootScope.$new();
|
||||
scope.user = {name: value};
|
||||
element = angular.element(_element);
|
||||
|
|
|
@ -11,7 +11,8 @@ describe('Component vnDropDown', () => {
|
|||
angular.mock.module('client');
|
||||
});
|
||||
|
||||
beforeEach(angular.mock.inject((_$componentController_, _$timeout_, _$filter_) => {
|
||||
beforeEach(angular.mock.inject((_$componentController_, _$timeout_, _$filter_, _$httpBackend_) => {
|
||||
_$httpBackend_.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
|
||||
$componentController = _$componentController_;
|
||||
$element = angular.element('<div><ul><li></li></ul></div>');
|
||||
$timeout = _$timeout_;
|
||||
|
@ -258,19 +259,22 @@ describe('Component vnDropDown', () => {
|
|||
});
|
||||
});
|
||||
|
||||
// describe('setScrollPosition()', () => {
|
||||
// it(`should call child.scrollIntoView if defined `, () => {
|
||||
// $element[0].firstChild.setAttribute('class', 'dropdown');
|
||||
// let child = $element[0].firstChild.firstChild;
|
||||
describe('setScrollPosition()', () => {
|
||||
it(`should call child.scrollIntoView if defined `, () => {
|
||||
$element[0].firstChild.setAttribute('class', 'dropdown');
|
||||
$element[0].firstChild.firstChild.setAttribute('class', 'active');
|
||||
let child = $element[0].firstChild.firstChild;
|
||||
spyOn(child, 'getBoundingClientRect').and.returnValue({top: 100});
|
||||
let container = $element[0].firstChild;
|
||||
spyOn(container, 'getBoundingClientRect').and.returnValue({top: 10, height: 70});
|
||||
child.scrollIntoView = () => {};
|
||||
spyOn(child, 'scrollIntoView');
|
||||
controller._activeOption = 0;
|
||||
controller.setScrollPosition();
|
||||
|
||||
// child.scrollIntoView = () => {};
|
||||
// spyOn(child, 'scrollIntoView');
|
||||
// controller._activeOption = 0;
|
||||
// controller.setScrollPosition();
|
||||
|
||||
// expect(child.scrollIntoView).toHaveBeenCalledWith();
|
||||
// });
|
||||
// });
|
||||
expect(child.scrollIntoView).toHaveBeenCalledWith();
|
||||
});
|
||||
});
|
||||
|
||||
describe('selectItem()', () => {
|
||||
it(`should pass item to selected and set controller._show to false`, () => {
|
||||
|
|
|
@ -15,6 +15,7 @@ describe('Component vnIconMenu', () => {
|
|||
beforeEach(angular.mock.inject((_$componentController_, $rootScope, _$httpBackend_, _$timeout_) => {
|
||||
$componentController = _$componentController_;
|
||||
$httpBackend = _$httpBackend_;
|
||||
$httpBackend.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
|
||||
$timeout = _$timeout_;
|
||||
$scope = $rootScope.$new();
|
||||
$element = angular.element('<div></div>');
|
||||
|
|
|
@ -10,9 +10,9 @@ export default class App {
|
|||
constructor($rootScope) {
|
||||
this.loaderStatus = 0;
|
||||
this.$rootScope = $rootScope;
|
||||
this.timeout = window.snackbarTimeout || 2000;
|
||||
}
|
||||
show(message) {
|
||||
this.timeout = window.snackbarTimeout || 2000;
|
||||
if (this.snackbar) this.snackbar.show({message: message, timeout: this.timeout});
|
||||
}
|
||||
showMessage(message) {
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
// Generic object to list models
|
||||
export default class FilterList {
|
||||
constructor($scope, $timeout, $state) {
|
||||
this.$ = $scope;
|
||||
this.$timeout = $timeout;
|
||||
this.$state = $state;
|
||||
|
||||
this.waitingMgCrud = 0;
|
||||
this.modelId = $state.params.id;
|
||||
}
|
||||
onOrder(field, order) {
|
||||
this.filter(`${field} ${order}`);
|
||||
}
|
||||
filter(order) {
|
||||
if (this.$.index && this.modelId && this.modelName) {
|
||||
this.waitingMgCrud = 0;
|
||||
this.$.index.filter = {
|
||||
page: 1,
|
||||
size: 10
|
||||
};
|
||||
|
||||
this.$.index.filter[this.modelName] = this.modelId;
|
||||
|
||||
if (order) {
|
||||
this.$.index.filter.order = order;
|
||||
}
|
||||
|
||||
this.$.index.accept();
|
||||
} else if (!this.modelId || !this.modelName) {
|
||||
throw new Error('Error: model not found');
|
||||
} else if (this.waitingMgCrud > 3) {
|
||||
throw new Error('Error: Magic Crud is not loaded');
|
||||
} else {
|
||||
this.waitingMgCrud++;
|
||||
this.$timeout(() => {
|
||||
this.filter(order);
|
||||
}, 250);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ import './app';
|
|||
import './interceptor';
|
||||
import './aclService';
|
||||
import './storageServices';
|
||||
import './filterList';
|
||||
|
||||
export * from './util';
|
||||
export {default as splitingRegister} from './splitingRegister';
|
||||
|
|
|
@ -3,6 +3,9 @@ import isEqual from './equals';
|
|||
|
||||
export default function getModifiedData(object, objectOld) {
|
||||
var newObject = {};
|
||||
if (objectOld === null) {
|
||||
return object;
|
||||
}
|
||||
for (var k in object) {
|
||||
var val = object[k];
|
||||
var valOld = objectOld[k] === undefined ? null : objectOld[k];
|
||||
|
|
|
@ -1,59 +1,59 @@
|
|||
import {module} from '../module';
|
||||
import splitingRegister from './splitingRegister';
|
||||
|
||||
factory.$inject = ['$translatePartialLoader', '$http', '$window', '$ocLazyLoad', '$q', '$translate'];
|
||||
export function factory($translatePartialLoader, $http, $window, $ocLazyLoad, $q, $translate) {
|
||||
factory.$inject = ['$http', '$window', '$ocLazyLoad', '$translatePartialLoader', '$translate'];
|
||||
export function factory($http, $window, $ocLazyLoad, $translatePartialLoader, $translate) {
|
||||
class ModuleLoader {
|
||||
constructor() {
|
||||
this._loadedModules = {};
|
||||
this._loaded = {};
|
||||
}
|
||||
load(moduleName, validations) {
|
||||
if (this._loadedModules[moduleName])
|
||||
return;
|
||||
let loaded = this._loaded;
|
||||
|
||||
this._loadedModules[moduleName] = true;
|
||||
if (loaded[moduleName])
|
||||
return loaded[moduleName];
|
||||
|
||||
loaded[moduleName] = Promise.resolve(true);
|
||||
|
||||
let deps = splitingRegister.getDependencies(moduleName);
|
||||
let modules = splitingRegister.modules;
|
||||
let promises = [];
|
||||
let depPromises = [];
|
||||
|
||||
if (deps)
|
||||
for (let dep of deps)
|
||||
depPromises.push(this.load(dep, validations));
|
||||
|
||||
loaded[moduleName] = new Promise((resolve, reject) => {
|
||||
Promise.all(depPromises)
|
||||
.then(() => {
|
||||
let promises = [];
|
||||
|
||||
// FIXME: https://github.com/angular-translate/angular-translate/pull/1674
|
||||
$translatePartialLoader.addPart(moduleName);
|
||||
promises.push($translate.refresh());
|
||||
|
||||
if (validations)
|
||||
promises.push(new Promise(resolve => {
|
||||
$http.get(`/${moduleName}/validations`).then(
|
||||
json => this.onValidationsReady(json, resolve),
|
||||
json => resolve()
|
||||
);
|
||||
}));
|
||||
|
||||
for (let dep of deps) {
|
||||
this._loadedModules[dep] = true;
|
||||
promises.push(modules[dep]());
|
||||
if (validations)
|
||||
promises.push(new Promise(resolve => {
|
||||
$http.get(`/${dep}/validations`).then(
|
||||
json => this.onValidationsReady(json, resolve),
|
||||
json => resolve()
|
||||
);
|
||||
splitingRegister.modules[moduleName](resolve);
|
||||
}));
|
||||
|
||||
$translatePartialLoader.addPart(dep);
|
||||
// FIXME: https://github.com/angular-translate/angular-translate/pull/1674
|
||||
// promises.push($translate.refresh());
|
||||
setTimeout(() => $translate.refresh(), 500);
|
||||
}
|
||||
|
||||
let ocDeps = deps.map(item => {
|
||||
return {name: item};
|
||||
Promise.all(promises)
|
||||
.then(() => {
|
||||
this._loaded[moduleName] = true;
|
||||
resolve($ocLazyLoad.load({name: moduleName}));
|
||||
})
|
||||
.catch(reject);
|
||||
})
|
||||
.catch(reject);
|
||||
});
|
||||
|
||||
return new Promise(resolve => {
|
||||
Promise.all(promises).then(
|
||||
() => resolve($ocLazyLoad.load(ocDeps))
|
||||
);
|
||||
});
|
||||
}
|
||||
parseValidation(val) {
|
||||
switch (val.validation) {
|
||||
case 'custom':
|
||||
// TODO: Reemplazar eval
|
||||
val.bindedFunction = eval(`(${val.bindedFunction})`);
|
||||
break;
|
||||
case 'format':
|
||||
val.with = new RegExp(val.with);
|
||||
break;
|
||||
}
|
||||
return loaded[moduleName];
|
||||
}
|
||||
onValidationsReady(json, resolve) {
|
||||
let entities = json.data;
|
||||
|
@ -69,6 +69,17 @@ export function factory($translatePartialLoader, $http, $window, $ocLazyLoad, $q
|
|||
Object.assign($window.validations, json.data);
|
||||
resolve();
|
||||
}
|
||||
parseValidation(val) {
|
||||
switch (val.validation) {
|
||||
case 'custom':
|
||||
// TODO: Replace eval
|
||||
val.bindedFunction = eval(`(${val.bindedFunction})`);
|
||||
break;
|
||||
case 'format':
|
||||
val.with = new RegExp(val.with);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new ModuleLoader();
|
||||
|
|
|
@ -1,29 +1,11 @@
|
|||
|
||||
class SplitingRegister {
|
||||
constructor() {
|
||||
this._graph = null;
|
||||
this._modules = {};
|
||||
this.graph = null;
|
||||
this.modules = {};
|
||||
}
|
||||
get modules() {
|
||||
return this._modules;
|
||||
}
|
||||
getDependencies(dependency) {
|
||||
var array = [];
|
||||
array.push(dependency);
|
||||
var first = this._graph[dependency];
|
||||
|
||||
if (first)
|
||||
while (first.length > 0) {
|
||||
dependency = first.shift();
|
||||
array = array.concat(this.getDependencies(dependency));
|
||||
}
|
||||
return array;
|
||||
}
|
||||
registerGraph(graph) {
|
||||
this._graph = graph;
|
||||
}
|
||||
register(moduleName, loader) {
|
||||
this._modules[moduleName] = loader;
|
||||
getDependencies(moduleName) {
|
||||
return this.graph[moduleName];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
{
|
||||
"Accept": "Accept",
|
||||
"Cancel": "Cancel",
|
||||
"Close": "Close",
|
||||
"Clear": "Clear",
|
||||
"Save": "Save",
|
||||
"Add": "Add",
|
||||
"Search": "Search"
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
Accept: Accept
|
||||
Cancel: Cancel
|
||||
Close: Close
|
||||
Clear: Clear
|
||||
Save: Save
|
||||
Add: Add
|
||||
Search: Search
|
|
@ -1,11 +0,0 @@
|
|||
{
|
||||
"Accept": "Aceptar",
|
||||
"Cancel": "Cancelar",
|
||||
"Close": "Cerrar",
|
||||
"Clear": "Borrar",
|
||||
"Save": "Guardar",
|
||||
"Add": "Añadir",
|
||||
"Search": "Buscar",
|
||||
"Show More": "Ver más",
|
||||
"No more results" : "No hay más resultados"
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
Accept: Aceptar
|
||||
Cancel: Cancelar
|
||||
Close: Cerrar
|
||||
Clear: Borrar
|
||||
Save: Guardar
|
||||
Add: Añadir
|
||||
Search: Buscar
|
||||
Show More: Ver más
|
||||
No more results : No hay más resultados
|
|
@ -1,6 +0,0 @@
|
|||
{
|
||||
"Are you sure exit without saving?": "¿Seguro que quieres salir sin guardar?",
|
||||
"Unsaved changes will be lost": "Los cambios que no hayas guardado se perderán",
|
||||
"No changes to save": "No hay cambios que guardar",
|
||||
"Some fields are invalid": "Algunos campos no son válidos"
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
Are you sure exit without saving?: ¿Seguro que quieres salir sin guardar?
|
||||
Unsaved changes will be lost: Los cambios que no hayas guardado se perderán
|
||||
No changes to save: No hay cambios que guardar
|
||||
Some fields are invalid: Algunos campos no son válidos
|
|
@ -47,7 +47,7 @@ export default class Watcher extends Component {
|
|||
|
||||
fetchData() {
|
||||
let id = this.data[this.idField];
|
||||
// return new Promise((resolve, reject) => {
|
||||
// return new Promise((resolve, reject) => {
|
||||
this.$http.get(`${this.url}/${id}`).then(
|
||||
json => {
|
||||
this.data = copyObject(json.data);
|
||||
|
@ -55,26 +55,33 @@ export default class Watcher extends Component {
|
|||
}
|
||||
// json => reject(json)
|
||||
);
|
||||
// });
|
||||
// });
|
||||
}
|
||||
|
||||
/**
|
||||
* Submits the data and goes back in the history.
|
||||
*
|
||||
* @return {Promise} The request promise
|
||||
*/
|
||||
submitBack() {
|
||||
return this.submit().then(
|
||||
() => this.window.history.back()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Submits the data and goes another state.
|
||||
*
|
||||
* @param {String} state The state name
|
||||
* @param {Object} params The request params
|
||||
* @return {Promise} The request promise
|
||||
*/
|
||||
submitGo(state, params) {
|
||||
return this.submit().then(
|
||||
() => this.$state.go(state, params || {})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Submits the data to the server.
|
||||
*
|
||||
|
@ -94,9 +101,11 @@ export default class Watcher extends Component {
|
|||
(resolve, reject) => this.noChanges(reject)
|
||||
);
|
||||
}
|
||||
let changedData = (this.$attrs.save && this.$attrs.save.toLowerCase() === 'post') ? this.copyInNewObject(this.data) : getModifiedData(this.data, this.orgData);
|
||||
let changedData = (this.$attrs.save && this.$attrs.save.toLowerCase() === 'post')
|
||||
? this.copyInNewObject(this.data)
|
||||
: getModifiedData(this.data, this.orgData);
|
||||
|
||||
if (this.save) {
|
||||
if (this.save && this.save.accept) {
|
||||
this.save.model = changedData; // this.copyInNewObject(changedData);
|
||||
return new Promise((resolve, reject) => {
|
||||
this.save.accept().then(
|
||||
|
@ -108,7 +117,7 @@ export default class Watcher extends Component {
|
|||
|
||||
// XXX: Alternative when mgCrud is not used
|
||||
|
||||
let id = this.orgData[this.idField];
|
||||
let id = this.idField ? this.orgData[this.idField] : null;
|
||||
|
||||
if (id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
@ -120,7 +129,7 @@ export default class Watcher extends Component {
|
|||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
this.$http.post(this.url, this.data).then(
|
||||
this.$http.post(this.url, changedData).then(
|
||||
json => this.writeData(json, resolve),
|
||||
json => reject(json)
|
||||
);
|
||||
|
@ -149,6 +158,8 @@ export default class Watcher extends Component {
|
|||
|
||||
updateOriginalData() {
|
||||
this.orgData = this.copyInNewObject(this.data);
|
||||
if (this.form && this.form.$dirty)
|
||||
this.form.$setPristine();
|
||||
}
|
||||
|
||||
copyInNewObject(data) {
|
||||
|
@ -181,7 +192,7 @@ export default class Watcher extends Component {
|
|||
}
|
||||
|
||||
dataChanged() {
|
||||
if (this.form && !this.form.$dirty) return false;
|
||||
if (this.form && this.form.$dirty) return true;
|
||||
let newData = this.copyInNewObject(this.data);
|
||||
return !isEqual(newData, this.orgData);
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ describe('Component vnWatcher', () => {
|
|||
vnApp = _vnApp_;
|
||||
$transitions = _$transitions_;
|
||||
$httpBackend = _$httpBackend_;
|
||||
$httpBackend.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
|
||||
$translate = _$translate_;
|
||||
$attrs = {
|
||||
save: "patch"
|
||||
|
@ -144,7 +145,7 @@ describe('Component vnWatcher', () => {
|
|||
|
||||
describe('when controller.save()', () => {
|
||||
it(`should set controller.save.model property`, () => {
|
||||
controller.save = {};
|
||||
controller.save = {accept: () => {}};
|
||||
controller.data = {originalInfo: 'original data', info: 'new data'};
|
||||
controller.orgData = {originalInfo: 'original data'};
|
||||
controller.submit();
|
||||
|
|
|
@ -14,7 +14,10 @@ class ItemCard {
|
|||
{relation: "origin"},
|
||||
{relation: "ink"},
|
||||
{relation: "producer"},
|
||||
{relation: "intrastat"}
|
||||
{relation: "intrastat"},
|
||||
{relation: "expence"},
|
||||
{relation: "taxClass"},
|
||||
{relation: "itemTag", scope: {order: "priority ASC", include: {relation: "tag"}}}
|
||||
]
|
||||
};
|
||||
this.$http.get(`/item/api/Items/${this.$state.params.id}?filter=${JSON.stringify(filter)}`).then(
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
import './item-card.js';
|
||||
|
||||
describe('Item', () => {
|
||||
describe('Component vnItemCard', () => {
|
||||
let $componentController;
|
||||
let $httpBackend;
|
||||
let $state;
|
||||
let controller;
|
||||
|
||||
beforeEach(() => {
|
||||
angular.mock.module('item');
|
||||
});
|
||||
|
||||
beforeEach(angular.mock.inject((_$componentController_, _$state_, _$httpBackend_) => {
|
||||
$componentController = _$componentController_;
|
||||
$httpBackend = _$httpBackend_;
|
||||
$state = _$state_;
|
||||
controller = $componentController('vnItemCard', {$state: $state});
|
||||
}));
|
||||
|
||||
describe('$onInit()', () => {
|
||||
it('should request to patch the propagation of tax status', () => {
|
||||
controller.client = {id: 123, isEqualizated: false};
|
||||
$httpBackend.whenGET('/item/api/Items/undefined?filter={"include":[{"relation":"itemType"},{"relation":"origin"},{"relation":"ink"},{"relation":"producer"},{"relation":"intrastat"},{"relation":"expence"},{"relation":"taxClass"},{"relation":"itemTag","scope":{"order":"priority ASC","include":{"relation":"tag"}}}]}').respond({data: 'item'});
|
||||
$httpBackend.expectGET('/item/api/Items/undefined?filter={"include":[{"relation":"itemType"},{"relation":"origin"},{"relation":"ink"},{"relation":"producer"},{"relation":"intrastat"},{"relation":"expence"},{"relation":"taxClass"},{"relation":"itemTag","scope":{"order":"priority ASC","include":{"relation":"tag"}}}]}');
|
||||
controller.$onInit();
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(controller.item).toEqual({data: 'item'});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -31,12 +31,10 @@
|
|||
order="description ASC"
|
||||
filter-search="{where: {description: {regexp: 'search'}} }"
|
||||
>
|
||||
<tpl-item>{{$parent.$parent.item.description}}</tpl-item>
|
||||
<tpl-item>{{$parent.$parent.item.description}}</tpl-item>
|
||||
</vn-autocomplete>
|
||||
<vn-textfield vn-one label="Relevancy" field="$ctrl.item.relevancy" type="number"></vn-textfield>
|
||||
|
||||
</vn-horizontal>
|
||||
|
||||
<vn-horizontal>
|
||||
<vn-autocomplete vn-one
|
||||
url="/item/api/Origins"
|
||||
|
@ -45,9 +43,13 @@
|
|||
value-field="id"
|
||||
field="$ctrl.item.originFk"
|
||||
></vn-autocomplete>
|
||||
<vn-one></vn-one>
|
||||
<vn-autocomplete vn-one
|
||||
url="/item/api/Expences"
|
||||
label="Expence"
|
||||
field="$ctrl.item.expenceFk"
|
||||
initial-data="$ctrl.item.expence"
|
||||
></vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
|
||||
</vn-vertical>
|
||||
</vn-card>
|
||||
<vn-button-bar>
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue