Views migrated to vn schema, Node v8, Error handling, async-await, bugs solved
This commit is contained in:
parent
506d6e0688
commit
a3188b204f
|
@ -1,5 +1,4 @@
|
|||
extends: [eslint:recommended, google, plugin:jasmine/recommended]
|
||||
installedESLint: true
|
||||
plugins:
|
||||
- jasmine
|
||||
env:
|
||||
|
|
|
@ -2,25 +2,10 @@
|
|||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Asociar",
|
||||
"type": "node",
|
||||
"request": "attach",
|
||||
"port": 5858,
|
||||
"address": "localhost",
|
||||
"restart": false,
|
||||
"sourceMaps": false,
|
||||
"outFiles": [],
|
||||
"localRoot": "${workspaceRoot}",
|
||||
"remoteRoot": null
|
||||
},
|
||||
{
|
||||
"name": "Asociar al proceso",
|
||||
"type": "node",
|
||||
"request": "attach",
|
||||
"processId": "${command:PickProcess}",
|
||||
"port": 5858,
|
||||
"sourceMaps": false,
|
||||
"outFiles": []
|
||||
"name": "Attach by Process ID",
|
||||
"processId": "${command:PickProcess}"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"name": "@salix/auth",
|
||||
"version": "0.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://git.verdnatura.es/salix"
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"name": "@salix/client",
|
||||
"version": "0.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://git.verdnatura.es/salix"
|
||||
}
|
||||
}
|
|
@ -13,7 +13,7 @@
|
|||
<vn-check vn-one label="Default" field="$ctrl.address.isDefaultAddress"></vn-check>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-one label="Consignee" field="$ctrl.address.consignee" vn-focus></vn-textfield>
|
||||
<vn-textfield vn-one label="Consignee" field="$ctrl.address.nickname" vn-focus></vn-textfield>
|
||||
<vn-textfield vn-one label="Street address" field="$ctrl.address.street"></vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
|
|
|
@ -4,7 +4,7 @@ export default class Controller {
|
|||
constructor($state) {
|
||||
this.address = {
|
||||
clientFk: parseInt($state.params.id),
|
||||
isEnabled: true
|
||||
isActive: true
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ describe('Client', () => {
|
|||
|
||||
it('should define and set address property', () => {
|
||||
expect(controller.address.clientFk).toBe(1234);
|
||||
expect(controller.address.isEnabled).toBe(true);
|
||||
expect(controller.address.isActive).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -12,14 +12,14 @@
|
|||
<vn-title>Address</vn-title>
|
||||
<vn-horizontal>
|
||||
<vn-one>
|
||||
<vn-check label="Enabled" field="$ctrl.address.isEnabled"></vn-check>
|
||||
<vn-check label="Enabled" field="$ctrl.address.isActive"></vn-check>
|
||||
</vn-one>
|
||||
<vn-one>
|
||||
<vn-check label="Is equalizated" field="$ctrl.address.isEqualizated" vn-acl="administrative"></vn-check>
|
||||
</vn-one>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-one label="Consignee" field="$ctrl.address.consignee" vn-focus></vn-textfield>
|
||||
<vn-textfield vn-one label="Consignee" field="$ctrl.address.nickname" vn-focus></vn-textfield>
|
||||
<vn-textfield vn-one label="Street" field="$ctrl.address.street"></vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
|
@ -36,8 +36,8 @@
|
|||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-autocomplete vn-one
|
||||
initial-data="$ctrl.address.defaultAgency"
|
||||
field="$ctrl.address.defaultAgencyFk"
|
||||
initial-data="$ctrl.address.agency"
|
||||
field="$ctrl.address.agencyFk"
|
||||
url="/client/api/AgencyModes"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<mg-ajax path="/client/api/Clients/{{index.params.id}}/addressesList" options="mgIndex"></mg-ajax>
|
||||
<mg-ajax path="/client/api/Clients/{{index.params.id}}/listAddresses" options="mgIndex"></mg-ajax>
|
||||
<vn-vertical pad-medium>
|
||||
<vn-card>
|
||||
<vn-vertical pad-large>
|
||||
|
@ -7,14 +7,14 @@
|
|||
</vn-horizontal>
|
||||
<vn-horizontal ng-repeat="i in index.model.items track by i.id" class="pad-medium-top" style="align-items: center;">
|
||||
<vn-one border-radius class="pad-small border-solid"
|
||||
ng-class="{'bg-dark-item': i.isDefaultAddress,'bg-opacity-item': !i.isEnabled && !i.isDefaultAddress}">
|
||||
ng-class="{'bg-dark-item': i.isDefaultAddress,'bg-opacity-item': !i.isActive && !i.isDefaultAddress}">
|
||||
<vn-horizontal style="align-items: center;">
|
||||
<vn-none pad-medium-h style="color:#FFA410;">
|
||||
<i class="material-icons" ng-if="i.isDefaultAddress">star</i>
|
||||
<i class="material-icons pointer" ng-if="!i.isDefaultAddress&&i.isEnabled" vn-tooltip="Set as default" tooltip-position="left" ng-click="$ctrl.setDefault(i.id)">star_border</i>
|
||||
<i class="material-icons pointer" ng-if="!i.isDefaultAddress&&i.isActive" vn-tooltip="Set as default" tooltip-position="left" ng-click="$ctrl.setDefault(i.id)">star_border</i>
|
||||
</vn-none>
|
||||
<vn-one>
|
||||
<div><b>{{::i.consignee}}</b></div>
|
||||
<div><b>{{::i.nickname}}</b></div>
|
||||
<div>{{::i.street}}</div>
|
||||
<div>{{::i.city}}, {{::i.province}}</div>
|
||||
<div>{{::i.phone}}, {{::i.mobile}}</div>
|
||||
|
|
|
@ -6,9 +6,10 @@ class ClientAddresses {
|
|||
this.$scope = $scope;
|
||||
}
|
||||
setDefault(id) {
|
||||
this.$http.patch(`/client/api/Addresses/${id}`, {id: id, isDefaultAddress: true}).then(() => {
|
||||
this.$scope.index.accept();
|
||||
});
|
||||
let params = {isDefaultAddress: true};
|
||||
this.$http.patch(`/client/api/Addresses/${id}`, params).then(
|
||||
() => this.$scope.index.accept()
|
||||
);
|
||||
}
|
||||
}
|
||||
ClientAddresses.$inject = ['$http', '$scope'];
|
||||
|
|
|
@ -19,8 +19,7 @@
|
|||
<vn-textfield vn-one
|
||||
label="Email"
|
||||
field="$ctrl.client.email"
|
||||
info="You can save multiple emails by chaining them using comma without spaces, example: user@domain.com,user2@domain.com the first email will be considered as the main"
|
||||
>
|
||||
info="You can save multiple emails by chaining them using comma without spaces, example: user@domain.com,user2@domain.com the first email will be considered as the main">
|
||||
</vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
|
@ -30,10 +29,9 @@
|
|||
url="/client/api/Clients/activeSalesPerson"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
select-fields="surname"
|
||||
select-fields="name"
|
||||
label="Salesperson"
|
||||
filter-search="{where: {or: [{name: {regexp: 'search'}}, {surname: {regexp: 'search'}}]}}"
|
||||
>
|
||||
filter-search="{where: {or: [{name: {regexp: 'search'}}, {name: {regexp: 'search'}}]}}">
|
||||
</vn-autocomplete>
|
||||
<vn-autocomplete vn-one
|
||||
initial-data="$ctrl.client.contactChannel"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<mg-ajax path="/client/api/Clients/createUserProfile" options="vnPost"></mg-ajax>
|
||||
<mg-ajax path="/client/api/Clients/createWithUser" options="vnPost"></mg-ajax>
|
||||
<vn-watcher
|
||||
vn-id="watcher"
|
||||
data="$ctrl.client"
|
||||
|
@ -25,10 +25,10 @@
|
|||
url="/client/api/Clients/activeSalesPerson"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
select-fields="surname"
|
||||
select-fields="name"
|
||||
label="Salesperson"
|
||||
filter-search="{where: {or: [{name: {regexp: 'search'}}, {surname: {regexp: 'search'}}]}}"
|
||||
></vn-autocomplete>
|
||||
filter-search="{where: {or: [{name: {regexp: 'search'}}, {name: {regexp: 'search'}}]}}">
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
</vn-vertical>
|
||||
</vn-card>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<vn-grid-header on-order="$ctrl.onOrder(field, order)">
|
||||
<vn-column-header vn-one pad-medium-h field="amount" text="Credit"></vn-column-header>
|
||||
<vn-column-header vn-two pad-medium-h field="created" text="Since" default-order="ASC"></vn-column-header>
|
||||
<vn-column-header vn-two pad-medium-h field="employee.name" text="Employee" order-locked></vn-column-header>
|
||||
<vn-column-header vn-two pad-medium-h field="worker.firstName" text="Employee" order-locked></vn-column-header>
|
||||
</vn-grid-header>
|
||||
<vn-one class="list list-content">
|
||||
<vn-horizontal
|
||||
|
@ -14,7 +14,7 @@
|
|||
ng-repeat="credit in index.model.instances track by credit.id">
|
||||
<vn-one pad-medium-h>{{::credit.amount | number:2}} €</vn-one>
|
||||
<vn-two pad-medium-h>{{::credit.created | date:'dd/MM/yyyy HH:mm' }}</vn-two>
|
||||
<vn-two pad-medium-h>{{::credit.employee.name}} {{::credit.employee.surname}}</vn-two>
|
||||
<vn-two pad-medium-h>{{::credit.worker.firstName}} {{::credit.worker.name}}</vn-two>
|
||||
</vn-horizontal>
|
||||
</vn-one>
|
||||
<vn-one class="text-center pad-small-v" ng-if="index.model.count === 0" translate>No results</vn-one>
|
||||
|
|
|
@ -10,9 +10,9 @@
|
|||
<vn-vertical pad-large>
|
||||
<vn-title>Fiscal data</vn-title>
|
||||
<vn-horizontal>
|
||||
<vn-textfield autofocus vn-two label="Social name" field="$ctrl.client.socialName" vn-acl="administrative"></vn-textfield>
|
||||
<vn-textfield vn-one label="Tax number" field="$ctrl.client.fi" vn-acl="administrative"></vn-textfield>
|
||||
<vn-check vn-one label="Is equalizated" field="$ctrl.client.isEqualizated" vn-acl="administrative"></vn-check>
|
||||
<vn-textfield autofocus vn-two label="Social name" field="$ctrl.client.socialName" vn-acl="administrative"></vn-textfield>
|
||||
<vn-textfield vn-one label="Tax number" field="$ctrl.client.fi" vn-acl="administrative"></vn-textfield>
|
||||
<vn-check vn-one label="Is equalizated" field="$ctrl.client.isEqualizated" vn-acl="administrative"></vn-check>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-two label="Street" field="$ctrl.client.street" vn-focus vn-acl="administrative"></vn-textfield>
|
||||
|
@ -27,18 +27,16 @@
|
|||
show-field="name"
|
||||
value-field="id"
|
||||
label="Province"
|
||||
vn-acl="administrative"
|
||||
>
|
||||
vn-acl="administrative">
|
||||
</vn-autocomplete>
|
||||
<vn-autocomplete vn-one
|
||||
initial-data="$ctrl.client.country"
|
||||
field="$ctrl.client.countryFk"
|
||||
url="/client/api/Countries"
|
||||
show-field="name"
|
||||
show-field="country"
|
||||
value-field="id"
|
||||
label="Country"
|
||||
vn-acl="administrative"
|
||||
>
|
||||
vn-acl="administrative">
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal margin-small-bottom>
|
||||
|
@ -64,17 +62,14 @@
|
|||
</vn-one>
|
||||
</vn-horizontal>
|
||||
</vn-vertical>
|
||||
|
||||
</vn-card>
|
||||
|
||||
<vn-button-bar>
|
||||
<vn-submit label="Save"></vn-submit>
|
||||
</vn-button-bar>
|
||||
</form>
|
||||
<vn-dialog
|
||||
vn-id="propagate-isEqualizated"
|
||||
on-response="$ctrl.returnDialogEt(response)"
|
||||
>
|
||||
on-response="$ctrl.returnDialogEt(response)">
|
||||
<tpl-body>
|
||||
<vn-vertical>
|
||||
<vn-one text-center translate>You changes the equivalen
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<a ui-sref="clientCard.basicData({ id: {{$ctrl.client.id}} })" pad-medium border-solid-bottom>
|
||||
<div class="vn-item-client-name">{{$ctrl.client.name}}</div>
|
||||
<div><span translate>Client id</span>: <b>{{$ctrl.client.id}}</b></div>
|
||||
<div><span translate>Phone</span>: <b>{{$ctrl.client.phone | phone}}</b></div>
|
||||
<div><span translate>Town/City</span>: <b>{{$ctrl.client.city}}</b></div>
|
||||
<div><span translate>Email</span>: <b>{{$ctrl.client.email}}</b></div>
|
||||
<a ui-sref="clientCard.basicData({ id: {{::$ctrl.client.id}} })" pad-medium border-solid-bottom>
|
||||
<div class="vn-item-client-name">{{::$ctrl.client.name}}</div>
|
||||
<div><span translate>Client id</span>: <b>{{::$ctrl.client.id}}</b></div>
|
||||
<div><span translate>Phone</span>: <b>{{::$ctrl.client.phone | phone}}</b></div>
|
||||
<div><span translate>Town/City</span>: <b>{{::$ctrl.client.city}}</b></div>
|
||||
<div><span translate>Email</span>: <b>{{::$ctrl.client.email}}</b></div>
|
||||
</a>
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
<vn-vertical pad-large>
|
||||
<vn-title>Notes</vn-title>
|
||||
<vn-one
|
||||
ng-repeat="n in $ctrl.observations"
|
||||
pad-small border-solid
|
||||
border-radius
|
||||
margin-small-bottom style="align-items: center;">
|
||||
ng-repeat="n in $ctrl.observations"
|
||||
pad-small border-solid
|
||||
border-radius
|
||||
margin-small-bottom style="align-items: center;">
|
||||
<vn-horizontal>
|
||||
<vn-one >{{::n.employee.name}} {{::n.employee.surname}}</vn-one>
|
||||
<vn-one >{{::n.worker.firstName}} {{::n.worker.name}}</vn-one>
|
||||
<vn-auto>{{::n.created | date:'dd/MM/yyyy HH:mm'}}</vn-auto>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
|
|
|
@ -16,7 +16,7 @@ export default class Controller {
|
|||
|
||||
isCustomer() {
|
||||
if (this.client && this.client.id) {
|
||||
this.$http.get(`/client/api/Clients/${this.client.id}/getRoleCustomer`).then(res => {
|
||||
this.$http.get(`/client/api/Clients/${this.client.id}/hasCustomerRole`).then(res => {
|
||||
this.canChangePassword = (res.data) ? res.data.isCustomer : false;
|
||||
});
|
||||
} else {
|
||||
|
|
|
@ -37,8 +37,8 @@ describe('Component VnClientWebAccess', () => {
|
|||
controller.client = {id: '1234'};
|
||||
controller.isCustomer();
|
||||
|
||||
$httpBackend.when('GET', `/client/api/Clients/${controller.client.id}/getRoleCustomer`).respond('ok');
|
||||
$httpBackend.expectGET(`/client/api/Clients/${controller.client.id}/getRoleCustomer`);
|
||||
$httpBackend.when('GET', `/client/api/Clients/${controller.client.id}/hasCustomerRole`).respond('ok');
|
||||
$httpBackend.expectGET(`/client/api/Clients/${controller.client.id}/hasCustomerRole`);
|
||||
$httpBackend.flush();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"name": "@salix/core",
|
||||
"version": "0.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://git.verdnatura.es/salix"
|
||||
}
|
||||
}
|
|
@ -18,5 +18,5 @@
|
|||
item-width="$ctrl.width"
|
||||
multiple="$ctrl.multiple"
|
||||
parent = "$ctrl.element"
|
||||
><vn-item ng-transclude="tplItem">{{$parent.item.name}}</vn-item></vn-drop-down>
|
||||
><vn-item ng-transclude="tplItem">{{$parent.item[$ctrl.showField]}}</vn-item></vn-drop-down>
|
||||
</vn-vertical>
|
|
@ -2,7 +2,6 @@ import {module} from '../module';
|
|||
import Component from '../lib/component';
|
||||
import copyObject from '../lib/copy';
|
||||
import './style.scss';
|
||||
import { log } from 'util';
|
||||
|
||||
class Autocomplete extends Component {
|
||||
constructor($element, $scope, $http, $timeout, $filter) {
|
||||
|
@ -20,9 +19,8 @@ class Autocomplete extends Component {
|
|||
this._field = null;
|
||||
this._preLoad = false;
|
||||
this.maxRow = 10;
|
||||
this.showField = this.showField || 'name';
|
||||
this.valueField = this.valueField || 'id';
|
||||
this.order = this.order || 'name ASC';
|
||||
this.showField = 'name';
|
||||
this.valueField = 'id';
|
||||
this.items = copyObject(this.data) || [];
|
||||
this.displayValueMultiCheck = [];
|
||||
this._multiField = [];
|
||||
|
@ -195,6 +193,10 @@ class Autocomplete extends Component {
|
|||
return fields;
|
||||
}
|
||||
|
||||
getOrder() {
|
||||
return this.order ? this.order : `${this.showField} ASC`;
|
||||
}
|
||||
|
||||
findItems(search) {
|
||||
if (this.url && search && !this.finding) {
|
||||
this.maxRow = false;
|
||||
|
@ -208,7 +210,7 @@ class Autocomplete extends Component {
|
|||
Object.assign(filter.where, this.filter.where);
|
||||
}
|
||||
}
|
||||
filter.order = this.order;
|
||||
filter.order = this.getOrder();
|
||||
let json = JSON.stringify(filter);
|
||||
this.finding = true;
|
||||
this.$http.get(`${this.url}?filter=${json}`).then(
|
||||
|
@ -252,7 +254,7 @@ class Autocomplete extends Component {
|
|||
filter.skip = this.items.length;
|
||||
}
|
||||
filter.limit = this.maxRow;
|
||||
filter.order = this.order;
|
||||
filter.order = this.getOrder();
|
||||
}
|
||||
if (this.filter) {
|
||||
Object.assign(filter, this.filter);
|
||||
|
|
|
@ -163,8 +163,8 @@ describe('Component vnAutocomplete', () => {
|
|||
let controller = $componentController('vnAutocomplete', {$scope, $element, $httpBackend, $timeout});
|
||||
controller.url = 'test.com';
|
||||
let search = 'The Joker';
|
||||
controller.filterSearch = "{where: {surname: {regexp: 'search'}}}";
|
||||
let json = JSON.stringify({where: {surname: {regexp: search}}, order: controller.order});
|
||||
controller.filterSearch = "{where: {name: {regexp: 'search'}}}";
|
||||
let json = JSON.stringify({where: {name: {regexp: search}}, order: controller.order});
|
||||
$httpBackend.whenGET(`${controller.url}?filter=${json}`).respond([{id: 3, name: 'The Joker'}]);
|
||||
$httpBackend.expectGET(`${controller.url}?filter=${json}`);
|
||||
controller.findItems(search);
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<vn-icon-button icon="textsms" ng-click="$ctrl.doAction('addComment')"></vn-icon-button>
|
||||
</vn-none>
|
||||
<vn-none margin-medium-right>
|
||||
<vn-icon-menu icon="person" url="/client/api/Clients/employeeList" selected="$ctrl.actionWorker"></vn-icon-menu>
|
||||
<vn-icon-menu icon="person" url="/client/api/Clients/listWorkers" selected="$ctrl.actionWorker"></vn-icon-menu>
|
||||
</vn-none>
|
||||
<vn-none margin-medium-right>
|
||||
<vn-icon-menu icon="query_builder" items="$ctrl.parent.sharedData.hourItems" selected="$ctrl.actionHours"></vn-icon-menu>
|
||||
|
|
|
@ -1,24 +1,23 @@
|
|||
<vn-watcher
|
||||
vn-id="watcher"
|
||||
data="$ctrl.route"
|
||||
form="form"
|
||||
>
|
||||
form="form">
|
||||
</vn-watcher>
|
||||
<form name="form" pad-medium>
|
||||
<vn-card>
|
||||
<vn-vertical pad-large>
|
||||
<vn-title>Logistic data</vn-title>
|
||||
<vn-horizontal>
|
||||
<vn-date-picker vn-one label="Start Hour" model="$ctrl.route.startHour" ini-options="{enableTime: true, noCalendar: true, enableSeconds: false, dateFormat: 'H:i'}"></vn-date-picker>
|
||||
<vn-date-picker vn-one label="End Hour" model="$ctrl.route.endHour" ini-options="{enableTime: true, noCalendar: true, enableSeconds: false, dateFormat: 'H:i'}"></vn-date-picker>
|
||||
<vn-textfield vn-one label="Start Km" model="$ctrl.route.starKm"></vn-textfield>
|
||||
<vn-textfield vn-one label="End Km" model="$ctrl.route.endKm"></vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-one label="Packages" model="$ctrl.route.packages"></vn-textfield>
|
||||
<vn-textfield vn-one label="M3" model="$ctrl.route.m3"></vn-textfield>
|
||||
<vn-one></vn-one>
|
||||
</vn-horizontal>
|
||||
<vn-title>Logistic data</vn-title>
|
||||
<vn-horizontal>
|
||||
<vn-date-picker vn-one label="Start Hour" model="$ctrl.route.startHour" ini-options="{enableTime: true, noCalendar: true, enableSeconds: false, dateFormat: 'H:i'}"></vn-date-picker>
|
||||
<vn-date-picker vn-one label="End Hour" model="$ctrl.route.endHour" ini-options="{enableTime: true, noCalendar: true, enableSeconds: false, dateFormat: 'H:i'}"></vn-date-picker>
|
||||
<vn-textfield vn-one label="Start Km" model="$ctrl.route.starKm"></vn-textfield>
|
||||
<vn-textfield vn-one label="End Km" model="$ctrl.route.endKm"></vn-textfield>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-one label="Packages" model="$ctrl.route.packages"></vn-textfield>
|
||||
<vn-textfield vn-one label="M3" model="$ctrl.route.m3"></vn-textfield>
|
||||
<vn-one></vn-one>
|
||||
</vn-horizontal>
|
||||
</vn-vertical>
|
||||
</vn-card>
|
||||
<vn-button-bar>
|
||||
|
|
|
@ -10,12 +10,10 @@
|
|||
order="printingOrder ASC"
|
||||
></vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
|
||||
<vn-horizontal>
|
||||
<vn-textfield vn-one label="Postcode" model="$ctrl.filter.postcode"></vn-textfield>
|
||||
<vn-textfield vn-one label="Route_Id" model="$ctrl.filter.id"></vn-textfield>
|
||||
</vn-horizontal>
|
||||
|
||||
<vn-horizontal margin-large-top>
|
||||
<vn-submit label="Search"></vn-submit>
|
||||
</vn-horizontal>
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"name": "@salix/salix",
|
||||
"version": "0.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "http://git.verdnatura.es:/salix"
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
}
|
||||
@font-face {
|
||||
font-family: vn-font;
|
||||
src: url(./fonts/Roboto.ttf);
|
||||
src: url(./fonts/Roboto-Regular.ttf);
|
||||
}
|
||||
@font-face {
|
||||
font-family: vn-font-bold;
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"name": "@salix/vendor",
|
||||
"version": "0.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://git.verdnatura.es/salix"
|
||||
}
|
||||
}
|
|
@ -8,8 +8,6 @@ services:
|
|||
build:
|
||||
context: ./services
|
||||
dockerfile: /auth/Dockerfile
|
||||
expose:
|
||||
- "3000"
|
||||
ports:
|
||||
- "3000:3000"
|
||||
|
||||
|
@ -21,8 +19,6 @@ services:
|
|||
build:
|
||||
context: ./services
|
||||
dockerfile: /salix/Dockerfile
|
||||
expose:
|
||||
- "3001"
|
||||
ports:
|
||||
- "3001:3001"
|
||||
|
||||
|
@ -34,8 +30,6 @@ services:
|
|||
build:
|
||||
context: ./services
|
||||
dockerfile: /client/Dockerfile
|
||||
expose:
|
||||
- "3002"
|
||||
ports:
|
||||
- "3002:3002"
|
||||
|
||||
|
@ -46,8 +40,6 @@ services:
|
|||
image: "mailer:${TAG}"
|
||||
build:
|
||||
context: ./services/mailer
|
||||
expose:
|
||||
- "3003"
|
||||
ports:
|
||||
- "3003:3003"
|
||||
|
||||
|
@ -59,8 +51,6 @@ services:
|
|||
build:
|
||||
context: ./services
|
||||
dockerfile: /production/Dockerfile
|
||||
expose:
|
||||
- "3004"
|
||||
ports:
|
||||
- "3004:3004"
|
||||
|
||||
|
@ -72,8 +62,6 @@ services:
|
|||
build:
|
||||
context: ./services
|
||||
dockerfile: /route/Dockerfile
|
||||
expose:
|
||||
- "3005"
|
||||
ports:
|
||||
- "3005:3005"
|
||||
print:
|
||||
|
@ -84,8 +72,6 @@ services:
|
|||
build:
|
||||
context: ./services
|
||||
dockerfile: /print/Dockerfile
|
||||
expose:
|
||||
- "3006"
|
||||
ports:
|
||||
- "3006:3006"
|
||||
item:
|
||||
|
@ -96,8 +82,6 @@ services:
|
|||
build:
|
||||
context: ./services
|
||||
dockerfile: /item/Dockerfile
|
||||
expose:
|
||||
- "3007"
|
||||
ports:
|
||||
- "3007:3007"
|
||||
nginx:
|
||||
|
@ -106,8 +90,6 @@ services:
|
|||
privileged: true
|
||||
build:
|
||||
context: ./services/nginx
|
||||
expose:
|
||||
- "80"
|
||||
ports:
|
||||
- "80:80"
|
||||
mem_limit: 200m
|
||||
|
|
|
@ -87,7 +87,7 @@ export default {
|
|||
addressesButton: `${components.vnMenuItem}[ui-sref="clientCard.addresses.list"]`,
|
||||
createAddress: `${components.vnFloatButton}`,
|
||||
defaultCheckboxInput: `${components.vnCheck}[label='Default'] > label > input`,
|
||||
consigneeInput: `${components.vnTextfield}[name="consignee"]`,
|
||||
consigneeInput: `${components.vnTextfield}[name="nickname"]`,
|
||||
streetAddressInput: `${components.vnTextfield}[name="street"]`,
|
||||
postcodeInput: `${components.vnTextfield}[name="postcode"]`,
|
||||
cityInput: `${components.vnTextfield}[name="city"]`,
|
||||
|
|
|
@ -250,8 +250,8 @@ describe('Edit addresses path', () => {
|
|||
nightmare
|
||||
.waitForSnackbarReset()
|
||||
.waitToClick(selectors.addresses.addressesButton)
|
||||
.wait(selectors.addresses.defaultAddress)
|
||||
.getInnerText(selectors.addresses.defaultAddress)
|
||||
.wait(selectors.addresses.isDefaultAddress)
|
||||
.getInnerText(selectors.addresses.isDefaultAddress)
|
||||
.then(result => {
|
||||
expect(result).toContain('320 Park Avenue New York');
|
||||
done();
|
||||
|
@ -263,8 +263,8 @@ describe('Edit addresses path', () => {
|
|||
nightmare
|
||||
.waitForSnackbarReset()
|
||||
.waitToClick(selectors.addresses.secondMakeDefaultStar)
|
||||
.waitForTextInElement(selectors.addresses.defaultAddress, 'Somewhere in Thailand')
|
||||
.getInnerText(selectors.addresses.defaultAddress)
|
||||
.waitForTextInElement(selectors.addresses.isDefaultAddress, 'Somewhere in Thailand')
|
||||
.getInnerText(selectors.addresses.isDefaultAddress)
|
||||
.then(result => {
|
||||
expect(result).toContain('Somewhere in Thailand');
|
||||
done();
|
||||
|
@ -274,7 +274,7 @@ describe('Edit addresses path', () => {
|
|||
|
||||
it(`should click on the edit icon of the default address`, done => {
|
||||
nightmare
|
||||
.waitForTextInElement(selectors.addresses.defaultAddress, 'Somewhere in Thailand')
|
||||
.waitForTextInElement(selectors.addresses.isDefaultAddress, 'Somewhere in Thailand')
|
||||
.waitToClick(selectors.addresses.firstEditButton)
|
||||
.waitForURL('/edit')
|
||||
.url()
|
||||
|
|
84
gulpfile.js
84
gulpfile.js
|
@ -1,5 +1,5 @@
|
|||
var gulp = require('gulp');
|
||||
const jasmine = require('gulp-jasmine');
|
||||
var jasmine = require('gulp-jasmine');
|
||||
var gutil = require('gulp-util');
|
||||
var wrap = require('gulp-wrap');
|
||||
var concat = require('gulp-concat');
|
||||
|
@ -12,55 +12,62 @@ var del = require('del');
|
|||
var fs = require('fs');
|
||||
var webpack = require('webpack');
|
||||
var WebpackDevServer = require('webpack-dev-server');
|
||||
|
||||
var exec = require('child_process').exec;
|
||||
|
||||
// Configuration
|
||||
|
||||
var srcDir = './client';
|
||||
var buildDir = './services/nginx/static';
|
||||
var langs = ['es', 'en'];
|
||||
|
||||
var modules = require('./client/modules.json');
|
||||
|
||||
var webpackConfig = require('./webpack.config.js');
|
||||
|
||||
// Main tasks
|
||||
|
||||
gulp.task('default', function() {
|
||||
gulp.task('default', () => {
|
||||
return gulp.start('services', 'client');
|
||||
});
|
||||
|
||||
gulp.task('build', ['clean'], function() {
|
||||
gulp.task('build', ['clean'], () => {
|
||||
return gulp.start('routes', 'locales', 'webpack');
|
||||
});
|
||||
|
||||
gulp.task('client', ['clean'], function() {
|
||||
gulp.task('client', ['clean'], () => {
|
||||
return gulp.start('watch', 'routes', 'locales', 'webpack-dev-server');
|
||||
});
|
||||
|
||||
gulp.task('nginxRestart', callback => {
|
||||
let isWindows = /^win/.test(process.platform);
|
||||
let command = isWindows ? '.\\dev.cmd' : './dev.sh';
|
||||
exec(command, (err, stdout, stderr) => {
|
||||
console.log(stdout);
|
||||
callback(err);
|
||||
});
|
||||
});
|
||||
|
||||
gulp.task('services', () => {
|
||||
gulp.task('services', ['nginx'], () => {
|
||||
process.env.NODE_ENV = gutil.env.env || 'development';
|
||||
const pathServices = './services/';
|
||||
const services = fs.readdirSync(pathServices);
|
||||
const servicesPath = './services/';
|
||||
const services = fs.readdirSync(servicesPath);
|
||||
services.splice(services.indexOf('loopback'), 1);
|
||||
return services.forEach(service => {
|
||||
const serviceJs = pathServices.concat(service, '/server/server.js');
|
||||
const serviceJs = servicesPath.concat(service, '/server/server.js');
|
||||
if (fs.existsSync(serviceJs))
|
||||
require(serviceJs).start();
|
||||
});
|
||||
});
|
||||
|
||||
gulp.task('clientDev', callback => {
|
||||
runSequence('nginxRestart', 'client', callback);
|
||||
gulp.task('clean', function() {
|
||||
return del([`${buildDir}/*`, `!${buildDir}/templates`, `!${buildDir}/images`], {force: true});
|
||||
});
|
||||
|
||||
gulp.task('install', () => {
|
||||
const servicesPath = './services/';
|
||||
const jsonFile = [];
|
||||
const services = fs.readdirSync(servicesPath);
|
||||
services.push('..');
|
||||
services.forEach(service => {
|
||||
jsonFile.push(servicesPath.concat(service, '/package.json'));
|
||||
});
|
||||
return gulp.src(jsonFile)
|
||||
.pipe(print(filepath => {
|
||||
return `Installing packages in ${filepath}`;
|
||||
}))
|
||||
.pipe(install({
|
||||
npm: ['--no-package-lock']
|
||||
}));
|
||||
});
|
||||
|
||||
gulp.task('servicesDev', callback => {
|
||||
|
@ -78,25 +85,16 @@ gulp.task('servicesDev', callback => {
|
|||
});
|
||||
});
|
||||
|
||||
gulp.task('clean', function() {
|
||||
return del([`${buildDir}/*`, `!${buildDir}/templates`, `!${buildDir}/images`], {force: true});
|
||||
});
|
||||
// Nginx
|
||||
|
||||
gulp.task('install', () => {
|
||||
const pathServices = './services/';
|
||||
const fileJson = [];
|
||||
const services = fs.readdirSync(pathServices);
|
||||
services.push('..');
|
||||
services.forEach(service => {
|
||||
fileJson.push(pathServices.concat(service, '/package.json'));
|
||||
gulp.task('nginx', callback => {
|
||||
let isWindows = /^win/.test(process.platform);
|
||||
let command = isWindows ? 'start.cmd' : 'start.sh';
|
||||
command = `./services/nginx/${command}`;
|
||||
exec(command, (err, stdout, stderr) => {
|
||||
console.log(stdout);
|
||||
callback(err);
|
||||
});
|
||||
return gulp.src(fileJson)
|
||||
.pipe(print(filepath => {
|
||||
return `Installing packages in ${filepath}`;
|
||||
}))
|
||||
.pipe(install({
|
||||
npm: ['--no-package-lock']
|
||||
}));
|
||||
});
|
||||
|
||||
// Webpack
|
||||
|
@ -171,17 +169,20 @@ gulp.task('routes', function() {
|
|||
});
|
||||
|
||||
// Watch
|
||||
|
||||
gulp.task('watch', function() {
|
||||
gulp.watch(routeFiles, ['routes']);
|
||||
gulp.watch(localeFiles, ['locales']);
|
||||
});
|
||||
|
||||
// Server side unit tests
|
||||
// Services tests
|
||||
|
||||
gulp.task('test', callback => {
|
||||
return require('./services_tests').start();
|
||||
});
|
||||
|
||||
// e2e tests
|
||||
// E2E tests
|
||||
|
||||
gulp.task('e2e', callback => {
|
||||
runSequence('docker', 'waitForMySQL', 'endToEndTests', callback);
|
||||
});
|
||||
|
@ -212,7 +213,8 @@ gulp.task('endToEndTests', callback => {
|
|||
.pipe(jasmine({reporter: 'none'}));
|
||||
});
|
||||
|
||||
// docker dblocal
|
||||
// Docker
|
||||
|
||||
gulp.task('docker', callback => {
|
||||
runSequence('deleteDockerDb', 'deleteDockerImageDb', 'buildDockerDb', 'runDockerDb', callback);
|
||||
});
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -62,7 +62,7 @@
|
|||
"merge-stream": "^1.0.1",
|
||||
"mysql": "^2.15.0",
|
||||
"nightmare": "^2.10.0",
|
||||
"node-sass": "^3.11.0",
|
||||
"node-sass": "^3.13.1",
|
||||
"raw-loader": "*",
|
||||
"run-sequence": "^2.2.0",
|
||||
"sass-loader": "^4.0.2",
|
||||
|
|
|
@ -22,6 +22,6 @@
|
|||
"dataSource": "salix"
|
||||
},
|
||||
"Account": {
|
||||
"dataSource": "salix"
|
||||
"dataSource": "account"
|
||||
}
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
var request = require('request');
|
||||
var app = require('../../../server/server');
|
||||
|
||||
module.exports = function(Client) {
|
||||
Client.remoteMethod('activate', {
|
||||
description: 'Activate or deactive client',
|
||||
accepts: [
|
||||
{
|
||||
arg: 'id',
|
||||
type: 'number',
|
||||
required: true,
|
||||
description: 'Model id',
|
||||
http: {source: 'path'}
|
||||
}, {
|
||||
arg: 'context',
|
||||
type: 'object',
|
||||
http: function(ctx) {
|
||||
return ctx;
|
||||
}
|
||||
}
|
||||
],
|
||||
returns: {
|
||||
arg: 'active',
|
||||
type: 'boolean'
|
||||
},
|
||||
http: {
|
||||
verb: 'put',
|
||||
path: '/:id/activate'
|
||||
}
|
||||
});
|
||||
|
||||
Client.activate = function(id, ctx, cb) {
|
||||
Client.findById(id, function(err, client) {
|
||||
if (!err) {
|
||||
Client.update({id: client.id}, {active: !client.active});
|
||||
|
||||
let filter = {where: {clientFk: client.id}, fields: ['started', 'ended']};
|
||||
|
||||
app.models.CreditClassification.findOne(filter, function(error, data) {
|
||||
if (error)
|
||||
return;
|
||||
|
||||
let currentDate = new Date();
|
||||
|
||||
if (data && client.active && (data.ended >= currentDate || data.ended == null)) {
|
||||
let referer = ctx.req.headers.referer;
|
||||
var options = {
|
||||
url: `${referer}/mailer/notification/client-deactivate/${client.id}`,
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'content-type': 'application/json',
|
||||
'Authorization': ctx.req.headers.authorization
|
||||
},
|
||||
json: {}
|
||||
};
|
||||
request(options);
|
||||
}
|
||||
});
|
||||
|
||||
cb(null, !client.active);
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
|
@ -1,147 +0,0 @@
|
|||
var app = require('../../../server/server');
|
||||
|
||||
module.exports = function(Client) {
|
||||
var CREDIT_CARD = 5;
|
||||
var models = app.models;
|
||||
|
||||
Client.observe('before save', function(ctx, next) {
|
||||
if (ctx.currentInstance) {
|
||||
let dataChange = Object.assign({}, ctx.data);
|
||||
let userId = ctx.options.accessToken.userId;
|
||||
|
||||
Object.assign(ctx.data, doIfNullSalesPerson(ctx.currentInstance));
|
||||
|
||||
if (!ctx.data.dueDay)
|
||||
ctx.data.dueDay = 5;
|
||||
|
||||
if (dataChange.hasOwnProperty('equalizationTax') && !canMarkEqualizationTax(ctx.data))
|
||||
next(generateErrorEqualizationTax());
|
||||
else if (dataChange.hasOwnProperty('credit'))
|
||||
canChangeCredit(dataChange, userId, next);
|
||||
else
|
||||
next();
|
||||
} else if (ctx.where && ctx.where.id) {
|
||||
Client.findById(ctx.where.id, (_, instance) => {
|
||||
Object.assign(ctx.data, doIfNullSalesPerson(instance));
|
||||
|
||||
if (instance
|
||||
&& instance.payMethodFk != ctx.data.payMethodFk
|
||||
&& instance.dueDay == ctx.data.dueDay)
|
||||
ctx.data.dueDay = 5;
|
||||
|
||||
if (instance.fi && ctx.data.equalizationTax && !canMarkEqualizationTax(instance)) {
|
||||
next(generateErrorEqualizationTax());
|
||||
} else if (instance.equalizationTax !== undefined && instance.equalizationTax && ctx.data.fi && canMarkEqualizationTax(ctx.data)) {
|
||||
next(generateErrorEqualizationTax());
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// newInstance
|
||||
next();
|
||||
}
|
||||
});
|
||||
|
||||
function doIfNullSalesPerson(instance) {
|
||||
var data = {};
|
||||
if (instance.salesPerson === null) {
|
||||
data.credit = 0;
|
||||
data.discount = 0;
|
||||
data.payMethodFk = CREDIT_CARD;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
function canMarkEqualizationTax(instance) {
|
||||
var firstLetter = (instance && instance.fi) ? instance.fi.toUpperCase().charAt(0) : '';
|
||||
if (firstLetter == "A" || firstLetter == "B")
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
function generateErrorEqualizationTax() {
|
||||
var error = new Error();
|
||||
error.message = "No se puede marcar el recargo de equivalencia";
|
||||
error.status = 500;
|
||||
return error;
|
||||
}
|
||||
|
||||
function generateErrorCredit() {
|
||||
var error = new Error();
|
||||
error.message = "No tienes privilegios para modificar el crédito";
|
||||
error.status = 500;
|
||||
return error;
|
||||
}
|
||||
|
||||
function canChangeCredit(data, userId, done) {
|
||||
let filter = {
|
||||
fields: ['roleFk'],
|
||||
where: {
|
||||
maxAmount: {gt: data.credit}
|
||||
}
|
||||
};
|
||||
|
||||
models.ClientCreditLimit.find(filter,
|
||||
(_, res) => limitCb(_, res));
|
||||
|
||||
function limitCb(_, instances) {
|
||||
let requiredRoles = [];
|
||||
for (instance of instances)
|
||||
requiredRoles.push(instance.roleFk);
|
||||
|
||||
let where = {
|
||||
roleId: {inq: requiredRoles},
|
||||
principalType: 'USER',
|
||||
principalId: userId
|
||||
};
|
||||
models.RoleMapping.count(where,
|
||||
(_, res) => roleCb(_, res));
|
||||
}
|
||||
function roleCb(_, count) {
|
||||
// si el usuario no tiene alguno de los roles no continua
|
||||
if (count <= 0) {
|
||||
done(generateErrorCredit());
|
||||
return;
|
||||
}
|
||||
// si tiene el rol hay que validar que el último movimiento no fuese crédito 0 insertado por gerencia
|
||||
validate();
|
||||
}
|
||||
|
||||
// Si se puso a 0 por gerencia, solo gerencia puede aumentarlo
|
||||
function validate() {
|
||||
let query = 'SELECT * FROM ClientCredit WHERE clientFk = ? ORDER BY created DESC LIMIT 1';
|
||||
Client.dataSource.connector.execute(query, [data.id],
|
||||
(_, res) => maxCb(_, res));
|
||||
}
|
||||
|
||||
function maxCb(_, instances) {
|
||||
if (!instances || instances.length !== 1 || instances[0].employeeFk == userId || instances[0].amount > 0) {
|
||||
done();
|
||||
return;
|
||||
}
|
||||
|
||||
// el ultimo registro tiene valor 0, hay que comprobar que no fue editado por un gerente
|
||||
let sql = `SELECT count(distinct r.id) as hasManagerRole
|
||||
FROM ClientCredit cc
|
||||
JOIN Employee em ON (em.id = cc.employeeFk)
|
||||
JOIN Account ac ON (ac.id = em.userFk)
|
||||
JOIN RoleMapping rm ON (rm.principalId = ac.id)
|
||||
JOIN Role r on (r.id = rm.roleId)
|
||||
WHERE rm.principalType = 'USER'
|
||||
AND cc.employeeFk = ?
|
||||
AND r.\`name\` = 'manager'`;
|
||||
|
||||
Client.dataSource.connector.execute(sql, [instances[0].employeeFk], (_, res) => clientCreditCb(_, res));
|
||||
}
|
||||
|
||||
function clientCreditCb(_, instance) {
|
||||
if (!instance || (instance.length && instance[0].hasManagerRole > 0)) {
|
||||
done(generateErrorCredit());
|
||||
return;
|
||||
}
|
||||
done();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
[
|
||||
{
|
||||
"relation": "salesPerson",
|
||||
"scope": {
|
||||
"fields": ["id", "name", "surname"]
|
||||
}
|
||||
}, {
|
||||
"relation": "contactChannel",
|
||||
"scope": {
|
||||
"fields": ["id", "name"]
|
||||
}
|
||||
}, {
|
||||
"relation": "province",
|
||||
"scope": {
|
||||
"fields": ["id", "name"]
|
||||
}
|
||||
}, {
|
||||
"relation": "country",
|
||||
"scope": {
|
||||
"fields": ["id", "name"]
|
||||
}
|
||||
}, {
|
||||
"relation": "payMethod",
|
||||
"scope": {
|
||||
"fields": ["id", "name"]
|
||||
}
|
||||
}, {
|
||||
"relation": "account",
|
||||
"scope": {
|
||||
"fields": ["id", "name", "active"]
|
||||
}
|
||||
}
|
||||
]
|
|
@ -1,42 +0,0 @@
|
|||
module.exports = function(Client) {
|
||||
Client.remoteMethod('employeeList', {
|
||||
description: 'List employee',
|
||||
accessType: 'READ',
|
||||
returns: {
|
||||
arg: 'data',
|
||||
type: 'Employee',
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/employeeList`,
|
||||
verb: 'get'
|
||||
}
|
||||
});
|
||||
|
||||
let getEmployees = listEmployees => {
|
||||
let employees = [];
|
||||
listEmployees.forEach(function(e) {
|
||||
employees.push({id: e.id, name: e.name});
|
||||
}, this);
|
||||
return employees;
|
||||
};
|
||||
|
||||
Client.employeeList = function(callback) {
|
||||
let query = `SELECT em.id, CASE em.surname WHEN NULL THEN em.name ELSE concat(em.name, " ", em.surname) END \`name\`
|
||||
FROM salix.Employee em
|
||||
JOIN salix.Account ac ON em.userFk = ac.id
|
||||
JOIN salix.RoleMapping rm on ac.id=rm.principalId
|
||||
JOIN salix.Role rl on rm.roleId = rl.id
|
||||
WHERE ac.active
|
||||
and rl.\`name\`='employee'
|
||||
ORDER BY em.name ASC`;
|
||||
|
||||
Client.rawSql(query, [], callback)
|
||||
.then(response => {
|
||||
callback(null, getEmployees(response));
|
||||
})
|
||||
.catch(reject => {
|
||||
callback(reject, null);
|
||||
});
|
||||
};
|
||||
};
|
|
@ -1,45 +0,0 @@
|
|||
module.exports = Client => {
|
||||
Client.remoteMethod('getRoleCustomer', {
|
||||
description: 'devuelve true/false si es Customer el client',
|
||||
accessType: 'READ',
|
||||
accepts: [
|
||||
{
|
||||
arg: 'id',
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: 'Model id',
|
||||
http: {source: 'path'}
|
||||
},
|
||||
{
|
||||
arg: 'filter',
|
||||
type: 'object',
|
||||
required: true,
|
||||
description: 'Filter defining where',
|
||||
http: function(context) {
|
||||
return context.req.query;
|
||||
}
|
||||
}
|
||||
],
|
||||
returns: {
|
||||
arg: 'data',
|
||||
type: 'boolean',
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/:id/getRoleCustomer`,
|
||||
verb: 'get'
|
||||
}
|
||||
});
|
||||
|
||||
Client.getRoleCustomer = (id, context, callback) => {
|
||||
let query = `SELECT count(*) isCustomer FROM salix.Account ac JOIN salix.Role r ON r.id = ac.roleFK WHERE r.\`name\`='customer' AND ac.id IN (?)`;
|
||||
const params = [id];
|
||||
Client.rawSql(query, params, callback)
|
||||
.then(response => {
|
||||
callback(null, response[0]);
|
||||
})
|
||||
.catch(reject => {
|
||||
callback(reject, null);
|
||||
});
|
||||
};
|
||||
};
|
|
@ -1,6 +1,6 @@
|
|||
module.exports = Self => {
|
||||
Self.remoteMethod('sumAmount', {
|
||||
description: 'returns sum greuge.ammount from client',
|
||||
description: 'Returns the sum of greuge for a client',
|
||||
accessType: 'READ',
|
||||
accepts: [{
|
||||
arg: 'id',
|
||||
|
@ -19,16 +19,13 @@ module.exports = Self => {
|
|||
});
|
||||
|
||||
Self.sumAmount = (clientFk, callback) => {
|
||||
let query = `SELECT sum(amount) as sumAmount FROM vn.greuge WHERE clientFk = ?`;
|
||||
Self.rawSql(query, [clientFk], callback).then(response => {
|
||||
if (response.length) {
|
||||
callback(null, response[0].sumAmount);
|
||||
} else {
|
||||
callback(null, 0);
|
||||
}
|
||||
})
|
||||
.catch(reject => {
|
||||
callback(reject, null);
|
||||
});
|
||||
let query = `SELECT SUM(amount) AS sumAmount FROM vn.greuge WHERE clientFk = ?`;
|
||||
Self.rawSql(query, [clientFk])
|
||||
.then(response => {
|
||||
callback(null, response.length ? response[0].sumAmount : 0);
|
||||
})
|
||||
.catch(err => {
|
||||
callback(err);
|
||||
});
|
||||
};
|
||||
};
|
|
@ -1,75 +0,0 @@
|
|||
module.exports = function(Self) {
|
||||
Self.validate('default', isEnabled, {message: 'No se puede poner predeterminado un consignatario desactivado'});
|
||||
function isEnabled(err) {
|
||||
if (!this.isEnabled && this.isDefaultAddress) err();
|
||||
}
|
||||
|
||||
Self.beforeRemote('create', function(ctx, modelInstance, next) {
|
||||
var data = ctx.req.body;
|
||||
create(data, next);
|
||||
});
|
||||
|
||||
function create(data, next) {
|
||||
if (data.isDefaultAddress) {
|
||||
removeAllDefault(data, next);
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
}
|
||||
|
||||
Self.beforeRemote('prototype.patchAttributes', function(ctx, modelInstance, next) {
|
||||
let newData = ctx.req.body;
|
||||
newData.id = ctx.req.params.id;
|
||||
getAddress(ctx, newData, next);
|
||||
});
|
||||
|
||||
Self.beforeRemote('findById', function(ctx, modelInstance, next) {
|
||||
ctx.args.filter = {
|
||||
include: [{
|
||||
relation: "province",
|
||||
scope: {
|
||||
fields: ["id", "name"]
|
||||
}
|
||||
},
|
||||
{
|
||||
relation: "defaultAgency",
|
||||
scope: {
|
||||
fields: ["id", "name"]
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
next();
|
||||
});
|
||||
|
||||
function getAddress(ctx, newData, next) {
|
||||
Self.findOne({where: {id: newData.id}}, (_, oldData) => {
|
||||
if (oldData)
|
||||
callbackGetAddress(ctx, newData, oldData, next);
|
||||
});
|
||||
}
|
||||
|
||||
function callbackGetAddress(ctx, newData, oldData, next) {
|
||||
if (newData.isDefaultAddress) {
|
||||
removeAllDefault(oldData, next);
|
||||
} else if (oldData.isDefaultAddress && newData.hasOwnProperty('isDefaultAddress') && !newData.isDefaultAddress) {
|
||||
next(generateErrorDefaultAddress());
|
||||
} else
|
||||
next();
|
||||
}
|
||||
|
||||
function removeAllDefault(client, next) {
|
||||
if (client && client.clientFk)
|
||||
Self.updateAll({clientFk: client.clientFk, isDefaultAddress: {neq: 0}}, {isDefaultAddress: false}, next);
|
||||
else
|
||||
next();
|
||||
}
|
||||
|
||||
function generateErrorDefaultAddress() {
|
||||
var error = new Error();
|
||||
error.message = "No se puede desmarcar el consignatario predeterminado";
|
||||
error.status = 500;
|
||||
return error;
|
||||
}
|
||||
};
|
||||
|
|
@ -1,6 +1,11 @@
|
|||
{
|
||||
"name": "AgencyMode",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "agencyMode"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "Number",
|
||||
|
@ -20,7 +25,7 @@
|
|||
"inflation": {
|
||||
"type": "Number"
|
||||
},
|
||||
"sendMailTo": {
|
||||
"reportMail": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
|
|
|
@ -10,9 +10,9 @@ module.exports = function(Self) {
|
|||
limit: params.size,
|
||||
order: params.order || 'created DESC',
|
||||
include: {
|
||||
relation: "employee",
|
||||
relation: "worker",
|
||||
scope: {
|
||||
fields: ["id", "name", "surname"]
|
||||
fields: ["id", "firstName", "name"]
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -27,10 +27,10 @@
|
|||
"model": "Client",
|
||||
"foreignKey": "clientFk"
|
||||
},
|
||||
"employee": {
|
||||
"worker": {
|
||||
"type": "belongsTo",
|
||||
"model": "Employee",
|
||||
"foreignKey": "employeeFk"
|
||||
"model": "Worker",
|
||||
"foreignKey": "workerFk"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,13 +8,11 @@ module.exports = function(Self) {
|
|||
ctx.instance.created = Date();
|
||||
let token = ctx.options.accessToken;
|
||||
let userId = token && token.userId;
|
||||
let app = require('../../server/server');
|
||||
let Employee = app.models.Employee;
|
||||
Employee.findOne({where: {userFk: userId}}, (err, user) => {
|
||||
if (user) {
|
||||
ctx.instance.employeeFk = user.id;
|
||||
next();
|
||||
}
|
||||
|
||||
Self.app.models.Worker.findOne({where: {userFk: userId}}, (err, user) => {
|
||||
if (err) return next(err);
|
||||
ctx.instance.workerFk = user.id;
|
||||
next();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
|
|
@ -2,6 +2,11 @@
|
|||
"name": "ClientObservation",
|
||||
"description": "Notas de los clientes.",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "clientObservation"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "Number",
|
||||
|
@ -21,10 +26,10 @@
|
|||
}
|
||||
},
|
||||
"relations": {
|
||||
"employee": {
|
||||
"worker": {
|
||||
"type": "belongsTo",
|
||||
"model": "Employee",
|
||||
"foreignKey": "employeeFk"
|
||||
"model": "Worker",
|
||||
"foreignKey": "workerFk"
|
||||
},
|
||||
"client": {
|
||||
"type": "hasOne",
|
||||
|
@ -33,6 +38,6 @@
|
|||
}
|
||||
},
|
||||
"scope": {
|
||||
"include": "employee"
|
||||
"include": "worker"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,73 +0,0 @@
|
|||
var app = require('../../server/server');
|
||||
|
||||
module.exports = function(Self) {
|
||||
var models = app.models;
|
||||
|
||||
// Methods
|
||||
|
||||
require('../methods/client/activate.js')(Self);
|
||||
require('../methods/client/addresses.js')(Self);
|
||||
require('../methods/client/before-save.js')(Self);
|
||||
require('../methods/client/card.js')(Self);
|
||||
require('../methods/client/create.js')(Self);
|
||||
require('../methods/client/employee.js')(Self);
|
||||
require('../methods/client/filter.js')(Self);
|
||||
require('../methods/client/roles.js')(Self);
|
||||
require('../methods/client/salesperson.js')(Self);
|
||||
require('../methods/client/addressesPropagateRe.js')(Self);
|
||||
|
||||
// Validations
|
||||
|
||||
Self.validatesUniquenessOf('fi', {
|
||||
message: 'El NIF/CIF debe ser único'
|
||||
});
|
||||
Self.validatesUniquenessOf('socialName', {
|
||||
message: 'La razón social debe ser única'
|
||||
});
|
||||
Self.validatesFormatOf('postcode', {
|
||||
message: 'El código postal solo debe contener números',
|
||||
allowNull: true,
|
||||
allowBlank: true,
|
||||
with: /^\d+$/
|
||||
});
|
||||
Self.validatesFormatOf('email', {
|
||||
message: 'Correo electrónico inválido',
|
||||
allowNull: true,
|
||||
allowBlank: true,
|
||||
with: /^[\w|.|-]+@\w[\w|.|-]*\w(,[\w|.|-]+@\w[\w|.|-]*\w)*$/
|
||||
});
|
||||
Self.validatesLengthOf('postcode', {
|
||||
allowNull: true,
|
||||
allowBlank: true,
|
||||
min: 3, max: 10
|
||||
});
|
||||
|
||||
var validateIban = require('../validations/validateIban');
|
||||
Self.validateBinded('iban', validateIban, {
|
||||
message: 'El iban no tiene el formato correcto'
|
||||
});
|
||||
|
||||
let validateDni = require('../validations/validateDni');
|
||||
Self.validateBinded('fi', validateDni, {
|
||||
message: 'DNI Incorrecto'
|
||||
});
|
||||
|
||||
Self.validate('payMethod', hasSalesMan, {
|
||||
message: 'No se puede cambiar la forma de pago si no hay comercial asignado'
|
||||
});
|
||||
function hasSalesMan(err) {
|
||||
if (this.payMethod && !this.salesPerson)
|
||||
err();
|
||||
}
|
||||
Self.validateAsync('payMethodFk', hasIban, {
|
||||
message: 'El método de pago seleccionado requiere que se especifique el IBAN'
|
||||
});
|
||||
|
||||
function hasIban(err, done) {
|
||||
models.PayMethod.findById(this.payMethodFk, (_, instance) => {
|
||||
if (instance && instance.ibanRequired && !this.iban)
|
||||
err();
|
||||
done();
|
||||
});
|
||||
}
|
||||
};
|
|
@ -3,8 +3,7 @@
|
|||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "company",
|
||||
"database": "vn"
|
||||
"table": "company"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
|
|
|
@ -3,8 +3,7 @@
|
|||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "greugeType",
|
||||
"database": "vn"
|
||||
"table": "greugeType"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
module.exports = function(Self) {
|
||||
require('../methods/greuge/filter.js')(Self);
|
||||
require('../methods/greuge/total.js')(Self);
|
||||
require('../methods/greuge/sumAmount.js')(Self);
|
||||
|
||||
Self.validatesLengthOf('description', {
|
||||
max: 45,
|
||||
|
|
|
@ -3,8 +3,7 @@
|
|||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "greuge",
|
||||
"database": "vn"
|
||||
"table": "greuge"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
|
|
|
@ -3,8 +3,7 @@
|
|||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "mandate",
|
||||
"database": "vn"
|
||||
"table": "mandate"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
|
|
|
@ -3,8 +3,7 @@
|
|||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "mandateType",
|
||||
"database": "vn"
|
||||
"table": "mandateType"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
"dataSource": "salix"
|
||||
},
|
||||
"Account": {
|
||||
"dataSource": "salix"
|
||||
"dataSource": "account"
|
||||
},
|
||||
"Client": {
|
||||
"dataSource": "vn"
|
||||
|
@ -31,34 +31,34 @@
|
|||
"dataSource": "vn"
|
||||
},
|
||||
"ClientCreditLimit": {
|
||||
"dataSource": "salix"
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"ClientObservation": {
|
||||
"dataSource": "salix"
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"PayMethod": {
|
||||
"dataSource": "salix"
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"Address": {
|
||||
"dataSource": "salix"
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"AgencyMode": {
|
||||
"dataSource": "salix"
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"Province": {
|
||||
"dataSource": "salix"
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"Country": {
|
||||
"dataSource": "salix"
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"ContactChannel": {
|
||||
"dataSource": "salix"
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"Employee": {
|
||||
"dataSource": "salix"
|
||||
"Worker": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"CreditClassification": {
|
||||
"dataSource": "salix"
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"Greuge": {
|
||||
"dataSource": "vn"
|
||||
|
|
|
@ -3,15 +3,7 @@ FROM mysql:5.6.37
|
|||
ENV MYSQL_ALLOW_EMPTY_PASSWORD yes
|
||||
ENV TZ GMT-1
|
||||
|
||||
COPY localDB01StructureAccount.sql /docker-entrypoint-initdb.d
|
||||
COPY localDB02StructureVn2008.sql /docker-entrypoint-initdb.d
|
||||
COPY localDB03StructureVn.sql /docker-entrypoint-initdb.d
|
||||
COPY localDB04StructureOthersDB.sql /docker-entrypoint-initdb.d
|
||||
COPY localDB05StructureUtil.sql /docker-entrypoint-initdb.d
|
||||
COPY localDB06ViewsVn.sql /docker-entrypoint-initdb.d
|
||||
COPY localDB07OthersViews.sql /docker-entrypoint-initdb.d
|
||||
COPY localDB08Views2008.sql /docker-entrypoint-initdb.d
|
||||
COPY localDB09Inserts.sql /docker-entrypoint-initdb.d
|
||||
COPY *.sql /docker-entrypoint-initdb.d/
|
||||
|
||||
RUN chmod -R 755 /docker-entrypoint-initdb.d
|
||||
|
||||
|
|
|
@ -3,8 +3,7 @@
|
|||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "expence",
|
||||
"database": "vn"
|
||||
"table": "expence"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
|
|
|
@ -3,8 +3,7 @@
|
|||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "ink",
|
||||
"database": "vn"
|
||||
"table": "ink"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
|
|
|
@ -3,8 +3,7 @@
|
|||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "intrastat",
|
||||
"database": "vn"
|
||||
"table": "intrastat"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
|
|
|
@ -3,8 +3,7 @@
|
|||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "itemType",
|
||||
"database": "vn"
|
||||
"table": "itemType"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
|
|
|
@ -3,8 +3,7 @@
|
|||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "item",
|
||||
"database": "vn"
|
||||
"table": "item"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
|
|
|
@ -3,8 +3,7 @@
|
|||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "origin",
|
||||
"database": "vn"
|
||||
"table": "origin"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
|
|
|
@ -3,8 +3,7 @@
|
|||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "producer",
|
||||
"database": "vn"
|
||||
"table": "producer"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
|
|
|
@ -3,8 +3,7 @@
|
|||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "taxClass",
|
||||
"database": "vn"
|
||||
"table": "taxClass"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
|
|
|
@ -3,8 +3,7 @@
|
|||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "taxCode",
|
||||
"database": "vn"
|
||||
"table": "taxCode"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
|
|
|
@ -3,8 +3,7 @@
|
|||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "taxType",
|
||||
"database": "vn"
|
||||
"table": "taxType"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
|
||||
exports.UserError = class extends Error {
|
||||
constructor(message) {
|
||||
super(message);
|
||||
this.statusCode = 400;
|
||||
}
|
||||
};
|
||||
|
||||
exports.getFinalState = function(ctx) {
|
||||
if (ctx.isNewInstance)
|
||||
return ctx.instance;
|
||||
if (ctx.currentInstance)
|
||||
return Object.assign({},
|
||||
ctx.currentInstance.__data,
|
||||
ctx.data || ctx.instance
|
||||
);
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
exports.isMultiple = function(ctx) {
|
||||
return !ctx.isNewInstance && !ctx.currentInstance;
|
||||
};
|
|
@ -1,3 +0,0 @@
|
|||
module.exports = function(Self) {
|
||||
Self.defineScope({where: {isManaged: {neq: 0}}});
|
||||
};
|
|
@ -0,0 +1,62 @@
|
|||
var request = require('request');
|
||||
|
||||
module.exports = function(Self) {
|
||||
Self.remoteMethod('activate', {
|
||||
description: 'Activate or deactive client',
|
||||
accepts: [
|
||||
{
|
||||
arg: 'id',
|
||||
type: 'number',
|
||||
required: true,
|
||||
description: 'Model id',
|
||||
http: {source: 'path'}
|
||||
}, {
|
||||
arg: 'context',
|
||||
type: 'object',
|
||||
http: function(ctx) {
|
||||
return ctx;
|
||||
}
|
||||
}
|
||||
],
|
||||
returns: {
|
||||
arg: 'active',
|
||||
type: 'boolean'
|
||||
},
|
||||
http: {
|
||||
verb: 'put',
|
||||
path: '/:id/activate'
|
||||
}
|
||||
});
|
||||
|
||||
Self.activate = function(id, ctx, cb) {
|
||||
Self.findById(id, function(err, client) {
|
||||
if (err) return cb(err);
|
||||
|
||||
Self.update({id: client.id}, {active: !client.active});
|
||||
|
||||
let filter = {where: {clientFk: client.id}, fields: ['started', 'ended']};
|
||||
|
||||
Self.app.models.CreditClassification.findOne(filter, function(error, data) {
|
||||
if (error) return;
|
||||
|
||||
let currentDate = new Date();
|
||||
|
||||
if (data && client.active && (data.ended >= currentDate || data.ended == null)) {
|
||||
let referer = ctx.req.headers.referer;
|
||||
var options = {
|
||||
url: `${referer}/mailer/notification/client-deactivate/${client.id}`,
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: ctx.req.headers.authorization
|
||||
},
|
||||
json: {}
|
||||
};
|
||||
request(options);
|
||||
}
|
||||
});
|
||||
|
||||
cb(null, !client.active);
|
||||
});
|
||||
};
|
||||
};
|
|
@ -1,6 +1,6 @@
|
|||
module.exports = Client => {
|
||||
Client.remoteMethod('activeSalesPerson', {
|
||||
description: 'returns actives employees with salesperson role',
|
||||
description: 'Returns actives workers with salesperson role',
|
||||
accessType: 'READ',
|
||||
accepts: [{
|
||||
arg: 'filter',
|
||||
|
@ -11,7 +11,7 @@ module.exports = Client => {
|
|||
}],
|
||||
returns: {
|
||||
arg: 'data',
|
||||
type: 'Employee',
|
||||
type: 'Worker',
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
|
@ -25,21 +25,19 @@ module.exports = Client => {
|
|||
let limit = filter.limit || 10;
|
||||
let where = getCondition(filter.where, limit, skip);
|
||||
|
||||
let query = `SELECT em.id, em.name, em.surname
|
||||
FROM salix.Employee em
|
||||
JOIN salix.Account ac ON em.userFk = ac.id
|
||||
JOIN salix.Role r ON r.id = ac.roleFK
|
||||
WHERE ac.active AND r.\`name\`='salesPerson' ${where.sql}
|
||||
ORDER BY em.name ASC
|
||||
LIMIT ? OFFSET ?`;
|
||||
let query =
|
||||
`SELECT em.id, em.firstName, em.name
|
||||
FROM worker em
|
||||
JOIN account.user ac ON em.userFk = ac.id
|
||||
JOIN account.role r ON r.id = ac.role
|
||||
WHERE ac.active AND r.\`name\` = 'salesPerson' ${where.sql}
|
||||
ORDER BY em.name ASC
|
||||
LIMIT ? OFFSET ?`;
|
||||
|
||||
Client.rawSql(query, where.params, callback)
|
||||
.then(response => {
|
||||
callback(null, formatSalesPerson(response));
|
||||
})
|
||||
.catch(reject => {
|
||||
callback(reject, null);
|
||||
});
|
||||
Client.rawSql(query, where.params).then(
|
||||
response => callback(null, formatSalesPerson(response)),
|
||||
err => callback(err)
|
||||
);
|
||||
};
|
||||
|
||||
function getCondition(where, limit, skip) {
|
||||
|
@ -48,7 +46,7 @@ module.exports = Client => {
|
|||
params: []
|
||||
};
|
||||
if (where && where.or) {
|
||||
out.sql = `AND (em.name regexp ? OR em.surname regexp ?)`;
|
||||
out.sql = `AND (em.firstName regexp ? OR em.name regexp ?)`;
|
||||
where.or.forEach(val => {
|
||||
Object.keys(val).forEach(key => {
|
||||
out.params.push(val[key].regexp);
|
||||
|
@ -66,7 +64,7 @@ module.exports = Client => {
|
|||
response.forEach(person => {
|
||||
results.push({
|
||||
id: person.id,
|
||||
name: `${person.name} ${person.surname}`
|
||||
name: `${person.firstName} ${person.name}`
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
module.exports = function(Client) {
|
||||
Client.remoteMethod('addressesPropagateRe', {
|
||||
description: 'Change property isEqualizated in all client addresses',
|
||||
accessType: 'WRITE',
|
||||
accepts: [
|
||||
{
|
||||
arg: 'id',
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: 'Client id',
|
||||
http: {source: 'path'}
|
||||
},
|
||||
{
|
||||
arg: 'data',
|
||||
type: 'Object',
|
||||
required: true,
|
||||
description: 'data with new value',
|
||||
http: {source: 'body'}
|
||||
}
|
||||
],
|
||||
returns: {
|
||||
arg: 'data',
|
||||
type: 'boolean',
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/:id/addressesPropagateRe`,
|
||||
verb: 'patch'
|
||||
}
|
||||
});
|
||||
|
||||
Client.addressesPropagateRe = (id, data, callback) => {
|
||||
if (data.hasOwnProperty('isEqualizated')) {
|
||||
Client.app.models.Address.updateAll({clientFk: id}, data, (err, info) => {
|
||||
if (err)
|
||||
return callback(err, null);
|
||||
callback(null, true);
|
||||
});
|
||||
} else {
|
||||
callback(null, false);
|
||||
}
|
||||
};
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
module.exports = function(Self) {
|
||||
Self.remoteMethod('card', {
|
||||
description: 'Get client basic data',
|
||||
accepts: {
|
||||
arg: 'id',
|
||||
type: 'number',
|
||||
required: true,
|
||||
description: 'The client id',
|
||||
http: {source: 'path'}
|
||||
},
|
||||
returns: {
|
||||
arg: 'data',
|
||||
type: 'Object',
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
verb: 'GET',
|
||||
path: '/:id/card'
|
||||
}
|
||||
});
|
||||
|
||||
Self.card = function(id, cb) {
|
||||
let filter = {
|
||||
where: {
|
||||
id: id
|
||||
},
|
||||
include: [
|
||||
{
|
||||
relation: 'salesPerson',
|
||||
scope: {
|
||||
fields: ['id', 'firstName', 'name']
|
||||
}
|
||||
}, {
|
||||
relation: 'contactChannel',
|
||||
scope: {
|
||||
fields: ['id', 'name']
|
||||
}
|
||||
}, {
|
||||
relation: 'province',
|
||||
scope: {
|
||||
fields: ['id', 'name']
|
||||
}
|
||||
}, {
|
||||
relation: 'country',
|
||||
scope: {
|
||||
fields: ['id', 'country']
|
||||
}
|
||||
}, {
|
||||
relation: 'payMethod',
|
||||
scope: {
|
||||
fields: ['id', 'name']
|
||||
}
|
||||
}, {
|
||||
relation: 'account',
|
||||
scope: {
|
||||
fields: ['id', 'name', 'active']
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
Self.findOne(filter, function(err, card) {
|
||||
if (err) return cb(err);
|
||||
|
||||
let formatedCard = JSON.parse(JSON.stringify(card));
|
||||
|
||||
if (formatedCard.salesPersonFk)
|
||||
formatedCard.salesPerson = {
|
||||
id: card.salesPerson().id,
|
||||
name: `${card.salesPerson().firstName} ${card.salesPerson().name}`
|
||||
};
|
||||
|
||||
cb(null, formatedCard);
|
||||
});
|
||||
};
|
||||
};
|
|
@ -0,0 +1,60 @@
|
|||
let md5 = require('md5');
|
||||
|
||||
module.exports = function(Self) {
|
||||
Self.remoteMethod('createWithUser', {
|
||||
description: 'Creates both client and its web account',
|
||||
accepts: {
|
||||
arg: 'data',
|
||||
type: 'object',
|
||||
http: {source: 'body'}
|
||||
},
|
||||
returns: {
|
||||
root: true,
|
||||
type: 'boolean'
|
||||
},
|
||||
http: {
|
||||
verb: 'post',
|
||||
path: '/createWithUser'
|
||||
}
|
||||
});
|
||||
|
||||
Self.createWithUser = (data, callback) => {
|
||||
let firstEmail = data.email ? data.email.split(',')[0] : null;
|
||||
let user = {
|
||||
name: data.userName,
|
||||
email: firstEmail,
|
||||
password: md5(parseInt(Math.random() * 100000000000000))
|
||||
};
|
||||
let Account = Self.app.models.Account;
|
||||
|
||||
Account.beginTransaction({}, (error, transaction) => {
|
||||
if (error) return callback(error);
|
||||
|
||||
Account.create(user, {transaction}, (error, account) => {
|
||||
if (error) {
|
||||
transaction.rollback();
|
||||
return callback(error);
|
||||
}
|
||||
|
||||
let client = {
|
||||
name: data.name,
|
||||
fi: data.fi,
|
||||
socialName: data.socialName,
|
||||
id: account.id,
|
||||
email: data.email,
|
||||
salesPersonFk: data.salesPersonFk
|
||||
};
|
||||
|
||||
Self.create(client, {transaction}, (error, newClient) => {
|
||||
if (error) {
|
||||
transaction.rollback();
|
||||
return callback(error);
|
||||
}
|
||||
|
||||
transaction.commit();
|
||||
callback(null, newClient);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
};
|
|
@ -0,0 +1,45 @@
|
|||
module.exports = Self => {
|
||||
Self.remoteMethod('hasCustomerRole', {
|
||||
description: 'Comprueba si un usuario tiene el rol de cliente',
|
||||
accessType: 'READ',
|
||||
accepts: [
|
||||
{
|
||||
arg: 'id',
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: 'The user id',
|
||||
http: {source: 'path'}
|
||||
}, {
|
||||
arg: 'context',
|
||||
type: 'object',
|
||||
required: true,
|
||||
description: 'Filter defining where',
|
||||
http: function(context) {
|
||||
return context.req.query;
|
||||
}
|
||||
}
|
||||
],
|
||||
returns: {
|
||||
type: 'boolean',
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/:id/hasCustomerRole`,
|
||||
verb: 'GET'
|
||||
}
|
||||
});
|
||||
|
||||
Self.hasCustomerRole = (id, context, callback) => {
|
||||
let query =
|
||||
`SELECT COUNT(*) > 0 isCustomer
|
||||
FROM salix.Account A
|
||||
JOIN salix.Role r ON r.id = A.roleFK
|
||||
WHERE r.name = 'customer'
|
||||
AND A.id IN (?)`;
|
||||
|
||||
Self.rawSql(query, [id]).then(
|
||||
instances => callback(null, instances[0]),
|
||||
err => callback(err)
|
||||
);
|
||||
};
|
||||
};
|
|
@ -0,0 +1,70 @@
|
|||
module.exports = function(Client) {
|
||||
Client.remoteMethod('listAddresses', {
|
||||
description: 'List items using a filter',
|
||||
accessType: 'READ',
|
||||
accepts: [
|
||||
{
|
||||
arg: 'id',
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: 'Model id',
|
||||
http: {source: 'path'}
|
||||
},
|
||||
{
|
||||
arg: 'filter',
|
||||
type: 'object',
|
||||
required: true,
|
||||
description: 'Filter defining where',
|
||||
http: function(ctx) {
|
||||
return ctx.req.query;
|
||||
}
|
||||
}
|
||||
],
|
||||
returns: {
|
||||
arg: 'data',
|
||||
type: ['Address'],
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/:id/listAddresses`,
|
||||
verb: 'GET'
|
||||
}
|
||||
});
|
||||
|
||||
Client.listAddresses = function(id, params, callback) {
|
||||
let filter = {
|
||||
where: {
|
||||
clientFk: id
|
||||
},
|
||||
skip: (params.page - 1) * params.size,
|
||||
limit: params.size,
|
||||
order: ['isDefaultAddress DESC', 'isActive DESC']
|
||||
};
|
||||
|
||||
let total = null;
|
||||
let items = null;
|
||||
|
||||
function response(type, value) {
|
||||
if (type === 'total') {
|
||||
total = value;
|
||||
} else {
|
||||
items = value;
|
||||
}
|
||||
|
||||
if (total !== null && items !== null) {
|
||||
callback(null, {total: total, items: items});
|
||||
}
|
||||
}
|
||||
|
||||
Client.app.models.Address.find(filter, function(err, instances) {
|
||||
if (err) return callback(err);
|
||||
response('find', instances);
|
||||
});
|
||||
|
||||
Client.app.models.Address.count(filter.where, function(err, total) {
|
||||
if (err) return callback(err);
|
||||
response('total', total);
|
||||
});
|
||||
};
|
||||
|
||||
};
|
|
@ -0,0 +1,30 @@
|
|||
module.exports = function(Self) {
|
||||
Self.remoteMethod('listWorkers', {
|
||||
description: 'List workers',
|
||||
accessType: 'READ',
|
||||
returns: {
|
||||
arg: 'data',
|
||||
type: 'Worker',
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/listWorkers`,
|
||||
verb: 'GET'
|
||||
}
|
||||
});
|
||||
|
||||
Self.listWorkers = function() {
|
||||
let query =
|
||||
`SELECT w.id,
|
||||
CONCAT(w.firstName, IFNULL(CONCAT(" ", w.name), "")) \`name\`
|
||||
FROM worker w
|
||||
JOIN account.user u ON w.userFk = u.id
|
||||
JOIN account.roleRole rr ON rr.role = u.role
|
||||
JOIN account.role r ON r.id = rr.inheritsFrom
|
||||
WHERE u.active
|
||||
AND r.\`name\` = 'employee'
|
||||
ORDER BY w.name ASC`;
|
||||
|
||||
return Self.rawSql(query);
|
||||
};
|
||||
};
|
|
@ -1,3 +0,0 @@
|
|||
module.exports = function(Self) {
|
||||
Self.defineScope({where: {isManaged: {neq: 0}}});
|
||||
};
|
|
@ -1,6 +1,11 @@
|
|||
{
|
||||
"name": "Account",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "user"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "number",
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
var UserError = require('../helpers').UserError;
|
||||
var getFinalState = require('../helpers').getFinalState;
|
||||
var isMultiple = require('../helpers').isMultiple;
|
||||
|
||||
module.exports = function(Self) {
|
||||
Self.validate('isDefaultAddress', isActive,
|
||||
{message: 'No se puede poner predeterminado un consignatario desactivado'}
|
||||
);
|
||||
function isActive(err) {
|
||||
if (!this.isActive && this.isDefaultAddress) err();
|
||||
}
|
||||
|
||||
Self.beforeRemote('findById', function(ctx, modelInstance, next) {
|
||||
ctx.args.filter = {
|
||||
include: [{
|
||||
relation: 'province',
|
||||
scope: {
|
||||
fields: ['id', 'name']
|
||||
}
|
||||
}, {
|
||||
relation: 'agency',
|
||||
scope: {
|
||||
fields: ['id', 'name']
|
||||
}
|
||||
}]
|
||||
};
|
||||
next();
|
||||
});
|
||||
|
||||
// Helpers
|
||||
|
||||
Self.observe('before save', async function(ctx) {
|
||||
if (isMultiple(ctx)) return;
|
||||
|
||||
let changes = ctx.data || ctx.instance;
|
||||
let finalState = getFinalState(ctx);
|
||||
|
||||
if (changes.isActive == false && finalState.isDefaultAddress)
|
||||
throw new UserError('No se puede desmarcar el consignatario predeterminado');
|
||||
|
||||
if (changes.isDefaultAddress == true) {
|
||||
let filter = {
|
||||
clientFk: finalState.clientFk,
|
||||
isDefaultAddress: {neq: false}
|
||||
};
|
||||
await Self.updateAll(filter, {isDefaultAddress: false});
|
||||
}
|
||||
});
|
||||
};
|
|
@ -1,13 +1,18 @@
|
|||
{
|
||||
"name": "Address",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "address"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "Number",
|
||||
"id": true,
|
||||
"description": "Identifier"
|
||||
},
|
||||
"consignee": {
|
||||
"nickname": {
|
||||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
|
@ -19,7 +24,7 @@
|
|||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
"postcode": {
|
||||
"postalCode": {
|
||||
"type": "string"
|
||||
},
|
||||
"phone": {
|
||||
|
@ -28,7 +33,7 @@
|
|||
"mobile": {
|
||||
"type": "string"
|
||||
},
|
||||
"isEnabled": {
|
||||
"isActive": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"isDefaultAddress": {
|
||||
|
@ -56,10 +61,10 @@
|
|||
"model": "Client",
|
||||
"foreignKey": "clientFk"
|
||||
},
|
||||
"defaultAgency": {
|
||||
"agency": {
|
||||
"type": "belongsTo",
|
||||
"model": "AgencyMode",
|
||||
"foreignKey": "defaultAgencyFk"
|
||||
"foreignKey": "agencyFk"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,3 +1,3 @@
|
|||
module.exports = function(Self) {
|
||||
require('../methods/agency/list.js')(Self);
|
||||
Self.defineScope({where: {isManaged: {neq: 0}}});
|
||||
};
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
{
|
||||
"name": "Agency",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "agency"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"id": true,
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
{
|
||||
"name": "ClientCreditLimit",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "clientCreditLimit"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "Number",
|
|
@ -0,0 +1,160 @@
|
|||
var UserError = require('../helpers').UserError;
|
||||
var getFinalState = require('../helpers').getFinalState;
|
||||
var isMultiple = require('../helpers').isMultiple;
|
||||
|
||||
module.exports = function(Self) {
|
||||
// Methods
|
||||
|
||||
require('../methods/client/activate')(Self);
|
||||
require('../methods/client/listAddresses')(Self);
|
||||
require('../methods/client/card')(Self);
|
||||
require('../methods/client/createWithUser')(Self);
|
||||
require('../methods/client/listWorkers')(Self);
|
||||
require('../methods/client/filter')(Self);
|
||||
require('../methods/client/hasCustomerRole')(Self);
|
||||
require('../methods/client/activeSalesPerson')(Self);
|
||||
require('../methods/client/addressesPropagateRe')(Self);
|
||||
|
||||
// Validations
|
||||
|
||||
Self.validatesUniquenessOf('fi', {
|
||||
message: 'El NIF/CIF debe ser único'
|
||||
});
|
||||
Self.validatesUniquenessOf('socialName', {
|
||||
message: 'La razón social debe ser única'
|
||||
});
|
||||
Self.validatesFormatOf('postcode', {
|
||||
message: 'El código postal solo debe contener números',
|
||||
allowNull: true,
|
||||
allowBlank: true,
|
||||
with: /^\d+$/
|
||||
});
|
||||
Self.validatesFormatOf('email', {
|
||||
message: 'Correo electrónico inválido',
|
||||
allowNull: true,
|
||||
allowBlank: true,
|
||||
with: /^[\w|.|-]+@\w[\w|.|-]*\w(,[\w|.|-]+@\w[\w|.|-]*\w)*$/
|
||||
});
|
||||
Self.validatesLengthOf('postcode', {
|
||||
allowNull: true,
|
||||
allowBlank: true,
|
||||
min: 3, max: 10
|
||||
});
|
||||
|
||||
var validateIban = require('../validations/validateIban');
|
||||
Self.validateBinded('iban', validateIban, {
|
||||
message: 'El iban no tiene el formato correcto'
|
||||
});
|
||||
|
||||
let validateDni = require('../validations/validateDni');
|
||||
Self.validateBinded('fi', validateDni, {
|
||||
message: 'DNI Incorrecto'
|
||||
});
|
||||
|
||||
Self.validate('payMethod', hasSalesMan, {
|
||||
message: 'No se puede cambiar la forma de pago si no hay comercial asignado'
|
||||
});
|
||||
function hasSalesMan(err) {
|
||||
if (this.payMethod && !this.salesPerson)
|
||||
err();
|
||||
}
|
||||
|
||||
Self.validateAsync('payMethodFk', hasIban, {
|
||||
message: 'El método de pago seleccionado requiere que se especifique el IBAN'
|
||||
});
|
||||
function hasIban(err, done) {
|
||||
Self.app.models.PayMethod.findById(this.payMethodFk, (_, instance) => {
|
||||
if (instance && instance.ibanRequired && !this.iban)
|
||||
err();
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
// Hooks
|
||||
|
||||
Self.observe('before save', async function(ctx) {
|
||||
let changes = ctx.data || ctx.instance;
|
||||
let finalState = getFinalState(ctx);
|
||||
|
||||
if (changes.salesPerson === null) {
|
||||
changes.credit = 0;
|
||||
changes.discount = 0;
|
||||
changes.payMethodFk = 5; // Credit card
|
||||
}
|
||||
|
||||
if (changes.payMethodFk !== undefined && changes.dueDay === undefined)
|
||||
changes.dueDay = 5;
|
||||
|
||||
if (isMultiple(ctx)) return;
|
||||
|
||||
if (changes.isEqualizated || changes.fi !== undefined) {
|
||||
let fiLetter = finalState.fi && finalState.fi.toUpperCase().charAt(0);
|
||||
let canMarkEqualizationTax = fiLetter != 'A' && fiLetter != 'B';
|
||||
|
||||
if (finalState.isEqualizated && !canMarkEqualizationTax)
|
||||
throw new UserError('No se puede marcar el recargo de equivalencia');
|
||||
}
|
||||
|
||||
if (changes.credit !== undefined)
|
||||
try {
|
||||
await validateCreditChange(ctx, finalState);
|
||||
} catch (e) {
|
||||
throw new UserError('No tienes privilegios para modificar el crédito');
|
||||
}
|
||||
});
|
||||
|
||||
async function validateCreditChange(ctx, finalState) {
|
||||
let models = Self.app.models;
|
||||
let userId = ctx.options.accessToken.userId;
|
||||
let filter = {
|
||||
fields: ['roleFk'],
|
||||
where: {
|
||||
maxAmount: {gt: ctx.data.credit}
|
||||
}
|
||||
};
|
||||
|
||||
let limits = await models.ClientCreditLimit.find(filter);
|
||||
|
||||
if (limits.length == 0)
|
||||
throw new Error('Credit limits not found');
|
||||
|
||||
// Si el usuario no tiene alguno de los roles no continua
|
||||
|
||||
let requiredRoles = [];
|
||||
for (limit of limits)
|
||||
requiredRoles.push(limit.roleFk);
|
||||
|
||||
let where = {
|
||||
roleId: {inq: requiredRoles},
|
||||
principalType: 'USER',
|
||||
principalId: userId
|
||||
};
|
||||
let count = await models.RoleMapping.count(where);
|
||||
|
||||
if (count <= 0)
|
||||
throw new Error('The role cannot set this credit amount');
|
||||
|
||||
// Si se puso a 0 por gerencia, solo gerencia puede aumentarlo
|
||||
|
||||
let query = 'SELECT * FROM clientCredit WHERE clientFk = ? ORDER BY created DESC LIMIT 1';
|
||||
let instances = await Self.rawSql(query, [finalState.id]);
|
||||
|
||||
if (instances.length !== 1 || instances[0].workerFk == userId || instances[0].amount > 0)
|
||||
return;
|
||||
|
||||
query = `SELECT COUNT(distinct r.id) > 0 as hasManagerRole
|
||||
FROM clientCredit cc
|
||||
JOIN worker em ON em.id = cc.workerFk
|
||||
JOIN account.user ac ON ac.id = em.userFk
|
||||
JOIN salix.RoleMapping rm ON rm.principalId = ac.id
|
||||
JOIN account.role r on r.id = rm.roleId
|
||||
WHERE rm.principalType = 'USER'
|
||||
AND cc.workerFk = ?
|
||||
AND r.name = 'manager'`;
|
||||
|
||||
let instance = await Self.rawSql(query, [instances[0].workerFk]);
|
||||
|
||||
if (instance[0].hasManagerRole > 0)
|
||||
throw new Error('Only manager can change the credit');
|
||||
}
|
||||
};
|
|
@ -3,8 +3,7 @@
|
|||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "client",
|
||||
"database": "vn"
|
||||
"table": "client"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
|
@ -121,7 +120,7 @@
|
|||
},
|
||||
"salesPerson": {
|
||||
"type": "belongsTo",
|
||||
"model": "Employee",
|
||||
"model": "Worker",
|
||||
"foreignKey": "salesPersonFk"
|
||||
},
|
||||
"province":{
|
|
@ -1,6 +1,11 @@
|
|||
{
|
||||
"name": "ContactChannel",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "contactChannel"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "Number",
|
|
@ -1,19 +1,21 @@
|
|||
{
|
||||
"name": "Country",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "country"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "Number",
|
||||
"id": true,
|
||||
"description": "Identifier"
|
||||
},
|
||||
"name": {
|
||||
"country": {
|
||||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
"inCee": {
|
||||
"type": "Number"
|
||||
},
|
||||
"code": {
|
||||
"type": "string"
|
||||
}
|
||||
|
@ -23,11 +25,6 @@
|
|||
"type": "belongsTo",
|
||||
"model": "Currency",
|
||||
"foreignKey": "currencyFk"
|
||||
},
|
||||
"realCountry": {
|
||||
"type": "belongsTo",
|
||||
"model": "Country",
|
||||
"foreignKey": "realCountryFk"
|
||||
}
|
||||
},
|
||||
"acls": [
|
||||
|
|
|
@ -2,6 +2,11 @@
|
|||
"name": "CreditClassification",
|
||||
"description": "Clientes clasificados.",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "creditClassification"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"id": true,
|
|
@ -1,6 +1,11 @@
|
|||
{
|
||||
"name": "PayMethod",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "payMethod"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "Number",
|
|
@ -1,6 +1,11 @@
|
|||
{
|
||||
"name": "Province",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "province"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "Number",
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue