Merge branch 'dev' of http://git.verdnatura.es/salix into dev

This commit is contained in:
Carlos Jimenez 2018-10-03 11:46:54 +02:00
commit cba95e6c76
37 changed files with 3700 additions and 2887 deletions

View File

@ -87,6 +87,9 @@
</vn-table> </vn-table>
</vn-vertical> </vn-vertical>
</vn-card> </vn-card>
<vn-button-bar>
<vn-submit label="Regularizar" vn-acl="administrative, salesAssistant"></vn-submit>
</vn-button-bar>
<!-- WIP <!-- WIP
<a ng-click="$ctrl.openAddSalesDialog()" vn-tooltip="New item" vn-bind="+" fixed-bottom-right> <a ng-click="$ctrl.openAddSalesDialog()" vn-tooltip="New item" vn-bind="+" fixed-bottom-right>
<vn-float-button icon="add"></vn-float-button> <vn-float-button icon="add"></vn-float-button>

View File

@ -22,7 +22,11 @@ class Controller {
}; };
} }
getClaim() { $onInit() {
this.getCard();
}
getCard() {
let json = encodeURIComponent(JSON.stringify(this.filter)); let json = encodeURIComponent(JSON.stringify(this.filter));
let query = `/claim/api/Claims/${this.$state.params.id}?filter=${json}`; let query = `/claim/api/Claims/${this.$state.params.id}?filter=${json}`;
this.$http.get(query).then(res => { this.$http.get(query).then(res => {
@ -31,11 +35,9 @@ class Controller {
} }
}); });
} }
$onInit() {
this.getClaim();
}
reload() { reload() {
this.getClaim(); this.getCard();
} }
} }

View File

