This commit is contained in:
Juan 2018-10-18 09:26:05 +02:00
commit ecee07530a
438 changed files with 15593 additions and 6239 deletions

1
client/agency/index.js Normal file
View File

@ -0,0 +1 @@
export * from './src';

67
client/agency/routes.json Normal file
View File

@ -0,0 +1,67 @@
{
"module": "agency",
"name": "Agencies",
"icon" : "local_shipping",
"validations" : true,
"routes": [
{
"url": "/zone",
"state": "zone",
"abstract": true,
"component": "ui-view",
"description": "Zones"
},
{
"url": "/index?q",
"state": "zone.index",
"component": "vn-zone-index",
"description": "List",
"acl": ["developer"]
},
{
"url": "/create",
"state": "zone.create",
"component": "vn-zone-create",
"description": "New zone"
},
{
"url": "/:id",
"state": "zone.card",
"abstract": true,
"component": "vn-zone-card"
},
{
"url" : "/summary",
"state": "zone.card.summary",
"component": "vn-zone-summary",
"description": "Summary",
"params": {
"zone": "$ctrl.zone"
}
},
{
"url": "/basic-data",
"state": "zone.card.basicData",
"component": "vn-zone-basic-data",
"description": "Basic data",
"params": {
"zone": "$ctrl.zone"
},
"menu": {
"icon": "settings"
}
},
{
"url": "/delivery-day",
"state": "zone.card.deliveryDay",
"component": "vn-zone-delivery-day",
"description": "Delivery days",
"params": {
"zone": "$ctrl.zone"
},
"menu": {
"icon": "today"
}
}
]
}

View File

@ -0,0 +1,12 @@
export * from './module';
// import components
import './zone/card';
import './zone/descriptor';
import './zone/search-panel';
import './zone/index';
import './zone/create';
import './zone/summary';
import './zone/basic-data';
import './zone/delivery-day';
import './zone/calendar';

View File

@ -0,0 +1 @@
Agencies: Agencies

View File

@ -0,0 +1,13 @@
Name: Nombre
Agency: Agencia
Warehouse: Almacén
Hour: Hora (ETD)
Price: Precio
Create: Crear
Zones: Zonas
List: Listado
Summary: Vista previa
New zone: Nueva zona
Basic data: Datos básicos
Delivery days: Días de envío

View File

@ -0,0 +1,5 @@
import {ng} from 'vendor';
import 'core';
const ngModule = ng.module('agency', ['vnCore']);
export default ngModule;

View File

@ -0,0 +1,67 @@
<mg-ajax path="/agency/api/Zones/{{patch.params.id}}" options="vnPatch"></mg-ajax>
<vn-watcher
vn-id="watcher"
data="$ctrl.zone"
form="form"
save="patch">
</vn-watcher>
<form name="form" ng-submit="$ctrl.onSubmit()">
<vn-card pad-large>
<vn-title>Basic data</vn-title>
<vn-horizontal>
<vn-textfield vn-two vn-focus
label="Name"
field="$ctrl.zone.name">
</vn-textfield>
</vn-horizontal>
<vn-horizontal>
<vn-autocomplete
vn-one
field="$ctrl.zone.warehouseFk"
url="/agency/api/Warehouses"
show-field="name"
value-field="id"
label="Warehouse">
</vn-autocomplete>
<vn-autocomplete
vn-one
field="$ctrl.zone.agencyModeFk"
url="/agency/api/AgencyModes"
show-field="name"
value-field="id"
label="Agency">
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal>
<vn-input-number
vn-two
min="0"
step="1"
label="Traveling days"
field="$ctrl.zone.travelingDays">
</vn-input-number>
<vn-input-time
vn-two
label="Estimated hour (ETD)"
field="$ctrl.zone.hour">
</vn-input-time>
</vn-horizontal>
<vn-horizontal>
<vn-input-number vn-one
label="Price"
field="$ctrl.zone.price"
min="0.00"
step="0.50">
</vn-input-number>
<vn-input-number vn-one
label="Bonus"
field="$ctrl.zone.bonus"
min="0.00"
step="0.50">
</vn-input-number>
</vn-horizontal>
</vn-card>
<vn-button-bar>
<vn-submit label="Save"></vn-submit>
</vn-button-bar>
</form>

View File

@ -0,0 +1,27 @@
import ngModule from '../../module';
class Controller {
constructor($scope) {
this.$scope = $scope;
}
onSubmit() {
this.$scope.watcher.submit().then(() => {
this.card.reload();
});
}
}
Controller.$inject = ['$scope'];
ngModule.component('vnZoneBasicData', {
template: require('./index.html'),
controller: Controller,
bindings: {
zone: '<'
},
require: {
card: '^vnZoneCard'
}
});

View File

@ -0,0 +1,16 @@
<!-- <vn-crud-model
vn-id="model"
url="/order/api/ItemCategories"
data="categories">
</vn-crud-model> -->
<vn-horizontal>
<vn-vertical vn-one>
<vn-card >
<vn-vertical>
<vn-horizontal pad-medium>
calendar
</vn-horizontal>
</vn-vertical>
</vn-card>
</vn-vertical>
</vn-horizontal>

View File

@ -0,0 +1,20 @@
import ngModule from '../../module';
class Controller {
constructor($scope) {
this.$scope = $scope;
}
}
Controller.$inject = ['$scope'];
ngModule.component('vnZoneCalendar', {
template: require('./index.html'),
controller: Controller,
require: {
catalog: '^vnZoneDeliveryDay'
},
bindings: {
zone: '<'
}
});

View File

@ -0,0 +1,11 @@
<vn-main-block>
<vn-horizontal>
<vn-auto class="left-block">
<vn-zone-descriptor zone="$ctrl.zone"></vn-zone-descriptor>
<vn-left-menu></vn-left-menu>
</vn-auto>
<vn-one>
<vn-vertical margin-medium ui-view></vn-vertical>
</vn-one>
</vn-horizontal>
</vn-main-block>

View File

@ -0,0 +1,38 @@
import ngModule from '../../module';
class Controller {
constructor($http, $stateParams) {
this.$http = $http;
this.$stateParams = $stateParams;
}
$onInit() {
this.getCard();
}
getCard() {
let filter = {
include: [
{relation: 'warehouse', fields: ['name']},
{relation: 'agencyMode', fields: ['name']}
]
};
let json = encodeURIComponent(JSON.stringify(filter));
let query = `/agency/api/Zones/${this.$stateParams.id}?filter=${json}`;
this.$http.get(query).then(res => {
if (res.data)
this.zone = res.data;
});
}
reload() {
this.getCard();
}
}
Controller.$inject = ['$http', '$stateParams'];
ngModule.component('vnZoneCard', {
template: require('./index.html'),
controller: Controller
});

View File

@ -0,0 +1,42 @@
import './index.js';
describe('Agency', () => {
describe('Component vnZoneCard', () => {
let $componentController;
let $scope;
let controller;
let $httpBackend;
let $stateParams;
beforeEach(() => {
angular.mock.module('agency');
});
beforeEach(angular.mock.inject((_$componentController_, $rootScope, _$httpBackend_) => {
$componentController = _$componentController_;
$httpBackend = _$httpBackend_;
$httpBackend.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
$scope = $rootScope.$new();
$stateParams = {id: 1};
controller = $componentController('vnZoneCard', {$scope: $scope, $stateParams});
}));
describe('getCard()', () => {
it(`should make a query and define zone property`, () => {
let filter = {
include: [
{relation: 'warehouse', fields: ['name']},
{relation: 'agencyMode', fields: ['name']}
]
};
let json = encodeURIComponent(JSON.stringify(filter));
$httpBackend.expectGET(`/agency/api/Zones/1?filter=${json}`).respond({id: 1});
controller.getCard();
$httpBackend.flush();
expect(controller.zone).toEqual({id: 1});
});
});
});
});

View File

@ -0,0 +1,71 @@
<mg-ajax path="/agency/api/Zones" options="vnPost"></mg-ajax>
<vn-watcher
vn-id="watcher"
data="$ctrl.zone"
form="form"
save="post">
</vn-watcher>
<form name="form" ng-submit="$ctrl.onSubmit()" margin-medium>
<div style="max-width: 50em; margin: 0 auto;">
<vn-card pad-large>
<vn-title>New zone</vn-title>
<vn-horizontal>
<vn-textfield vn-two vn-focus
label="Name"
field="$ctrl.zone.name">
</vn-textfield>
</vn-horizontal>
<vn-horizontal>
<vn-autocomplete
vn-one
field="$ctrl.zone.warehouseFk"
url="/agency/api/Warehouses"
show-field="name"
value-field="id"
label="Warehouse">
</vn-autocomplete>
<vn-autocomplete
vn-one
field="$ctrl.zone.agencyModeFk"
url="/agency/api/AgencyModes"
show-field="name"
value-field="id"
label="Agency">
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal>
<vn-input-number
vn-two
min="0"
value="$ctrl.zone.travelingDays"
step="1"
label="Traveling days"
field="$ctrl.zone.travelingDays">
</vn-input-number>
<vn-input-time
vn-two
label="Estimated hour (ETD)"
field="$ctrl.zone.hour">
</vn-input-time>
</vn-horizontal>
<vn-horizontal>
<vn-input-number vn-one
label="Price"
field="$ctrl.zone.price"
min="0.00"
step="0.50">
</vn-input-number>
<vn-input-number vn-one
label="Bonus"
field="$ctrl.zone.bonus"
min="0.00"
step="0.50">
</vn-input-number>
</vn-horizontal>
</vn-card>
<vn-button-bar>
<vn-submit label="Create"></vn-submit>
<vn-button ui-sref="zone.index" label="Cancel"></vn-button>
</vn-button-bar>
</div>
</form>

View File

@ -0,0 +1,26 @@
import ngModule from '../../module';
export default class Controller {
constructor($scope, $state) {
this.$scope = $scope;
this.$state = $state;
this.zone = {
travelingDays: 0,
price: 0.50,
bonus: 0.50,
hour: new Date()
};
}
onSubmit() {
this.$scope.watcher.submit().then(res => {
this.$state.go('zone.card.basicData', {id: res.data.id});
});
}
}
Controller.$inject = ['$scope', '$state'];
ngModule.component('vnZoneCreate', {
template: require('./index.html'),
controller: Controller
});

View File

@ -0,0 +1,47 @@
import './index';
import {watcher} from '../../../../helpers/watcherHelper';
describe('Agency', () => {
describe('Component vnZoneCreate', () => {
let $componentController;
let $httpBackend;
let $scope;
let $state;
let controller;
beforeEach(() => {
angular.mock.module('agency');
});
beforeEach(angular.mock.inject((_$componentController_, $rootScope, _$httpBackend_, _$state_) => {
$componentController = _$componentController_;
$httpBackend = _$httpBackend_;
$httpBackend.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
$scope = $rootScope.$new();
$state = _$state_;
$scope.watcher = watcher;
$scope.watcher.submit = () => {
return {
then: callback => {
callback({data: {id: 1234}});
}
};
};
controller = $componentController('vnZoneCreate', {$scope: $scope});
}));
describe('onSubmit()', () => {
it(`should call submit() on the watcher then expect a callback`, () => {
spyOn($state, 'go');
controller.zone = {
name: 'Zone One'
};
controller.onSubmit();
expect(controller.$state.go).toHaveBeenCalledWith('zone.card.basicData', {id: 1234});
});
});
});
});

View File

@ -0,0 +1,3 @@
Traveling days: Días de viaje
Estimated hour (ETD): Hora estimada (ETD)
Bonus: Bonificación

View File

@ -0,0 +1,19 @@
<vn-watcher
vn-id="watcher"
data="$ctrl.zone"
form="form"
save="patch">
</vn-watcher>
<vn-horizontal>
<vn-vertical vn-one>
<vn-card pad-large>
<vn-title>Delivery days</vn-title>
a
</vn-card>
</vn-vertical>
<vn-auto class="right-block">
<vn-zone-calendar zone="$ctrl.zone"></vn-zone-calendar>
</vn-auto>
</vn-horizontal>

View File

@ -0,0 +1,21 @@
import ngModule from '../../module';
class Controller {
constructor($scope) {
this.$scope = $scope;
}
}
Controller.$inject = ['$scope'];
ngModule.component('vnZoneDeliveryDay', {
template: require('./index.html'),
controller: Controller,
bindings: {
zone: '<'
},
require: {
card: '^vnZoneCard'
}
});

View File

@ -0,0 +1,34 @@
<vn-card margin-medium-v class="vn-descriptor">
<vn-horizontal class="header">
<a translate-attr="{title: 'Return to module index'}" ui-sref="zone.index">
<vn-icon icon="chevron_left"></vn-icon>
</a>
<vn-icon icon="my_location"></vn-icon>
<a translate-attr="{title: 'Preview'}" ui-sref="zone.card.summary">
<vn-icon icon="desktop_windows"></vn-icon>
</a>
</vn-horizontal>
<div pad-medium>
<vn-label-value label="Id"
value="{{$ctrl.zone.id}}">
</vn-label-value>
<vn-label-value label="Name"
value="{{$ctrl.zone.name}}">
</vn-label-value>
<vn-label-value label="Warehouse"
value="{{$ctrl.zone.warehouse.name}}">
</vn-label-value>
<vn-label-value label="Agency"
value="{{$ctrl.zone.agencyMode.name}}">
</vn-label-value>
<vn-label-value label="Estimated hour (ETD)"
value="{{$ctrl.zone.hour | date: 'HH:mm'}}">
</vn-label-value>
<vn-label-value label="Price"
value="{{$ctrl.zone.price | currency: '€': 2}}">
</vn-label-value>
<vn-label-value label="Bonus"
value="{{$ctrl.zone.price | currency: '€': 2}}">
</vn-label-value>
</div>
</vn-card>

View File

@ -0,0 +1,8 @@
import ngModule from '../../module';
ngModule.component('vnZoneDescriptor', {
template: require('./index.html'),
bindings: {
zone: '<'
}
});

View File

@ -0,0 +1,70 @@
<vn-crud-model
vn-id="model"
url="/agency/api/Zones"
filter="::$ctrl.filter"
limit="20"
data="zones"
auto-load="false">
</vn-crud-model>
<div margin-medium>
<div class="vn-list">
<vn-card pad-medium-h>
<vn-searchbar
panel="vn-zone-search-panel"
model="model"
expr-builder="$ctrl.exprBuilder(param, value)"
vn-focus>
</vn-searchbar>
</vn-card>
</div>
<vn-card margin-medium-v pad-medium>
<vn-table model="model">
<vn-thead>
<vn-tr>
<vn-th field="id" number>Id</vn-th>
<vn-th field="name">Name</vn-th>
<vn-th field="agencyModeFk">Agency</vn-th>
<vn-th field="warehouseFK">Warehouse</vn-th>
<vn-th field="hour">Hour</vn-th>
<vn-th field="price" number>Price</vn-th>
<vn-th></vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>
<vn-tr ng-repeat="zone in zones" ui-sref="zone.card.basicData({id: zone.id})" class=clickable>
<vn-td number>{{::zone.id}}</vn-td>
<vn-td>{{::zone.name}}</vn-td>
<vn-td>{{::zone.agencyMode.name}}</vn-td>
<vn-td>{{::zone.warehouse.name}}</vn-td>
<vn-td>{{::zone.hour | date: 'HH:mm'}}</vn-td>
<vn-td number>{{::zone.price | currency:'€':2}}</vn-td>
<vn-td>
<vn-icon-button
ng-click="$ctrl.preview(zone)"
vn-tooltip="Preview"
icon="desktop_windows">
</vn-icon-button>
</vn-td>
</vn-tr>
</vn-tbody>
<vn-empty-rows ng-if="model.data.length === 0" translate>
No results
</vn-empty-rows>
</vn-table>
</vn-card>
<vn-pagination
model="model"
scroll-selector="ui-view">
</vn-pagination>
</div>
<vn-dialog class="dialog-summary"
vn-id="dialog">
<tpl-body>
<vn-zone-summary vn-id="summary"></vn-zone-summary>
</tpl-body>
</vn-dialog>
<a ui-sref="zone.create" vn-tooltip="New zone" vn-bind="+" fixed-bottom-right>
<vn-float-button icon="add"></vn-float-button>
</a>

View File

@ -0,0 +1,39 @@
import ngModule from '../../module';
export default class Controller {
constructor($scope) {
this.$scope = $scope;
this.filter = {
include: [
{relation: 'agencyMode', fields: ['name']},
{relation: 'warehouse', fields: ['name']}
]
};
}
exprBuilder(param, value) {
switch (param) {
case 'search':
return /^\d+$/.test(value)
? {id: value}
: {name: {regexp: value}};
case 'warehouseFk':
case 'agencyModeFk':
return {[param]: value};
}
}
preview(event, zone) {
event.preventDefault();
event.stopImmediatePropagation();
this.$scope.summary.zone = zone;
this.$scope.dialog.show();
}
}
Controller.$inject = ['$scope'];
ngModule.component('vnZoneIndex', {
template: require('./index.html'),
controller: Controller
});

View File

@ -0,0 +1,43 @@
import './index.js';
describe('Agency', () => {
describe('Component vnZoneIndex', () => {
let $componentController;
let controller;
beforeEach(() => {
angular.mock.module('agency');
});
beforeEach(angular.mock.inject(_$componentController_ => {
$componentController = _$componentController_;
controller = $componentController('vnZoneIndex');
}));
describe('exprBuilder()', () => {
it('should return a formated object with the id in case of search', () => {
let param = 'search';
let value = 1;
let result = controller.exprBuilder(param, value);
expect(result).toEqual({id: 1});
});
it('should return a formated object with the warehouseFk in case of warehouseFk', () => {
let param = 'warehouseFk';
let value = 'Silla';
let result = controller.exprBuilder(param, value);
expect(result).toEqual({warehouseFk: 'Silla'});
});
it('should return a formated object with the warehouseFk in case of warehouseFk', () => {
let param = 'agencyModeFk';
let value = 'My Delivery';
let result = controller.exprBuilder(param, value);
expect(result).toEqual({agencyModeFk: 'My Delivery'});
});
});
});
});

View File

@ -0,0 +1,33 @@
<div pad-large style="min-width: 30em">
<form ng-submit="$ctrl.onSearch()">
<vn-horizontal>
<vn-textfield
vn-one
label="Name"
model="filter.name"
vn-focus>
</vn-textfield>
</vn-horizontal>
<vn-horizontal>
<vn-autocomplete
vn-one
label="Agency"
field="filter.agencyModeFk"
url="/agency/api/AgencyModes"
show-field="name"
value-field="id">
</vn-autocomplete>
<vn-autocomplete
vn-one
label="Warehouse"
field="filter.warehouseFk"
url="/agency/api/Warehouses"
show-field="name"
value-field="id">
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal margin-large-top>
<vn-submit label="Search"></vn-submit>
</vn-horizontal>
</form>
</div>

View File

@ -0,0 +1,7 @@
import ngModule from '../../module';
import SearchPanel from 'core/src/components/searchbar/search-panel';
ngModule.component('vnZoneSearchPanel', {
template: require('./index.html'),
controller: SearchPanel
});

View File

@ -0,0 +1,30 @@
<vn-card class="summary">
<vn-vertical pad-medium>
<vn-horizontal>
<vn-one margin-medium>
<vn-vertical name="basicData">
<h5 translate>Basic data</h5>
<vn-label-value label="Name"
value="{{$ctrl.zone.name}}">
</vn-label-value>
<vn-label-value label="Warehouse"
value="{{$ctrl.zone.warehouse.name}}">
</vn-label-value>
<vn-label-value label="Agency"
value="{{$ctrl.zone.agencyMode.name}}">
</vn-label-value>
<vn-label-value label="Estimated hour (ETD)"
value="{{$ctrl.zone.hour | date: 'HH:mm'}}">
</vn-label-value>
<vn-label-value label="Price"
value="{{$ctrl.zone.price | currency: '€': 2}}">
</vn-label-value>
<vn-label-value label="Bonus"
value="{{$ctrl.zone.price | currency: '€': 2}}">
</vn-label-value>
</vn-vertical>
</vn-one>
<vn-one margin-medium></vn-one>
</vn-horizontal>
</vn-vertical>
</vn-card>

View File

@ -0,0 +1,35 @@
import ngModule from '../../module';
class Controller {
constructor($http) {
this.$http = $http;
}
get zone() {
return this._zone;
}
set zone(value) {
this._zone = value;
if (!value) return;
this.getSummary();
}
getSummary() {
this.$http.get(`/agency/api/Zones/${this.zone.id}`).then(response => {
this.summary = response.data;
});
}
}
Controller.$inject = ['$http'];
ngModule.component('vnZoneSummary', {
template: require('./index.html'),
controller: Controller,
bindings: {
zone: '<'
}
});

View File

@ -0,0 +1,42 @@
import './index.js';
describe('Agency', () => {
describe('Component summary', () => {
let $componentController;
let controller;
let $httpBackend;
beforeEach(() => {
angular.mock.module('agency');
});
beforeEach(angular.mock.inject((_$componentController_, _$httpBackend_) => {
$componentController = _$componentController_;
$httpBackend = _$httpBackend_;
$httpBackend.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
controller = $componentController('vnZoneSummary');
controller.zone = {id: 1};
}));
describe('getSummary()', () => {
it("should perform a query to set summary", () => {
let data = {name: 'Zone One', price: 0};
$httpBackend.when('GET', `/agency/api/Zones/1`).respond(200, data);
$httpBackend.expect('GET', `/agency/api/Zones/1`);
controller.getSummary();
$httpBackend.flush();
expect(controller.summary).toEqual(data);
});
});
describe('setter zone()', () => {
it("should call getSummary and define summary property", () => {
spyOn(controller, 'getSummary');
controller.zone = {id: 1};
expect(controller.getSummary).toHaveBeenCalledWith();
});
});
});
});

View File

@ -0,0 +1,2 @@
Niche: Nichos
Barcode: Códigos de barras

View File

@ -15,8 +15,7 @@
"url": "/index?q",
"state": "claim.index",
"component": "vn-claim-index",
"description": "List",
"acl": ["salesAssistant", "salesPerson"]
"description": "List"
},
{
"url": "/:id",
@ -43,7 +42,8 @@
},
"menu": {
"icon": "settings"
}
},
"acl": ["salesPerson"]
},
{
"url": "/detail",
@ -55,7 +55,8 @@
},
"menu": {
"icon": "icon-details"
}
},
"acl": ["salesPerson"]
},
{
"url": "/development",
@ -67,7 +68,8 @@
},
"menu": {
"icon": "icon-traceability"
}
},
"acl": ["salesAssistant"]
},
{
"url": "/action",
@ -79,7 +81,8 @@
},
"menu": {
"icon": "icon-actions"
}
},
"acl": ["salesAssistant"]
}
]
}

View File

@ -15,6 +15,21 @@
</vn-label-value>
</div>
</vn-horizontal>
<vn-horizontal>
<vn-tool-bar margin-medium-bottom>
<vn-button
label="Import claim"
ng-click="$ctrl.importToNewRefundTicket()"
vn-tooltip="Imports claim details">
</vn-button>
<vn-button
label="Import ticket"
ng-click="$ctrl.showLastTickets($event)"
vn-tooltip="Imports ticket lines">
</vn-button>
</vn-tool-bar>
</vn-horizontal>
<vn-table model="model">
<vn-thead>
<vn-tr>
@ -58,7 +73,7 @@
<vn-icon-button
medium-grey
margin-medium-v
vn-tooltip="Remove tag"
vn-tooltip="Remove line"
icon="remove_circle_outline"
ng-click="$ctrl.deleteClaimedSale(saleClaimed.id)"
tabindex="-1">
@ -72,6 +87,14 @@
</vn-table>
</vn-vertical>
</vn-card>
<vn-button-bar>
{{$ctrl.resolvedStateText}}
<vn-button
label="Regularize"
ng-click="$ctrl.regularize()"
disabled="$ctrl.claim.claimStateFk == $ctrl.resolvedState">
</vn-button>
</vn-button-bar>
<!-- WIP
<a ng-click="$ctrl.openAddSalesDialog()" vn-tooltip="New item" vn-bind="+" fixed-bottom-right>
<vn-float-button icon="add"></vn-float-button>
@ -113,4 +136,38 @@
</vn-empty-rows>
</vn-table>
</tpl-body>
</vn-dialog>
</vn-dialog>
<vn-crud-model
vn-id="lastTicketsModel"
url="/claim/api/Tickets"
filter="{}"
data="lastTickets" auto-load="false">
</vn-crud-model>
<!-- Transfer Popover -->
<vn-popover class="lastTicketsPopover" vn-id="lastTicketsPopover">
<div class="ticketList" pad-medium>
<vn-table model="lastTicketsModel" class="vn-grid">
<vn-thead>
<vn-tr>
<vn-th field="id" number>ID</vn-th>
<vn-th field="shipped" default-order="DESC">F. envio</vn-th>
<vn-th>Agencia</vn-th>
<vn-th>Almacen</vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>
<vn-tr
class="clickable"
ng-repeat="ticket in lastTickets"
ng-click="$ctrl.importTicketLines(ticket.id)">
<vn-td number>{{::ticket.id}}</vn-td>
<vn-td>{{::ticket.shipped | date: 'dd/MM/yyyy'}}</vn-td>
<vn-td>{{::ticket.agencyMode.name}}</vn-td>
<vn-td>{{::ticket.warehouse.name}}</vn-td>
</vn-tr>
</vn-tbody>
</vn-table>
</div>
</vn-popover>

View File

