Merge branch 'dev' of https://git.verdnatura.es/salix into dev
This commit is contained in:
commit
a6994b0179
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"salixHost": "localhost",
|
||||||
|
"salixPort": "3306",
|
||||||
|
"salixUser": "root",
|
||||||
|
"salixPassword": "root"
|
||||||
|
}
|
|
@ -6,10 +6,14 @@ def branchTest = "test";
|
||||||
|
|
||||||
env.BRANCH_NAME = branchName;
|
env.BRANCH_NAME = branchName;
|
||||||
env.TAG = "${env.BUILD_NUMBER}";
|
env.TAG = "${env.BUILD_NUMBER}";
|
||||||
|
env.salixUser="${env.salixUser}";
|
||||||
|
env.salixPassword="${env.salixPassword}";
|
||||||
|
|
||||||
switch (branchName){
|
switch (branchName){
|
||||||
case branchTest:
|
case branchTest:
|
||||||
env.NODE_ENV = "test";
|
env.NODE_ENV = "test";
|
||||||
|
env.salixHost = "${env.testSalixHost}";
|
||||||
|
env.salixPort = "${env.testSalixPort}";
|
||||||
break;
|
break;
|
||||||
case branchProduction:
|
case branchProduction:
|
||||||
env.DOCKER_HOST = "tcp://172.16.255.29:2375";
|
env.DOCKER_HOST = "tcp://172.16.255.29:2375";
|
||||||
|
@ -20,7 +24,7 @@ switch (branchName){
|
||||||
node
|
node
|
||||||
{
|
{
|
||||||
stage ('Print environment variables'){
|
stage ('Print environment variables'){
|
||||||
echo "Branch ${branchName}, Build ${env.TAG}, NODE_ENV ${env.NODE_ENV} en docker Host ${env.DOCKER_HOST}"
|
echo "Branch ${branchName}, Build ${env.TAG}, salixHost ${env.salixHost}, NODE_ENV ${env.NODE_ENV} en docker Host ${env.DOCKER_HOST}"
|
||||||
}
|
}
|
||||||
stage ('Checkout') {
|
stage ('Checkout') {
|
||||||
checkout scm
|
checkout scm
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"module": "client",
|
"module": "client",
|
||||||
"name": "Clients",
|
"name": "Clients",
|
||||||
"icon": "/static/images/icon_client.png",
|
"icon": "person",
|
||||||
"validations" : true,
|
"validations" : true,
|
||||||
"routes": [
|
"routes": [
|
||||||
{
|
{
|
||||||
|
|
|
@ -59,9 +59,7 @@
|
||||||
field="observation.observationTypeFk"
|
field="observation.observationTypeFk"
|
||||||
data="observationsTypes.model"
|
data="observationsTypes.model"
|
||||||
show-field="description"
|
show-field="description"
|
||||||
label="Observation type"
|
label="Observation type">
|
||||||
order="description ASC"
|
|
||||||
filter-search="{where: {description: {regexp: 'search'}}}">
|
|
||||||
<tpl-item>{{$parent.$parent.item.description}}</tpl-item>
|
<tpl-item>{{$parent.$parent.item.description}}</tpl-item>
|
||||||
</vn-autocomplete>
|
</vn-autocomplete>
|
||||||
<vn-textfield
|
<vn-textfield
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
<span>{{::observation.description}}</span>
|
<span>{{::observation.description}}</span>
|
||||||
</vn-one>
|
</vn-one>
|
||||||
</vn-vertical>
|
</vn-vertical>
|
||||||
<a vn-auto ui-sref="clientCard.addresses.edit({addressId: {{address.id}}})">
|
<a vn-auto ui-sref="clientCard.addresses.edit({addressId: {{::address.id}}})">
|
||||||
<vn-icon-button icon="edit"></vn-icon-button>
|
<vn-icon-button icon="edit"></vn-icon-button>
|
||||||
</a>
|
</a>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
value-field="id"
|
value-field="id"
|
||||||
select-fields="name"
|
select-fields="name"
|
||||||
label="Salesperson"
|
label="Salesperson"
|
||||||
filter-search="{where: {or: [{name: {regexp: 'search'}}, {name: {regexp: 'search'}}]}}">
|
where="{or: [{firstName: {regexp: 'search'}}, {name: {regexp: 'search'}}]}">
|
||||||
</vn-autocomplete>
|
</vn-autocomplete>
|
||||||
<vn-autocomplete vn-one
|
<vn-autocomplete vn-one
|
||||||
initial-data="$ctrl.client.contactChannel"
|
initial-data="$ctrl.client.contactChannel"
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
value-field="id"
|
value-field="id"
|
||||||
select-fields="name"
|
select-fields="name"
|
||||||
label="Salesperson"
|
label="Salesperson"
|
||||||
filter-search="{where: {or: [{name: {regexp: 'search'}}, {name: {regexp: 'search'}}]}}">
|
where="{or: [{firstName: {regexp: 'search'}}, {name: {regexp: 'search'}}]}">
|
||||||
</vn-autocomplete>
|
</vn-autocomplete>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
</vn-card>
|
</vn-card>
|
||||||
|
|
|
@ -25,6 +25,7 @@ class ClientDescriptor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ClientDescriptor.$inject = ['$http'];
|
||||||
|
|
||||||
ngModule.component('vnClientDescriptor', {
|
ngModule.component('vnClientDescriptor', {
|
||||||
template: require('./descriptor.html'),
|
template: require('./descriptor.html'),
|
||||||
|
|
|
@ -9,13 +9,6 @@ vn-autocomplete > div > .mdl-textfield {
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
&:focus {
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
&::-moz-focus-inner {
|
|
||||||
border: 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
& > .icons {
|
& > .icons {
|
||||||
display: none;
|
display: none;
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
vn-date-picker {
|
vn-date-picker {
|
||||||
div {
|
|
||||||
outline: none; //remove chrome outline
|
|
||||||
}
|
|
||||||
.mdl-chip__action {
|
.mdl-chip__action {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: auto;
|
width: auto;
|
||||||
|
|
|
@ -1,35 +1,38 @@
|
||||||
<div
|
<vn-model
|
||||||
class="body"
|
vn-id="model"
|
||||||
ng-mousedown="$ctrl.onMouseDown($event)">
|
on-data-change="$ctrl.onModelDataChange()">
|
||||||
<div ng-show="$ctrl.showFilter" class="filter">
|
</vn-model>
|
||||||
<input
|
<vn-popover
|
||||||
type="text"
|
vn-id="popover"
|
||||||
ng-model="$ctrl.search"
|
on-open="$ctrl.onOpen()"
|
||||||
tabindex="-1"
|
on-close="$ctrl.onClose()">
|
||||||
class="search"
|
<div class="dropdown">
|
||||||
ng-blur="$ctrl.onFocusOut()"
|
<div ng-show="$ctrl.showFilter" class="filter">
|
||||||
translate-attr="{placeholder: 'Search'}"/>
|
<input
|
||||||
<vn-icon
|
type="text"
|
||||||
icon="clear"
|
ng-model="$ctrl.search"
|
||||||
ng-click="$ctrl.onClearClick()"
|
tabindex="-1"
|
||||||
translate-attr="{title: 'Clear'}">
|
class="search"
|
||||||
</vn-icon>
|
ng-blur="$ctrl.onFocusOut()"
|
||||||
</div>
|
translate-attr="{placeholder: 'Search'}"/>
|
||||||
<vn-model
|
<vn-icon
|
||||||
vn-id="model"
|
icon="clear"
|
||||||
on-data-change="$ctrl.onModelDataChange()">
|
ng-click="$ctrl.onClearClick()"
|
||||||
</vn-model>
|
translate-attr="{title: 'Clear'}">
|
||||||
<div class="list" tabindex="-1">
|
</vn-icon>
|
||||||
<ul
|
</div>
|
||||||
class="dropdown"
|
<div class="list" tabindex="-1">
|
||||||
ng-click="$ctrl.onContainerClick($event)">
|
<ul
|
||||||
</ul>
|
class="dropdown"
|
||||||
<div
|
ng-click="$ctrl.onContainerClick($event)">
|
||||||
ng-if="$ctrl.statusText"
|
</ul>
|
||||||
ng-click="$ctrl.onLoadMoreClick($event)"
|
<div
|
||||||
class="status"
|
ng-if="$ctrl.statusText"
|
||||||
translate>
|
ng-click="$ctrl.onLoadMoreClick($event)"
|
||||||
{{$ctrl.statusText}}
|
class="status"
|
||||||
|
translate>
|
||||||
|
{{$ctrl.statusText}}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</vn-popover>
|
||||||
|
|
|
@ -4,45 +4,34 @@ import './style.scss';
|
||||||
import './model';
|
import './model';
|
||||||
|
|
||||||
export default class DropDown extends Component {
|
export default class DropDown extends Component {
|
||||||
constructor($element, $scope, $transclude, $timeout, $http, $translate) {
|
constructor($element, $scope, $transclude, $timeout, $http) {
|
||||||
super($element, $scope);
|
super($element, $scope);
|
||||||
this.$transclude = $transclude;
|
this.$transclude = $transclude;
|
||||||
this.$timeout = $timeout;
|
this.$timeout = $timeout;
|
||||||
this.$translate = $translate;
|
|
||||||
|
|
||||||
this.valueField = 'id';
|
this.valueField = 'id';
|
||||||
this.showField = 'name';
|
this.showField = 'name';
|
||||||
this._search = undefined;
|
this._search = undefined;
|
||||||
this._shown = false;
|
|
||||||
this._activeOption = -1;
|
this._activeOption = -1;
|
||||||
this.showLoadMore = true;
|
this.showLoadMore = true;
|
||||||
this.showFilter = true;
|
this.showFilter = true;
|
||||||
|
|
||||||
this.input = this.element.querySelector('.search');
|
|
||||||
this.body = this.element.querySelector('.body');
|
|
||||||
this.container = this.element.querySelector('ul');
|
|
||||||
this.list = this.element.querySelector('.list');
|
|
||||||
|
|
||||||
this.docKeyDownHandler = e => this.onDocKeyDown(e);
|
this.docKeyDownHandler = e => this.onDocKeyDown(e);
|
||||||
this.docFocusInHandler = e => this.onDocFocusIn(e);
|
}
|
||||||
|
|
||||||
this.element.addEventListener('mousedown',
|
$postLink() {
|
||||||
e => this.onBackgroundMouseDown(e));
|
this.input = this.element.querySelector('.search');
|
||||||
this.element.addEventListener('focusin',
|
this.ul = this.element.querySelector('ul');
|
||||||
e => this.onFocusIn(e));
|
this.list = this.element.querySelector('.list');
|
||||||
this.list.addEventListener('scroll',
|
this.list.addEventListener('scroll', e => this.onScroll(e));
|
||||||
e => this.onScroll(e));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get shown() {
|
get shown() {
|
||||||
return this._shown;
|
return this.$.popover.shown;
|
||||||
}
|
}
|
||||||
|
|
||||||
set shown(value) {
|
set shown(value) {
|
||||||
if (value)
|
this.$.popover.shown = value;
|
||||||
this.show();
|
|
||||||
else
|
|
||||||
this.hide();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get search() {
|
get search() {
|
||||||
|
@ -97,62 +86,18 @@ export default class DropDown extends Component {
|
||||||
* @param {String} search The initial search term or %null
|
* @param {String} search The initial search term or %null
|
||||||
*/
|
*/
|
||||||
show(search) {
|
show(search) {
|
||||||
if (this._shown) return;
|
|
||||||
this._shown = true;
|
|
||||||
this._activeOption = -1;
|
|
||||||
this.search = search;
|
this.search = search;
|
||||||
|
this._activeOption = -1;
|
||||||
this.buildList();
|
this.buildList();
|
||||||
this.element.style.display = 'block';
|
this.$.popover.parent = this.parent;
|
||||||
this.list.scrollTop = 0;
|
this.$.popover.show();
|
||||||
this.$timeout(() => this.$element.addClass('shown'), 40);
|
|
||||||
this.document.addEventListener('keydown', this.docKeyDownHandler);
|
|
||||||
this.document.addEventListener('focusin', this.docFocusInHandler);
|
|
||||||
this.relocate();
|
|
||||||
this.input.focus();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hides the drop-down.
|
* Hides the drop-down.
|
||||||
*/
|
*/
|
||||||
hide() {
|
hide() {
|
||||||
if (!this._shown) return;
|
this.$.popover.hide();
|
||||||
this._shown = false;
|
|
||||||
this.element.style.display = '';
|
|
||||||
this.$element.removeClass('shown');
|
|
||||||
this.document.removeEventListener('keydown', this.docKeyDownHandler);
|
|
||||||
this.document.removeEventListener('focusin', this.docFocusInHandler);
|
|
||||||
if (this.parent)
|
|
||||||
this.parent.focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Repositions the drop-down to a correct location relative to the parent.
|
|
||||||
*/
|
|
||||||
relocate() {
|
|
||||||
if (!this.parent) return;
|
|
||||||
|
|
||||||
let style = this.body.style;
|
|
||||||
style.width = '';
|
|
||||||
style.height = '';
|
|
||||||
|
|
||||||
let parentRect = this.parent.getBoundingClientRect();
|
|
||||||
let bodyRect = this.body.getBoundingClientRect();
|
|
||||||
|
|
||||||
let top = parentRect.top + parentRect.height;
|
|
||||||
let height = bodyRect.height;
|
|
||||||
let width = Math.max(bodyRect.width, parentRect.width);
|
|
||||||
|
|
||||||
let margin = 10;
|
|
||||||
|
|
||||||
if (top + height + margin > window.innerHeight)
|
|
||||||
top = Math.max(parentRect.top - height, margin);
|
|
||||||
|
|
||||||
style.top = `${top}px`;
|
|
||||||
style.left = `${parentRect.left}px`;
|
|
||||||
style.width = `${width}px`;
|
|
||||||
|
|
||||||
if (height + margin * 2 > window.innerHeight)
|
|
||||||
style.height = `${window.innerHeight - margin * 2}px`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -190,7 +135,7 @@ export default class DropDown extends Component {
|
||||||
let data = this.$.model.data;
|
let data = this.$.model.data;
|
||||||
|
|
||||||
if (option >= 0 && data && option < data.length) {
|
if (option >= 0 && data && option < data.length) {
|
||||||
this.activeLi = this.container.children[option];
|
this.activeLi = this.ul.children[option];
|
||||||
this.activeLi.className = 'active';
|
this.activeLi.className = 'active';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -224,7 +169,7 @@ export default class DropDown extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.multiple)
|
if (!this.multiple)
|
||||||
this.hide();
|
this.$.popover.hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
refreshModel() {
|
refreshModel() {
|
||||||
|
@ -260,22 +205,14 @@ export default class DropDown extends Component {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
onMouseDown(event) {
|
onOpen() {
|
||||||
this.lastMouseEvent = event;
|
this.document.addEventListener('keydown', this.docKeyDownHandler);
|
||||||
|
this.list.scrollTop = 0;
|
||||||
|
this.input.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
onBackgroundMouseDown(event) {
|
onClose() {
|
||||||
if (event != this.lastMouseEvent)
|
this.document.removeEventListener('keydown', this.docKeyDownHandler);
|
||||||
this.hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
onFocusIn(event) {
|
|
||||||
this.lastFocusEvent = event;
|
|
||||||
}
|
|
||||||
|
|
||||||
onDocFocusIn(event) {
|
|
||||||
if (event !== this.lastFocusEvent)
|
|
||||||
this.hide();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onClearClick() {
|
onClearClick() {
|
||||||
|
@ -299,7 +236,7 @@ export default class DropDown extends Component {
|
||||||
|
|
||||||
onContainerClick(event) {
|
onContainerClick(event) {
|
||||||
if (event.defaultPrevented) return;
|
if (event.defaultPrevented) return;
|
||||||
let index = getPosition(this.container, event);
|
let index = getPosition(this.ul, event);
|
||||||
if (index != -1) this.selectOption(index);
|
if (index != -1) this.selectOption(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -318,9 +255,6 @@ export default class DropDown extends Component {
|
||||||
case 13: // Enter
|
case 13: // Enter
|
||||||
this.selectOption(option);
|
this.selectOption(option);
|
||||||
break;
|
break;
|
||||||
case 27: // Escape
|
|
||||||
this.hide();
|
|
||||||
break;
|
|
||||||
case 38: // Up
|
case 38: // Up
|
||||||
this.moveToOption(option <= 0 ? nOpts : option - 1);
|
this.moveToOption(option <= 0 ? nOpts : option - 1);
|
||||||
break;
|
break;
|
||||||
|
@ -342,8 +276,7 @@ export default class DropDown extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
buildList() {
|
buildList() {
|
||||||
this.destroyScopes();
|
this.destroyList();
|
||||||
this.scopes = [];
|
|
||||||
|
|
||||||
let hasTemplate = this.$transclude &&
|
let hasTemplate = this.$transclude &&
|
||||||
this.$transclude.isSlotFilled('tplItem');
|
this.$transclude.isSlotFilled('tplItem');
|
||||||
|
@ -377,23 +310,26 @@ export default class DropDown extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.container.innerHTML = '';
|
this.ul.appendChild(fragment);
|
||||||
this.container.appendChild(fragment);
|
|
||||||
this.activateOption(this._activeOption);
|
this.activateOption(this._activeOption);
|
||||||
this.relocate();
|
this.$.$applyAsync(() => this.$.popover.relocate());
|
||||||
}
|
}
|
||||||
|
|
||||||
destroyScopes() {
|
destroyList() {
|
||||||
|
this.ul.innerHTML = '';
|
||||||
|
|
||||||
if (this.scopes)
|
if (this.scopes)
|
||||||
for (let scope of this.scopes)
|
for (let scope of this.scopes)
|
||||||
scope.$destroy();
|
scope.$destroy();
|
||||||
|
|
||||||
|
this.scopes = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
$onDestroy() {
|
$onDestroy() {
|
||||||
this.destroyScopes();
|
this.destroyList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DropDown.$inject = ['$element', '$scope', '$transclude', '$timeout', '$http', '$translate'];
|
DropDown.$inject = ['$element', '$scope', '$transclude', '$timeout', '$http'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the position of an event element relative to a parent.
|
* Gets the position of an event element relative to a parent.
|
||||||
|
|
|
@ -7,6 +7,7 @@ describe('Component vnDropDown', () => {
|
||||||
let $element;
|
let $element;
|
||||||
let $scope;
|
let $scope;
|
||||||
let $httpBackend;
|
let $httpBackend;
|
||||||
|
let $transitions;
|
||||||
let $q;
|
let $q;
|
||||||
let $filter;
|
let $filter;
|
||||||
let controller;
|
let controller;
|
||||||
|
@ -15,18 +16,25 @@ describe('Component vnDropDown', () => {
|
||||||
angular.mock.module('client');
|
angular.mock.module('client');
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(angular.mock.inject((_$componentController_, $rootScope, _$timeout_, _$httpBackend_, _$q_, _$filter_) => {
|
beforeEach(angular.mock.inject((_$componentController_, $rootScope, _$timeout_, _$httpBackend_, _$q_, _$filter_, _$transitions_) => {
|
||||||
$componentController = _$componentController_;
|
$componentController = _$componentController_;
|
||||||
$element = angular.element(`<div>${template}</div>`);
|
$element = angular.element(`<div>${template}</div>`);
|
||||||
$timeout = _$timeout_;
|
$timeout = _$timeout_;
|
||||||
|
$transitions = _$transitions_;
|
||||||
$q = _$q_;
|
$q = _$q_;
|
||||||
$filter = _$filter_;
|
$filter = _$filter_;
|
||||||
$scope = $rootScope.$new();
|
$scope = $rootScope.$new();
|
||||||
$httpBackend = _$httpBackend_;
|
$httpBackend = _$httpBackend_;
|
||||||
$httpBackend.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
|
$httpBackend.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
|
||||||
|
|
||||||
|
let popoverTemplate = require('../popover/popover.html');
|
||||||
|
let $popover = angular.element(`<div>${popoverTemplate}</div>`);
|
||||||
|
$scope.popover = $componentController('vnPopover', {$element: $popover, $scope, $timeout, $transitions});
|
||||||
|
$scope.popover.$postLink();
|
||||||
|
|
||||||
$scope.model = $componentController('vnModel', {$httpBackend, $q, $filter});
|
$scope.model = $componentController('vnModel', {$httpBackend, $q, $filter});
|
||||||
controller = $componentController('vnDropDown', {$element, $scope, $transclude: null, $timeout, $httpBackend, $translate: null});
|
controller = $componentController('vnDropDown', {$element, $scope, $transclude: null, $timeout, $httpBackend, $translate: null});
|
||||||
|
controller.$postLink();
|
||||||
controller.parent = angular.element('<vn-parent></vn-parent>')[0];
|
controller.parent = angular.element('<vn-parent></vn-parent>')[0];
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
|
@ -1,30 +1,7 @@
|
||||||
vn-drop-down {
|
vn-drop-down {
|
||||||
z-index: 10;
|
.dropdown {
|
||||||
position: fixed;
|
|
||||||
display: none;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
|
|
||||||
&.shown {
|
|
||||||
& > .body {
|
|
||||||
transform: translateY(0);
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
& > .body {
|
|
||||||
position: fixed;
|
|
||||||
box-shadow: 0 .1em .4em rgba(1, 1, 1, .4);
|
|
||||||
border-radius: .1em;
|
|
||||||
background-color: white;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
transform: translateY(-.4em);
|
|
||||||
opacity: 0;
|
|
||||||
transition-property: opacity, transform;
|
|
||||||
transition-duration: 250ms;
|
|
||||||
transition-timing-function: ease-in-out;
|
|
||||||
|
|
||||||
& > .filter {
|
& > .filter {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
@ -35,6 +12,7 @@ vn-drop-down {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
border: none;
|
border: none;
|
||||||
border-bottom: 1px solid #ccc;
|
border-bottom: 1px solid #ccc;
|
||||||
|
font-size: inherit;
|
||||||
padding: .6em;
|
padding: .6em;
|
||||||
}
|
}
|
||||||
& > vn-icon[icon=clear] {
|
& > vn-icon[icon=clear] {
|
||||||
|
@ -64,10 +42,9 @@ vn-drop-down {
|
||||||
ul {
|
ul {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
list-style-type: none;
|
||||||
}
|
}
|
||||||
li, .status {
|
li, .status {
|
||||||
outline: none;
|
|
||||||
list-style-type: none;
|
|
||||||
padding: .6em;
|
padding: .6em;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
|
|
@ -2,8 +2,6 @@ import './textfield/textfield';
|
||||||
import './watcher/watcher';
|
import './watcher/watcher';
|
||||||
import './paging/paging';
|
import './paging/paging';
|
||||||
import './icon/icon';
|
import './icon/icon';
|
||||||
import './autocomplete/autocomplete';
|
|
||||||
import './popover/popover';
|
|
||||||
import './dialog/dialog';
|
import './dialog/dialog';
|
||||||
import './confirm/confirm';
|
import './confirm/confirm';
|
||||||
import './title/title';
|
import './title/title';
|
||||||
|
@ -12,7 +10,10 @@ import './spinner/spinner';
|
||||||
import './snackbar/snackbar';
|
import './snackbar/snackbar';
|
||||||
import './tooltip/tooltip';
|
import './tooltip/tooltip';
|
||||||
import './icon-menu/icon-menu';
|
import './icon-menu/icon-menu';
|
||||||
|
import './popover/popover';
|
||||||
|
import './autocomplete/autocomplete';
|
||||||
import './drop-down/drop-down';
|
import './drop-down/drop-down';
|
||||||
|
import './menu/menu';
|
||||||
import './column-header/column-header';
|
import './column-header/column-header';
|
||||||
import './grid-header/grid-header';
|
import './grid-header/grid-header';
|
||||||
import './multi-check/multi-check';
|
import './multi-check/multi-check';
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
import ngModule from '../../module';
|
||||||
|
import Popover from '../popover/popover';
|
||||||
|
|
||||||
|
export default class Menu extends Popover {
|
||||||
|
$postLink() {
|
||||||
|
super.$postLink();
|
||||||
|
this.element.addEventListener('click',
|
||||||
|
() => this.onClick());
|
||||||
|
}
|
||||||
|
|
||||||
|
onClick() {
|
||||||
|
this.hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ngModule.component('vnMenu', {
|
||||||
|
template: require('../popover/popover.html'),
|
||||||
|
controller: Menu,
|
||||||
|
transclude: true,
|
||||||
|
bindings: {
|
||||||
|
onOpen: '&?',
|
||||||
|
onClose: '&?'
|
||||||
|
}
|
||||||
|
});
|
|
@ -2,10 +2,6 @@
|
||||||
vn-icon{
|
vn-icon{
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
&:focus, &:active, &:hover{
|
|
||||||
outline: none;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
.primaryCheckbox {
|
.primaryCheckbox {
|
||||||
vn-icon{
|
vn-icon{
|
||||||
font-size: 22px;
|
font-size: 22px;
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
<div class="popover">
|
||||||
|
<div class="arrow"></div>
|
||||||
|
<div class="content" ng-transclude></div>
|
||||||
|
</div>
|
|
@ -1,205 +1,223 @@
|
||||||
import ngModule from '../../module';
|
import ngModule from '../../module';
|
||||||
import './style.css';
|
import Component from '../../lib/component';
|
||||||
|
import './style.scss';
|
||||||
|
|
||||||
directive.$inject = ['vnPopover'];
|
/**
|
||||||
export function directive(vnPopover) {
|
* A simple popover.
|
||||||
return {
|
*/
|
||||||
restrict: 'A',
|
export default class Popover extends Component {
|
||||||
link: function($scope, $element, $attrs) {
|
constructor($element, $scope, $timeout, $transitions) {
|
||||||
$element.on('click', function(event) {
|
super($element, $scope);
|
||||||
vnPopover.showComponent($attrs.vnDialog, $scope, $element);
|
this.$timeout = $timeout;
|
||||||
event.preventDefault();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
ngModule.directive('vnPopover', directive);
|
|
||||||
|
|
||||||
export class Popover {
|
|
||||||
constructor($document, $compile, $transitions) {
|
|
||||||
this.document = $document[0];
|
|
||||||
this.$compile = $compile;
|
|
||||||
this.$transitions = $transitions;
|
this.$transitions = $transitions;
|
||||||
this.removeScope = false;
|
this._shown = false;
|
||||||
this.popOpens = 0;
|
|
||||||
}
|
}
|
||||||
_init() {
|
|
||||||
this.docMouseDownHandler = e => this.onDocMouseDown(e);
|
$postLink() {
|
||||||
this.document.addEventListener('mousedown', this.docMouseDownHandler);
|
this.$element.addClass('vn-popover');
|
||||||
|
|
||||||
this.docKeyDownHandler = e => this.onDocKeyDown(e);
|
this.docKeyDownHandler = e => this.onDocKeyDown(e);
|
||||||
|
this.docFocusInHandler = e => this.onDocFocusIn(e);
|
||||||
|
|
||||||
|
this.element.addEventListener('mousedown',
|
||||||
|
e => this.onBackgroundMouseDown(e));
|
||||||
|
this.element.addEventListener('focusin',
|
||||||
|
e => this.onFocusIn(e));
|
||||||
|
|
||||||
|
this.popover = this.element.querySelector('.popover');
|
||||||
|
this.popover.addEventListener('mousedown',
|
||||||
|
e => this.onMouseDown(e));
|
||||||
|
|
||||||
|
this.arrow = this.element.querySelector('.arrow');
|
||||||
|
this.content = this.element.querySelector('.content');
|
||||||
|
}
|
||||||
|
|
||||||
|
set child(value) {
|
||||||
|
this.content.appendChild(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
get child() {
|
||||||
|
return this.content.firstChild;
|
||||||
|
}
|
||||||
|
|
||||||
|
get shown() {
|
||||||
|
return this._shown;
|
||||||
|
}
|
||||||
|
|
||||||
|
set shown(value) {
|
||||||
|
if (value)
|
||||||
|
this.show();
|
||||||
|
else
|
||||||
|
this.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows the popover. If a parent is specified it is shown in a visible
|
||||||
|
* relative position to it.
|
||||||
|
*/
|
||||||
|
show() {
|
||||||
|
if (this._shown) return;
|
||||||
|
|
||||||
|
this._shown = true;
|
||||||
|
this.element.style.display = 'block';
|
||||||
|
this.$timeout.cancel(this.showTimeout);
|
||||||
|
this.showTimeout = this.$timeout(() => {
|
||||||
|
this.$element.addClass('shown');
|
||||||
|
this.showTimeout = null;
|
||||||
|
}, 30);
|
||||||
|
|
||||||
this.document.addEventListener('keydown', this.docKeyDownHandler);
|
this.document.addEventListener('keydown', this.docKeyDownHandler);
|
||||||
this.deregisterCallback = this.$transitions.onStart({},
|
this.document.addEventListener('focusin', this.docFocusInHandler);
|
||||||
() => this.hideAll());
|
|
||||||
|
this.deregisterCallback = this.$transitions.onStart({}, () => this.hide());
|
||||||
|
this.relocate();
|
||||||
|
|
||||||
|
if (this.onOpen)
|
||||||
|
this.onOpen();
|
||||||
}
|
}
|
||||||
_destroy() {
|
|
||||||
this.document.removeEventListener('mousedown', this.docMouseDownHandler);
|
/**
|
||||||
|
* Hides the popover.
|
||||||
|
*/
|
||||||
|
hide() {
|
||||||
|
if (!this._shown) return;
|
||||||
|
|
||||||
|
this._shown = false;
|
||||||
|
this.$element.removeClass('shown');
|
||||||
|
this.$timeout.cancel(this.showTimeout);
|
||||||
|
this.showTimeout = this.$timeout(() => {
|
||||||
|
this.element.style.display = 'none';
|
||||||
|
this.showTimeout = null;
|
||||||
|
}, 250);
|
||||||
|
|
||||||
this.document.removeEventListener('keydown', this.docKeyDownHandler);
|
this.document.removeEventListener('keydown', this.docKeyDownHandler);
|
||||||
this.docMouseDownHandler = null;
|
this.document.removeEventListener('focusin', this.docFocusInHandler);
|
||||||
this.docKeyDownHandler = null;
|
|
||||||
this.deregisterCallback();
|
|
||||||
}
|
|
||||||
show(childElement, parent, popoverId) {
|
|
||||||
this.childElement = childElement;
|
|
||||||
let popover = this.document.createElement('div');
|
|
||||||
this.popOpens++;
|
|
||||||
|
|
||||||
if (!popoverId) {
|
if (this.deregisterCallback)
|
||||||
popoverId = 'popover-' + this.popOpens;
|
this.deregisterCallback();
|
||||||
popover.id = popoverId;
|
|
||||||
}
|
|
||||||
|
|
||||||
popover.className = 'vn-popover';
|
if (this.parent)
|
||||||
popover.addEventListener('mousedown',
|
this.parent.focus();
|
||||||
e => this.onPopoverMouseDown(e));
|
|
||||||
popover.appendChild(childElement);
|
|
||||||
this.popover = popover;
|
|
||||||
|
|
||||||
let style = popover.style;
|
if (this.onClose)
|
||||||
|
this.onClose();
|
||||||
let spacing = 0;
|
|
||||||
let screenMargin = 20;
|
|
||||||
let dblMargin = screenMargin * 2;
|
|
||||||
|
|
||||||
let width = popover.offsetWidth;
|
|
||||||
let height = popover.offsetHeight;
|
|
||||||
let innerWidth = window.innerWidth;
|
|
||||||
let innerHeight = window.innerHeight;
|
|
||||||
|
|
||||||
if (width + dblMargin > innerWidth) {
|
|
||||||
width = innerWidth - dblMargin;
|
|
||||||
style.width = width + 'px';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (height + dblMargin > innerHeight) {
|
|
||||||
height = innerHeight - dblMargin;
|
|
||||||
style.height = height + 'px';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parent) {
|
|
||||||
let parentNode = parent;
|
|
||||||
let rect = parentNode.getBoundingClientRect();
|
|
||||||
let left = rect.left;
|
|
||||||
let top = rect.top + spacing + parentNode.offsetHeight;
|
|
||||||
|
|
||||||
if (left + width > innerWidth)
|
|
||||||
left -= (left + width) - innerWidth + margin;
|
|
||||||
|
|
||||||
if (top + height > innerHeight)
|
|
||||||
top -= height + parentNode.offsetHeight + spacing * 2;
|
|
||||||
|
|
||||||
if (left < 0)
|
|
||||||
left = screenMargin;
|
|
||||||
|
|
||||||
if (top < 0)
|
|
||||||
top = screenMargin;
|
|
||||||
|
|
||||||
style.top = (top) + 'px';
|
|
||||||
style.left = (left) + 'px';
|
|
||||||
style.minWidth = (rect.width) + 'px';
|
|
||||||
}
|
|
||||||
|
|
||||||
this.document.body.appendChild(popover);
|
|
||||||
|
|
||||||
if (this.popOpens === 1) {
|
|
||||||
this._init();
|
|
||||||
}
|
|
||||||
return popoverId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
showComponent(childComponent, $scope, parent) {
|
/**
|
||||||
let childElement = this.document.createElement(childComponent);
|
* Repositions the popover to a correct location relative to the parent.
|
||||||
let id = 'popover-' + this.popOpens;
|
*/
|
||||||
childElement.id = id;
|
relocate() {
|
||||||
this.removeScope = true;
|
if (!(this.parent && this._shown)) return;
|
||||||
this.$compile(childElement)($scope.$new());
|
|
||||||
this.show(childElement, parent, id);
|
|
||||||
return childElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
_checkOpens() {
|
let style = this.popover.style;
|
||||||
this.popOpens = this.document.querySelectorAll('*[id^="popover-"]').length;
|
style.width = '';
|
||||||
if (this.popOpens === 0) {
|
style.height = '';
|
||||||
this._destroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_removeElement(val) {
|
let arrowStyle = this.arrow.style;
|
||||||
if (!val) return;
|
arrowStyle.top = '';
|
||||||
let element = angular.element(val);
|
arrowStyle.bottom = '';
|
||||||
let parent = val.parentNode;
|
|
||||||
if (element.scope() && element.scope().$id > 1) {
|
|
||||||
element.scope().$destroy();
|
|
||||||
}
|
|
||||||
element.remove();
|
|
||||||
if (parent.className.indexOf('vn-popover') !== -1)
|
|
||||||
this._removeElement(parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
hide(id) {
|
let parentRect = this.parent.getBoundingClientRect();
|
||||||
let popover = this.document.querySelector(`#${id}`);
|
let popoverRect = this.popover.getBoundingClientRect();
|
||||||
if (popover) {
|
let arrowRect = this.arrow.getBoundingClientRect();
|
||||||
this._removeElement(popover);
|
|
||||||
}
|
|
||||||
this._checkOpens();
|
|
||||||
}
|
|
||||||
|
|
||||||
hideChilds(id) {
|
let arrowHeight = Math.sqrt(Math.pow(arrowRect.height, 2) * 2) / 2;
|
||||||
let popovers = this.document.querySelectorAll('*[id^="popover-"]');
|
|
||||||
let idNumber = parseInt(id.split('-')[1], 10);
|
|
||||||
popovers.forEach(
|
|
||||||
val => {
|
|
||||||
if (parseInt(val.id.split('-')[1], 10) > idNumber)
|
|
||||||
this._removeElement(val);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
this._checkOpens();
|
|
||||||
}
|
|
||||||
|
|
||||||
hideAll() {
|
let top = parentRect.top + parentRect.height + arrowHeight;
|
||||||
let popovers = this.document.querySelectorAll('*[id^="popover-"]');
|
let left = parentRect.left;
|
||||||
popovers.forEach(
|
let height = popoverRect.height;
|
||||||
val => {
|
let width = Math.max(popoverRect.width, parentRect.width);
|
||||||
this._removeElement(val);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
this._checkOpens();
|
|
||||||
}
|
|
||||||
|
|
||||||
_findPopOver(node) {
|
let margin = 10;
|
||||||
while (node != null) {
|
let showTop = top + height + margin > window.innerHeight;
|
||||||
if (node.id && node.id.startsWith('popover-')) {
|
|
||||||
return node.id;
|
|
||||||
}
|
|
||||||
node = node.parentNode;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
onDocMouseDown(event) {
|
if (showTop)
|
||||||
let targetId = this._findPopOver(event.target);
|
top = Math.max(parentRect.top - height - arrowHeight, margin);
|
||||||
if (targetId) {
|
if (left + width + margin > window.innerWidth)
|
||||||
this.hideChilds(targetId);
|
left = window.innerWidth - width - margin;
|
||||||
} else {
|
|
||||||
this.hideAll();
|
if (showTop)
|
||||||
}
|
arrowStyle.bottom = `0`;
|
||||||
|
else
|
||||||
|
arrowStyle.top = `0`;
|
||||||
|
|
||||||
|
arrowStyle.left = `${(parentRect.left - left) + parentRect.width / 2}px`;
|
||||||
|
|
||||||
|
style.top = `${top}px`;
|
||||||
|
style.left = `${left}px`;
|
||||||
|
style.width = `${width}px`;
|
||||||
|
|
||||||
|
if (height + margin * 2 + arrowHeight > window.innerHeight)
|
||||||
|
style.height = `${window.innerHeight - margin * 2 - arrowHeight}px`;
|
||||||
}
|
}
|
||||||
|
|
||||||
onDocKeyDown(event) {
|
onDocKeyDown(event) {
|
||||||
if (event.keyCode === 27) {
|
if (event.defaultPrevented) return;
|
||||||
let targetId = this._findPopOver(this.lastTarget);
|
|
||||||
if (targetId) {
|
if (event.keyCode == 27) { // Esc
|
||||||
this.hideChilds(targetId);
|
event.preventDefault();
|
||||||
} else {
|
this.hide();
|
||||||
this.hideAll();
|
|
||||||
}
|
|
||||||
this.lastTarget = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onPopoverMouseDown(event) {
|
onMouseDown(event) {
|
||||||
this.lastTarget = event.target;
|
this.lastMouseEvent = event;
|
||||||
|
}
|
||||||
|
|
||||||
|
onBackgroundMouseDown(event) {
|
||||||
|
if (event != this.lastMouseEvent)
|
||||||
|
this.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
onFocusIn(event) {
|
||||||
|
this.lastFocusEvent = event;
|
||||||
|
}
|
||||||
|
|
||||||
|
onDocFocusIn(event) {
|
||||||
|
if (event !== this.lastFocusEvent)
|
||||||
|
this.hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Popover.$inject = ['$document', '$compile', '$transitions'];
|
Popover.$inject = ['$element', '$scope', '$timeout', '$transitions'];
|
||||||
|
|
||||||
ngModule.service('vnPopover', Popover);
|
ngModule.component('vnPopover', {
|
||||||
|
template: require('./popover.html'),
|
||||||
|
controller: Popover,
|
||||||
|
transclude: true,
|
||||||
|
bindings: {
|
||||||
|
onOpen: '&?',
|
||||||
|
onClose: '&?'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
class PopoverService {
|
||||||
|
constructor($document, $compile, $transitions, $rootScope) {
|
||||||
|
this.$compile = $compile;
|
||||||
|
this.$rootScope = $rootScope;
|
||||||
|
this.$document = $document;
|
||||||
|
this.stack = [];
|
||||||
|
}
|
||||||
|
show(child, parent, $scope) {
|
||||||
|
let element = this.$compile('<vn-popover/>')($scope || this.$rootScope)[0];
|
||||||
|
let popover = element.$ctrl;
|
||||||
|
popover.parent = parent;
|
||||||
|
popover.child = child;
|
||||||
|
popover.show();
|
||||||
|
popover.onClose = () => {
|
||||||
|
this.$document[0].body.removeChild(element);
|
||||||
|
if ($scope) $scope.$destroy();
|
||||||
|
};
|
||||||
|
this.$document[0].body.appendChild(element);
|
||||||
|
return popover;
|
||||||
|
}
|
||||||
|
|
||||||
|
showComponent(componentTag, $scope, parent) {
|
||||||
|
let $newScope = $scope.$new();
|
||||||
|
let childElement = this.$compile(`<${componentTag}/>`)($newScope)[0];
|
||||||
|
this.show(childElement, parent, $newScope);
|
||||||
|
return childElement;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PopoverService.$inject = ['$document', '$compile', '$transitions', '$rootScope'];
|
||||||
|
|
||||||
|
ngModule.service('vnPopover', PopoverService);
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
.vn-popover {
|
|
||||||
position: fixed;
|
|
||||||
box-shadow: 0 0 .4em rgba(1,1,1,.4);
|
|
||||||
background-color: white;
|
|
||||||
z-index: 100;
|
|
||||||
border-radius: .1em;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
}
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
.vn-popover {
|
||||||
|
display: none;
|
||||||
|
z-index: 10;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-.6em);
|
||||||
|
transition-property: opacity, transform;
|
||||||
|
transition-duration: 200ms;
|
||||||
|
transition-timing-function: ease-in-out;
|
||||||
|
|
||||||
|
&.shown {
|
||||||
|
transform: translateY(0);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
& > .popover {
|
||||||
|
position: absolute;
|
||||||
|
display: flex;
|
||||||
|
box-shadow: 0 .1em .4em rgba(1, 1, 1, .4);
|
||||||
|
|
||||||
|
& > .arrow {
|
||||||
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
|
margin: -.5em;
|
||||||
|
background-color: white;
|
||||||
|
box-shadow: 0 .1em .4em rgba(1, 1, 1, .4);
|
||||||
|
position: absolute;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
& > .content {
|
||||||
|
width: 100%;
|
||||||
|
border-radius: .1em;
|
||||||
|
overflow: auto;
|
||||||
|
background-color: white;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
vn-textarea {
|
||||||
|
& > .mdl-textfield {
|
||||||
|
width: initial;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
import ngModule from '../../module';
|
import ngModule from '../../module';
|
||||||
import template from './textarea.html';
|
import template from './textarea.html';
|
||||||
|
import './style.scss';
|
||||||
|
|
||||||
directive.$inject = ['vnTemplate'];
|
directive.$inject = ['vnTemplate'];
|
||||||
export function directive(vnTemplate) {
|
export function directive(vnTemplate) {
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
vn-textfield {
|
vn-textfield {
|
||||||
div {
|
|
||||||
outline: none; //remove chrome outline
|
|
||||||
}
|
|
||||||
.mdl-chip__action {
|
.mdl-chip__action {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: auto;
|
width: auto;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import './id';
|
import './id';
|
||||||
import './focus';
|
import './focus';
|
||||||
import './dialog';
|
import './dialog';
|
||||||
|
import './popover';
|
||||||
import './validation';
|
import './validation';
|
||||||
import './acl';
|
import './acl';
|
||||||
import './on-error-src';
|
import './on-error-src';
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
import ngModule from '../module';
|
||||||
|
import Popover from '../components/popover/popover';
|
||||||
|
import {kebabToCamel} from '../lib/string';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Directive used to open a popover.
|
||||||
|
*
|
||||||
|
* @return {Object} The directive
|
||||||
|
*/
|
||||||
|
export function directive() {
|
||||||
|
return {
|
||||||
|
restrict: 'A',
|
||||||
|
link: function($scope, $element, $attrs) {
|
||||||
|
$element.on('click', function(event) {
|
||||||
|
let popoverKey = kebabToCamel($attrs.vnPopover);
|
||||||
|
let popover = $scope[popoverKey];
|
||||||
|
if (popover instanceof Popover) {
|
||||||
|
popover.parent = $element[0];
|
||||||
|
popover.show();
|
||||||
|
}
|
||||||
|
event.preventDefault();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
ngModule.directive('vnPopover', directive);
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"module": "item",
|
"module": "item",
|
||||||
"name": "Items",
|
"name": "Items",
|
||||||
"icon": "/static/images/icon_item.png",
|
"icon": "inbox",
|
||||||
"validations" : true,
|
"validations" : true,
|
||||||
"routes": [
|
"routes": [
|
||||||
{
|
{
|
||||||
|
|
|
@ -23,12 +23,9 @@
|
||||||
<vn-autocomplete vn-one
|
<vn-autocomplete vn-one
|
||||||
url="/item/api/Intrastats"
|
url="/item/api/Intrastats"
|
||||||
label="Intrastat"
|
label="Intrastat"
|
||||||
show-field="description"
|
|
||||||
value-field="id"
|
value-field="id"
|
||||||
field="$ctrl.item.intrastatFk"
|
show-field="description"
|
||||||
order="description ASC"
|
field="$ctrl.item.intrastatFk">
|
||||||
filter-search="{where: {description: {regexp: 'search'}} }">
|
|
||||||
<tpl-item>{{$parent.$parent.item.description}}</tpl-item>
|
|
||||||
</vn-autocomplete>
|
</vn-autocomplete>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
<vn-horizontal>
|
<vn-horizontal>
|
||||||
|
|
|
@ -30,10 +30,9 @@
|
||||||
show-field="description"
|
show-field="description"
|
||||||
value-field="id"
|
value-field="id"
|
||||||
field="$ctrl.item.intrastatFk"
|
field="$ctrl.item.intrastatFk"
|
||||||
order="description ASC"
|
where="{or: [{id: {regexp: 'search'}}, {description: {regexp: 'search'}}]}"
|
||||||
filter-search= "{where: {or: [{id: {regexp: 'search'}}, {description: {regexp: 'search'}}]}}"
|
|
||||||
initial-data="$ctrl.item.intrastat">
|
initial-data="$ctrl.item.intrastat">
|
||||||
<tpl-item>{{$parent.$parent.item.id}} : {{$parent.$parent.item.description}}</tpl-item>
|
<tpl-item>{{id}} : {{description}}</tpl-item>
|
||||||
</vn-autocomplete>
|
</vn-autocomplete>
|
||||||
<vn-textfield vn-one label="Relevancy" field="$ctrl.item.relevancy" type="number"></vn-textfield>
|
<vn-textfield vn-one label="Relevancy" field="$ctrl.item.relevancy" type="number"></vn-textfield>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<vn-watcher
|
<vn-watcher
|
||||||
vn-id="watcher"
|
vn-id="watcher"
|
||||||
data="$ctrl.item"
|
data="$ctrl.item"
|
||||||
form = "form">
|
form="form">
|
||||||
</vn-watcher>
|
</vn-watcher>
|
||||||
<form name="form" ng-submit="$ctrl.submit()">
|
<form name="form" ng-submit="$ctrl.submit()">
|
||||||
<vn-card pad-large>
|
<vn-card pad-large>
|
||||||
|
@ -9,13 +9,12 @@
|
||||||
<vn-horizontal ng-repeat="itemNiche in $ctrl.niches track by $index">
|
<vn-horizontal ng-repeat="itemNiche in $ctrl.niches track by $index">
|
||||||
<vn-autocomplete
|
<vn-autocomplete
|
||||||
vn-three
|
vn-three
|
||||||
initial-data = "itemNiche.warehouse"
|
data="$ctrl.warehouses"
|
||||||
field = "itemNiche.warehouseFk"
|
show-field="name"
|
||||||
data = "$ctrl.warehouses"
|
value-field="id"
|
||||||
show-field = "name"
|
initial-data="itemNiche.warehouse"
|
||||||
value-field = "id"
|
field="itemNiche.warehouseFk"
|
||||||
label = "Warehouse"
|
label="Warehouse"
|
||||||
order = "name ASC"
|
|
||||||
vn-acl="buyer,replenisher">
|
vn-acl="buyer,replenisher">
|
||||||
</vn-autocomplete>
|
</vn-autocomplete>
|
||||||
<vn-textfield
|
<vn-textfield
|
||||||
|
@ -39,7 +38,7 @@
|
||||||
margin-medium-left
|
margin-medium-left
|
||||||
orange
|
orange
|
||||||
icon="add_circle"
|
icon="add_circle"
|
||||||
ng-if = "itemNiche.showAddIcon"
|
ng-if="itemNiche.showAddIcon"
|
||||||
ng-click="$ctrl.addNiche()">
|
ng-click="$ctrl.addNiche()">
|
||||||
</vn-icon>
|
</vn-icon>
|
||||||
</vn-one>
|
</vn-one>
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
data="tags.model"
|
data="tags.model"
|
||||||
show-field="name"
|
show-field="name"
|
||||||
label="Tag"
|
label="Tag"
|
||||||
order="name ASC"
|
|
||||||
vn-acl="buyer">
|
vn-acl="buyer">
|
||||||
</vn-autocomplete>
|
</vn-autocomplete>
|
||||||
<vn-textfield
|
<vn-textfield
|
||||||
|
|
|
@ -6,3 +6,4 @@ locator: []
|
||||||
production: []
|
production: []
|
||||||
salix: []
|
salix: []
|
||||||
route: []
|
route: []
|
||||||
|
ticket: []
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"module": "production",
|
"module": "production",
|
||||||
"name": "Production",
|
"name": "Production",
|
||||||
"icon": "/static/images/icon_production.png",
|
"icon": "local_florist",
|
||||||
"validations" : false,
|
"validations" : false,
|
||||||
"routes": [
|
"routes": [
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,29 +6,33 @@
|
||||||
<vn-icon
|
<vn-icon
|
||||||
id="apps"
|
id="apps"
|
||||||
icon="apps"
|
icon="apps"
|
||||||
|
vn-popover="apps-menu"
|
||||||
translate-attr="{title: 'Applications'}">
|
translate-attr="{title: 'Applications'}">
|
||||||
</vn-icon>
|
</vn-icon>
|
||||||
<ul id="apps-menu" for="apps" class="mdl-menu mdl-js-menu mdl-menu--bottom-right" pad-small>
|
<vn-menu vn-id="apps-menu">
|
||||||
<li ng-repeat="mod in ::$ctrl.modules" class="mdl-menu__item" ui-sref="{{::mod.route.state}}">
|
<ul pad-small>
|
||||||
<vn-icon ng-if="::mod.icon && !mod.icon.startsWith('/')" icon="{{::mod.icon}}"></vn-icon>
|
<li ng-repeat="mod in ::$ctrl.modules" ui-sref="{{::mod.route.state}}">
|
||||||
<img ng-if="::mod.icon && mod.icon.startsWith('/')" ng-src="{{::mod.icon}}" />
|
<vn-icon icon="{{::mod.icon}}"></vn-icon>
|
||||||
<span translate="{{::mod.name}}"></span>
|
<span translate>{{::mod.name}}</span>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
</vn-menu>
|
||||||
<vn-icon
|
<vn-icon
|
||||||
id="lang"
|
id="lang"
|
||||||
icon="language"
|
icon="language"
|
||||||
|
vn-popover="langs-menu"
|
||||||
translate-attr="{title: 'Change language'}">
|
translate-attr="{title: 'Change language'}">
|
||||||
</vn-icon>
|
</vn-icon>
|
||||||
<ul id="langs-menu" for="lang" class="mdl-menu mdl-js-menu mdl-menu--bottom-right" pad-small>
|
<vn-menu vn-id="langs-menu">
|
||||||
<li
|
<ul pad-small>
|
||||||
ng-repeat="lang in ::$ctrl.langs"
|
<li
|
||||||
name="{{::lang}}"
|
ng-repeat="lang in ::$ctrl.langs"
|
||||||
class="mdl-menu__item"
|
name="{{::lang}}"
|
||||||
ng-click="$ctrl.onChangeLangClick(lang)">
|
ng-click="$ctrl.onChangeLangClick(lang)">
|
||||||
<span>{{::lang}}</span>
|
<span>{{::lang}}</span>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
</vn-menu>
|
||||||
<vn-icon
|
<vn-icon
|
||||||
id="logout"
|
id="logout"
|
||||||
icon="exit_to_app"
|
icon="exit_to_app"
|
||||||
|
|
|
@ -14,26 +14,30 @@ vn-main-menu {
|
||||||
color: #FF9300;
|
color: #FF9300;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
li.mdl-menu__item {
|
.vn-popover ul {
|
||||||
background-color: #FF9300;
|
list-style-type: none;
|
||||||
margin-bottom: 8px;
|
margin: 0;
|
||||||
color: white;
|
color: white;
|
||||||
img {
|
|
||||||
max-width: 18px;
|
li {
|
||||||
vertical-align: middle;
|
background-color: #FF9300;
|
||||||
margin-top: -3px;
|
margin-bottom: .6em;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: .8em;
|
||||||
|
border-radius: .1em;
|
||||||
|
min-width: 8em;
|
||||||
|
|
||||||
|
& > vn-icon {
|
||||||
|
padding-right: .3em;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
background-color: #FF9300;
|
||||||
|
opacity: 0.7 !important;
|
||||||
|
}
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
i {
|
|
||||||
float: left;
|
|
||||||
padding-top: 13px;
|
|
||||||
margin-right: 3px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
li.mdl-menu__item:hover {
|
|
||||||
background-color: #FF9300;
|
|
||||||
opacity: 0.7 !important;
|
|
||||||
}
|
|
||||||
li.mdl-menu__item:last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -3,6 +3,21 @@
|
||||||
@import "colors";
|
@import "colors";
|
||||||
@import "border";
|
@import "border";
|
||||||
|
|
||||||
|
|
||||||
|
a:focus,
|
||||||
|
input:focus,
|
||||||
|
button:focus
|
||||||
|
{
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
button::-moz-focus-inner,
|
||||||
|
input[type=submit]::-moz-focus-inner,
|
||||||
|
input[type=button]::-moz-focus-inner,
|
||||||
|
input[type=reset]::-moz-focus-inner
|
||||||
|
{
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
.form {
|
.form {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|
|
@ -8,5 +8,7 @@ export default {
|
||||||
locator:
|
locator:
|
||||||
cb => require.ensure([], () => cb(require('locator'))),
|
cb => require.ensure([], () => cb(require('locator'))),
|
||||||
item:
|
item:
|
||||||
cb => require.ensure([], () => cb(require('item')))
|
cb => require.ensure([], () => cb(require('item'))),
|
||||||
|
ticket:
|
||||||
|
cb => require.ensure([], () => cb(require('ticket')))
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
export * from './src/ticket';
|
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"module": "ticket",
|
||||||
|
"name": "Tickets",
|
||||||
|
"icon": "receipt",
|
||||||
|
"validations": false,
|
||||||
|
"routes": [
|
||||||
|
{
|
||||||
|
"url": "/tickets",
|
||||||
|
"state": "tickets",
|
||||||
|
"component": "vn-ticket-index",
|
||||||
|
"acl": ["developer"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
<mg-ajax path="/client/api/Clients/filter" options="mgIndex"></mg-ajax>
|
||||||
|
<div margin-medium>
|
||||||
|
<div class="vn-list">
|
||||||
|
<vn-card>
|
||||||
|
<vn-horizontal pad-medium>
|
||||||
|
<vn-searchbar vn-one
|
||||||
|
index="index"
|
||||||
|
on-search="$ctrl.search(index)"
|
||||||
|
ignore-keys = "['page', 'size', 'search']">
|
||||||
|
</vn-searchbar>
|
||||||
|
</vn-horizontal>
|
||||||
|
</vn-card>
|
||||||
|
<vn-card margin-medium-top>
|
||||||
|
<vn-ticket-item
|
||||||
|
ng-repeat="ticket in index.model.instances"
|
||||||
|
ticket="ticket">
|
||||||
|
</vn-ticket-item>
|
||||||
|
</vn-card>
|
||||||
|
<vn-paging index="index" total="index.model.count"></vn-paging>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<a ui-sref="create" fixed-bottom-right>
|
||||||
|
<vn-float-button icon="person_add"></vn-float-button>
|
||||||
|
</a>
|
|
@ -0,0 +1,14 @@
|
||||||
|
import ngModule from '../module';
|
||||||
|
import './item';
|
||||||
|
|
||||||
|
export default class Controller {
|
||||||
|
search(index) {
|
||||||
|
index.accept();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Controller.$inject = [];
|
||||||
|
|
||||||
|
ngModule.component('vnTicketIndex', {
|
||||||
|
template: require('./index.html'),
|
||||||
|
controller: Controller
|
||||||
|
});
|
|
@ -0,0 +1,17 @@
|
||||||
|
<a
|
||||||
|
ui-sref="clientCard.basicData({ id: {{::$ctrl.ticket.id}} })"
|
||||||
|
translate-attr="{title: 'View client'}"
|
||||||
|
class="vn-list-item">
|
||||||
|
<vn-horizontal ng-click="$ctrl.onClick($event)">
|
||||||
|
<vn-one>
|
||||||
|
<h6>{{::$ctrl.ticket.name}}</h6>
|
||||||
|
<div><vn-label translate>Id</vn-label> {{::$ctrl.ticket.id}}</div>
|
||||||
|
</vn-one>
|
||||||
|
<vn-horizontal class="buttons">
|
||||||
|
<vn-icon
|
||||||
|
vn-tooltip="Preview"
|
||||||
|
icon="icon-preview">
|
||||||
|
</vn-icon>
|
||||||
|
</vn-horizontal>
|
||||||
|
</vn-horizontal>
|
||||||
|
</a>
|
|
@ -0,0 +1,20 @@
|
||||||
|
import ngModule from '../module';
|
||||||
|
|
||||||
|
class Controller {
|
||||||
|
onClick(event) {
|
||||||
|
if (event.defaultPrevented)
|
||||||
|
event.stopImmediatePropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
preview(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ngModule.component('vnTicketItem', {
|
||||||
|
controller: Controller,
|
||||||
|
template: require('./item.html'),
|
||||||
|
bindings: {
|
||||||
|
ticket: '<'
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,3 @@
|
||||||
|
vn-ticket-item {
|
||||||
|
display: block;
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
Tickets: Tickets
|
|
@ -0,0 +1 @@
|
||||||
|
Tickets: Tickets
|
|
@ -0,0 +1,5 @@
|
||||||
|
import {ng} from 'vendor';
|
||||||
|
import 'core';
|
||||||
|
|
||||||
|
const ngModule = ng.module('ticket', ['vnCore']);
|
||||||
|
export default ngModule;
|
|
@ -0,0 +1,4 @@
|
||||||
|
export * from './module';
|
||||||
|
|
||||||
|
import './index/index';
|
||||||
|
|
|
@ -8,7 +8,6 @@ export default {
|
||||||
vnSubmit: 'vn-submit > input',
|
vnSubmit: 'vn-submit > input',
|
||||||
vnTopbar: 'vn-topbar > header',
|
vnTopbar: 'vn-topbar > header',
|
||||||
vnIcon: 'vn-icon',
|
vnIcon: 'vn-icon',
|
||||||
vnMainMenu: 'vn-main-menu > div',
|
|
||||||
vnModuleContainer: 'vn-module-container > a',
|
vnModuleContainer: 'vn-module-container > a',
|
||||||
vnSearchBar: 'vn-searchbar > form > vn-horizontal',
|
vnSearchBar: 'vn-searchbar > form > vn-horizontal',
|
||||||
vnFloatButton: 'vn-float-button > button',
|
vnFloatButton: 'vn-float-button > button',
|
||||||
|
|
|
@ -23,7 +23,7 @@ Nightmare.action('changeLanguageToEnglish', function(done) {
|
||||||
this.then(done);
|
this.then(done);
|
||||||
} else {
|
} else {
|
||||||
this.click('#lang')
|
this.click('#lang')
|
||||||
.click('#langs-menu > li[name="en"]')
|
.click('vn-main-menu [vn-id="langs-menu"] ul > li[name="en"]')
|
||||||
.then(done);
|
.then(done);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -6,8 +6,8 @@ export default {
|
||||||
globalItems: {
|
globalItems: {
|
||||||
logOutButton: `#logout`,
|
logOutButton: `#logout`,
|
||||||
applicationsMenuButton: `#apps`,
|
applicationsMenuButton: `#apps`,
|
||||||
applicationsMenuVisible: `${components.vnMainMenu} .is-visible > div`,
|
applicationsMenuVisible: `vn-main-menu [vn-id="apps-menu"] ul`,
|
||||||
clientsButton: `${components.vnMainMenu} > div > ul > li:nth-child(1)`
|
clientsButton: `vn-main-menu [vn-id="apps-menu"] ul > li:nth-child(1)`
|
||||||
},
|
},
|
||||||
moduleAccessView: {
|
moduleAccessView: {
|
||||||
clientsSectionButton: `${components.vnModuleContainer}[ui-sref="clients"]`,
|
clientsSectionButton: `${components.vnModuleContainer}[ui-sref="clients"]`,
|
||||||
|
|
20
gulpfile.js
20
gulpfile.js
|
@ -6,6 +6,7 @@ const exec = require('child_process').exec;
|
||||||
const PluginError = require('plugin-error');
|
const PluginError = require('plugin-error');
|
||||||
const argv = require('minimist')(process.argv.slice(2));
|
const argv = require('minimist')(process.argv.slice(2));
|
||||||
const log = require('fancy-log');
|
const log = require('fancy-log');
|
||||||
|
const environment = require('gulp-env');
|
||||||
|
|
||||||
// Configuration
|
// Configuration
|
||||||
|
|
||||||
|
@ -37,7 +38,13 @@ let defaultPort = proxyConf.defaultPort;
|
||||||
// Development
|
// Development
|
||||||
|
|
||||||
gulp.task('default', () => {
|
gulp.task('default', () => {
|
||||||
return gulp.start('services', 'client');
|
return gulp.start('environment', 'services', 'client');
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task('environment', async () => {
|
||||||
|
await environment({
|
||||||
|
file: '.env.json'
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('client', ['build-clean'], async () => {
|
gulp.task('client', ['build-clean'], async () => {
|
||||||
|
@ -48,7 +55,7 @@ gulp.task('client', ['build-clean'], async () => {
|
||||||
* Starts all backend services, including the nginx proxy and the database.
|
* Starts all backend services, including the nginx proxy and the database.
|
||||||
*/
|
*/
|
||||||
gulp.task('services', async () => {
|
gulp.task('services', async () => {
|
||||||
await runSequenceP('docker-start', 'services-only', 'nginx');
|
await runSequenceP('environment', 'docker-start', 'services-only', 'nginx');
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -137,7 +144,7 @@ gulp.task('install', () => {
|
||||||
// Deployment
|
// Deployment
|
||||||
|
|
||||||
gulp.task('build', ['clean'], async () => {
|
gulp.task('build', ['clean'], async () => {
|
||||||
await runSequenceP(['routes', 'locales', 'webpack', 'docker-compose', 'nginx-conf']);
|
await runSequenceP(['environment', 'routes', 'locales', 'webpack', 'docker-compose', 'nginx-conf']);
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('docker-compose', async () => {
|
gulp.task('docker-compose', async () => {
|
||||||
|
@ -154,7 +161,9 @@ gulp.task('docker-compose', async () => {
|
||||||
// dockerFile = 'Dockerfile';
|
// dockerFile = 'Dockerfile';
|
||||||
|
|
||||||
composeYml.services[service.name] = {
|
composeYml.services[service.name] = {
|
||||||
environment: ['NODE_ENV=${NODE_ENV}'],
|
environment: ['NODE_ENV=${NODE_ENV}' ,'salixHost=${salixHost}', 'salixPort=${salixPort}',
|
||||||
|
'salixUser=${salixUser}', 'salixPassword=${salixPassword}'
|
||||||
|
],
|
||||||
container_name: `\${BRANCH_NAME}-${service.name}`,
|
container_name: `\${BRANCH_NAME}-${service.name}`,
|
||||||
image: `${service.name}:\${TAG}`,
|
image: `${service.name}:\${TAG}`,
|
||||||
build: {
|
build: {
|
||||||
|
@ -480,7 +489,8 @@ gulp.task('docker-wait', callback => {
|
||||||
|
|
||||||
let conn = mysql.createConnection({
|
let conn = mysql.createConnection({
|
||||||
host: 'localhost',
|
host: 'localhost',
|
||||||
user: 'root'
|
user: 'root',
|
||||||
|
password: 'root'
|
||||||
});
|
});
|
||||||
conn.on('error', () => {});
|
conn.on('error', () => {});
|
||||||
conn.connect(err => {
|
conn.connect(err => {
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
"file-loader": "^1.1.6",
|
"file-loader": "^1.1.6",
|
||||||
"gulp": "^3.9.1",
|
"gulp": "^3.9.1",
|
||||||
"gulp-concat": "^2.6.0",
|
"gulp-concat": "^2.6.0",
|
||||||
|
"gulp-env": "^0.4.0",
|
||||||
"gulp-extend": "^0.2.0",
|
"gulp-extend": "^0.2.0",
|
||||||
"gulp-install": "^1.1.0",
|
"gulp-install": "^1.1.0",
|
||||||
"gulp-jasmine": "^3.0.0",
|
"gulp-jasmine": "^3.0.0",
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
// const SpecReporter = require('jasmine-spec-reporter').SpecReporter;
|
|
||||||
|
|
||||||
// module.exports = {
|
|
||||||
// reporter: new SpecReporter({
|
|
||||||
// spec: {
|
|
||||||
// // displayStacktrace: 'summary',
|
|
||||||
// displaySuccessful: false,
|
|
||||||
// displayFailedSpec: true,
|
|
||||||
// displaySpecDuration: true
|
|
||||||
// }
|
|
||||||
// }),
|
|
||||||
// config: {
|
|
||||||
// spec_dir: 'services',
|
|
||||||
// spec_files: [
|
|
||||||
// // '**/*.spec.js',
|
|
||||||
// 'auth/server/**/*.spec.js',
|
|
||||||
// 'client/common/**/*.spec.js',
|
|
||||||
// 'loopback/common/**/*.spec.js'
|
|
||||||
// ],
|
|
||||||
// helpers: [
|
|
||||||
// '/services/utils/jasmineHelpers.js'
|
|
||||||
// ]
|
|
||||||
// }
|
|
||||||
// };
|
|
File diff suppressed because it is too large
Load Diff
|
@ -2,5 +2,5 @@
|
||||||
|
|
||||||
for file in changes/*/*.sql; do
|
for file in changes/*/*.sql; do
|
||||||
echo "Importing $file"
|
echo "Importing $file"
|
||||||
mysql -u root < $file
|
mysql -u root -proot < $file
|
||||||
done
|
done
|
||||||
|
|
|
@ -24,8 +24,6 @@ INSERT INTO `account`.`user`(`id`,`name`,`password`,`role`,`active`,`email`)
|
||||||
(109, 'BruceBanner', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'BruceBanner@verdnatura.es'),
|
(109, 'BruceBanner', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'BruceBanner@verdnatura.es'),
|
||||||
(110, 'JessicaJones', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'JessicaJones@verdnatura.es');
|
(110, 'JessicaJones', 'ac754a330530832ba1bf7687f577da91', 2, 1, 'JessicaJones@verdnatura.es');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
INSERT INTO `vn`.`worker`(`workerCode`, `id`, `firstName`, `name`, `userFk`)
|
INSERT INTO `vn`.`worker`(`workerCode`, `id`, `firstName`, `name`, `userFk`)
|
||||||
VALUES
|
VALUES
|
||||||
('LGN', 106, 'David Charles', 'Haller', 106),
|
('LGN', 106, 'David Charles', 'Haller', 106),
|
||||||
|
@ -273,6 +271,12 @@ INSERT INTO `vn2008`.`empresa`(`id`, `abbreviation`, `registro`, `gerente_id`, `
|
||||||
(9, 5, 5, NULL, CURDATE(), 105, 'Hulk', 109),
|
(9, 5, 5, NULL, CURDATE(), 105, 'Hulk', 109),
|
||||||
(10, 6, 5, NULL, CURDATE(), 105, 'Jessica Jones', 110);
|
(10, 6, 5, NULL, CURDATE(), 105, 'Jessica Jones', 110);
|
||||||
|
|
||||||
|
INSERT INTO `vn`.`ticketObservation`(`id`, `ticketFk`, `observationTypeFk`, `description`)
|
||||||
|
VALUES
|
||||||
|
( 1, 1 , 1, 'ready' ),
|
||||||
|
( 2, 2 , 2, 'do it fast please'),
|
||||||
|
( 3, 3 , 3, '');
|
||||||
|
|
||||||
INSERT INTO `vn`.`ticketTracking`(`id`, `ticketFk`, `stateFk`, `workerFk`, `created`)
|
INSERT INTO `vn`.`ticketTracking`(`id`, `ticketFk`, `stateFk`, `workerFk`, `created`)
|
||||||
VALUES
|
VALUES
|
||||||
(1, 1, 1, 5, CURDATE()),
|
(1, 1, 1, 5, CURDATE()),
|
||||||
|
@ -393,6 +397,24 @@ INSERT INTO `vn`.`item`(`id`, `name`,`typeFk`,`size`,`inkFk`,`category`,`stems`,
|
||||||
(4, 'Mark I', 1, 60, 'AMR', 'EXT', 1, 1, 'Iron Mans first armor', 1, 05080000, 1, 2, 0, NULL, 0, 66090, 2),
|
(4, 'Mark I', 1, 60, 'AMR', 'EXT', 1, 1, 'Iron Mans first armor', 1, 05080000, 1, 2, 0, NULL, 0, 66090, 2),
|
||||||
(5, 'Mjolnir', 3, 30, 'AZR', 'EXT', 1, 2, 'Thors hammer!', 2, 06021010, 1, 2, 0, NULL, 0, 67350, 2);
|
(5, 'Mjolnir', 3, 30, 'AZR', 'EXT', 1, 2, 'Thors hammer!', 2, 06021010, 1, 2, 0, NULL, 0, 67350, 2);
|
||||||
|
|
||||||
|
INSERT INTO `vn`.`packaging`(`id`, `volume`, `width`, `height`, `depth`, `isPackageReturnable`, `created`, `itemFk`, `price`)
|
||||||
|
VALUES
|
||||||
|
(1, 0.00, 10, 10, 0, 0, CURDATE(), 1, 1.50),
|
||||||
|
(2, 100.00, 20, 20, 0, 0, CURDATE(), 2, 1.00),
|
||||||
|
('a', 50.00, 30, 30, 0, 1, CURDATE(), 3, 0.00);
|
||||||
|
|
||||||
|
INSERT INTO `vn`.`ticketPackaging`(`id`, `ticketFk`, `packagingFk`, `quantity`, `created`, `pvp`)
|
||||||
|
VALUES
|
||||||
|
( 1, 1, 1, 2, CURDATE(), NULL),
|
||||||
|
( 2, 2, 2, 1, CURDATE(), NULL),
|
||||||
|
( 3, 3, 'a', 4, CURDATE(), NULL);
|
||||||
|
|
||||||
|
INSERT INTO `vn`.`sale`(`id`, `itemFk`, `ticketFk`, `concept`, `quantity`, `price`, `discount`, `reserved`, `isPicked`, `created`)
|
||||||
|
VALUES
|
||||||
|
( 1, 1, 1, 'Gem of Time', 5 , 1.5, 0, 0, 0, CURDATE()),
|
||||||
|
( 2, 1, 1, 'Gem of Time', 2 , 1.5, 0, 0, 0, CURDATE()),
|
||||||
|
( 3, 2, 2, 'Mjolnir' , 10, 4 , 0, 0, 0, CURDATE());
|
||||||
|
|
||||||
INSERT INTO `vn`.`itemBarcode`(`id`, `itemFk`, `code`)
|
INSERT INTO `vn`.`itemBarcode`(`id`, `itemFk`, `code`)
|
||||||
VALUES
|
VALUES
|
||||||
(1, 1 ,1 ),
|
(1, 1 ,1 ),
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
FROM mysql:5.6.37
|
FROM mysql:5.6.37
|
||||||
|
|
||||||
ENV MYSQL_ALLOW_EMPTY_PASSWORD yes
|
ENV MYSQL_ROOT_PASSWORD root
|
||||||
ENV TZ GMT-1
|
ENV TZ GMT-1
|
||||||
|
|
||||||
WORKDIR /docker-entrypoint-initdb.d
|
WORKDIR /docker-entrypoint-initdb.d
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('Ticket', '*', '*', 'ALLOW', 'ROLE', 'employee');
|
||||||
|
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('TicketObservation', '*', '*', 'ALLOW', 'ROLE', 'employee');
|
||||||
|
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('Route', '*', 'READ', 'ALLOW', 'ROLE', 'employee');
|
||||||
|
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('Sale', '*', '*', 'ALLOW', 'ROLE', 'employee');
|
||||||
|
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('TicketTracking', '*', '*', 'ALLOW', 'ROLE', 'employee');
|
||||||
|
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('TicketState', '*', '*', 'ALLOW', 'ROLE', 'employee');
|
||||||
|
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('TicketPackaging', '*', '*', 'ALLOW', 'ROLE', 'employee');
|
||||||
|
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('Packaging', '*', 'READ', 'ALLOW', 'ROLE', 'employee');
|
||||||
|
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('Packaging', '*', 'WRITE', 'ALLOW', 'ROLE', 'logistic');
|
|
@ -0,0 +1,18 @@
|
||||||
|
USE `vn`;
|
||||||
|
CREATE
|
||||||
|
OR REPLACE ALGORITHM = UNDEFINED
|
||||||
|
DEFINER = `root`@`%`
|
||||||
|
SQL SECURITY DEFINER
|
||||||
|
VIEW `vn`.`packaging` AS
|
||||||
|
SELECT
|
||||||
|
`c`.`Id_Cubo` AS `id`,
|
||||||
|
`c`.`Volumen` AS `volume`,
|
||||||
|
`c`.`X` AS `width`,
|
||||||
|
`c`.`Y` AS `height`,
|
||||||
|
`c`.`Z` AS `depth`,
|
||||||
|
`c`.`Retornable` AS `isPackageReturnable`,
|
||||||
|
`c`.`odbc_date` AS `created`,
|
||||||
|
`c`.`item_id` AS `itemFk`,
|
||||||
|
`c`.`pvp` AS `price`
|
||||||
|
FROM
|
||||||
|
`vn2008`.`Cubos` `c`;
|
|
@ -1,2 +1,2 @@
|
||||||
|
|
||||||
mysqldump --defaults-file=connect.ini --default-character-set=utf8 --no-data --triggers --routines --events --databases account util vn2008 vn edi bs bi pbx cache salix vncontrol hedera > 01-structure.sql
|
mysqldump --defaults-file=connect.ini --default-character-set=utf8 --no-data --triggers --routines --events --databases account util vn2008 vn edi bs bi pbx cache salix vncontrol hedera stock > 01-structure.sql
|
||||||
|
|
|
@ -4,7 +4,7 @@ let connection = mysql.createConnection({
|
||||||
multipleStatements: true,
|
multipleStatements: true,
|
||||||
host: 'localhost',
|
host: 'localhost',
|
||||||
user: 'root',
|
user: 'root',
|
||||||
password: '',
|
password: 'root',
|
||||||
database: 'salix'
|
database: 'salix'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
let md5 = require('md5');
|
|
||||||
|
|
||||||
module.exports = function(Self) {
|
module.exports = function(Self) {
|
||||||
Self.remoteMethod('createWithUser', {
|
Self.remoteMethod('createWithUser', {
|
||||||
description: 'Creates both client and its web account',
|
description: 'Creates both client and its web account',
|
||||||
|
@ -18,7 +16,7 @@ module.exports = function(Self) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Self.createWithUser = (data, callback) => {
|
Self.createWithUser = async data => {
|
||||||
let firstEmail = data.email ? data.email.split(',')[0] : null;
|
let firstEmail = data.email ? data.email.split(',')[0] : null;
|
||||||
let user = {
|
let user = {
|
||||||
name: data.userName,
|
name: data.userName,
|
||||||
|
@ -27,34 +25,24 @@ module.exports = function(Self) {
|
||||||
};
|
};
|
||||||
let Account = Self.app.models.Account;
|
let Account = Self.app.models.Account;
|
||||||
|
|
||||||
Account.beginTransaction({}, (error, transaction) => {
|
let transaction = await Account.beginTransaction({});
|
||||||
if (error) return callback(error);
|
|
||||||
|
|
||||||
Account.create(user, {transaction}, (error, account) => {
|
try {
|
||||||
if (error) {
|
let account = await Account.create(user, {transaction});
|
||||||
transaction.rollback();
|
let client = {
|
||||||
return callback(error);
|
id: account.id,
|
||||||
}
|
name: data.name,
|
||||||
|
fi: data.fi,
|
||||||
let client = {
|
socialName: data.socialName,
|
||||||
name: data.name,
|
email: data.email,
|
||||||
fi: data.fi,
|
salesPersonFk: data.salesPersonFk
|
||||||
socialName: data.socialName,
|
};
|
||||||
id: account.id,
|
newClient = await Self.create(client, {transaction});
|
||||||
email: data.email,
|
await transaction.commit();
|
||||||
salesPersonFk: data.salesPersonFk
|
return newClient;
|
||||||
};
|
} catch (e) {
|
||||||
|
transaction.rollback();
|
||||||
Self.create(client, {transaction}, (error, newClient) => {
|
throw e;
|
||||||
if (error) {
|
}
|
||||||
transaction.rollback();
|
|
||||||
return callback(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
transaction.commit();
|
|
||||||
callback(null, newClient);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -48,45 +48,39 @@ describe('Client Create', () => {
|
||||||
.catch(catchErrors(done));
|
.catch(catchErrors(done));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not be able to create a user if exists', done => {
|
it('should not be able to create a user if exists', async() => {
|
||||||
app.models.Client.findOne({where: {name: 'Charles Xavier'}})
|
let client = await app.models.Client.findOne({where: {name: 'Charles Xavier'}});
|
||||||
.then(client => {
|
let account = await app.models.Account.findOne({where: {id: client.id}});
|
||||||
app.models.Account.findOne({where: {id: client.id}})
|
|
||||||
.then(account => {
|
|
||||||
let formerAccountData = {
|
|
||||||
name: client.name,
|
|
||||||
userName: account.name,
|
|
||||||
email: client.email,
|
|
||||||
fi: client.fi,
|
|
||||||
socialName: client.socialName
|
|
||||||
};
|
|
||||||
|
|
||||||
app.models.Client.createWithUser(formerAccountData, (err, client) => {
|
let formerAccountData = {
|
||||||
expect(err.details.codes.name[0]).toEqual('uniqueness');
|
name: client.name,
|
||||||
done();
|
userName: account.name,
|
||||||
});
|
email: client.email,
|
||||||
});
|
fi: client.fi,
|
||||||
})
|
socialName: client.socialName
|
||||||
.catch(catchErrors(done));
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
let client = await app.models.Client.createWithUser(formerAccountData);
|
||||||
|
|
||||||
|
expect(client).toBeNull();
|
||||||
|
} catch (err) {
|
||||||
|
expect(err.details.codes.name[0]).toEqual('uniqueness');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create a new account', done => {
|
it('should create a new account', async() => {
|
||||||
app.models.Client.createWithUser(newAccountData, (error, client) => {
|
let client = await app.models.Client.createWithUser(newAccountData);
|
||||||
if (error) return catchErrors(done)(error);
|
let account = await app.models.Account.findOne({where: {name: newAccountData.userName}});
|
||||||
app.models.Account.findOne({where: {name: newAccountData.userName}})
|
|
||||||
.then(account => {
|
expect(account.name).toEqual(newAccountData.userName);
|
||||||
expect(account.name).toEqual(newAccountData.userName);
|
|
||||||
app.models.Client.findOne({where: {name: newAccountData.name}})
|
client = await app.models.Client.findOne({where: {name: newAccountData.name}});
|
||||||
.then(client => {
|
|
||||||
expect(client.id).toEqual(account.id);
|
expect(client.id).toEqual(account.id);
|
||||||
expect(client.name).toEqual(newAccountData.name);
|
expect(client.name).toEqual(newAccountData.name);
|
||||||
expect(client.email).toEqual(newAccountData.email);
|
expect(client.email).toEqual(newAccountData.email);
|
||||||
expect(client.fi).toEqual(newAccountData.fi);
|
expect(client.fi).toEqual(newAccountData.fi);
|
||||||
expect(client.socialName).toEqual(newAccountData.socialName);
|
expect(client.socialName).toEqual(newAccountData.socialName);
|
||||||
done();
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch(catchErrors(done));
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,13 +1,6 @@
|
||||||
module.exports = function(Ticket) {
|
module.exports = function(Ticket) {
|
||||||
Ticket.remoteMethod('list', {
|
Ticket.remoteMethod('list', {
|
||||||
description: 'List tickets for production',
|
description: 'List tickets for production',
|
||||||
/* accepts: {
|
|
||||||
arg: 'id',
|
|
||||||
type: 'number',
|
|
||||||
required: true,
|
|
||||||
description: 'Model id',
|
|
||||||
http: {source: 'path'}
|
|
||||||
},*/
|
|
||||||
returns: {
|
returns: {
|
||||||
arg: 'tickets',
|
arg: 'tickets',
|
||||||
type: 'object'
|
type: 'object'
|
||||||
|
@ -19,19 +12,8 @@ module.exports = function(Ticket) {
|
||||||
});
|
});
|
||||||
|
|
||||||
Ticket.list = function(cb) {
|
Ticket.list = function(cb) {
|
||||||
// list();
|
|
||||||
};
|
|
||||||
|
|
||||||
function list() {
|
|
||||||
var params = [1, 0];
|
var params = [1, 0];
|
||||||
|
|
||||||
var query = 'CALL production_control_source(?, ?)';
|
var query = 'CALL production_control_source(?, ?)';
|
||||||
|
|
||||||
var cb = function(error, res) {
|
|
||||||
if (error) console.log(error);
|
|
||||||
else console.log(res);
|
|
||||||
};
|
|
||||||
|
|
||||||
Ticket.rawSql(query, params, cb);
|
Ticket.rawSql(query, params, cb);
|
||||||
};
|
};
|
||||||
};
|
};
|
|
@ -44,10 +44,22 @@ module.exports = function(Self) {
|
||||||
allowBlank: true
|
allowBlank: true
|
||||||
});
|
});
|
||||||
|
|
||||||
let validateDni = require('../validations/validateDni');
|
Self.validateAsync('fi', fiIsValid, {
|
||||||
Self.validateBinded('fi', validateDni, {
|
|
||||||
message: 'DNI Incorrecto'
|
message: 'DNI Incorrecto'
|
||||||
});
|
});
|
||||||
|
let validateDni = require('../validations/validateDni');
|
||||||
|
async function fiIsValid(err, done) {
|
||||||
|
let filter = {
|
||||||
|
fields: ['code'],
|
||||||
|
where: {id: this.countryFk}
|
||||||
|
};
|
||||||
|
let country = await Self.app.models.Country.findOne(filter);
|
||||||
|
let code = country ? country.code.toLowerCase() : null;
|
||||||
|
|
||||||
|
if (!validateDni(this.fi, code))
|
||||||
|
err();
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
|
||||||
Self.validate('payMethod', hasSalesMan, {
|
Self.validate('payMethod', hasSalesMan, {
|
||||||
message: 'No se puede cambiar la forma de pago si no hay comercial asignado'
|
message: 'No se puede cambiar la forma de pago si no hay comercial asignado'
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
{
|
||||||
|
"name": "Ticket",
|
||||||
|
"base": "VnModel",
|
||||||
|
"options": {
|
||||||
|
"mysql": {
|
||||||
|
"table": "ticket"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"id": true,
|
||||||
|
"type": "Number",
|
||||||
|
"description": "Identifier"
|
||||||
|
},
|
||||||
|
"shipped": {
|
||||||
|
"type": "date",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"landed": {
|
||||||
|
"type": "date"
|
||||||
|
},
|
||||||
|
"nickname": {
|
||||||
|
"type": "String"
|
||||||
|
},
|
||||||
|
"location": {
|
||||||
|
"type": "String"
|
||||||
|
},
|
||||||
|
"solution": {
|
||||||
|
"type": "String"
|
||||||
|
},
|
||||||
|
"packages": {
|
||||||
|
"type": "Number"
|
||||||
|
},
|
||||||
|
"created": {
|
||||||
|
"type": "date"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"relations": {
|
||||||
|
"client": {
|
||||||
|
"type": "belongsTo",
|
||||||
|
"model": "Client",
|
||||||
|
"foreignKey": "clientFk"
|
||||||
|
},
|
||||||
|
"warehouse": {
|
||||||
|
"type": "belongsTo",
|
||||||
|
"model": "Warehouse",
|
||||||
|
"foreignKey": "warehouseFk"
|
||||||
|
},
|
||||||
|
"invoiceOut": {
|
||||||
|
"type": "belongsTo",
|
||||||
|
"model": "InvoiceOut",
|
||||||
|
"foreignKey": "refFk"
|
||||||
|
},
|
||||||
|
"address": {
|
||||||
|
"type": "belongsTo",
|
||||||
|
"model": "Address",
|
||||||
|
"foreignKey": "addressFk"
|
||||||
|
},
|
||||||
|
"route": {
|
||||||
|
"type": "belongsTo",
|
||||||
|
"model": "Route",
|
||||||
|
"foreignKey": "routeFk"
|
||||||
|
},
|
||||||
|
"company": {
|
||||||
|
"type": "belongsTo",
|
||||||
|
"model": "Company",
|
||||||
|
"foreignKey": "companyFk"
|
||||||
|
},
|
||||||
|
"agencyMode": {
|
||||||
|
"type": "belongsTo",
|
||||||
|
"model": "AgencyMode",
|
||||||
|
"foreignKey": "agencyModeFk",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,39 +1,39 @@
|
||||||
const validateDni = require('../validateDni');
|
const validateDni = require('../validateDni');
|
||||||
|
|
||||||
describe('DNI validation', () => {
|
describe('DNI validation', () => {
|
||||||
it('should return false for invented DNI', () => {
|
it('should return true for any DNI when no country is passed', () => {
|
||||||
let isValid = validateDni('Pepinillos');
|
let isValid = validateDni('Pepinillos');
|
||||||
|
|
||||||
expect(isValid).toBeFalsy();
|
expect(isValid).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Spanish', () => {
|
describe('Spanish', () => {
|
||||||
it('should return true for valid spanish DNI', () => {
|
it('should return true for valid spanish DNI', () => {
|
||||||
let isValid = validateDni('20849756A');
|
let isValid = validateDni('20849756A', 'es');
|
||||||
|
|
||||||
expect(isValid).toBeTruthy();
|
expect(isValid).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return true for spanish DNI with exceeded digits', () => {
|
it('should return false for spanish DNI with exceeded digits', () => {
|
||||||
let isValid = validateDni('208497563239A');
|
let isValid = validateDni('208497563239A', 'es');
|
||||||
|
|
||||||
expect(isValid).toBeFalsy();
|
expect(isValid).toBeFalsy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return false for spanish DNI with invalid letter', () => {
|
it('should return false for spanish DNI with invalid letter', () => {
|
||||||
let isValid = validateDni('20243746E');
|
let isValid = validateDni('20243746E', 'es');
|
||||||
|
|
||||||
expect(isValid).toBeFalsy();
|
expect(isValid).toBeFalsy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return true for valid spanish CIF', () => {
|
it('should return true for valid spanish CIF', () => {
|
||||||
let isValid = validateDni('B97367486');
|
let isValid = validateDni('B97367486', 'es');
|
||||||
|
|
||||||
expect(isValid).toBeTruthy();
|
expect(isValid).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return false for spanish CIF with invalid letter', () => {
|
it('should return false for spanish CIF with invalid letter', () => {
|
||||||
let isValid = validateDni('A97527786');
|
let isValid = validateDni('A97527786', 'es');
|
||||||
|
|
||||||
expect(isValid).toBeFalsy();
|
expect(isValid).toBeFalsy();
|
||||||
});
|
});
|
||||||
|
@ -41,19 +41,19 @@ describe('DNI validation', () => {
|
||||||
|
|
||||||
describe('French', () => {
|
describe('French', () => {
|
||||||
it('should return true for valid french DNI', () => {
|
it('should return true for valid french DNI', () => {
|
||||||
let isValid = validateDni('FR1B123456789');
|
let isValid = validateDni('1B123456789', 'fr');
|
||||||
|
|
||||||
expect(isValid).toBeTruthy();
|
expect(isValid).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return true for french DNI with exceeded digits', () => {
|
it('should return false for french DNI with exceeded digits', () => {
|
||||||
let isValid = validateDni('FR1B12345678910');
|
let isValid = validateDni('1B12345678910', 'fr');
|
||||||
|
|
||||||
expect(isValid).toBeFalsy();
|
expect(isValid).toBeFalsy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return true for french DNI with bad syntax', () => {
|
it('should return false for french DNI with bad syntax', () => {
|
||||||
let isValid = validateDni('FR1B12345678A');
|
let isValid = validateDni('1B12345678A', 'fr');
|
||||||
|
|
||||||
expect(isValid).toBeFalsy();
|
expect(isValid).toBeFalsy();
|
||||||
});
|
});
|
||||||
|
@ -61,19 +61,19 @@ describe('DNI validation', () => {
|
||||||
|
|
||||||
describe('Italian', () => {
|
describe('Italian', () => {
|
||||||
it('should return true for valid italian DNI', () => {
|
it('should return true for valid italian DNI', () => {
|
||||||
let isValid = validateDni('IT12345678911');
|
let isValid = validateDni('12345678911', 'it');
|
||||||
|
|
||||||
expect(isValid).toBeTruthy();
|
expect(isValid).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return true for italian DNI with exceeded digits', () => {
|
it('should return false for italian DNI with exceeded digits', () => {
|
||||||
let isValid = validateDni('IT123456789112');
|
let isValid = validateDni('123456789112', 'it');
|
||||||
|
|
||||||
expect(isValid).toBeFalsy();
|
expect(isValid).toBeFalsy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return true for italian DNI with bad syntax', () => {
|
it('should return false for italian DNI with bad syntax', () => {
|
||||||
let isValid = validateDni('IT1234567891A');
|
let isValid = validateDni('1234567891A', 'it');
|
||||||
|
|
||||||
expect(isValid).toBeFalsy();
|
expect(isValid).toBeFalsy();
|
||||||
});
|
});
|
||||||
|
@ -81,19 +81,19 @@ describe('DNI validation', () => {
|
||||||
|
|
||||||
describe('Portuguese', () => {
|
describe('Portuguese', () => {
|
||||||
it('should return true for valid portuguese DNI', () => {
|
it('should return true for valid portuguese DNI', () => {
|
||||||
let isValid = validateDni('PT123456789');
|
let isValid = validateDni('123456789', 'pt');
|
||||||
|
|
||||||
expect(isValid).toBeTruthy();
|
expect(isValid).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return true for portuguese DNI with exceeded digits', () => {
|
it('should return false for portuguese DNI with exceeded digits', () => {
|
||||||
let isValid = validateDni('PT12345678910');
|
let isValid = validateDni('12345678910', 'pt');
|
||||||
|
|
||||||
expect(isValid).toBeFalsy();
|
expect(isValid).toBeFalsy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return true for portuguese DNI with bad syntax', () => {
|
it('should return false for portuguese DNI with bad syntax', () => {
|
||||||
let isValid = validateDni('PT12345678A');
|
let isValid = validateDni('12345678A', 'pt');
|
||||||
|
|
||||||
expect(isValid).toBeFalsy();
|
expect(isValid).toBeFalsy();
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,14 +1,12 @@
|
||||||
module.exports = function(fiWithCountry) {
|
module.exports = function(fi, country) {
|
||||||
if (fiWithCountry == null) return true;
|
if (fi == null || country == null)
|
||||||
if (typeof fiWithCountry != 'string') return false;
|
return true;
|
||||||
|
if (typeof fi != 'string' || typeof country != 'string')
|
||||||
|
return false;
|
||||||
|
|
||||||
fiWithCountry = fiWithCountry.toUpperCase();
|
fi = fi.toUpperCase();
|
||||||
|
country = country.toLowerCase();
|
||||||
|
|
||||||
if (!/^[A-Z]{2}/.test(fiWithCountry))
|
|
||||||
fiWithCountry = `ES${fiWithCountry}`;
|
|
||||||
|
|
||||||
let country = fiWithCountry.substring(0, 2).toLowerCase();
|
|
||||||
let fi = fiWithCountry.substring(2);
|
|
||||||
let len = fi.length;
|
let len = fi.length;
|
||||||
|
|
||||||
let validators = {
|
let validators = {
|
||||||
|
@ -38,7 +36,7 @@ module.exports = function(fiWithCountry) {
|
||||||
|
|
||||||
let sum = (pairSum + oddSum).toString();
|
let sum = (pairSum + oddSum).toString();
|
||||||
let units = parseInt(sum.charAt(sum.length - 1));
|
let units = parseInt(sum.charAt(sum.length - 1));
|
||||||
let control = units != 0 ? 10 - units : 0;
|
let control = units == 0 ? 0 : 10 - units;
|
||||||
let index = 'JABCDEFGHI'.indexOf(lastDigit);
|
let index = 'JABCDEFGHI'.indexOf(lastDigit);
|
||||||
computedDigit = index == -1 ? control.toString() : index;
|
computedDigit = index == -1 ? control.toString() : index;
|
||||||
} else {
|
} else {
|
||||||
|
@ -67,7 +65,7 @@ module.exports = function(fiWithCountry) {
|
||||||
let validator = validators[country];
|
let validator = validators[country];
|
||||||
|
|
||||||
if (!validator)
|
if (!validator)
|
||||||
return false;
|
return true;
|
||||||
|
|
||||||
return validator.regExp.test(fi)
|
return validator.regExp.test(fi)
|
||||||
&& (!validator.validate || validator.validate());
|
&& (!validator.validate || validator.validate());
|
||||||
|
|
|
@ -4,7 +4,7 @@ module.exports = function(iban) {
|
||||||
|
|
||||||
iban = iban.toUpperCase();
|
iban = iban.toUpperCase();
|
||||||
iban = trim(iban);
|
iban = trim(iban);
|
||||||
iban = iban.replace(/\s/g, "");
|
iban = iban.replace(/\s/g, '');
|
||||||
|
|
||||||
if (iban.length != 24) {
|
if (iban.length != 24) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -33,7 +33,7 @@ module.exports = function(iban) {
|
||||||
|
|
||||||
function module97(iban) {
|
function module97(iban) {
|
||||||
var parts = Math.ceil(iban.length / 7);
|
var parts = Math.ceil(iban.length / 7);
|
||||||
var remainer = "";
|
var remainer = '';
|
||||||
|
|
||||||
for (var i = 1; i <= parts; i++) {
|
for (var i = 1; i <= parts; i++) {
|
||||||
remainer = String(parseFloat(remainer + iban.substr((i - 1) * 7, 7)) % 97);
|
remainer = String(parseFloat(remainer + iban.substr((i - 1) * 7, 7)) % 97);
|
||||||
|
@ -48,6 +48,6 @@ module.exports = function(iban) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function trim(text) {
|
function trim(text) {
|
||||||
return (text || "").replace(/^(\s|\u00A0)+|(\s|\u00A0)+$/g, "" );
|
return (text || '').replace(/^(\s|\u00A0)+|(\s|\u00A0)+$/g, '');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,37 +1,41 @@
|
||||||
{
|
{
|
||||||
"db": {
|
"db": {
|
||||||
|
"name": "db",
|
||||||
"connector": "memory"
|
"connector": "memory"
|
||||||
},
|
},
|
||||||
"vn": {
|
"vn": {
|
||||||
|
"name": "mysql",
|
||||||
"connector": "mysql",
|
"connector": "mysql",
|
||||||
"database": "vn",
|
"database": "vn",
|
||||||
"debug": false,
|
"debug": false,
|
||||||
"host": "localhost",
|
"host": "${salixHost}",
|
||||||
"port": 3306,
|
"port": "${salixPort}",
|
||||||
"username": "root",
|
"username": "${salixUser}",
|
||||||
"password": "",
|
"password": "${salixPassword}",
|
||||||
"connectTimeout": 20000,
|
"connectTimeout": 20000,
|
||||||
"acquireTimeout": 20000
|
"acquireTimeout": 20000
|
||||||
},
|
},
|
||||||
"salix": {
|
"salix": {
|
||||||
|
"name": "mysql",
|
||||||
"connector": "mysql",
|
"connector": "mysql",
|
||||||
"database": "salix",
|
"database": "salix",
|
||||||
"debug": false,
|
"debug": false,
|
||||||
"host": "localhost",
|
"host": "${salixHost}",
|
||||||
"port": 3306,
|
"port": "${salixPort}",
|
||||||
"username": "root",
|
"username": "${salixUser}",
|
||||||
"password": "",
|
"password": "${salixPassword}",
|
||||||
"connectTimeout": 20000,
|
"connectTimeout": 20000,
|
||||||
"acquireTimeout": 20000
|
"acquireTimeout": 20000
|
||||||
},
|
},
|
||||||
"account": {
|
"account": {
|
||||||
|
"name": "mysql",
|
||||||
"connector": "mysql",
|
"connector": "mysql",
|
||||||
"database": "account",
|
"database": "account",
|
||||||
"debug": false,
|
"debug": false,
|
||||||
"host": "localhost",
|
"host": "${salixHost}",
|
||||||
"port": 3306,
|
"port": "${salixPort}",
|
||||||
"username": "root",
|
"username": "${salixUser}",
|
||||||
"password": "",
|
"password": "${salixPassword}",
|
||||||
"connectTimeout": 20000,
|
"connectTimeout": 20000,
|
||||||
"acquireTimeout": 20000
|
"acquireTimeout": 20000
|
||||||
},
|
},
|
||||||
|
@ -39,10 +43,10 @@
|
||||||
"connector": "mysql",
|
"connector": "mysql",
|
||||||
"database": "edi",
|
"database": "edi",
|
||||||
"debug": false,
|
"debug": false,
|
||||||
"host": "localhost",
|
"host": "${salixHost}",
|
||||||
"port": 3306,
|
"port": "${salixPort}",
|
||||||
"username": "root",
|
"username": "${salixUser}",
|
||||||
"password": "",
|
"password": "${salixPassword}",
|
||||||
"connectTimeout": 20000,
|
"connectTimeout": 20000,
|
||||||
"acquireTimeout": 20000
|
"acquireTimeout": 20000
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,5 +56,17 @@
|
||||||
},
|
},
|
||||||
"Worker": {
|
"Worker": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
}
|
},
|
||||||
|
"Ticket": {
|
||||||
|
"dataSource": "vn"
|
||||||
|
},
|
||||||
|
"Route": {
|
||||||
|
"dataSource": "vn"
|
||||||
|
},
|
||||||
|
"State":{
|
||||||
|
"dataSource": "vn"
|
||||||
|
},
|
||||||
|
"TicketState":{
|
||||||
|
"dataSource": "vn"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
"port": 3306,
|
"port": 3306,
|
||||||
"database": "vn",
|
"database": "vn",
|
||||||
"user": "root",
|
"user": "root",
|
||||||
"password": ""
|
"password": "root"
|
||||||
},
|
},
|
||||||
"smtp": {
|
"smtp": {
|
||||||
"host": "localhost",
|
"host": "localhost",
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
"port": 3306,
|
"port": 3306,
|
||||||
"database": "vn",
|
"database": "vn",
|
||||||
"user": "root",
|
"user": "root",
|
||||||
"password": ""
|
"password": "root"
|
||||||
},
|
},
|
||||||
"pdf": {
|
"pdf": {
|
||||||
"format": "A4",
|
"format": "A4",
|
||||||
|
|
|
@ -1,19 +0,0 @@
|
||||||
{
|
|
||||||
"name": "Ticket",
|
|
||||||
"base": "VnModel",
|
|
||||||
"options": {
|
|
||||||
"mysql": {
|
|
||||||
"table": "ticket"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"properties": {
|
|
||||||
"id": {
|
|
||||||
"id": true,
|
|
||||||
"type": "Number",
|
|
||||||
"forceId": false
|
|
||||||
},
|
|
||||||
"shipped": {
|
|
||||||
"type": "date"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -7,20 +7,5 @@
|
||||||
},
|
},
|
||||||
"MessageInbox": {
|
"MessageInbox": {
|
||||||
"dataSource": "vn"
|
"dataSource": "vn"
|
||||||
},
|
|
||||||
"Route": {
|
|
||||||
"dataSource": "vn"
|
|
||||||
},
|
|
||||||
"State":{
|
|
||||||
"dataSource": "vn"
|
|
||||||
},
|
|
||||||
"Ticket": {
|
|
||||||
"dataSource": "vn"
|
|
||||||
},
|
|
||||||
"TicketState":{
|
|
||||||
"dataSource": "vn"
|
|
||||||
},
|
|
||||||
"TicketTracking": {
|
|
||||||
"dataSource": "vn"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
FROM node:8.9.4
|
||||||
|
|
||||||
|
COPY ticket /app
|
||||||
|
COPY loopback /loopback
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
RUN npm install
|
||||||
|
RUN npm -g install pm2
|
||||||
|
|
||||||
|
CMD ["pm2-docker", "./server/server.js"]
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
{
|
||||||
|
"name": "ObservationType",
|
||||||
|
"base": "VnModel",
|
||||||
|
"options": {
|
||||||
|
"mysql": {
|
||||||
|
"table": "observationType"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"id": true,
|
||||||
|
"type": "Number",
|
||||||
|
"description": "Identifier"
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"type": "String",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"acls": [
|
||||||
|
{
|
||||||
|
"accessType": "READ",
|
||||||
|
"principalType": "ROLE",
|
||||||
|
"principalId": "$everyone",
|
||||||
|
"permission": "ALLOW"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
{
|
||||||
|
"name": "Packaging",
|
||||||
|
"base": "VnModel",
|
||||||
|
"options": {
|
||||||
|
"mysql": {
|
||||||
|
"table": "packaging"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"id": true,
|
||||||
|
"type": "Number",
|
||||||
|
"description": "Identifier"
|
||||||
|
},
|
||||||
|
"volume": {
|
||||||
|
"type": "Number"
|
||||||
|
},
|
||||||
|
"X": {
|
||||||
|
"type": "Date"
|
||||||
|
},
|
||||||
|
"Y": {
|
||||||
|
"type": "Number"
|
||||||
|
},
|
||||||
|
"Z": {
|
||||||
|
"type": "Number"
|
||||||
|
},
|
||||||
|
"isPackageReturnable": {
|
||||||
|
"type": "Number"
|
||||||
|
},
|
||||||
|
"created": {
|
||||||
|
"type": "Date"
|
||||||
|
},
|
||||||
|
"price": {
|
||||||
|
"type": "Number"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"relations": {
|
||||||
|
"item": {
|
||||||
|
"type": "belongsTo",
|
||||||
|
"model": "Iicket",
|
||||||
|
"foreignKey": "itemFk"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
{
|
||||||
|
"name": "Sale",
|
||||||
|
"base": "VnModel",
|
||||||
|
"options": {
|
||||||
|
"mysql": {
|
||||||
|
"table": "sale"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"id": true,
|
||||||
|
"type": "Number",
|
||||||
|
"description": "Identifier"
|
||||||
|
},
|
||||||
|
"concept": {
|
||||||
|
"type": "String"
|
||||||
|
},
|
||||||
|
"quantity": {
|
||||||
|
"type": "Number"
|
||||||
|
},
|
||||||
|
"price": {
|
||||||
|
"type": "Number"
|
||||||
|
},
|
||||||
|
"discount": {
|
||||||
|
"type": "Number"
|
||||||
|
},
|
||||||
|
"reserved": {
|
||||||
|
"type": "Number"
|
||||||
|
},
|
||||||
|
"isPicked": {
|
||||||
|
"type": "Number"
|
||||||
|
},
|
||||||
|
"created": {
|
||||||
|
"type": "date"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"relations": {
|
||||||
|
"item": {
|
||||||
|
"type": "belongsTo",
|
||||||
|
"model": "Item",
|
||||||
|
"foreignKey": "itemFk",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"ticket": {
|
||||||
|
"type": "belongsTo",
|
||||||
|
"model": "Ticket",
|
||||||
|
"foreignKey": "ticketFk",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
{
|
||||||
|
"name": "TicketObservation",
|
||||||
|
"base": "VnModel",
|
||||||
|
"options": {
|
||||||
|
"mysql": {
|
||||||
|
"table": "ticketObservation"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"id": true,
|
||||||
|
"type": "Number",
|
||||||
|
"description": "Identifier"
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"type": "String",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"relations": {
|
||||||
|
"ticket": {
|
||||||
|
"type": "belongsTo",
|
||||||
|
"model": "Ticket",
|
||||||
|
"foreignKey": "ticketFk",
|
||||||
|
"required": true
|
||||||
|
},
|
||||||
|
"observationType": {
|
||||||
|
"type": "belongsTo",
|
||||||
|
"model": "ObservationType",
|
||||||
|
"foreignKey": "observationTypeFk",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
{
|
||||||
|
"name": "TicketPackaging",
|
||||||
|
"base": "VnModel",
|
||||||
|
"options": {
|
||||||
|
"mysql": {
|
||||||
|
"table": "ticketPackaging"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"id": true,
|
||||||
|
"type": "Number",
|
||||||
|
"description": "Identifier"
|
||||||
|
},
|
||||||
|
"quantity": {
|
||||||
|
"type": "Number"
|
||||||
|
},
|
||||||
|
"created": {
|
||||||
|
"type": "Date"
|
||||||
|
},
|
||||||
|
"pvp": {
|
||||||
|
"type": "Number"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"relations": {
|
||||||
|
"ticket": {
|
||||||
|
"type": "belongsTo",
|
||||||
|
"model": "Ticket",
|
||||||
|
"foreignKey": "ticketFk"
|
||||||
|
},
|
||||||
|
"packaging": {
|
||||||
|
"type": "belongsTo",
|
||||||
|
"model": "Packaging",
|
||||||
|
"foreignKey": "packagingFk"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
},
|
},
|
||||||
"worker": {
|
"worker": {
|
||||||
"type": "belongsTo",
|
"type": "belongsTo",
|
||||||
"model": "worker",
|
"model": "Worker",
|
||||||
"foreignKey": "workerFk"
|
"foreignKey": "workerFk"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"name": "vn-ticket",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "server/server.js",
|
||||||
|
"scripts": {
|
||||||
|
"lint": "eslint .",
|
||||||
|
"start": "node .",
|
||||||
|
"posttest": "npm run lint && nsp check"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://git.verdnatura.es/salix"
|
||||||
|
},
|
||||||
|
"license": "GPL-3.0",
|
||||||
|
"description": "vn-ticket"
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"TicketObservation": {
|
||||||
|
"dataSource": "vn"
|
||||||
|
},
|
||||||
|
"ObservationType": {
|
||||||
|
"dataSource": "vn"
|
||||||
|
},
|
||||||
|
"Sale": {
|
||||||
|
"dataSource": "vn"
|
||||||
|
},
|
||||||
|
"TicketTracking": {
|
||||||
|
"dataSource": "vn"
|
||||||
|
},
|
||||||
|
"TicketPackaging": {
|
||||||
|
"dataSource": "vn"
|
||||||
|
},
|
||||||
|
"Packaging": {
|
||||||
|
"dataSource": "vn"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
|
||||||
|
var vnLoopback = require('../../loopback/server/server.js');
|
||||||
|
|
||||||
|
var app = module.exports = vnLoopback.loopback();
|
||||||
|
vnLoopback.boot(app, __dirname, module);
|
|
@ -13,6 +13,9 @@ if (process.argv[2] === '--v') {
|
||||||
var Jasmine = require('jasmine');
|
var Jasmine = require('jasmine');
|
||||||
var jasmine = new Jasmine();
|
var jasmine = new Jasmine();
|
||||||
var SpecReporter = require('jasmine-spec-reporter').SpecReporter;
|
var SpecReporter = require('jasmine-spec-reporter').SpecReporter;
|
||||||
|
let environment = require('gulp-env');
|
||||||
|
|
||||||
|
environment(".env.json");
|
||||||
|
|
||||||
jasmine.loadConfig({
|
jasmine.loadConfig({
|
||||||
spec_dir: 'services',
|
spec_dir: 'services',
|
||||||
|
|
Loading…
Reference in New Issue