@ -21,11 +21,11 @@ describe('Claim', () => {
controller = $componentController('vnClaimCard', {$scope: $scope, $state: $state}); controller = $componentController('vnClaimCard', {$scope: $scope, $state: $state});
})); }));
describe('getClaim()', () => { describe('getCard()', () => {
it(`should make a query and save the data in claim`, () => { it(`should make a query and save the data in claim`, () => {
let json = encodeURIComponent(JSON.stringify(controller.filter)); let json = encodeURIComponent(JSON.stringify(controller.filter));
$httpBackend.expectGET(`/claim/api/Claims/${controller.$state.params.id}?filter=${json}`).respond({id: 1}); $httpBackend.expectGET(`/claim/api/Claims/${controller.$state.params.id}?filter=${json}`).respond({id: 1});
controller.getClaim(); controller.getCard();
$httpBackend.flush(); $httpBackend.flush();
expect(controller.claim).toEqual({id: 1}); expect(controller.claim).toEqual({id: 1});

View File

@ -30,22 +30,29 @@
</vn-auto> </vn-auto>
</vn-vertical> </vn-vertical>
<vn-horizontal pad-small class="quicklinks"> <vn-horizontal pad-small class="quicklinks">
<vn-button ng-if="$ctrl.quicklinks.btnOne" pad-small-right <a ng-if="$ctrl.quicklinks.btnOne" pad-small-right
vn-tooltip="{{::$ctrl.quicklinks.btnOne.tooltip}}" vn-tooltip="{{::$ctrl.quicklinks.btnOne.tooltip}}"
icon="{{::$ctrl.quicklinks.btnOne.icon}}" ui-sref="{{::$ctrl.quicklinks.btnOne.state}}" target="_blank">
ng-click="$ctrl.quicklinkGo($ctrl.quicklinks.btnOne.state, $ctrl.quicklinks.btnOne.params)"> <vn-icon
</vn-button> class="mdl-button mdl-js-button mdl-button--colored"
icon="{{::$ctrl.quicklinks.btnOne.icon}}">
<vn-button ng-if="$ctrl.quicklinks.btnTwo" pad-small-right </vn-icon>
</a>
<a ng-if="$ctrl.quicklinks.btnTwo" pad-small-right
vn-tooltip="{{::$ctrl.quicklinks.btnTwo.tooltip}}" vn-tooltip="{{::$ctrl.quicklinks.btnTwo.tooltip}}"
icon="{{::$ctrl.quicklinks.btnTwo.icon}}" ui-sref="{{::$ctrl.quicklinks.btnTwo.state}}" target="_blank">
ng-click="$ctrl.quicklinkGo($ctrl.quicklinks.btnTwo.state, $ctrl.quicklinks.btnTwo.params)"> <vn-icon
</vn-button> class="mdl-button mdl-js-button mdl-button--colored"
icon="{{::$ctrl.quicklinks.btnTwo.icon}}">
<vn-button ng-if="$ctrl.quicklinks.btnThree" pad-small-right </vn-icon>
</a>
<a ng-if="$ctrl.quicklinks.btnThree" pad-small-right
vn-tooltip="{{::$ctrl.quicklinks.btnThree.tooltip}}" vn-tooltip="{{::$ctrl.quicklinks.btnThree.tooltip}}"
icon="{{::$ctrl.quicklinks.btnThree.icon}}" ui-sref="{{::$ctrl.quicklinks.btnThree.state}}" target="_blank">
ng-click="$ctrl.quicklinkGo($ctrl.quicklinks.btnThree.state, $ctrl.quicklinks.btnThree.params)"> <vn-icon
</vn-button> class="mdl-button mdl-js-button mdl-button--colored"
icon="{{::$ctrl.quicklinks.btnThree.icon}}">
</vn-icon>
</a>
</vn-horizontal> </vn-horizontal>
</vn-card> </vn-card>

View File

@ -3,7 +3,24 @@ import ngModule from '../module';
class Controller { class Controller {
constructor($state) { constructor($state) {
this.$state = $state; this.$state = $state;
this._quicklinks = {}; }
get claim() {
return this._claim;
}
set claim(value) {
this._claim = value;
if (!value) return;
this._quicklinks = {
btnOne: {
icon: 'person',
state: `client.card.summary({id: ${value.clientFk}})`,
tooltip: 'Client card'
}
};
} }
set quicklinks(value = {}) { set quicklinks(value = {}) {
@ -13,10 +30,6 @@ class Controller {
get quicklinks() { get quicklinks() {
return this._quicklinks; return this._quicklinks;
} }
quicklinkGo(state, params) {
this.$state.go(state, params);
}
} }
Controller.$inject = ['$state']; Controller.$inject = ['$state'];

View File

@ -341,6 +341,15 @@
"menu": { "menu": {
"icon": "web" "icon": "web"
} }
},
{
"url" : "/history",
"state": "client.card.history",
"component": "vn-client-history",
"description": "History",
"menu": {
"icon": "history"
}
} }
] ]
} }

View File

@ -32,3 +32,4 @@ import './contact';
import './sample/index'; import './sample/index';
import './sample/create'; import './sample/create';
import './web-payment'; import './web-payment';
import './history';

View File

@ -8,8 +8,6 @@ class Controller extends Component {
this.$http = $http; this.$http = $http;
this.$timeout = $timeout; this.$timeout = $timeout;
this.isTooltip = true; this.isTooltip = true;
this.client = {};
this._quicklinks = {};
} }
set clientFk(value) { set clientFk(value) {
@ -38,10 +36,6 @@ class Controller extends Component {
}); });
} }
goToClientTickets() {
this.$state.go('ticket.index', {q: `{"clientFk": ${this.client.id}}`});
}
show() { show() {
this.$.popover.parent = this.parent; this.$.popover.parent = this.parent;
setTimeout(() => { setTimeout(() => {

View File

@ -6,12 +6,6 @@ class Controller {
this.$http = $http; this.$http = $http;
} }
set clientFk(value) {
if (!value) return;
this.getCard(value);
}
set client(value) { set client(value) {
this._client = value; this._client = value;
@ -37,21 +31,6 @@ class Controller {
get quicklinks() { get quicklinks() {
return this._quicklinks; return this._quicklinks;
} }
getCard(clientFk) {
this.$http.get(`/client/api/Clients/${clientFk}/getCard`)
.then(response => {
Object.assign(this.client, response.data);
});
}
goToClientTickets() {
this.$state.go('ticket.index', {q: `{"clientFk": ${this.client.id}}`});
}
quicklinkGo(state, params) {
this.$state.go(state, params);
}
} }
Controller.$inject = ['$http', '$state']; Controller.$inject = ['$http', '$state'];
@ -60,7 +39,6 @@ ngModule.component('vnClientDescriptor', {
template: require('./index.html'), template: require('./index.html'),
bindings: { bindings: {
client: '<', client: '<',
clientFk: '<?',
quicklinks: '<' quicklinks: '<'
}, },
controller: Controller controller: Controller

View File

@ -1,34 +0,0 @@
import './index';
describe('Descriptor', () => {
describe('Component vnClientDescriptor', () => {
let $componentController;
let $httpBackend;
let controller;
beforeEach(() => {
angular.mock.module('client');
});
beforeEach(angular.mock.inject((_$componentController_, _$httpBackend_) => {
$componentController = _$componentController_;
$httpBackend = _$httpBackend_;
$httpBackend.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
controller = $componentController('vnClientDescriptor');
}));
describe('getCard()', () => {
it(`should perform a query and store the client into the controller`, () => {
controller.client = {};
let clientFk = 101;
let response = {id: 101, name: 'Batman', debt: 100};
$httpBackend.when('GET', `/client/api/Clients/${clientFk}/getCard`).respond(response);
$httpBackend.expect('GET', `/client/api/Clients/${clientFk}/getCard`);
controller.getCard(clientFk);
$httpBackend.flush();
expect(controller.client).toEqual(response);
});
});
});
});

View File

@ -0,0 +1,65 @@
<vn-crud-model
vn-id="model"
url="/client/api/ClientLogs"
filter="$ctrl.filter"
link="{originFk: $ctrl.$stateParams.id}"
limit="20"
data="logs" on-data-change="$ctrl.onDataChange()">
</vn-crud-model>
<vn-vertical>
<vn-card pad-large>
<vn-vertical>
<vn-title>History</vn-title>
<vn-table model="model">
<vn-thead>
<vn-tr>
<vn-th field="creationDate" default-order="DESC">Date</vn-th>
<vn-th field="model">Model</vn-th>
<vn-th field="action">Action</vn-th>
<vn-th field="userFk">Changed by</vn-th>
<vn-th field="before">Before</vn-th>
<vn-th field="after">After</vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>
<vn-tr ng-repeat="clientLog in logs">
<vn-td>
{{::clientLog.creationDate | date:'dd/MM/yyyy HH:mm'}}
</vn-td>
<vn-td>
{{::clientLog.model}}
</vn-td>
<vn-td translate>
{{::clientLog.action}}
</vn-td>
<vn-td>
{{::clientLog.user.name}}
</vn-td>
<vn-td>
<vn-one ng-repeat="old in clientLog.oldProperties">
<vn-label-value label="{{old.key}}"
value="{{old.value}}">
</vn-label-value>
</vn-one>
</vn-td>
<vn-td>
<vn-one ng-repeat="new in clientLog.newProperties">
<vn-label-value label="{{new.key}}"
value="{{new.value}}">
</vn-label-value>
</vn-one>
</vn-td>
</vn-tr>
</vn-tbody>
<vn-empty-rows ng-if="model.data.length === 0" translate>
No results
</vn-empty-rows>
</vn-table>
</vn-vertical>
<vn-pagination
model="model"
scroll-selector="ui-view">
</vn-pagination>
</vn-card>
</vn-vertical>

View File

@ -0,0 +1,42 @@
import ngModule from '../module';
class Controller {
constructor($scope, $stateParams) {
this.$scope = $scope;
this.$stateParams = $stateParams;
this.filter = {
include: [{
relation: "user",
scope: {
fields: ["name"]
}
}]
};
}
onDataChange() {
let logs = this.$scope.model.data;
logs.forEach(log => {
log.oldProperties = this.getInstance(log.oldInstance);
log.newProperties = this.getInstance(log.newInstance);
});
}
getInstance(instance) {
let properties = [];
Object.keys(instance).forEach(property => {
properties.push({key: property, value: instance[property]});
});
return properties;
}
}
Controller.$inject = ['$scope', '$stateParams'];
ngModule.component('vnClientHistory', {
template: require('./index.html'),
controller: Controller
});

View File

@ -0,0 +1,39 @@
import './index';
describe('Client', () => {
describe('Component vnClientHistory', () => {
let $componentController;
let $scope;
let controller;
beforeEach(() => {
angular.mock.module('client');
});
beforeEach(angular.mock.inject((_$componentController_, $rootScope) => {
$componentController = _$componentController_;
$scope = $rootScope.$new();
controller = $componentController('vnClientHistory', {$scope: $scope});
controller.$scope.model = {data: [{newInstance: {id: 1}, oldInstance: {id: 2}}]}
}));
describe('onDataChange()', () => {
it('should call the function getInstance() twice', () => {
spyOn(controller, 'getInstance').and.callFake(() => {});
controller.onDataChange();
expect(controller.getInstance.calls.count()).toBe(2);
expect(controller.getInstance).toHaveBeenCalledWith({id: 1});
expect(controller.getInstance).toHaveBeenCalledWith({id: 2});
});
});
describe('getInstance(instance)', () => {
it('should transform the object given in to an array', () => {
let newInstance = controller.getInstance(controller.$scope.model.data[0].newInstance);
expect(newInstance).toEqual([{key: 'id', value: 1}]);
});
});
});
});

View File

@ -0,0 +1,8 @@
Model: Modelo
Action: Acción
Changed by: Cambiado por
Before: Antes
After: Despues
update: Actualizar
Create: Crear
History: Historial

View File

@ -6,7 +6,6 @@ class Controller extends Component {
constructor($element, $scope, $http) { constructor($element, $scope, $http) {
super($element, $scope); super($element, $scope);
this.$http = $http; this.$http = $http;
this._quicklinks = {};
this.isTooltip = true; this.isTooltip = true;
this.clear(); this.clear();
} }

View File

@ -4,7 +4,6 @@ import './style.scss';
class Controller { class Controller {
constructor($state) { constructor($state) {
this.$state = $state; this.$state = $state;
this._quicklinks = {};
} }
set quicklinks(value = {}) { set quicklinks(value = {}) {
@ -14,10 +13,6 @@ class Controller {
get quicklinks() { get quicklinks() {
return this._quicklinks; return this._quicklinks;
} }
quicklinkGo(state, params) {
this.$state.go(state, params);
}
} }
Controller.$inject = ['$state']; Controller.$inject = ['$state'];

View File

@ -1,27 +0,0 @@
import './index.js';
describe('Item', () => {
describe('Component vnItemDescriptor', () => {
let $componentController;
let controller;
beforeEach(() => {
angular.mock.module('item');
});
beforeEach(angular.mock.inject(_$componentController_ => {
$componentController = _$componentController_;
controller = $componentController('vnItemDescriptor');
controller.$state.go = () => {};
}));
describe('quicklinkGo()', () => {
it(`shoud set _itemFk to a given value and call _getItem if the given value is not null`, () => {
spyOn(controller.$state, 'go');
controller.quicklinkGo('state', 'params');
expect(controller.$state.go).toHaveBeenCalledWith('state', 'params');
});
});
});
});

View File

@ -38,6 +38,7 @@ Tag: Etiqueta
Worker: Trabajador Worker: Trabajador
Available: Disponible Available: Disponible
Create: Crear Create: Crear
Client card: Ficha del cliente
#Sections #Sections
Items: Artículos Items: Artículos

View File

@ -6,7 +6,6 @@ class Controller extends Component {
constructor($element, $scope, $http) { constructor($element, $scope, $http) {
super($element, $scope); super($element, $scope);
this.$http = $http; this.$http = $http;
this._quicklinks = {};
this.isTooltip = true; this.isTooltip = true;
this.clear(); this.clear();
} }

View File

@ -31,10 +31,6 @@ class Controller {
get quicklinks() { get quicklinks() {
return this._quicklinks; return this._quicklinks;
} }
quicklinkGo(state, params) {
this.$state.go(state, params);
}
} }
Controller.$inject = ['$state', '$scope']; Controller.$inject = ['$state', '$scope'];

View File

@ -24,7 +24,11 @@ class Controller {
}; };
} }
getOrder() { $onInit() {
this.getCard();
}
getCard() {
let json = encodeURIComponent(JSON.stringify(this.filter)); let json = encodeURIComponent(JSON.stringify(this.filter));
let query = `/order/api/Orders/${this.$state.params.id}?filter=${json}`; let query = `/order/api/Orders/${this.$state.params.id}?filter=${json}`;
this.$http.get(query).then(res => { this.$http.get(query).then(res => {
@ -35,6 +39,10 @@ class Controller {
}); });
} }
reload() {
this.getCard();
}
getTotal() { getTotal() {
let query = `/order/api/Orders/${this.$state.params.id}/getTotal`; let query = `/order/api/Orders/${this.$state.params.id}/getTotal`;
this.$http.get(query).then(res => { this.$http.get(query).then(res => {
@ -43,13 +51,6 @@ class Controller {
} }
}); });
} }
$onInit() {
this.getOrder();
}
reload() {
this.getOrder();
}
} }
Controller.$inject = ['$http', '$state']; Controller.$inject = ['$http', '$state'];

View File

@ -22,12 +22,12 @@ describe('Order', () => {
controller = $componentController('vnOrderCard', {$scope: $scope, $state: $state}); controller = $componentController('vnOrderCard', {$scope: $scope, $state: $state});
})); }));
describe('getOrder()', () => { describe('getCard()', () => {
it(`should make a query, save the data in order and call get order if the response has data`, () => { it(`should make a query, save the data in order and call get order if the response has data`, () => {
spyOn(controller, 'getTotal'); spyOn(controller, 'getTotal');
let json = encodeURIComponent(JSON.stringify(controller.filter)); let json = encodeURIComponent(JSON.stringify(controller.filter));
$httpBackend.expectGET(`/order/api/Orders/${controller.$state.params.id}?filter=${json}`).respond({id: 1}); $httpBackend.expectGET(`/order/api/Orders/${controller.$state.params.id}?filter=${json}`).respond({id: 1});
controller.getOrder(); controller.getCard();
$httpBackend.flush(); $httpBackend.flush();
expect(controller.order).toEqual({id: 1}); expect(controller.order).toEqual({id: 1});
@ -38,7 +38,7 @@ describe('Order', () => {
spyOn(controller, 'getTotal'); spyOn(controller, 'getTotal');
let json = encodeURIComponent(JSON.stringify(controller.filter)); let json = encodeURIComponent(JSON.stringify(controller.filter));
$httpBackend.expectGET(`/order/api/Orders/${controller.$state.params.id}?filter=${json}`).respond(undefined); $httpBackend.expectGET(`/order/api/Orders/${controller.$state.params.id}?filter=${json}`).respond(undefined);
controller.getOrder(); controller.getCard();
$httpBackend.flush(); $httpBackend.flush();
expect(controller.order).toEqual({}); expect(controller.order).toEqual({});

View File

@ -37,4 +37,30 @@
value="{{$ctrl.order.total | currency: ' €': 2}}"> value="{{$ctrl.order.total | currency: ' €': 2}}">
</vn-label-value> </vn-label-value>
</div> </div>
<vn-horizontal pad-small class="quicklinks">
<a ng-if="$ctrl.quicklinks.btnOne" pad-small-right
vn-tooltip="{{::$ctrl.quicklinks.btnOne.tooltip}}"
ui-sref="{{::$ctrl.quicklinks.btnOne.state}}" target="_blank">
<vn-icon
class="mdl-button mdl-js-button mdl-button--colored"
icon="{{::$ctrl.quicklinks.btnOne.icon}}">
</vn-icon>
</a>
<a ng-if="$ctrl.quicklinks.btnTwo" pad-small-right
vn-tooltip="{{::$ctrl.quicklinks.btnTwo.tooltip}}"
ui-sref="{{::$ctrl.quicklinks.btnTwo.state}}" target="_blank">
<vn-icon
class="mdl-button mdl-js-button mdl-button--colored"
icon="{{::$ctrl.quicklinks.btnTwo.icon}}">
</vn-icon>
</a>
<a ng-if="$ctrl.quicklinks.btnThree" pad-small-right
vn-tooltip="{{::$ctrl.quicklinks.btnThree.tooltip}}"
ui-sref="{{::$ctrl.quicklinks.btnThree.state}}" target="_blank">
<vn-icon
class="mdl-button mdl-js-button mdl-button--colored"
icon="{{::$ctrl.quicklinks.btnThree.icon}}">
</vn-icon>
</a>
</vn-horizontal>
</vn-card> </vn-card>

View File

@ -5,6 +5,14 @@ class Controller {
constructor($translate) { constructor($translate) {
this.translate = $translate; this.translate = $translate;
} }
set quicklinks(value = {}) {
this._quicklinks = Object.assign(value, this._quicklinks);
}
get quicklinks() {
return this._quicklinks;
}
} }
Controller.$inject = ['$translate']; Controller.$inject = ['$translate'];

View File

@ -4,10 +4,7 @@ class Controller {
constructor($http, $state) { constructor($http, $state) {
this.$http = $http; this.$http = $http;
this.$state = $state; this.$state = $state;
} this.filter = {
getTicket() {
let filter = {
include: [ include: [
{relation: 'warehouse', scope: {fields: ['name']}}, {relation: 'warehouse', scope: {fields: ['name']}},
{relation: 'agencyMode', scope: {fields: ['name']}}, {relation: 'agencyMode', scope: {fields: ['name']}},
@ -33,8 +30,14 @@ class Controller {
} }
] ]
}; };
}
let json = encodeURIComponent(JSON.stringify(filter)); $onInit() {
this.getCard();
}
getCard() {
let json = encodeURIComponent(JSON.stringify(this.filter));
let query = `/ticket/api/Tickets/${this.$state.params.id}?filter=${json}`; let query = `/ticket/api/Tickets/${this.$state.params.id}?filter=${json}`;
this.$http.get(query).then(res => { this.$http.get(query).then(res => {
if (res.data) if (res.data)
@ -42,12 +45,8 @@ class Controller {
}); });
} }
$onInit() {
this.getTicket();
}
reload() { reload() {
this.getTicket(); this.getCard();
} }
} }

View File

@ -20,7 +20,7 @@ describe('Ticket', () => {
controller = $componentController('vnTicketCard', {$state: $state}); controller = $componentController('vnTicketCard', {$state: $state});
})); }));
describe('getTicket()', () => { describe('getCard()', () => {
it('should perform a GET query and define the ticket property on controller', () => { it('should perform a GET query and define the ticket property on controller', () => {
let filter = { let filter = {
include: [ include: [
@ -53,7 +53,7 @@ describe('Ticket', () => {
$httpBackend.when('GET', `/ticket/api/Tickets/1?filter=${filter}`).respond({id: 1}); $httpBackend.when('GET', `/ticket/api/Tickets/1?filter=${filter}`).respond({id: 1});
$httpBackend.expect('GET', `/ticket/api/Tickets/1?filter=${filter}`); $httpBackend.expect('GET', `/ticket/api/Tickets/1?filter=${filter}`);
controller.getTicket(); controller.getCard();
$httpBackend.flush(); $httpBackend.flush();
expect(controller.ticket).toBeDefined(); expect(controller.ticket).toBeDefined();

5826
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -9,33 +9,33 @@
"url": "https://git.verdnatura.es/salix" "url": "https://git.verdnatura.es/salix"
}, },
"dependencies": { "dependencies": {
"@uirouter/angularjs": "^1.0.3", "@uirouter/angularjs": "^1.0.20",
"angular": "^1.7.0", "angular": "^1.7.4",
"angular-cookies": "^1.7.0", "angular-cookies": "^1.7.4",
"angular-paging": "^2.2.2", "angular-paging": "^2.2.2",
"angular-translate": "^2.18.1", "angular-translate": "^2.18.1",
"angular-translate-loader-partial": "^2.18.1", "angular-translate-loader-partial": "^2.18.1",
"flatpickr": "^4.4.6", "flatpickr": "^4.5.2",
"fs-extra": "^5.0.0", "fs-extra": "^5.0.0",
"js-yaml": "^3.10.0", "js-yaml": "^3.12.0",
"material-design-lite": "^1.3.0", "material-design-lite": "^1.3.0",
"mg-crud": "^1.1.2", "mg-crud": "^1.1.2",
"npm": "^5.10.0", "npm": "^5.10.0",
"oclazyload": "^0.6.3", "oclazyload": "^0.6.3",
"require-yaml": "0.0.1", "require-yaml": "0.0.1",
"validator": "^6.2.1" "validator": "^6.3.0"
}, },
"devDependencies": { "devDependencies": {
"angular-mocks": "^1.7.0", "angular-mocks": "^1.7.4",
"assets-webpack-plugin": "^3.5.1", "assets-webpack-plugin": "^3.9.6",
"babel": "^6.23.0", "babel": "^6.23.0",
"babel-core": "^6.26.0", "babel-core": "^6.26.3",
"babel-loader": "^7.1.2", "babel-loader": "^7.1.5",
"babel-preset-es2015": "^6.24.1", "babel-preset-es2015": "^6.24.1",
"cors": "^2.8.1", "cors": "^2.8.4",
"css-loader": "^0.25.0", "css-loader": "^0.25.0",
"del": "^2.2.2", "del": "^2.2.2",
"electron": "^1.8.7", "electron": "^1.8.8",
"eslint": "^3.19.0", "eslint": "^3.19.0",
"eslint-config-angular": "^0.5.0", "eslint-config-angular": "^0.5.0",
"eslint-config-google": "^0.6.0", "eslint-config-google": "^0.6.0",
@ -43,9 +43,9 @@
"eslint-config-xo": "^0.17.0", "eslint-config-xo": "^0.17.0",
"eslint-plugin-jasmine": "^2.10.1", "eslint-plugin-jasmine": "^2.10.1",
"fancy-log": "^1.3.2", "fancy-log": "^1.3.2",
"file-loader": "^1.1.6", "file-loader": "^1.1.11",
"gulp": "^3.9.1", "gulp": "^3.9.1",
"gulp-concat": "^2.6.0", "gulp-concat": "^2.6.1",
"gulp-env": "^0.4.0", "gulp-env": "^0.4.0",
"gulp-extend": "^0.2.0", "gulp-extend": "^0.2.0",
"gulp-install": "^1.1.0", "gulp-install": "^1.1.0",
@ -53,30 +53,30 @@
"gulp-print": "^2.0.1", "gulp-print": "^2.0.1",
"gulp-wrap": "^0.13.0", "gulp-wrap": "^0.13.0",
"gulp-yaml": "^1.0.1", "gulp-yaml": "^1.0.1",
"html-loader": "^0.4.4", "html-loader": "^0.4.5",
"jasmine": "^2.99.0", "jasmine": "^2.99.0",
"jasmine-spec-reporter": "^4.2.1", "jasmine-spec-reporter": "^4.2.1",
"karma": "^1.7.1", "karma": "^1.7.1",
"karma-chrome-launcher": "^2.2.0", "karma-chrome-launcher": "^2.2.0",
"karma-firefox-launcher": "^1.1.0", "karma-firefox-launcher": "^1.1.0",
"karma-jasmine": "^1.1.1", "karma-jasmine": "^1.1.2",
"karma-sourcemap-loader": "^0.3.7", "karma-sourcemap-loader": "^0.3.7",
"karma-webpack": "^2.0.9", "karma-webpack": "^2.0.13",
"merge-stream": "^1.0.1", "merge-stream": "^1.0.1",
"minimist": "^1.2.0", "minimist": "^1.2.0",
"mustache": "^2.3.0", "mustache": "^2.3.2",
"mysql2": "^1.5.2", "mysql2": "^1.6.1",
"nightmare": "^2.10.0", "nightmare": "^2.10.0",
"node-sass": "^4.7.2", "node-sass": "^4.9.3",
"nodemon": "^1.18.3", "nodemon": "^1.18.4",
"plugin-error": "^1.0.1", "plugin-error": "^1.0.1",
"raw-loader": "*", "raw-loader": "*",
"run-sequence": "^2.2.0", "run-sequence": "^2.2.1",
"sass-loader": "^6.0.6", "sass-loader": "^6.0.7",
"style-loader": "^0.20.1", "style-loader": "^0.20.3",
"webpack": "^3.10.0", "webpack": "^3.12.0",
"webpack-dev-server": "^2.11.1", "webpack-dev-server": "^2.11.3",
"webpack-merge": "^4.1.1", "webpack-merge": "^4.1.4",
"yaml-loader": "^0.5.0" "yaml-loader": "^0.5.0"
}, },
"scripts": { "scripts": {

View File

@ -813,9 +813,27 @@ INSERT INTO `vn`.`deliveryMethod`(`id`, `code`, `description`)
INSERT INTO `hedera`.`order`(`id`, `date_send`, `customer_id`, `delivery_method_id`, `agency_id`, `address_id`, `company_id`, `note`, `source_app`, `confirmed`, `date_make`, `first_row_stamp`, `confirm_date`) INSERT INTO `hedera`.`order`(`id`, `date_send`, `customer_id`, `delivery_method_id`, `agency_id`, `address_id`, `company_id`, `note`, `source_app`, `confirmed`, `date_make`, `first_row_stamp`, `confirm_date`)
VALUES VALUES
( 1, CURDATE(), 101, 1, 1, 121, 442, NULL, 'TPV' , 0, CURDATE(), CURDATE() , CURDATE()), (1 , DATE_ADD(CURDATE(), INTERVAL -15 DAY) , 101, 1, 1, 121, 442, NULL, 'TPV', 1, DATE_ADD(CURDATE(), INTERVAL -15 DAY) , DATE_ADD(CURDATE(), INTERVAL -15 DAY) , DATE_ADD(CURDATE(), INTERVAL -15 DAY) ),
( 2, CURDATE(), 102, 2, 2, 122, 442, NULL, 'WEB' , 1, CURDATE(), CURDATE() , CURDATE()), (2 , DATE_ADD(CURDATE(), INTERVAL -10 DAY) , 101, 2, 1, 121, 442, NULL, 'WEB', 1, DATE_ADD(CURDATE(), INTERVAL -10 DAY) , DATE_ADD(CURDATE(), INTERVAL -10 DAY) , DATE_ADD(CURDATE(), INTERVAL -10 DAY) ),
( 3, CURDATE(), 103, 3, 7, 123, 442, NULL, 'ANDROID', 0, CURDATE(), DATE_ADD(CURDATE(), INTERVAL +5 DAY), DATE_ADD(CURDATE(),INTERVAL +5 DAY)); (3 , DATE_ADD(CURDATE(), INTERVAL -5 DAY) , 102, 3, 2, 122, 442, NULL, 'ANDROID', 1, DATE_ADD(CURDATE(), INTERVAL -5 DAY) , DATE_ADD(CURDATE(), INTERVAL -5 DAY) , DATE_ADD(CURDATE(), INTERVAL -5 DAY) ),
(4 , DATE_ADD(CURDATE(), INTERVAL -4 DAY) , 102, 1, 2, 122, 442, NULL, 'SALIX', 1, DATE_ADD(CURDATE(), INTERVAL -4 DAY) , DATE_ADD(CURDATE(), INTERVAL -4 DAY) , DATE_ADD(CURDATE(), INTERVAL -4 DAY) ),
(5 , DATE_ADD(CURDATE(), INTERVAL -3 DAY) , 103, 2, 3, 123, 442, NULL, 'SALIX', 1, DATE_ADD(CURDATE(), INTERVAL -3 DAY) , DATE_ADD(CURDATE(), INTERVAL -3 DAY) , DATE_ADD(CURDATE(), INTERVAL -3 DAY) ),
(6 , DATE_ADD(CURDATE(), INTERVAL -2 DAY) , 103, 3, 3, 123, 442, NULL, 'SALIX', 1, DATE_ADD(CURDATE(), INTERVAL -2 DAY) , DATE_ADD(CURDATE(), INTERVAL -2 DAY) , DATE_ADD(CURDATE(), INTERVAL -2 DAY) ),
(7 , DATE_ADD(CURDATE(), INTERVAL -1 DAY) , 104, 1, 4, 124, 442, NULL, 'SALIX', 1, DATE_ADD(CURDATE(), INTERVAL -1 DAY) , DATE_ADD(CURDATE(), INTERVAL -1 DAY) , DATE_ADD(CURDATE(), INTERVAL -1 DAY) ),
(8 , DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 104, 2, 4, 124, 442, NULL, 'SALIX', 1, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(CURDATE(), INTERVAL -1 MONTH)),
(9 , DATE_ADD(CURDATE(), INTERVAL -2 MONTH), 105, 3, 5, 125, 442, NULL, 'SALIX', 1, DATE_ADD(CURDATE(), INTERVAL -2 MONTH), DATE_ADD(CURDATE(), INTERVAL -2 MONTH), DATE_ADD(CURDATE(), INTERVAL -2 MONTH)),
(10, DATE_ADD(CURDATE(), INTERVAL -3 MONTH), 105, 1, 6, 125, 442, NULL, 'SALIX', 1, DATE_ADD(CURDATE(), INTERVAL -3 MONTH), DATE_ADD(CURDATE(), INTERVAL -3 MONTH), DATE_ADD(CURDATE(), INTERVAL -3 MONTH)),
(11, CURDATE() , 101, 2, 7, 121, 442, NULL, 'SALIX', 1, CURDATE() , CURDATE() , CURDATE() ),
(12, DATE_ADD(CURDATE(), INTERVAL +1 MONTH), 101, 3, 1, 121, 442, NULL, 'SALIX', 1, DATE_ADD(CURDATE(), INTERVAL +1 MONTH), DATE_ADD(CURDATE(), INTERVAL +1 MONTH), DATE_ADD(CURDATE(), INTERVAL +1 MONTH)),
(13, DATE_ADD(CURDATE(), INTERVAL +2 MONTH), 101, 1, 2, 121, 442, NULL, 'SALIX', 1, DATE_ADD(CURDATE(), INTERVAL +2 MONTH), DATE_ADD(CURDATE(), INTERVAL +2 MONTH), DATE_ADD(CURDATE(), INTERVAL +2 MONTH)),
(14, DATE_ADD(CURDATE(), INTERVAL +3 MONTH), 101, 2, 2, 121, 442, NULL, 'SALIX', 1, DATE_ADD(CURDATE(), INTERVAL +3 MONTH), DATE_ADD(CURDATE(), INTERVAL +3 MONTH), DATE_ADD(CURDATE(), INTERVAL +3 MONTH)),
(15, DATE_ADD(CURDATE(), INTERVAL +4 MONTH), 101, 3, 3, 121, 442, NULL, 'SALIX', 1, DATE_ADD(CURDATE(), INTERVAL +4 MONTH), DATE_ADD(CURDATE(), INTERVAL +4 MONTH), DATE_ADD(CURDATE(), INTERVAL +4 MONTH)),
(16, CURDATE() , 101, 1, 1, 121, 442, NULL, 'SALIX', 0, CURDATE() , CURDATE() , CURDATE() ),
(17, CURDATE() , 106, 2, 4, 126, 442, NULL, 'SALIX', 0, CURDATE() , CURDATE() , CURDATE() ),
(18, CURDATE() , 107, 3, 4, 127, 442, NULL, 'SALIX', 0, CURDATE() , CURDATE() , CURDATE() ),
(19, CURDATE() , 108, 1, 5, 128, 442, NULL, 'SALIX', 0, CURDATE() , CURDATE() , CURDATE() ),
(20, CURDATE() , 109, 2, 5, 119, 442, NULL, 'SALIX', 0, CURDATE() , CURDATE() , CURDATE() ),
(21, CURDATE() , 110, 3, 5, 129, 442, NULL, 'SALIX', 0, CURDATE() , CURDATE() , CURDATE() );
INSERT INTO `hedera`.`orderRow`(`id`, `orderFk`, `itemFk`, `warehouseFk`, `shipment`, `amount`, `price`, `rate`, `created`, `saleFk`) INSERT INTO `hedera`.`orderRow`(`id`, `orderFk`, `itemFk`, `warehouseFk`, `shipment`, `amount`, `price`, `rate`, `created`, `saleFk`)
VALUES VALUES
@ -878,4 +896,28 @@ INSERT INTO `hedera`.`tpvTransaction`(`id`,`merchantFk`, `clientFk`,`receiptFk`,
(1, 1, 101, NULL, 2000, NULL, 'SIS0042', 'ok', CURDATE()), (1, 1, 101, NULL, 2000, NULL, 'SIS0042', 'ok', CURDATE()),
(2, 1, 101, NULL, 1000, NULL, 'SIS0051', 'started', CURDATE()), (2, 1, 101, NULL, 1000, NULL, 'SIS0051', 'started', CURDATE()),
(3, 2, 101, NULL, 7268, 0, NULL, 'ok', CURDATE()), (3, 2, 101, NULL, 7268, 0, NULL, 'ok', CURDATE()),
(4, 2, 101, NULL, 4698, 100, NULL, 'started', CURDATE()); (4, 2, 101, NULL, 4698, 100, NULL, 'started', CURDATE());
INSERT INTO `vn`.`orderTicket`(`orderFk`, `ticketFk`)
VALUES
(1, 1),
(2, 2),
(3, 3),
(4, 4),
(5, 5),
(6, 6),
(7, 7),
(8, 8),
(9, 9),
(10, 10),
(11, 11),
(12, 12),
(13, 13),
(14, 14),
(15, 15),
(16, 16),
(17, 17),
(18, 18),
(19, 19),
(20, 20),
(21, 21);

View File

@ -1,5 +1,5 @@
module.exports = function(Client) { module.exports = function(Self) {
Client.remoteMethod('addressesPropagateRe', { Self.remoteMethod('addressesPropagateRe', {
description: 'Change property isEqualizated in all client addresses', description: 'Change property isEqualizated in all client addresses',
accessType: 'WRITE', accessType: 'WRITE',
accepts: [ accepts: [
@ -29,10 +29,11 @@ module.exports = function(Client) {
} }
}); });
Client.addressesPropagateRe = async (id, data) => { Self.addressesPropagateRe = async (id, data) => {
if (data.hasOwnProperty('isEqualizated')) { if (data.hasOwnProperty('isEqualizated')) {
await Client.app.models.Address.updateAll({clientFk: id}, data); await Self.app.models.Address.updateAll({clientFk: id}, data);
await Client.update({id: id}, {hasToInvoiceByAddress: false}); let client = await Self.app.models.Client.findById(id)
await client.updateAttributes({hasToInvoiceByAddress: false});
return true; return true;
} }
return false; return false;

View File

@ -0,0 +1,50 @@
{
"name": "ClientLog",
"base": "VnModel",
"options": {
"mysql": {
"table": "clientLog"
}
},
"properties": {
"id": {
"id": true,
"type": "Number",
"forceId": false
},
"originFk": {
"type": "Number",
"required": true
},
"userFk": {
"type": "Number",
"required": true
},
"action": {
"type": "String",
"required": true
},
"model": {
"type": "String",
"required": true
},
"oldInstance": {
"type": "Object",
"required": true
},
"newInstance": {
"type": "Object",
"required": true
},
"creationDate": {
"type": "Date"
}
},
"relations": {
"user": {
"type": "belongsTo",
"model": "Account",
"foreignKey": "userFk"
}
}
}

View File

@ -1,6 +1,9 @@
{ {
"name": "Client", "name": "Client",
"base": "VnModel", "base": "Loggable",
"log": {
"model":"ClientLog"
},
"options": { "options": {
"mysql": { "mysql": {
"table": "client" "table": "client"

View File

@ -0,0 +1,155 @@
const pick = require('object.pick');
const LoopBackContext = require('loopback-context');
module.exports = function(Self) {
Self.setup = function() {
Self.super_.setup.call(this);
};
Self.observe('after save', async function(ctx) {
const loopBackContext = LoopBackContext.getCurrentContext();
await logInModel(ctx, loopBackContext);
});
Self.observe('before save', async function(ctx) {
let oldInstance;
let oldInstanceFk;
let newInstance;
if (ctx.data) {
oldInstanceFk = pick(ctx.currentInstance, Object.keys(ctx.data));
newInstance = await fkToValue(ctx.data, ctx);
oldInstance = await fkToValue(oldInstanceFk, ctx);
}
if (ctx.isNewInstance) {
newInstance = await fkToValue(ctx.instance.__data, ctx);
}
ctx.hookState.oldInstance = oldInstance;
ctx.hookState.newInstance = newInstance;
});
/* Self.observe('before delete', async function(ctx, next) {
let oldInstance;
if (ctx.instance) {
oldInstance = await fkToValue(ctx.data, ctx);
}
await logInModel(ctx);
next();
});
Self.observe('after delete', async function(ctx, next) {
let oldInstance;
if (ctx.instance) {
oldInstance = await fkToValue(ctx.data, ctx);
}
await logInModel(ctx);
next();
});
*/
async function fkToValue(instance, ctx) {
let result = {};
for (let key in instance) {
if (key == 'id') continue;
let val = instance[key];
if (val === undefined) continue;
for (let key1 in ctx.Model.relations) {
let val1 = ctx.Model.relations[key1];
if (val1.keyFrom == key) {
let recordSet = await val1.modelTo.findById(val);
val = recordSet.name; // FIXME preparar todos los modelos con campo name
break;
}
}
result[key] = val;
}
return result;
}
async function logInModel(ctx, loopBackContext) {
let definition = ctx.Model.definition;
let primaryKey;
for (let property in definition.properties) {
if (definition.properties[property].id) {
primaryKey = property;
break;
}
}
if (!primaryKey) throw new Error('Primary key not found');
let originId;
if (definition.settings.log.relation) {
// RELATIONS LOG
primaryKey = ctx.Model.relations[definition.settings.log.relation].keyFrom;
if(ctx.where && ctx.where[primaryKey])
originId = ctx.where[primaryKey]
else
originId = ctx.instance[primaryKey];
} else {
if (ctx.instance) {
originId = ctx.instance.id;
} else {
originId = ctx.currentInstance.id;
}
}
// This adds the originDescription field if it doesnt exists in the instances
let originDescription = definition.settings.log.originDescription;
if (originDescription && (!ctx.instance || !ctx.instance[originDescription]))
await Self.modelBuilder.models[definition.name].findById()
if (ctx.hookState.oldInstance && !ctx.hookState.oldInstance[originDescription]){
ctx.hookState.oldInstance[originDescription] = ctx.instance[originDescription];
ctx.hookState.newInstance[originDescription] = ctx.instance[originDescription];
}
// This put some order in the intances putting the originDescription in first place
let oldInstance = {};
if (ctx.hookState.oldInstance) {
oldInstance[originDescription] = ctx.hookState.oldInstance[originDescription];
delete ctx.hookState.oldInstance[originDescription];
Object.assign(oldInstance, ctx.hookState.oldInstance);
}
let newInstance = {};
if (ctx.hookState.newInstance) {
newInstance[originDescription] = ctx.hookState.newInstance[originDescription];
delete ctx.hookState.newInstance[originDescription];
Object.assign(newInstance, ctx.hookState.newInstance)
}
let action = setActionType(ctx);
let userFk = loopBackContext.active.accessToken.userId;
let logRecord = {
originFk: originId,
userFk: userFk,
model: ctx.Model.definition.name,
action: action,
oldInstance: oldInstance,
newInstance: newInstance
};
let logModel = definition.settings.log.model
await Self.modelBuilder.models[logModel].create(logRecord);
}
function setActionType(ctx) {
let oldInstance = ctx.hookState.oldInstance;
let newInstance = ctx.hookState.newInstance;
if (oldInstance && newInstance) {
return 'update';
} else if (!oldInstance && newInstance) {
return 'insert';
}
}
};

View File

@ -0,0 +1,5 @@
{
"name": "Loggable",
"base": "VnModel",
"validateUpsert": true
}

View File

@ -45,6 +45,9 @@
"Client": { "Client": {
"dataSource": "vn" "dataSource": "vn"
}, },
"ClientLog": {
"dataSource": "vn"
},
"ClientCreditLimit": { "ClientCreditLimit": {
"dataSource": "vn" "dataSource": "vn"
}, },

View File

@ -5,7 +5,7 @@ describe('order catalogFilter()', () => {
order: 'relevancy DESC, name' order: 'relevancy DESC, name'
}; };
let args = { let args = {
orderFk: 3, orderFk: 11,
categoryFk: 1, categoryFk: 1,
typeFk: 2 typeFk: 2
}; };
@ -23,7 +23,7 @@ describe('order catalogFilter()', () => {
order: 'relevancy DESC, name' order: 'relevancy DESC, name'
}; };
let args = { let args = {
orderFk: 3, orderFk: 11,
categoryFk: 1, categoryFk: 1,
typeFk: 2 typeFk: 2
}; };

View File

@ -14,7 +14,7 @@ describe('order isEditable()', () => {
}); });
it('should return true when the given order is editable', async() => { it('should return true when the given order is editable', async() => {
let isEditable = await app.models.Order.isEditable(1); let isEditable = await app.models.Order.isEditable(16);
expect(isEditable).toBeTruthy(); expect(isEditable).toBeTruthy();
}); });