@ -2,14 +2,14 @@ import ngModule from '../module';
import './style.scss';
class Controller {
constructor($state, $scope, $http, $translate, vnApp) {
this.$state = $state;
constructor($stateParams, $scope, $http, $translate, vnApp) {
this.$stateParams = $stateParams;
this.$ = $scope;
this.$http = $http;
this.$translate = $translate;
this.vnApp = vnApp;
this.filter = {
where: {claimFk: $state.params.id},
where: {claimFk: $stateParams.id},
include: [
{relation: 'sale',
scope: {
@ -22,6 +22,7 @@ class Controller {
{relation: 'claimBeggining'}
]
};
this.resolvedState = 3;
}
openAddSalesDialog() {
@ -59,6 +60,14 @@ class Controller {
});
}
importToNewRefundTicket() {
let query = `claim/api/ClaimBeginnings/${this.$stateParams.id}/importToNewRefundTicket`;
this.$http.post(query).then(() => {
this.$.model.refresh();
this.vnApp.showSuccess(this.$translate.instant('Data saved!'));
});
}
focusLastInput() {
let inputs = document.querySelectorAll("#claimDestinationFk");
inputs[inputs.length - 1].querySelector("input").focus();
@ -80,14 +89,56 @@ class Controller {
this.claimedTotal += (sale.sale.quantity * sale.sale.price) - ((sale.sale.discount * (sale.sale.quantity * sale.sale.price)) / 100);
});
}
showLastTickets(event) {
let pastWeek = new Date();
pastWeek.setDate(-7);
let filter = {
include: [
{relation: 'agencyMode', fields: ['name']},
{relation: 'warehouse', fields: ['name']}
],
where: {
created: {gt: pastWeek}
}
};
this.$.lastTicketsModel.filter = filter;
this.$.lastTicketsModel.refresh();
this.$.lastTicketsPopover.parent = event.target;
this.$.lastTicketsPopover.show();
}
importTicketLines(ticketFk) {
let data = {claimFk: this.$stateParams.id, ticketFk: ticketFk};
let query = `/claim/api/ClaimEnds/importTicketSales`;
this.$http.post(query, data).then(() => {
this.vnApp.showSuccess(this.$translate.instant('Data saved!'));
this.$.lastTicketsPopover.hide();
this.$.model.refresh();
});
}
regularize() {
let data = {claimFk: this.$stateParams.id};
let query = `/claim/api/Claims/regularizeClaim`;
this.$http.post(query, data).then(() => {
this.card.reload();
this.vnApp.showSuccess(this.$translate.instant('Data saved!'));
});
}
}
Controller.$inject = ['$state', '$scope', '$http', '$translate', 'vnApp'];
Controller.$inject = ['$stateParams', '$scope', '$http', '$translate', 'vnApp'];
ngModule.component('vnClaimAction', {
template: require('./index.html'),
controller: Controller,
bindings: {
claim: '<'
},
require: {
card: '^vnClaimCard'
}
});

View File

@ -1,7 +1,8 @@
import './index.js';
import {crudModel} from '../../../helpers/crudModelHelper';
describe('claim', () => {
describe('Component vnClaimDetail', () => {
describe('Component vnClaimAction', () => {
let $componentController;
let controller;
let $httpBackend;
@ -11,42 +12,48 @@ describe('claim', () => {
angular.mock.module('claim');
});
beforeEach(angular.mock.inject((_$componentController_, _$state_, _$httpBackend_, $rootScope) => {
beforeEach(angular.mock.inject((_$componentController_, _$state_, _$httpBackend_) => {
$componentController = _$componentController_;
$httpBackend = _$httpBackend_;
$httpBackend.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
$httpBackend.when('GET', 'claim/api/Claims/ClaimBeginnings').respond({});
$state = _$state_;
$state.params.id = 1;
controller = $componentController('vnClaimDetail', {$state: $state});
controller = $componentController('vnClaimAction', {$state: $state});
controller.claim = {ticketFk: 1};
controller.$.model = {refresh: () => {}};
controller.$.addSales = {
hide: () => {},
show: () => {}
};
controller.$.lastTicketsModel = crudModel;
controller.$.lastTicketsPopover = {
hide: () => {},
show: () => {}
};
controller.card = {reload: () => {}};
}));
describe('openAddSalesDialog()', () => {
it('should call getClaimableFromTicket and $.addSales.show', () => {
controller.$ = {addSales: {show: () => {}}};
spyOn(controller, 'getClaimableFromTicket');
spyOn(controller, 'getClaimedSales');
spyOn(controller.$.addSales, 'show');
controller.openAddSalesDialog();
expect(controller.getClaimableFromTicket).toHaveBeenCalledWith();
expect(controller.getClaimedSales).toHaveBeenCalledWith();
expect(controller.$.addSales.show).toHaveBeenCalledWith();
});
});
describe('getClaimableFromTicket()', () => {
describe('getClaimedSales()', () => {
it('should make a query and set salesToClaim', () => {
$httpBackend.expectGET(`/api/Sales/getClaimableFromTicket?ticketFk=1`).respond(200, 1);
controller.getClaimableFromTicket();
controller.claim.id = 1;
$httpBackend.expectGET(`/claim/api/ClaimBeginnings/1`).respond(200, 1);
controller.getClaimedSales();
$httpBackend.flush();
expect(controller.salesToClaim).toEqual(1);
expect(controller.claimedSales).toEqual(1);
});
});
@ -55,7 +62,7 @@ describe('claim', () => {
spyOn(controller.$.model, 'refresh');
spyOn(controller.$.addSales, 'hide');
spyOn(controller.vnApp, 'showSuccess');
$httpBackend.expectPOST(`claim/api/ClaimBeginnings/`).respond({});
$httpBackend.expectPOST(`claim/api/ClaimEnds/`).respond({});
controller.addClaimedSale(1);
$httpBackend.flush();
@ -69,7 +76,7 @@ describe('claim', () => {
it('should make a delete and call refresh and showSuccess', () => {
spyOn(controller.$.model, 'refresh');
spyOn(controller.vnApp, 'showSuccess');
$httpBackend.expectDELETE(`claim/api/ClaimBeginnings/1`).respond({});
$httpBackend.expectDELETE(`claim/api/ClaimEnds/1`).respond({});
controller.deleteClaimedSale(1);
$httpBackend.flush();
@ -78,17 +85,85 @@ describe('claim', () => {
});
});
describe('setClaimedQuantity(id, claimedQuantity)', () => {
describe('setClaimDestination(id, claimDestinationFk)', () => {
it('should make a patch and call refresh and showSuccess', () => {
spyOn(controller.$.model, 'refresh');
spyOn(controller.vnApp, 'showSuccess');
$httpBackend.expectPATCH(`claim/api/ClaimBeginnings/`).respond({});
controller.setClaimedQuantity(1, 1);
$httpBackend.expectPATCH(`claim/api/ClaimEnds/`).respond({});
controller.setClaimDestination(1, 1);
$httpBackend.flush();
expect(controller.$.model.refresh).toHaveBeenCalledWith();
expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Data saved!');
});
});
describe('calculateTotals()', () => {
it('should calculate the total price of the items claimed', () => {
controller.salesClaimed = [
{sale: {quantity: 5, price: 2, discount: 0}},
{sale: {quantity: 10, price: 2, discount: 0}},
{sale: {quantity: 10, price: 2, discount: 0}}
];
controller.calculateTotals();
expect(controller.claimedTotal).toEqual(50);
});
});
describe('importToNewRefundTicket()', () => {
it('should perform a post query', () => {
spyOn(controller.$.model, 'refresh');
spyOn(controller.vnApp, 'showSuccess');
$httpBackend.expect('POST', `claim/api/ClaimBeginnings/1/importToNewRefundTicket`).respond({});
controller.importToNewRefundTicket();
$httpBackend.flush();
expect(controller.$.model.refresh).toHaveBeenCalledWith();
expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Data saved!');
});
});
describe('showLastTickets()', () => {
it('should get a list of tickets and call lastTicketsPopover show() method', () => {
spyOn(controller.$.lastTicketsModel, 'refresh');
spyOn(controller.$.lastTicketsPopover, 'show');
controller.showLastTickets({});
expect(controller.$.lastTicketsModel.refresh).toHaveBeenCalledWith();
expect(controller.$.lastTicketsPopover.show).toHaveBeenCalledWith();
});
});
describe('importTicketLines()', () => {
it('should perform a post query', () => {
spyOn(controller.$.model, 'refresh');
spyOn(controller.vnApp, 'showSuccess');
spyOn(controller.$.lastTicketsPopover, 'hide');
let data = {claimFk: 1, ticketFk: 1};
$httpBackend.expect('POST', `/claim/api/ClaimEnds/importTicketSales`, data).respond({});
controller.importTicketLines(1);
$httpBackend.flush();
expect(controller.$.model.refresh).toHaveBeenCalledWith();
expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Data saved!');
expect(controller.$.lastTicketsPopover.hide).toHaveBeenCalledWith();
});
});
describe('regularize()', () => {
it('should perform a post query and reload the claim card', () => {
spyOn(controller.card, 'reload');
spyOn(controller.vnApp, 'showSuccess');
let data = {claimFk: $state.params.id};
$httpBackend.expect('POST', `/claim/api/Claims/regularizeClaim`, data).respond({});
controller.regularize();
$httpBackend.flush();
expect(controller.card.reload).toHaveBeenCalledWith();
expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Data saved!');
});
});
});
});

View File

@ -1,3 +1,8 @@
Destination: Destino
Action: Actuaciones
Total claimed: Total Reclamado
Total claimed: Total Reclamado
Import claim: Importar reclamacion
Imports claim details: Importa detalles de la reclamacion
Import ticket: Importar ticket
Imports ticket lines: Importa las lineas de un ticket
Regularize: Regularizar

View File

@ -12,5 +12,16 @@ vn-claim-action {
}
}
}
}
vn-popover.lastTicketsPopover {
vn-table {
min-width: 650px;
overflow: auto
}
div.ticketList {
overflow: auto;
max-height: 350px
}
}
}

View File

@ -1,10 +1,9 @@
<vn-watcher
vn-id="watcher"
data="$ctrl.claim"
id-field="id"
form="form"
url="/claim/api/Claims"
save="patch">
url="/claim/api/Claims/updateClaim"
save="post">
</vn-watcher>
<form name="form" ng-submit="watcher.submit()">
<vn-card pad-large>
@ -50,7 +49,8 @@
<vn-check
vn-one
label="Is paid with mana"
field="$ctrl.claim.isChargedToMana">
field="$ctrl.claim.isChargedToMana"
vn-acl="salesAssistant">
</vn-check>
<vn-input-range
vn-one
@ -58,7 +58,8 @@
value="$ctrl.claim.responsibility"
max="4"
min="0"
step="1">
step="1"
vn-acl="salesAssistant">
</vn-input-range>
</vn-horizontal>
</vn-horizontal>

View File

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

View File

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

View File

@ -15,7 +15,7 @@
value="{{::$ctrl.claim.client.name}}">
</vn-label-value>
<vn-label-value label="State"
value="{{::$ctrl.claim.claimState.description}}">
value="{{$ctrl.claim.claimState.description}}">
</vn-label-value>
<vn-label-value label="Created"
value="{{$ctrl.claim.created | dateTime: 'dd/MM/yyyy'}}">
@ -30,22 +30,29 @@
</vn-auto>
</vn-vertical>
<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}}"
icon="{{::$ctrl.quicklinks.btnOne.icon}}"
ng-click="$ctrl.quicklinkGo($ctrl.quicklinks.btnOne.state, $ctrl.quicklinks.btnOne.params)">
</vn-button>
<vn-button ng-if="$ctrl.quicklinks.btnTwo" pad-small-right
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}}"
icon="{{::$ctrl.quicklinks.btnTwo.icon}}"
ng-click="$ctrl.quicklinkGo($ctrl.quicklinks.btnTwo.state, $ctrl.quicklinks.btnTwo.params)">
</vn-button>
<vn-button ng-if="$ctrl.quicklinks.btnThree" pad-small-right
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}}"
icon="{{::$ctrl.quicklinks.btnThree.icon}}"
ng-click="$ctrl.quicklinkGo($ctrl.quicklinks.btnThree.state, $ctrl.quicklinks.btnThree.params)">
</vn-button>
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>

View File

@ -3,7 +3,24 @@ import ngModule from '../module';
class Controller {
constructor($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 = {}) {
@ -13,10 +30,6 @@ class Controller {
get quicklinks() {
return this._quicklinks;
}
quicklinkGo(state, params) {
this.$state.go(state, params);
}
}
Controller.$inject = ['$state'];

View File

@ -58,7 +58,7 @@
<vn-icon-button
medium-grey
margin-medium-v
vn-tooltip="Remove tag"
vn-tooltip="Remove sale"
icon="remove_circle_outline"
ng-click="$ctrl.deleteClaimedSale(saleClaimed.id)"
tabindex="-1">
@ -72,7 +72,7 @@
</vn-table>
</vn-vertical>
</vn-card>
<a ng-click="$ctrl.openAddSalesDialog()" vn-tooltip="New item" vn-bind="+" fixed-bottom-right>
<a ng-click="$ctrl.openAddSalesDialog()" vn-tooltip="Add sale item" vn-bind="+" fixed-bottom-right>
<vn-float-button icon="add"></vn-float-button>
</a>

View File

@ -1,7 +1,8 @@
Claimed: Reclamados
Disc.: Dto.
Attended by: Atendida por
Landed: Recibido
Landed: F. entrega
Price: Precio
Claimable sales from ticket: Lineas reclamables del ticket
Detail: Detalles
Detail: Detalles
Add sale item: Añadir artículo

View File

@ -95,7 +95,7 @@
<vn-icon-button
medium-grey
margin-medium-v
vn-tooltip="Remove tag"
vn-tooltip="Remove sale"
icon="remove_circle_outline"
ng-click="model.remove($index)"
tabindex="-1"
@ -106,7 +106,7 @@
<vn-one pad-medium-top>
<vn-icon-button
vn-bind="+"
vn-tooltip="Add tag"
vn-tooltip="Add sale"
icon="add_circle"
ng-click="model.insert()"
vn-acl="salesAssistant">

View File

@ -2,12 +2,9 @@ import ngModule from '../module';
import './style.scss';
class Controller {
constructor($state, $scope, $http, $translate, vnApp) {
constructor($state, $scope) {
this.$state = $state;
this.$ = $scope;
this.$http = $http;
this.$translate = $translate;
this.vnApp = vnApp;
}
onSubmit() {
@ -19,7 +16,7 @@ class Controller {
}
}
Controller.$inject = ['$state', '$scope', '$http', '$translate', 'vnApp'];
Controller.$inject = ['$state', '$scope'];
ngModule.component('vnClaimDevelopment', {
template: require('./index.html'),

View File

@ -4,4 +4,5 @@ Reason: Motivo
Result: Consecuencia
Responsible: Responsable
Worker: Trabajador
Redelivery: Devolución
Redelivery: Devolución
Add line: Añadir Linea

View File

@ -12,7 +12,8 @@
<vn-searchbar
panel="vn-claim-search-panel"
model="model"
expr-builder="$ctrl.exprBuilder(param, value)">
expr-builder="$ctrl.exprBuilder(param, value)"
vn-focus>
</vn-searchbar>
</vn-card>
</div>
@ -41,13 +42,16 @@
<vn-td>{{::claim.claimState.description}}</vn-td>
<vn-td>
<vn-icon-button
ng-click="$ctrl.preview($event, claim)"
ng-click="$ctrl.preview(claim)"
vn-tooltip="Preview"
icon="desktop_windows">
</vn-icon-button>
</vn-td>
</vn-tr>
</vn-tbody>
<vn-empty-rows ng-if="model.data.length === 0" translate>
No results
</vn-empty-rows>
</vn-table>
</vn-card>
<vn-pagination

View File

@ -1,7 +1,9 @@
#Ordenar alfabeticamente
Add sale: Añadir linea
Client Id: Id cliente
Observation: Observación
Responsible: Responsable
Remove sale: Borrar linea
Claim Id: Id reclamación
Created: Creado

View File

@ -332,6 +332,24 @@
"params": {
"client": "$ctrl.client"
}
},
{
"url": "/web-payment",
"state": "client.card.webPayment",
"component": "vn-client-web-payment",
"description": "Web Payment",
"menu": {
"icon": ""
}
},
{
"url" : "/history",
"state": "client.card.history",
"component": "vn-client-history",
"description": "History",
"menu": {
"icon": "history"
}
}
]
}

View File

@ -102,6 +102,6 @@
</vn-card>
<vn-button-bar>
<vn-submit label="Save"></vn-submit>
<vn-button ng-click="$ctrl.cancel($event)" label="Cancel"></vn-button>
<vn-button ng-click="$ctrl.cancel()" label="Cancel"></vn-button>
</vn-button-bar>
</form>

View File

@ -12,9 +12,7 @@ export default class Controller {
this.$.model.remove(index);
}
cancel(event) {
event.preventDefault();
event.stopImmediatePropagation();
cancel() {
this.goToIndex();
}

View File

@ -45,19 +45,11 @@ describe('Client', () => {
});
});
describe('cancel(event)', () => {
it('should call event.preventDefault(), event.stopImmediatePropagation() and goToIndex', () => {
let event = {
preventDefault: () => {},
stopImmediatePropagation: () => {}
};
spyOn(event, 'preventDefault');
spyOn(event, 'stopImmediatePropagation');
describe('cancel()', () => {
it('should call goToIndex()', () => {
spyOn(controller, 'goToIndex');
controller.cancel(event);
controller.cancel();
expect(event.preventDefault).toHaveBeenCalledWith();
expect(event.stopImmediatePropagation).toHaveBeenCalledWith();
expect(controller.goToIndex).toHaveBeenCalledWith();
});
});

View File

@ -14,24 +14,19 @@
ng-class="{'bg-main': address.isDefaultAddress,'bg-opacity-item': !address.isActive && !address.isDefaultAddress}">
<vn-horizontal style="align-items: center;">
<vn-none pad-medium-h>
<i class="material-icons"
orange
<vn-icon-button icon="star"
ng-if="address.isDefaultAddress">
star
</i>
<i class="material-icons"
orange
</vn-icon-button>
<vn-icon-button icon="star_border"
ng-if="!address.isActive"
vn-tooltip="Active first to set as default">
star_border
</i>
<i class="material-icons pointer"
orange
ng-if="address.isActive && !address.isDefaultAddress"
</vn-icon-button>
<vn-icon-button orange
icon="star_border"
vn-tooltip="Set as default"
ng-click="$ctrl.setDefault(address)">
star_border
</i>
ng-click="$ctrl.setDefault(address)"
ng-if="address.isActive && !address.isDefaultAddress">
</vn-icon-button>
</vn-none>
<vn-one border-solid-right>
<vn-horizontal>

View File

@ -1,9 +1,9 @@
<mg-ajax path="/client/api/Clients/{{patch.params.id}}" options="vnPatch"></mg-ajax>
<mg-ajax path="/client/api/Clients/{{post.params.id}}/updateBillingData" options="vnPost"></mg-ajax>
<vn-watcher
vn-id="watcher"
data="$ctrl.client"
form="form"
save="patch">
save="post">
</vn-watcher>
<form name="form" ng-submit="$ctrl.onSubmit()">
<vn-card pad-large>
@ -12,7 +12,7 @@
<vn-autocomplete
vn-one
label="Pay method"
vn-acl="administrative, salesAssistant"
vn-acl="salesAssistant"
field="$ctrl.client.payMethodFk"
url="/client/api/PayMethods"
fields="['ibanRequired']"
@ -22,7 +22,7 @@
vn-one
label="Due day"
field="$ctrl.client.dueDay"
vn-acl="administrative, salesAssistant">
vn-acl="salesAssistant">
</vn-textfield>
</vn-horizontal>
<vn-horizontal>
@ -30,34 +30,94 @@
vn-one
label="IBAN"
field="$ctrl.client.iban"
vn-acl="administrative, salesAssistant">
vn-acl="salesAssistant">
</vn-textfield>
<vn-autocomplete vn-one
label="Swift / BIC"
url="/client/api/BankEntities"
field="$ctrl.client.bankEntityFk"
select-fields="['name']"
initial-data="$ctrl.client.bankEntityFk"
where="{or: [{bic: {regexp: 'search'}}, {name: {regexp: 'search'}}]}"
value-field="id"
show-field="bic"
vn-acl="salesAssistant">
<tpl-item>
<vn-horizontal>
<vn-one>{{bic}}</vn-one>
<vn-one>
<div class="ellipsize" style="max-width: 10em">{{name}}</div>
</vn-one>
</vn-horizontal>
</tpl-item>
</vn-autocomplete>
<vn-icon-button vn-auto margin-medium-v
icon="add_circle"
vn-tooltip="New bank entity"
vn-dialog="bankEntityDialog"
vn-acl="salesAssistant">
</vn-icon-button>
</vn-horizontal>
<vn-horizontal pad-small-v>
<vn-one>
<vn-check
label="Received LCR"
field="$ctrl.client.hasLcr"
vn-acl="administrative, salesAssistant">
vn-acl="salesAssistant">
</vn-check>
</vn-one>
<vn-one>
<vn-check
label="Received core VNL"
field="$ctrl.client.hasCoreVnl"
vn-acl="administrative, salesAssistant">
vn-acl="salesAssistant">
</vn-check>
</vn-one>
<vn-one>
<vn-check
label="Received B2B VNL"
field="$ctrl.client.hasSepaVnl"
vn-acl="administrative, salesAssistant">
vn-acl="salesAssistant">
</vn-check>
</vn-one>
</vn-horizontal>
</vn-card>
<vn-button-bar>
<vn-submit label="Save" vn-acl="administrative, salesAssistant"></vn-submit>
<vn-submit label="Save" vn-acl="salesAssistant"></vn-submit>
</vn-button-bar>
</form>
</form>
<!-- Create bank entity dialog -->
<vn-dialog class="edit"
vn-id="bankEntityDialog"
on-open="$ctrl.onBankEntityOpen()"
on-response="$ctrl.onBankEntityResponse(response)">
<tpl-body>
<h5 pad-small-v translate>New bank entity</h5>
<vn-horizontal>
<vn-textfield vn-one
label="Name"
model="$ctrl.newBankEntity.name">
</vn-textfield>
</vn-horizontal>
<vn-horizontal>
<vn-autocomplete vn-one
label="Country"
field="$ctrl.newBankEntity.countryFk"
url="/client/api/Countries"
value-field="id"
show-field="country">
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal>
<vn-textfield vn-one
label="Swift / BIC"
model="$ctrl.newBankEntity.bic">
</vn-textfield>
</vn-horizontal>
</tpl-body>
<tpl-buttons>
<input type="button" response="CANCEL" translate-attr="{value: 'Cancel'}"/>
<button response="ACCEPT" translate>Create</button>
</tpl-buttons>
</vn-dialog>

View File

@ -5,40 +5,76 @@ export default class Controller {
this.$scope = $scope;
this.$http = $http;
this.vnApp = vnApp;
this.translate = $translate;
}
set client(value) {
this._client = value;
if (value)
this.orgData = Object.assign({}, value);
this.$translate = $translate;
}
get client() {
return this._client;
}
set client(value) {
this._client = value;
if (!value) return;
this.newBankEntity = {
countryFk: Number.parseInt(value.countryFk)
};
}
onSubmit() {
let shouldNotify = false;
if (this.hasPaymethodChanges())
shouldNotify = true;
this.$scope.watcher.submit().then(() => {
if (this.hasPaymethodChanged())
if (shouldNotify)
this.notifyChanges();
});
}
notifyChanges() {
this.$http.get(`/mailer/notification/payment-update/${this.client.id}`).then(
() => this.vnApp.showMessage(this.translate.instant('Notification sent!'))
() => this.vnApp.showMessage(this.$translate.instant('Notification sent!'))
);
}
hasPaymethodChanged() {
let payMethod = this.orgData.payMethodFk != this.client.payMethodFk;
let iban = this.orgData.iban != this.client.iban;
let dueDay = this.orgData.dueDay != this.client.dueDay;
hasPaymethodChanges() {
let orgData = this.$scope.watcher.orgData;
let payMethod = orgData.payMethodFk != this.client.payMethodFk;
let iban = orgData.iban != this.client.iban;
let dueDay = orgData.dueDay != this.client.dueDay;
return payMethod || iban || dueDay;
}
onBankEntityOpen() {
this.newBankEntity.name = '';
this.newBankEntity.bic = '';
this.$scope.$apply();
}
onBankEntityResponse(response) {
if (response == 'ACCEPT')
try {
if (!this.newBankEntity.name)
throw new Error(`Name can't be empty`);
if (!this.newBankEntity.bic)
throw new Error(`Swift / BIC can't be empty`);
this.$http.post(`/client/api/BankEntities`, this.newBankEntity).then(response => {
if (response.data)
this.client.bankEntityFk = response.data.id;
});
} catch (e) {
this.vnApp.showError(this.$translate.instant(e.message));
return false;
}
return true;
}
}
Controller.$inject = ['$scope', '$http', 'vnApp', '$translate'];

View File

@ -1,4 +1,5 @@
import './index';
import {watcher} from '../../../helpers/watcherHelper';
describe('Client', () => {
describe('Component vnClientBillingData', () => {
@ -6,48 +7,37 @@ describe('Client', () => {
let $httpBackend;
let $scope;
let controller;
let vnApp;
beforeEach(() => {
angular.mock.module('client');
});
beforeEach(angular.mock.inject((_$componentController_, $rootScope, _$httpBackend_) => {
beforeEach(angular.mock.inject((_$componentController_, $rootScope, _$httpBackend_, _vnApp_) => {
$componentController = _$componentController_;
$httpBackend = _$httpBackend_;
$httpBackend.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
$scope = $rootScope.$new();
$scope.watcher = {
submit: () => {
return {
then: callback => {
callback();
}
};
}
};
$scope.watcher = watcher;
vnApp = _vnApp_;
spyOn(vnApp, 'showError');
controller = $componentController('vnClientBillingData', {$scope: $scope});
controller.client = {id: 101, name: 'Client name', payMethodFk: 4};
$scope.watcher.orgData = {id: 101, name: 'Client name', payMethodFk: 4};
}));
describe('client()', () => {
it(`should call setter client`, () => {
expect(controller.orgData).toEqual(controller.client);
});
});
describe('onSubmit()', () => {
it(`should call notifyChanges() if there are changes on payMethod data`, () => {
spyOn(controller, 'notifyChanges');
controller.client.payMethodFk = 5;
controller.onSubmit();
expect(controller.hasPaymethodChanged()).toBeTruthy();
expect(controller.notifyChanges).toHaveBeenCalledWith();
});
});
describe('notifyChanges()', () => {
it(`should call notifyChanges() and perform a GET query`, () => {
it(`should perform a GET query`, () => {
$httpBackend.when('GET', `/mailer/notification/payment-update/101`).respond(true);
$httpBackend.expect('GET', `/mailer/notification/payment-update/101`);
controller.notifyChanges();
@ -55,17 +45,65 @@ describe('Client', () => {
});
});
describe('hasPaymethodChanged()', () => {
it(`should call hasPaymethodChanged() and return true if there are changes on payMethod data`, () => {
describe('hasPaymethodChanges()', () => {
it(`should return true if there are changes on payMethod data`, () => {
controller.client.payMethodFk = 5;
expect(controller.hasPaymethodChanged()).toBeTruthy();
expect(controller.hasPaymethodChanges()).toBeTruthy();
});
it(`should call hasPaymethodChanged() and return false if there are no changes on payMethod data`, () => {
it(`should return false if there are no changes on payMethod data`, () => {
controller.client.payMethodFk = 4;
expect(controller.hasPaymethodChanged()).toBeFalsy();
expect(controller.hasPaymethodChanges()).toBeFalsy();
});
});
describe('onBankEntityOpen()', () => {
it('should set reset the new bank entity properties', () => {
controller.newBankEntity.name = 'My new bank entity';
controller.newBankEntity.bic = 'ES123';
controller.onBankEntityOpen();
expect(controller.newBankEntity.name).toBe('');
expect(controller.newBankEntity.bic).toBe('');
});
});
describe('onBankEntityResponse()', () => {
it(`should throw an error if name property is empty`, () => {
controller.newBankEntity = {
name: '',
bic: 'ES123',
countryFk: 1
};
controller.onBankEntityResponse('ACCEPT');
expect(vnApp.showError).toHaveBeenCalledWith(`Name can't be empty`);
});
it(`should throw an error if bic property is empty`, () => {
controller.newBankEntity = {
name: 'My new bank entity',
bic: '',
countryFk: 1
};
controller.onBankEntityResponse('ACCEPT');
expect(vnApp.showError).toHaveBeenCalledWith(`Swift / BIC can't be empty`);
});
it('should request to create a new bank entity', () => {
let newBankEntity = {
name: 'My new bank entity',
bic: 'ES123',
countryFk: 1
};
controller.newBankEntity = newBankEntity;
$httpBackend.when('POST', '/client/api/BankEntities').respond('done');
$httpBackend.expectPOST('/client/api/BankEntities', newBankEntity);
controller.onBankEntityResponse('ACCEPT');
$httpBackend.flush();
});
});
});

View File

@ -12,4 +12,7 @@ Due day: Vencimiento
Received LCR: Recibido LCR
Received core VNL: Recibido core VNL
Received B2B VNL: Recibido B2B VNL
Save: Guardar
Save: Guardar
New bank entity: Nueva entidad bancaria
Name can't be empty: El nombre no puede quedar vacío
Swift / BIC can't be empty: El Swift / BIC no puede quedar vacío

View File

@ -1,12 +1,7 @@
<vn-main-block>
<mg-ajax
path="/client/api/Clients/{{edit.params.id}}/card"
actions="$ctrl.client = edit.model"
options="mgEdit">
</mg-ajax>
<vn-horizontal>
<vn-auto class="left-block">
<vn-client-descriptor client="$ctrl.client" clientFk="$ctrl.client.id"></vn-client-descriptor>
<vn-client-descriptor client="$ctrl.client"></vn-client-descriptor>
<vn-left-menu></vn-left-menu>
</vn-auto>
<vn-one>

View File

@ -1,16 +1,28 @@
import ngModule from '../module';
export default class Controller {
constructor($scope) {
constructor($scope, $stateParams, $http) {
this.$scope = $scope;
this.$http = $http;
this.$stateParams = $stateParams;
this.client = null;
}
$onInit() {
this.getCard();
}
getCard() {
this.$http.get(`/client/api/Clients/${this.$stateParams.id}/getCard`).then(response => {
this.client = response.data;
});
}
reload() {
this.$scope.edit.accept();
this.getCard();
}
}
Controller.$inject = ['$scope'];
Controller.$inject = ['$scope', '$stateParams', '$http'];
ngModule.component('vnClientCard', {
template: require('./index.html'),

View File

@ -31,3 +31,5 @@ import './credit-insurance/insurance/create';
import './contact';
import './sample/index';
import './sample/create';
import './web-payment';
import './history';

View File

@ -26,5 +26,6 @@
</vn-card>
<vn-button-bar>
<vn-submit label="Save"></vn-submit>
<vn-button ui-sref="client.card.creditInsurance.index" label="Cancel"></vn-button>
</vn-button-bar>
</form>

View File

@ -5,10 +5,11 @@
<vn-one border-radius class="pad-small border-solid" ng-class="{'bg-main': !classification.finished,'bg-opacity-item': classification.finished}">
<vn-horizontal style="align-items: center;">
<vn-none pad-medium-h orange>
<i class="material-icons pointer"
<vn-icon-button icon="lock" orange
ng-if="!classification.finished"
vn-tooltip="Close contract"
ng-click="$ctrl.closeContract(classification)">lock_outline</i>
ng-click="$ctrl.closeContract(classification)">
</vn-icon-button>
</vn-none>
<vn-one border-solid-right>
<div><vn-label translate>Since</vn-label> {{::classification.started | date:'dd/MM/yyyy'}}</div>

View File

@ -14,7 +14,7 @@
</vn-card>
<vn-button-bar>
<vn-submit label="Save"></vn-submit>
<vn-button ng-click="$ctrl.cancel($event)" label="Cancel"></vn-button>
<vn-button ng-click="$ctrl.cancel()" label="Cancel"></vn-button>
</vn-button-bar>
</form>
<vn-confirm

View File

@ -17,9 +17,7 @@ class Controller {
});
}
cancel(event) {
event.preventDefault();
event.stopImmediatePropagation();
cancel() {
this.goToIndex();
}

View File

@ -68,19 +68,11 @@ describe('Client', () => {
});
describe('cancel()', () => {
it('should call preventDefault, stopImmediatePropagation and goToIndex', () => {
let event = {
preventDefault: () => {},
stopImmediatePropagation: () => {}
};
spyOn(event, 'preventDefault');
spyOn(event, 'stopImmediatePropagation');
it('should call goToIndex()', () => {
spyOn(controller, 'goToIndex');
controller.cancel(event);
controller.cancel();
expect(controller.goToIndex).toHaveBeenCalledWith();
expect(event.preventDefault).toHaveBeenCalledWith();
expect(event.stopImmediatePropagation).toHaveBeenCalledWith();
});
});

View File

@ -1,7 +1,6 @@
<vn-popover vn-id="popover">
<vn-client-descriptor
client="$ctrl.client"
clientFk="$ctrl.clientFk"
quicklinks="$ctrl.quicklinks">
</vn-client-descriptor>
</vn-popover>

View File

@ -8,14 +8,11 @@ class Controller extends Component {
this.$http = $http;
this.$timeout = $timeout;
this.isTooltip = true;
this.client = {};
this._quicklinks = {};
}
set clientFk(value) {
if (value) {
this._getClient(value);
this._getClientDebt(value);
this.getCard(value);
}
}
@ -32,24 +29,13 @@ class Controller extends Component {
this.clientFk = null;
}
_getClientDebt(clientFk) {
this.$http.get(`/client/api/Clients/${clientFk}/getDebt`)
.then(response => {
this.clientDebt = response.data.debt;
});
}
_getClient(clientFk) {
this.$http.get(`/client/api/Clients/${clientFk}/card`)
getCard(clientFk) {
this.$http.get(`/client/api/Clients/${clientFk}/getCard`)
.then(response => {
this.client = response.data;
});
}
goToClientTickets() {
this.$state.go('ticket.index', {q: `{"clientFk": ${this.client.id}}`});
}
show() {
this.$.popover.parent = this.parent;
setTimeout(() => {
@ -64,7 +50,6 @@ ngModule.component('vnClientDescriptorPopover', {
template: require('./index.html'),
controller: Controller,
bindings: {
client: '<',
clientFk: '<',
quicklinks: '<'
}

View File

@ -21,25 +21,13 @@ describe('Client', () => {
controller = $componentController('vnClientDescriptorPopover', {$scope: $scope, $element: $element});
}));
describe('_getClientDebt()', () => {
it(`should perform a get query to store the client debt into the controller`, () => {
let clientFk = 1;
$httpBackend.when('GET', `/client/api/Clients/${clientFk}/getDebt`).respond({debt: 100});
$httpBackend.expect('GET', `/client/api/Clients/${clientFk}/getDebt`);
controller._getClientDebt(clientFk);
$httpBackend.flush();
expect(controller.clientDebt).toEqual(100);
});
});
describe('_getClient()', () => {
describe('getCard()', () => {
it(`should perform a get query to store the client data into the controller`, () => {
let clientFk = 1;
let response = {id: 1, name: 'name'};
$httpBackend.when('GET', `/client/api/Clients/${clientFk}/card`).respond(response);
$httpBackend.expect('GET', `/client/api/Clients/${clientFk}/card`);
controller._getClient(clientFk);
let response = {id: 1, name: 'name', debt: 1000};
$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

@ -45,7 +45,7 @@
<vn-icon
vn-tooltip="Client has debt"
icon="icon-risk"
ng-class="{bright: $ctrl.clientDebt > 0}">
ng-class="{bright: $ctrl.client.debt > 0}">
</vn-icon>
<vn-icon
vn-tooltip="Client not checked"

View File

@ -6,13 +6,6 @@ class Controller {
this.$http = $http;
}
set clientFk(value) {
if (!value) return;
this._getClient(value);
this._getClientDebt(value);
}
set client(value) {
this._client = value;
@ -38,28 +31,6 @@ class Controller {
get quicklinks() {
return this._quicklinks;
}
_getClientDebt(clientFk) {
this.$http.get(`/client/api/Clients/${clientFk}/getDebt`)
.then(response => {
this.clientDebt = response.data.debt;
});
}
_getClient(clientFk) {
this.$http.get(`/client/api/Clients/${clientFk}/card`)
.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'];
@ -68,7 +39,6 @@ ngModule.component('vnClientDescriptor', {
template: require('./index.html'),
bindings: {
client: '<',
clientFk: '<?',
quicklinks: '<'
},
controller: Controller

View File

@ -1,46 +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('_getClientDebt()', () => {
it(`should call _getClientDebt() and define the clientDebt value on the controller`, () => {
controller.client = {};
let response = {debt: 100};
$httpBackend.whenGET(`/client/api/Clients/101/getDebt`).respond(response);
$httpBackend.expectGET(`/client/api/Clients/101/getDebt`);
controller._getClientDebt(101);
$httpBackend.flush();
expect(controller.clientDebt).toEqual(100);
});
});
describe('_getClient()', () => {
it(`should call _getClient() and define the client value on the controller`, () => {
controller.client = {};
let response = {id: 101, name: 'Batman'};
$httpBackend.whenGET(`/client/api/Clients/101/card`).respond(response);
$httpBackend.expectGET(`/client/api/Clients/101/card`);
controller._getClient(101);
$httpBackend.flush();
expect(controller.client.name).toEqual('Batman');
});
});
});
});

View File

@ -40,6 +40,6 @@
</vn-card>
<vn-button-bar>
<vn-submit label="Save"></vn-submit>
<vn-button ng-click="$ctrl.cancel($event)" label="Cancel"></vn-button>
<vn-button ng-click="$ctrl.cancel()" label="Cancel"></vn-button>
</vn-button-bar>
</form>

View File

@ -9,9 +9,7 @@ class Controller {
};
}
cancel(event) {
event.preventDefault();
event.stopImmediatePropagation();
cancel() {
this.goToIndex();
}

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,9 @@
Model: Modelo
Action: Acción
Changed by: Cambiado por
Before: Antes
After: Despues
update: Actualizar
Create: Crear
History: Historial
insert: Crear

View File

@ -13,8 +13,9 @@
<vn-searchbar
panel="vn-client-search-panel"
model="model"
expr-builder="$ctrl.exprBuilder(param, value)">
</vn-searchbar>
expr-builder="$ctrl.exprBuilder(param, value)"
vn-focus>
</vn-searchbar>
</vn-card>
<vn-card margin-medium-v>
<vn-item-client

View File

@ -21,6 +21,6 @@
</vn-card>
<vn-button-bar>
<vn-submit label="Save"></vn-submit>
<vn-button ng-click="$ctrl.cancel($event)" label="Cancel"></vn-button>
<vn-button ng-click="$ctrl.cancel()" label="Cancel"></vn-button>
</vn-button-bar>
</form>

View File

@ -9,9 +9,7 @@ export default class Controller {
};
}
cancel(event) {
event.preventDefault();
event.stopImmediatePropagation();
cancel() {
this.$state.go('client.card.note.index', {id: this.$state.params.id});
}
}

View File

@ -38,6 +38,6 @@
</vn-card>
<vn-button-bar>
<vn-submit label="Save"></vn-submit>
<vn-button ng-click="$ctrl.cancel($event)" label="Cancel"></vn-button>
<vn-button ng-click="$ctrl.cancel()" label="Cancel"></vn-button>
</vn-button-bar>
</form>

View File

@ -9,9 +9,7 @@ class Controller {
};
}
cancel(event) {
event.preventDefault();
event.stopImmediatePropagation();
cancel() {
this.goToIndex();
}

View File

@ -24,13 +24,13 @@
<vn-tbody>
<vn-tr ng-repeat="recovery in recoveries">
<vn-td>
<vn-icon
class="bright pointer"
icon="lock"
<vn-icon-button icon="lock"
vn-acl="administrative"
vn-acl-action="remove"
vn-tooltip="Finish that recovery period"
ng-if="!recovery.finished"
ng-click="$ctrl.setFinished(recovery)">
</vn-icon>
</vn-icon-button>
</vn-td>
<vn-td>{{::recovery.started | date:'dd/MM/yyyy' }}</vn-td>
<vn-td>{{recovery.finished | date:'dd/MM/yyyy' }}</vn-td>
@ -49,7 +49,11 @@
</vn-pagination>
</vn-card>
</vn-vertical>
<a vn-tooltip="New recovery" ui-sref="client.card.recovery.create"
vn-bind="+" fixed-bottom-right>
<vn-float-button icon="add"></vn-float-button>
</a>
<vn-float-button icon="add" fixed-bottom-right
vn-tooltip="New recovery"
vn-bind="+"
vn-acl="administrative"
vn-acl-action="remove"
ui-sref="client.card.recovery.create">
</vn-float-button>

View File

@ -34,7 +34,7 @@
</vn-card>
<vn-button-bar>
<vn-submit label="Send"></vn-submit>
<vn-button label="Preview" ng-click="$ctrl.showPreview($event)"></vn-button>
<vn-button label="Preview" ng-click="$ctrl.showPreview()"></vn-button>
<vn-button ui-sref="client.card.sample.index" label="Cancel"></vn-button>
</vn-button-bar>
</form>

View File

@ -14,9 +14,7 @@ class Controller {
};
}
showPreview(event) {
event.preventDefault();
showPreview() {
let sampleType = this.$scope.sampleType.selection;
let queryParams;

View File

@ -158,45 +158,49 @@
</vn-vertical>
</vn-one>
<vn-one margin-medium>
<h5 translate>Recovery</h5>
<vn-vertical ng-if="$ctrl.summary.recovery">
<vn-label-value label="Since"
value="{{$ctrl.summary.recovery.started | date:'dd/MM/yyyy'}}">
<h5 translate>Business data</h5>
<vn-label-value label="Total greuge"
value="{{$ctrl.summary.totalGreuge | currency:'€ ':2}}">
</vn-label-value>
<vn-label-value label="To"
value="{{$ctrl.summary.recovery.finished | date:'dd/MM/yyyy'}}">
<vn-label-value label="Mana"
value="{{$ctrl.summary.mana.mana | currency:'€ ':2}}">
</vn-label-value>
<vn-label-value label="Amount"
value="{{$ctrl.summary.recovery.amount | currency:'€ ':2}}">
<vn-label-value label="Rate"
value="{{$ctrl.summary.claimsRatio[0].priceIncreasing | percentage}}">
</vn-label-value>
<vn-label-value label="Period"
value="{{$ctrl.summary.recovery.period}}">
<vn-label-value label="Average invoiced"
value="{{$ctrl.summary.averageInvoiced.invoiced | currency:'€ ':2}}">
</vn-label-value>
<vn-label-value label="Claims"
value="{{$ctrl.summary.claimsRatio[0].claimingRate | percentage}}">
</vn-label-value>
</vn-vertical>
</vn-one>
<vn-one margin-medium>
<h5 translate>Financial data</h5>
<vn-label-value label="Mana"
value="{{$ctrl.summary.mana.mana | currency:'€ ':2}}">
</vn-label-value>
<h5 translate>Financial information</h5>
<vn-label-value label="Risk"
value="{{$ctrl.summary.debt.debt | currency:'€ ':2}}">
</vn-label-value>
<vn-label-value label="Average invoiced"
value="{{$ctrl.summary.averageInvoiced.invoiced | currency:'€ ':2}}">
</vn-label-value>
<vn-label-value label="Total greuge"
value="{{$ctrl.summary.totalGreuge | currency:'€ ':2}}">
value="{{$ctrl.summary.debt.debt | currency:'€ ':2}}"
ng-class="{bold: $ctrl.summary.debt.debt > $ctrl.summary.credit}">
</vn-label-value>
<vn-label-value label="Credit"
value="{{$ctrl.summary.credit | currency:'€ ':2}}">
value="{{$ctrl.summary.credit | currency:'€ ':2}}"
ng-class="{bold: $ctrl.summary.credit > $ctrl.summary.creditInsurance ||
($ctrl.summary.credit && $ctrl.summary.creditInsurance == null)}">
</vn-label-value>
<vn-label-value label="Secured credit"
value="{{$ctrl.summary.creditInsurance | currency:'€ ':2}}">
</vn-label-value>
<vn-label-value label="Grade"
value="{{$ctrl.grade}}">
<vn-label-value label="Balance"
value="{{$ctrl.summary.clientRisks[0].amount | currency:'€ ':2}}">
</vn-label-value>
<vn-label-value label="Balance due"
value="{{$ctrl.summary.defaulters[0].amount | currency:'€ ':2}}"
ng-class="{bold: $ctrl.summary.defaulters[0].amount}">
</vn-label-value>
<vn-vertical ng-if="$ctrl.summary.recovery.started">
<vn-label-value label="Recovery since"
value="{{$ctrl.summary.recovery.started | date:'dd/MM/yyyy'}}">
</vn-label-value>
</vn-vertical>
</vn-one>
</vn-horizontal>
</vn-vertical>

View File

@ -1,9 +1,13 @@
Default address: Consignatario pred.
Total greuge: Greuge total
Financial data: Datos financieros
Financial information: Datos financieros
Mana: Maná
Risk: Riesgo
Secured credit: Crédito asegurado
Average invoiced: Consumo medio
Sales person: Comercial
Recovery: Recobro
Recovery: Recobro
Balance due: Saldo vencido
Rate: Tarifa
Business data: Datos comerciales
Recovery since: Recobro desde

View File

@ -1,4 +1,9 @@
vn-dialog vn-one {
min-width: 15em;
vn-dialog {
vn-client-summary vn-one {
min-width: 10em;
}
}
vn-client-summary .bold {
font-family: vn-font-bold;
}

View File

@ -1,10 +1,11 @@
import ngModule from '../module';
export default class Controller {
constructor($scope, $http, vnApp) {
constructor($scope, $http, vnApp, $translate) {
this.$ = $scope;
this.$http = $http;
this.vnApp = vnApp;
this.$translate = $translate;
this.canChangePassword = false;
this.canEnableCheckBox = true;
}
@ -52,14 +53,14 @@ export default class Controller {
this.$http.patch(`/client/api/Accounts/${this.client.id}`, account);
} catch (e) {
this.vnApp.showError(e.message);
this.vnApp.showError(this.$translate.instant(e.message));
return false;
}
return true;
}
}
Controller.$inject = ['$scope', '$http', 'vnApp'];
Controller.$inject = ['$scope', '$http', 'vnApp', '$translate'];
ngModule.component('vnClientWebAccess', {
template: require('./index.html'),

View File

@ -0,0 +1,57 @@
<vn-crud-model
vn-id="model"
url="/client/api/clients/getTransactions"
filter="{}"
link="{clientFk: $ctrl.$stateParams.id}"
limit="20"
data="transactions">
</vn-crud-model>
<vn-vertical>
<vn-card pad-large>
<vn-vertical>
<vn-title>Web Payment</vn-title>
<vn-table model="model">
<vn-thead>
<vn-tr>
<vn-th></vn-th>
<vn-th field="id">Id</vn-th>
<vn-th field="amount" number>Amount</vn-th>
<vn-th field="created" default-order="DESC">Payed</vn-th>
<vn-th></vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>
<vn-tr ng-repeat="transaction in transactions">
<vn-td style="width: 3em; text-align: center">
<vn-icon-button
icon="check"
vn-acl="administrative"
vn-tooltip="Confirm transaction"
ng-show="::!transaction.isConfirmed"
ng-click="$ctrl.confirm(transaction)">
</vn-icon-button>
</vn-td>
<vn-td>{{::transaction.id}}</vn-td>
<vn-td number>{{::transaction.amount | currency: '€ '}}</vn-td>
<vn-td>{{::transaction.created | date:'dd/MM/yyyy'}}</vn-td>
<vn-td>
<vn-icon orange
vn-tooltip="{{$ctrl.getFormattedMessage(transaction)}}"
ng-show="::(transaction.errorMessage || transaction.responseMessage)"
icon="warning">
</vn-icon>
</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,33 @@
import ngModule from '../module';
class Controller {
constructor($scope, $http, $stateParams) {
this.$scope = $scope;
this.$http = $http;
this.$stateParams = $stateParams;
}
confirm(transaction) {
const path = '/client/api/Clients/confirmTransaction';
let data = {id: transaction.id};
this.$http.post(path, data).then(res => {
this.$scope.model.refresh();
});
}
getFormattedMessage(transaction) {
const errorMessage = transaction.errorMessage ? transaction.errorMessage : '';
const separator = transaction.errorMessage && transaction.responseMessage ? '<br/>' : '';
const responseMessage = transaction.responseMessage ? transaction.responseMessage : '';
return `<strong style="font-size:13px">${errorMessage}</strong>`
+ separator
+ `<span style="font-size:13px">${responseMessage}</span>`;
}
}
Controller.$inject = ['$scope', '$http', '$stateParams'];
ngModule.component('vnClientWebPayment', {
template: require('./index.html'),
controller: Controller
});

View File

@ -0,0 +1,50 @@
import './index';
import {crudModel} from '../../../helpers/crudModelHelper';
describe('Component vnClientWebPayment', () => {
let $componentController;
let $httpBackend;
let $scope;
let vnApp;
let controller;
beforeEach(() => {
angular.mock.module('client');
});
beforeEach(angular.mock.inject((_$componentController_, $rootScope, _$httpBackend_, _vnApp_) => {
$componentController = _$componentController_;
$scope = $rootScope.$new();
$scope.model = crudModel;
$httpBackend = _$httpBackend_;
$httpBackend.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
vnApp = _vnApp_;
spyOn(vnApp, 'showError');
controller = $componentController('vnClientWebPayment', {$scope: $scope});
}));
describe('confirm()', () => {
it(`should confirm a transaction`, () => {
let transaction = {id: 1};
let query = '/client/api/Clients/confirmTransaction';
controller.confirm(transaction);
$httpBackend.when('POST', query, transaction).respond('ok');
$httpBackend.expect('POST', query, transaction);
$httpBackend.flush();
});
});
describe('getFormattedMessage()', () => {
it(`should return error message and response Message`, () => {
let transaction = {
errorMessage: 'My error message',
responseMessage: 'My response message'
};
let result = controller.getFormattedMessage(transaction);
expect(result).toContain('My error message');
expect(result).toContain('My response message');
});
});
});

View File

@ -0,0 +1,4 @@
Web Payment: Pago Web
Confirmed: Confirmado
Payed: Pagado
Confirm transaction: Confirmar transacción

View File

@ -4,8 +4,7 @@
type="button"
class="mdl-textfield__input"
ng-click="$ctrl.onMouseDown($event)"
ng-keydown="$ctrl.onKeyDown($event)">
</input>
ng-keydown="$ctrl.onKeyDown($event)"/>
<div class="icons">
<vn-icon
ng-show="!$ctrl.disabled"

View File

@ -13,6 +13,12 @@ export default class Button extends Input {
event.stopImmediatePropagation();
});
}
$onInit() {
if (!this.type) {
this.type = 'button';
}
}
}
Button.$inject = ['$element'];
@ -22,7 +28,8 @@ ngModule.component('vnButton', {
bindings: {
label: '@?',
disabled: '<?',
icon: '@?'
icon: '@?',
type: '@?'
}
});

View File

@ -10,11 +10,12 @@ export default class Controller extends Input {
this.input.addEventListener('change', () => this.onChange());
}
set field(value) {
this._field = value;
this.input.checked = value == true;
this.mdlUpdate();
}
get field() {
return this.input.checked == true;
return this._field;
}
$onInit() {
if (this.model) {
@ -30,6 +31,7 @@ export default class Controller extends Input {
}
}
onChange() {
this._field = this.input.checked == true;
this.$.$applyAsync();
}
}

View File

@ -1,8 +1,8 @@
<div>
<vn-one>
<span ng-class="{'mdl-chip--deletable': !$ctrl.disabled}" class="mdl-chip">
<span class="mdl-chip__text" ng-transclude></span>
<span class="mdl-chip__text ellipsize" ng-transclude></span>
<button ng-click="$ctrl.remove()" ng-show="!$ctrl.disabled" type="button" class="mdl-chip__action">
<i class="material-icons">cancel</i>
</button>
</span>
</div>
</vn-one>

View File

@ -2,11 +2,6 @@ import ngModule from '../../module';
import './style.scss';
export default class Chip {
constructor($element, $scope, $transclude) {
$transclude($scope.$parent, clone => {
angular.element($element[0].querySelector('div')).append(clone);
});
}
/**
* Remove chip event

View File

@ -1,11 +1,18 @@
@import 'colors';
vn-chip {
margin: 0 0.5em 0.5em 0;
.mdl-chip {
background-color: rgba($main-01, 0.9);
color: #FFF
}
.mdl-chip:active {
background-color: $main-01
}
& > vn-one > span > span {
max-width: 100%;
}
}

View File

@ -20,7 +20,6 @@ export default class DropDown extends Component {
this.$filter = $filter;
this.valueField = 'id';
this.showField = 'name';
this._search = undefined;
this._activeOption = -1;
this.showLoadMore = true;

Some files were not shown because too many files have changed in this diff Show More