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

This commit is contained in:
gerard 2018-08-31 14:35:30 +02:00
commit f81c97dee9
89 changed files with 4008 additions and 5460 deletions

1
.gitignore vendored
View File

@ -3,3 +3,4 @@ build
npm-debug.log
docker-compose.yml
.eslintcache
.env.json

View File

@ -2,5 +2,6 @@
{
// Carácter predeterminado de final de línea.
"files.eol": "\n",
"vsicons.presets.angular": false
"vsicons.presets.angular": false,
"eslint.autoFixOnSave": true
}

View File

@ -1,9 +0,0 @@
import FilterList from 'core/src/lib/filter-list';
export default class FilterClientList extends FilterList {
constructor($scope, $timeout, $state) {
super($scope, $timeout, $state);
this.modelName = 'clientFk';
}
}
FilterClientList.$inject = ['$scope', '$timeout', '$state'];

View File

@ -12,13 +12,36 @@ describe('Component vnStepControl', () => {
beforeEach(angular.mock.inject((_$componentController_, _$state_) => {
$componentController = _$componentController_;
$state = _$state_;
spyOn($state, 'go');
controller = $componentController('vnStepControl', {$state: $state});
}));
describe('steps()', () => {
it(`should do nothing if called without args`, () => {
controller.steps = undefined;
expect(controller._steps).not.toEqual(null);
});
it(`should set _steps property in the controller and call state.go()`, () => {
controller.$state.current.name = 'test';
controller.steps = [{state: 'nothing'}, {state: 'test'}];
expect(controller._steps).toEqual([{state: 'nothing'}, {state: 'test'}]);
expect(controller.currentStepIndex).toEqual(1);
expect(controller.$state.go).toHaveBeenCalledWith('nothing');
});
});
describe('currentState()', () => {
it(`should call the go method if the's no onStepChange`, () => {
controller.currentState = 'hello state!';
expect(controller.$state.go).toHaveBeenCalledWith('hello state!');
});
it(`should call the onStepChange method then return false and never call the go method`, () => {
controller.onStepChange = jasmine.createSpy(controller, 'onStepChange').and.returnValue(false);
spyOn(controller.$state, 'go');
controller.currentState = "something";
@ -28,7 +51,6 @@ describe('Component vnStepControl', () => {
it(`should call the onStepChange method then return true and finally call the go method`, () => {
controller.onStepChange = jasmine.createSpy(controller, 'onStepChange').and.returnValue(true);
spyOn(controller.$state, 'go');
controller.currentState = "something";

View File

@ -1,45 +0,0 @@
/**
* Generic class to list models.
*/
export default class FilterList {
constructor($scope, $timeout, $state) {
this.$ = $scope;
this.$timeout = $timeout;
this.$state = $state;
this.waitingMgCrud = 0;
this.modelId = $state.params.id;
this.instances = [];
}
onOrder(field, order) {
this.filter(`${field} ${order}`);
}
filter(order) {
if (this.$.index && this.modelId && this.modelName) {
this.waitingMgCrud = 0;
this.$.index.filter = {
page: 1,
size: 10
};
this.$.index.filter[this.modelName] = this.modelId;
if (order) {
this.$.index.filter.order = order;
}
this.$.index.accept().then(res => {
this.instances = res.instances;
});
} else if (!this.modelId || !this.modelName) {
throw new Error('Error: model not found');
} else if (this.waitingMgCrud > 3) {
throw new Error('Error: Magic Crud is not loaded');
} else {
this.waitingMgCrud++;
this.$timeout(() => {
this.filter(order);
}, 250);
}
}
}

View File

@ -4,7 +4,6 @@ import './app';
import './interceptor';
import './acl-service';
import './storage-services';
import './filter-list';
import './template';
import './spliting-register';
import './interpolate';

View File

@ -15,8 +15,7 @@ export function factory($http, $window, $ocLazyLoad, $translatePartialLoader, $t
if (loaded[moduleName] instanceof Promise)
return loaded[moduleName];
if (loaded[moduleName] === false)
return $q.reject(
new Error(`Module dependency loop detected: ${moduleName}`));
return $q.reject(new Error(`Module dependency loop detected: ${moduleName}`));
loaded[moduleName] = false;

View File

@ -9,7 +9,7 @@ describe('Service acl', () => {
$provide.value('aclConstant', {});
}));
beforeEach(inject((_aclService_, $httpBackend) => {
beforeEach(inject(_aclService_ => {
aclService = _aclService_;
}));

View File

@ -0,0 +1,48 @@
describe('factory vnModuleLoader', () => {
let vnModuleLoader;
let $scope;
beforeEach(() => {
angular.mock.module('vnCore');
});
beforeEach(angular.mock.inject((_vnModuleLoader_, $rootScope, $httpBackend) => {
vnModuleLoader = _vnModuleLoader_;
$scope = $rootScope;
$httpBackend.when('GET', /\/locale\/\w+\/[a-z]{2}\.json/).respond({});
}));
describe('load()', () => {
it('should return truthy promise if the module was loaded', async() => {
vnModuleLoader._loaded.myModule = true;
let result = await vnModuleLoader.load('myModule', {myValidations: () => {}});
expect(result).toEqual(true);
});
it('should return a promise if the module was still a promise', () => {
vnModuleLoader._loaded.myModule = new Promise(() => {
return 'I promise you a module!';
});
let result = vnModuleLoader.load('myModule', {myValidations: () => {}});
expect(result).toEqual(jasmine.any(Promise));
});
it('should return an error if the module wasnt loaded', done => {
vnModuleLoader._loaded.myModule = false;
vnModuleLoader.load('myModule', {myValidations: () => {}})
.then(() => {
done.fail('this must fail');
})
.catch(error => {
expect(error.toString()).toEqual(`Error: Module dependency loop detected: myModule`);
done();
});
$scope.$apply();
});
});
});

View File

@ -1,9 +0,0 @@
import FilterList from 'core/src/lib/filter-list';
export default class FilterItemList extends FilterList {
constructor($scope, $timeout, $state) {
super($scope, $timeout, $state);
this.modelName = 'itemFk';
}
}
FilterItemList.$inject = ['$scope', '$timeout', '$state'];

View File

@ -1,7 +1,6 @@
export * from './module';
import './index';
import './filter-item-list';
import './search-panel';
import './diary';
import './create';

View File

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

View File

@ -1,14 +0,0 @@
/* {
"module": "locator",
"name": "Locator",
"icon": "add_location",
"validations" : false,
"routes": [
{
"url": "/locator",
"state": "locator",
"component": "vn-locator-index",
"acl": ["developer"]
}
]
} */

View File

@ -1,39 +0,0 @@
<vn-card margin-large>
<vn-vertical pad-medium>
<vn-horizontal vn-one margin-large-bottom class="locator-header">
<vn-title vn-one>Routes locator</vn-title>
<form vn-two vn-horizontal class="filterPanel" ng-submit="$ctrl.searchRoutes()">
<vn-textfield vn-one label="Filter" model="$ctrl.search"></vn-textfield>
<vn-icon
vn-none
margin-medium-right
pad-medium-top
icon="keyboard_arrow_down"
ng-click="$ctrl.moreFilters($event)">
</vn-icon>
<vn-button vn-none pad-small-top label="Filtrar" ng-click="$ctrl.searchRoutes()"></vn-button>
</form>
<vn-one vn-horizontal>
<vn-one></vn-one>
<vn-autocomplete vn-two
initial-value="$ctrl.filter.warehouseFk"
show-field="name"
value-field="id"
field="$ctrl.filter.warehouseFk"
url="/production/api/Warehouses"
on-change = "$ctrl.onChangeWareHouse(item)"
label="Store">
</vn-autocomplete>
<vn-icon-button vn-none pad-ten-top margin-medium-left icon="refresh" ng-click="$ctrl.refreshRoutes()"></vn-icon-button>
</vn-one>
</vn-horizontal>
<vn-horizontal vn-one margin-large-bottom>
<vn-one>
<vn-locator-actions routes="$ctrl.routes" states="$ctrl.states" hour-items="$ctrl.hourItems"></vn-locator-actions>
</vn-one>
<vn-two></vn-two>
</vn-horizontal>
<vn-locator-table check-all="$ctrl.checkAll" routes="$ctrl.routes" footer="$ctrl.footer"></vn-locator-table>
</vn-vertical>
</vn-card>

View File

@ -1,33 +0,0 @@
import ngModule from '../module';
class LocatorIndex {
constructor($state) {
this.$state = $state;
this.routes = [];
for (let i = 1; i < 100; i++) {
let route = {
id: i,
zoneFk: Math.floor(Math.random() * 6) + 1,
postalcode: 46006,
order: Math.floor(Math.random() * 3) + 1,
preparado: '25/08',
entrada: '26/08',
ticket: 1547890 + i,
routeFk: Math.floor(Math.random() * 9999) + 1000,
alias: `Flores X${Math.floor(Math.random() * 3) + 1}`,
bultos: Math.floor(Math.random() * 20) + 10,
m3: (Math.random()).toFixed(2),
error: (Math.floor(Math.random() * 3) + 1) === 1
};
route.success = (!route.error && (Math.floor(Math.random() * 3) + 1) === 1);
this.routes.push(route);
}
}
}
LocatorIndex.$inject = ['$state'];
ngModule.component('vnLocatorIndex', {
template: require('./index.html'),
controller: LocatorIndex
});

View File

@ -1,4 +0,0 @@
Routes locator: Routes locator
Filter: Filter
Store: Store
Address: Address

View File

@ -1,4 +0,0 @@
Routes locator: Localizador de rutas
Filter: Filtro
Store: Almacén
Address: Dirección

View File

@ -1,14 +0,0 @@
<vn-horizontal class="actionPanel">
<vn-none margin-medium-right>
<vn-icon-button icon="local_shipping"></vn-icon-button>
</vn-none>
<vn-none margin-medium-right>
<vn-icon-menu icon="local_shipping" selected="$ctrl.actionRoute" items="[{id:1,name:'test_01'},{id:2,name:'test_02'}]"></vn-icon-menu>
</vn-none>
<vn-none margin-medium-right>
</vn-none>
<vn-none margin-medium-right>
</vn-none>
</vn-horizontal>

View File

@ -1,13 +0,0 @@
import ngModule from '../module';
class LocatorActions {
constructor($state) {
this.$state = $state;
}
}
LocatorActions.$inject = ['$state'];
ngModule.component('vnLocatorActions', {
template: require('./locator-actions.html'),
controller: LocatorActions
});

View File

@ -1,55 +0,0 @@
<vn-vertical>
<vn-grid-header on-order="$ctrl.onOrder(field, order)">
<vn-column-header vn-one pad-medium-h>
<vn-multi-check
check-all="$ctrl.checkAll"
models="$ctrl.routes"
options="[{id:'all',name:'Todos'},{id:'any',name:'Ninguno'}, {id:'error', name:'Con problema'}, {id:'no-error', name:'Sin problema'}]">
</vn-multi-check>
</vn-column-header>
<vn-column-header vn-two pad-medium-h field="zoneFk" text="Zona"></vn-column-header>
<vn-column-header vn-two pad-medium-h field="postalcode" text="Postal Code"></vn-column-header>
<vn-column-header vn-two pad-medium-h field="order" text="Order" default-order="DESC"></vn-column-header>
<vn-column-header vn-two pad-medium-h field="preparado" text="Preparado"></vn-column-header>
<vn-column-header vn-two pad-medium-h field="entrada" text="Entrada"></vn-column-header>
<vn-column-header vn-two pad-medium-h field="ticket" text="Ticket"></vn-column-header>
<vn-column-header vn-two pad-medium-h field="routeFk" text="ID de ruta"></vn-column-header>
<vn-column-header vn-two pad-medium-h field="alias" text="Alias"></vn-column-header>
<vn-column-header vn-two pad-medium-h field="bultos" text="Bultos"></vn-column-header>
<vn-column-header vn-two pad-medium-h field="m3" text="m3"></vn-column-header>
</vn-grid-header>
<vn-one class="list list-content">
<vn-vertical
class="list list-element text-center"
ng-repeat="route in $ctrl.pageTable.model track by route.id"
ng-class="{warning: route.error, success: route.success}">
<vn-horizontal>
<vn-one pad-medium-h></vn-one>
<vn-two pad-medium-h>{{::route.zoneFk}}</vn-two>
<vn-two pad-medium-h>{{::route.postalcode}}</vn-two>
<vn-two pad-medium-h>{{::route.order}}</vn-two>
<vn-two pad-medium-h>{{::route.preparado}}</vn-two>
<vn-two pad-medium-h>{{::route.entrada}}</vn-two>
<vn-two pad-medium-h>{{::route.ticket}}</vn-two>
<vn-two pad-medium-h>{{::route.routeFk}}</vn-two>
<vn-two pad-medium-h>{{::route.alias}}</vn-two>
<vn-two pad-medium-h>{{::route.bultos}}</vn-two>
<vn-two pad-medium-h>{{::route.m3}}</vn-two>
</vn-horizontal>
<vn-horizontal margin-small-top>
<vn-none pad-medium-h margin--small-top>
<vn-check model="route.checked"></vn-check>
</vn-none>
<vn-none pad-medium-h></vn-none>
<vn-one text-left pad-small border-solid>
<strong translate>Address</strong>: {{::route.address}}
</vn-one>
</vn-horizontal>
</vn-vertical>
</vn-one>
<vn-horizontal vn-one class="list list-footer">
</vn-horizontal>
<vn-one>
<vn-paging page-change="$ctrl.paginate()" index="$ctrl.pageTable" total="$ctrl.totalFilter"></vn-paging>
</vn-one>
</vn-vertical>

View File

@ -1,46 +0,0 @@
import ngModule from '../module';
class LocatorTable {
constructor($filter) {
this.$filter = $filter;
this.itemsDisplayedInList = 7;
this.pageTable = {
filter: {
page: 1,
size: this.itemsDisplayedInList
},
model: []
};
this._routes = [];
}
set routes(value) {
this._routes = value;
this.totalFilter = this._routes.length;
this.pageTable.filter.page = 1;
this.paginate();
}
get routes() {
return this._routes;
}
onOrder(field, order) {
let reverse = order === 'DESC';
this.routes = this.$filter('orderBy')(this.routes, field, reverse);
this.paginate();
}
paginate() {
let init = (this.pageTable.filter.page - 1) * this.itemsDisplayedInList;
let fin = this.pageTable.filter.page * this.itemsDisplayedInList;
this.pageTable.model = this.routes.slice(init, fin);
}
}
LocatorTable.$inject = ['$filter'];
ngModule.component('vnLocatorTable', {
template: require('./locator-table.html'),
bindings: {
routes: '<'
},
controller: LocatorTable
});

View File

@ -1,5 +0,0 @@
export * from './module';
import './index/index';
import './locator-actions/locator-actions';
import './locator-table/locator-table';

View File

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

View File

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

View File

@ -1,14 +0,0 @@
/* {
"module": "production",
"name": "Production",
"icon": "local_florist",
"validations" : false,
"routes": [
{
"url": "/production",
"state": "production",
"component": "vn-production-index",
"acl": ["developer"]
}
]
} */

View File

@ -1,39 +0,0 @@
<mg-ajax path="/production/api/States/list" options="vnIndex as states" actions="$ctrl.sharedData.states = states.model;"></mg-ajax>
<mg-ajax path="/production/api/FakeProductions/list" options="vnIndexNonAuto as index"></mg-ajax>
<vn-card margin-large>
<vn-vertical pad-medium>
<vn-horizontal vn-one margin-large-bottom class="locator-header">
<vn-title vn-one><span translate>Finder</span></vn-title>
<vn-searchbar
vn-two
index="index"
on-search="$ctrl.searchTickets(index.filter)"
advanced="true"
popover="vn-production-filter-panel"
ignore-keys = "['page', 'size', 'search', 'warehouseFk']"
data ="$ctrl.sharedData">
</vn-searchbar>
<vn-one vn-horizontal>
<vn-one></vn-one>
<vn-autocomplete
vn-two
initial-value="$ctrl.filter.warehouseFk"
show-field="name"
value-field="id"
field="$ctrl.filter.warehouseFk"
url="/production/api/Warehouses"
on-change = "$ctrl.onChangeWareHouse(item)"
label="Store">
</vn-autocomplete>
<vn-icon-button vn-none pad-ten-top margin-medium-left icon="refresh" ng-click="$ctrl.refreshTickets()"></vn-icon-button>
</vn-one>
</vn-horizontal>
<vn-horizontal vn-one margin-large-bottom>
<vn-one>
<vn-production-actions></vn-production-actions>
</vn-one>
<vn-two></vn-two>
</vn-horizontal>
<vn-production-table check-all="$ctrl.checkAll" tickets="$ctrl.tickets" footer="$ctrl.footer"></vn-production-table>
</vn-vertical>
</vn-card>

View File

@ -1,103 +0,0 @@
import ngModule from '../module';
import './style.scss';
export default class ProductionIndex {
constructor($element, $scope, $http, aclConstant) {
this.$element = $element;
this.$ = $scope;
this.$http = $http;
this.filter = {};
this.tickets = [];
this.checkAll = 0;
this.footer = {
total: null,
lines: null,
meters: null
};
this._search = null;
this.sharedData = {
states: [],
hourItems: []
};
this.child = undefined;
this.userProfile = aclConstant.userProfile;
this.filter.warehouseFk = this.userProfile.warehouseId;
}
get checkAll() {
return this._checkAll;
}
set checkAll(value) {
this._checkAll = value;
}
// Actions Callbacks
_changeState(ids, stateId, stateName, index) {
this.$http.put(`/production/api/TicketStates/${stateId}/changeState`, {tickets: ids}).then(() => {
index.forEach(val => {
this.tickets[val].state = stateName;
this.tickets[val].stateFk = stateId;
});
});
}
_sendMessage(tickets) {
this.$http.post(`/production/api/FakeProductions/messageSend`, {tickets: tickets}).then(() => {
this.vnApp.showMessage(this.$translate.instant('Success: message send!'));
});
}
_changeTime(ids, time, index) {
this.$http.put(`/production/api/Tickets/${time}/changeTime`, {tickets: ids}).then(() => {
index.forEach(val => {
this.tickets[val].hour = time;
});
});
}
searchTickets(filter) {
this.$.index.filter.filter = Object.assign({}, this.filter, filter || {});
this.checkAll = 0;
this.$.index.accept().then(json => {
this.tickets = json.tickets;
this.footer.lines = json.lines;
this.footer.meters = json.m3;
this.footer.total = json.total;
});
}
refreshTickets() {
this.filter = {};
this.filter.warehouseFk = this.$.displayValue = this.userProfile.warehouseId;
}
onChangeWareHouse(warehouse) {
if (warehouse && warehouse != this.filter.warehouseFk) {
this.filter.warehouseFk = warehouse;
this.searchTickets(this.filter);
}
}
$onInit() {
for (let i = 1; i <= 24; i++) {
let hour = [i].join('');
if (hour.length === 1) {
hour = [0, i].join('');
}
hour += ':00';
this.sharedData.hourItems.push({id: i, name: hour});
}
this.filter.warehouseFk = this.$.displayValue = this.userProfile.warehouseId;
}
}
ProductionIndex.$inject = ['$element', '$scope', '$http', 'aclConstant'];
ngModule.component('vnProductionIndex', {
template: require('./index.html'),
controller: ProductionIndex
});

View File

@ -1,39 +0,0 @@
import './index.js';
describe('Production', () => {
describe('Component vnProductionIndex', () => {
let $componentController;
let $httpBackend;
let $scope;
let controller;
let $element;
let aclConstant;
beforeEach(() => {
angular.mock.module('production');
});
beforeEach(angular.mock.inject((_$componentController_, $rootScope, _$httpBackend_) => {
$element = angular.element('<div></div>');
$componentController = _$componentController_;
$httpBackend = _$httpBackend_;
$scope = $rootScope.$new();
aclConstant = {userProfile: {warehouseId: 1}};
controller = $componentController('vnProductionIndex', {$scope: $scope, $element: $element, aclConstant: aclConstant});
}));
describe('_changeState()', () => {
it('should request to update the ticket state', () => {
let ids = [1, 2, 3, 4];
let stateId = 1;
let stateName = 'state';
let index = [];
controller.tickets = ['ticketVal'];
$httpBackend.whenPUT('/production/api/TicketStates/1/changeState', {tickets: ids}).respond({data: 'ticketVal'});
$httpBackend.expectPUT('/production/api/TicketStates/1/changeState', {tickets: ids});
controller._changeState(ids, stateId, stateName, index);
$httpBackend.flush();
});
});
});
});

View File

@ -1,36 +0,0 @@
vn-production-index {
flex: 1;
button {
height: 20px;
padding: 0 6px;
}
vn-searchbar {
vn-icon{
padding-top: 20px;
}
vn-icon-button{
padding-top: 10px;
}
}
[pad-ten-top] {
padding-top: 10px;
}
.icon-square{
height: 36px;
}
.locator-header{
i{
cursor: pointer;
}
.moreFilters{
position: absolute;
z-index: 99;
background-color: white;
padding: 15px;
border: 1px solid #9D9D9D;
margin-top: 60px;
width: 600px;
}
}
}

View File

@ -1 +0,0 @@
Production: Production

View File

@ -1,27 +0,0 @@
Finder: Localizador
Production: Producción
'Error: No tickets selected!': 'Error: ¡No hay tickets seleccionados!'
'Error: Action not implemented!': 'Error: ¡Acción no implementada!'
State: Estado
Alarm: Alarma
Agencies: Agencias
Agency: Agencia
Store: Almacén
Printed: Impreso
Commercial: Comercial
Hour: Hora
Lines: Líneas
Boxes: Cajas
Comment: Comentario
Message: Mensaje
Send: Enviar
Date: Fecha
Ticket ID: ID Ticket
Route ID: ID Ruta
Province: Provincia
Filter: Filtrar
Cancel: Cancelar
Worker: Trabajador
Town: Población
Client ID: ID Cliente
Ticket with incidence: Ticket con incidencia

View File

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

View File

@ -1,15 +0,0 @@
<vn-horizontal class="actionPanel">
<vn-button vn-none margin-medium-right label="Printed" ng-click="$ctrl.doAction('markPrinted')"></vn-button>
<vn-none margin-medium-right>
<vn-icon-menu icon="assignment" items="$ctrl.parent.sharedData.states" selected="$ctrl.actionState"></vn-icon-menu>
</vn-none>
<vn-none margin-medium-right>
<vn-icon-button icon="textsms" ng-click="$ctrl.doAction('addComment')"></vn-icon-button>
</vn-none>
<vn-none margin-medium-right>
<vn-icon-menu icon="person" url="/client/api/Clients/listWorkers" selected="$ctrl.actionWorker"></vn-icon-menu>
</vn-none>
<vn-none margin-medium-right>
<vn-icon-menu icon="query_builder" items="$ctrl.parent.sharedData.hourItems" selected="$ctrl.actionHours"></vn-icon-menu>
</vn-none>
</vn-horizontal>

View File

@ -1,118 +0,0 @@
import ngModule from '../module';
export default class ProductionActions {
constructor($http, $translate, vnApp) {
this.$http = $http;
this.$translate = $translate;
this.vnApp = vnApp;
this._actionState = null;
this._actionWorker = null;
this._actionHours = null;
}
set actionState(value) {
this._actionState = value;
this.doAction('changeState');
}
get actionState() {
return this._actionState;
}
set actionHours(value) {
this._actionHours = value;
this.doAction('changeTime');
}
get actionHours() {
return this._actionHours;
}
set actionWorker(value) {
this._actionWorker = value;
this.doAction('changeWorker');
}
get actionWorker() {
return this._actionWorker;
}
_changeState(ids, sateteId) {
this.$http.put(`/production/api/TicketStates/${sateteId}/changeState`, {tickets: ids})
.then(
() => {
this.parent.searchTickets();
}
);
}
_sendMessage(tickets) {
this.$http.post(`/production/api/FakeProductions/messageSend`, {tickets: tickets})
.then(
() => {
this.vnApp.showMessage(this.$translate.instant('Success: message send!'));
}
);
}
_changeTime(ids, time, index) {
this.$http.put(`/production/api/Tickets/${time}/changeTime`, {tickets: ids})
.then(
() => {
this.parent.searchTickets();
}
);
}
_changeWorker(ids, workerFk, index) {
this.$http.put(`/production/api/Tickets/${workerFk}/changeWorker`, {tickets: ids})
.then(
() => {
this.parent.searchTickets();
}
);
}
doAction(actionName) {
let ids = [];
let index = [];
let tickets = [];
this.parent.tickets.forEach(
(val, i) => {
if (val.checked) {
ids.push(val.ticketFk);
index.push(i);
tickets.push({ticketFk: val.ticketFk, salesPerson: val.salesPerson});
}
}
);
if (tickets.length) {
switch (actionName) {
case 'changeState' :
this._changeState(ids, this.actionState.id);
break;
case 'addComment':
this._sendMessage(tickets);
break;
case 'markPrinted':
this._changeState(ids, 4);
break;
case 'changeTime':
this._changeTime(ids, this.actionHours.name, index);
break;
case 'changeWorker':
this._changeWorker(ids, this.actionWorker.id, index);
break;
default:
this.vnApp.showMessage(this.$translate.instant('Error: Action not implemented!'));
}
} else {
this.vnApp.showMessage(this.$translate.instant('Error: No tickets selected!'));
}
}
}
ProductionActions.$inject = ['$http', '$translate', 'vnApp'];
ngModule.component('vnProductionActions', {
template: require('./production-actions.html'),
controller: ProductionActions,
require: {
parent: '^^vnProductionIndex'
}
});

View File

@ -1,6 +0,0 @@
<form ng-submit="$ctrl.onComment($ctrl.ids, $ctrl.comment)" pad-large>
<vn-horizontal>
<vn-textfield vn-one label="Message" model="$ctrl.comment"></vn-textfield>
<vn-submit vn-none pad-small-top label="Send"></vn-submit>
</vn-horizontal>
</form>

View File

@ -1,5 +0,0 @@
import ngModule from '../module';
ngModule.component('vnProductionComment', {
template: require('./production-comment.html')
});

View File

@ -1,32 +0,0 @@
<form ng-submit="$ctrl.onSubmit($ctrl.filter)" pad-large>
<vn-horizontal>
<vn-textfield vn-one label="Route ID" model="$ctrl.filter.routeFk"></vn-textfield>
<vn-date-picker vn-one label="Date" model="$ctrl.filter.date"></vn-date-picker>
</vn-horizontal>
<vn-horizontal>
<vn-autocomplete vn-one
field="$ctrl.filter.provinceFk"
url="/client/api/Provinces"
show-field="name"
value-field="id"
label="Province">
</vn-autocomplete>
<vn-autocomplete vn-one
data="$ctrl.data.hourItems"
label="Hour"
value-field="name"
field="$ctrl.filter.hour"
>
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal>
<vn-autocomplete vn-one margin-medium-right field="$ctrl.filter.stateFk" data="$ctrl.data.states" label="State"></vn-autocomplete>
<vn-autocomplete vn-one margin-medium-right field="$ctrl.filter.agencyFk" url="/production/api/Agencies" label="Agency"></vn-autocomplete>
</vn-horizontal>
<vn-horizontal margin-large-top>
<vn-one></vn-one>
<vn-none>
<vn-submit label="Filter"></vn-submit>
</vn-none>
</vn-horizontal>
</form>

View File

@ -1,5 +0,0 @@
import ngModule from '../module';
ngModule.component('vnProductionFilterPanel', {
template: require('./production-filters.html')
});

View File

@ -1,92 +0,0 @@
<vn-vertical>
<vn-grid-header on-order="$ctrl.onOrder(field, order)">
<vn-none min-none></vn-none>
<vn-column-header vn-none min-none>
<vn-multi-check
check-all="$ctrl.checkAll"
models="$ctrl.tickets"
options="[{id:'all',name:'Todos'},{id:'any',name:'Ninguno'},{id:'problem',name:'Con incidencia'},{id:'no-problem',name:'Sin incidencia'}]">
</vn-multi-check>
</vn-column-header>
<vn-column-header vn-one pad-medium-h field="ticketFk" text="Ticket ID"></vn-column-header>
<vn-column-header vn-two pad-medium-h field="agency" text="Agency"></vn-column-header>
<vn-column-header vn-one pad-medium-h field="routeFk" text="Route ID"></vn-column-header>
<vn-column-header vn-two pad-medium-h field="salesPerson" text="Commercial"></vn-column-header>
<vn-column-header vn-two pad-medium-h field="worker" text="Worker"></vn-column-header>
<vn-column-header vn-one pad-medium-h field="hour" text="Hour"></vn-column-header>
<vn-column-header vn-one pad-medium-h field="state" text="State"></vn-column-header>
<vn-column-header vn-one pad-medium-h field="lines" text="Lines"></vn-column-header>
<vn-column-header vn-one pad-medium-h field="m3" text="m3"></vn-column-header>
<vn-column-header vn-one pad-medium-h field="boxes" text="Boxes"></vn-column-header>
<vn-none min-none></vn-none>
</vn-grid-header>
<vn-one class="list list-content">
<vn-horizontal vn-one class="list list-element text-center" ng-repeat="ticket in $ctrl.pageTable.model" ng-class="{warning: ticket.problem==='RIESGO'}">
<vn-none>
<vn-icon
margin-small-left
icon="report_problem"
ng-if="ticket.problem"
vn-tooltip="{{ticket.problem}}">
</vn-icon>
</vn-none>
<vn-none>
<vn-check model="ticket.checked"></vn-check>
</vn-none>
<vn-one pad-medium-h>{{::ticket.ticketFk}}</vn-one>
<vn-two pad-medium-h>{{::ticket.agency}}</vn-two>
<vn-one pad-medium-h>{{::ticket.routeFk}}</vn-one>
<vn-two pad-medium-h>{{::ticket.salesPerson | ucwords}}</vn-two>
<vn-two pad-medium-h>{{::ticket.worker | ucwords}}</vn-two>
<vn-one pad-medium-h>{{::ticket.hour}}</vn-one>
<vn-one pad-medium-h>{{::ticket.state}}</vn-one>
<vn-one pad-medium-h>{{::ticket.lines}}</vn-one>
<vn-one pad-medium-h>{{::ticket.m3}}</vn-one>
<vn-one pad-medium-h>{{::ticket.boxes}}</vn-one>
<vn-none>
<vn-icon
icon="more"
vn-tooltip
vn-tooltip-id="more-tooltip">
</vn-icon>
<vn-tooltip position="left" id="more-tooltip">
<vn-vertical>
<vn-horizontal class="list list-header">
<vn-one margin-medium-right translate>Town</vn-one>
<vn-one margin-medium-right translate>Province</vn-one>
<vn-two margin-medium-right translate>Client ID</vn-two>
<vn-two translate>Worker</vn-two>
</vn-horizontal>
<vn-horizontal class="list list-element">
<vn-one margin-medium-right>{{::ticket.city | ucwords}}</vn-one>
<vn-one margin-medium-right>{{::ticket.province | ucwords}}</vn-one>
<vn-two margin-medium-right>{{::ticket.client | ucwords}}</vn-two>
<vn-two>{{::ticket.worker | ucwords}}</vn-two>
</vn-horizontal>
</vn-vertical>
</vn-tooltip>
</vn-none>
</vn-horizontal>
</vn-one>
<vn-horizontal vn-one class="list list-footer">
<vn-none></vn-none>
<vn-none></vn-none>
<vn-one pad-medium-h>
<span translate="Resultados"></span>:
<span>{{$ctrl.footer.total}}</span>
</vn-one>
<vn-two pad-medium-h></vn-two>
<vn-one pad-medium-h></vn-one>
<vn-two pad-medium-h></vn-two>
<vn-two pad-medium-h></vn-two>
<vn-one pad-medium-h></vn-one>
<vn-one pad-medium-h></vn-one>
<vn-one pad-medium-h text-center>{{$ctrl.footer.lines}}</vn-one>
<vn-one pad-medium-h text-center>{{$ctrl.footer.meters}}</vn-one>
<vn-one pad-medium-h></vn-one>
<vn-none></vn-none>
</vn-horizontal>
<vn-one>
<vn-paging page-change="$ctrl.pageTickets()" index="$ctrl.pageTable" total="$ctrl.totalFilter"></vn-paging>
</vn-one>
</vn-vertical>

View File

@ -1,56 +0,0 @@
import ngModule from '../module';
export class ProductionTable {
constructor($filter) {
this.$filter = $filter;
this._tickets = [];
this.itemsDisplayedInList = 14;
this._checkAll = 0;
this.pageTable = {
filter: {
page: 1,
size: this.itemsDisplayedInList
},
model: []
};
this.filteredField = null;
this.filteredReverse = null;
}
get checkAll() {
return this._checkAll;
}
set checkAll(value) {
this._checkAll = value;
}
set tickets(value) {
this._tickets = this.filteredField ? this.$filter('orderBy')(value, this.filteredField, this.filteredReverse) : value;
this.totalFilter = this._tickets.length;
this.pageTable.filter.page = 1;
this.pageTickets();
}
get tickets() {
return this._tickets;
}
onOrder(field, order) {
this.filteredField = field;
this.filteredReverse = order === 'DESC';
this.tickets = this.tickets; // call tickets setter
}
pageTickets() {
let init = (this.pageTable.filter.page - 1) * this.itemsDisplayedInList;
let fin = this.pageTable.filter.page * this.itemsDisplayedInList;
this.pageTable.model = this.tickets.slice(init, fin);
}
}
ProductionTable.$inject = ['$filter'];
ngModule.component('vnProductionTable', {
template: require('./production-table.html'),
bindings: {
tickets: '<',
footer: '<',
checkAll: '<'
},
controller: ProductionTable
});

View File

@ -1,7 +0,0 @@
export * from './module';
// import components
import './index/index';
import './production-filters/production-filters';
import './production-actions/production-actions';
import './production-table/production-table';

View File

@ -20,7 +20,6 @@ name: Nombre
phone: Teléfono
Preview: Vista previa
Profile: Perfil
Production : Producción
Push on applications menu: Para abrir un módulo pulsa en el menú de aplicaciones
Return to module index: Volver a la página principal del módulo
Routes: Rutas

View File

@ -1,12 +1,8 @@
export default {
client:
cb => require.ensure([], () => cb(require('client'))),
production:
cb => require.ensure([], () => cb(require('production'))),
route:
cb => require.ensure([], () => cb(require('route'))),
locator:
cb => require.ensure([], () => cb(require('locator'))),
item:
cb => require.ensure([], () => cb(require('item'))),
ticket:

View File

@ -1,4 +1,10 @@
<mg-ajax path="/ticket/api/Sales/saleComponentFilter" options="vnIndexNonAuto" actions="$ctrl.sales = index.model.instances"></mg-ajax>
<vn-crud-model
vn-id="model"
url="/ticket/api/Sales"
link="{ticketFk: $ctrl.$stateParams.id}"
filter="::$ctrl.filter"
data="components">
</vn-crud-model>
<vn-vertical>
<vn-card pad-large>
<vn-vertical>
@ -32,7 +38,7 @@
</td>
</tr>
</tfoot>
<tbody ng-repeat="sale in $ctrl.sales track by sale.id">
<tbody ng-repeat="sale in components track by sale.id">
<tr>
<td rowspan="{{
::sale.components.length + 1
@ -61,13 +67,13 @@
first: $index == 0,last: $index == sale.components.length - 1
}" number>{{::sale.quantity * component.value | currency:'€':3}}</td>
</tr>
<tr ng-if="index.model.count === 0" class="list list-element">
<tr ng-if="model.data.length === 0" class="list list-element">
<td colspan="7" style="text-align: center" translate>No results</td>
</tr>
</tbody>
</table>
</vn-vertical>
<vn-paging vn-one margin-large-top index="index" total="index.model.count"></vn-paging>
<!-- <vn-paging vn-one margin-large-top index="index" total="index.model.count"></vn-paging> -->
</vn-card>
</vn-vertical>
<vn-item-descriptor-popover vn-id="descriptor"></vn-item-descriptor-popover>

View File

@ -1,46 +1,89 @@
import ngModule from '../module';
import './style.scss';
import FilterTicketList from '../filter-ticket-list';
class Controller extends FilterTicketList {
constructor($scope, $timeout, $stateParams) {
super($scope, $timeout, $stateParams);
class Controller {
constructor($scope, $stateParams) {
this.$stateParams = $stateParams;
this.$scope = $scope;
this.onOrder('itemFk', 'ASC');
this.filter = {
order: 'concept ASC',
include: [{
relation: 'item',
scope: {
include: {
relation: 'tags',
scope: {
fields: ['tagFk', 'value'],
include: {
relation: 'tag',
scope: {
fields: ['name']
}
},
limit: 6
}
},
fields: ['itemFk', 'name']
}
},
{
relation: 'components',
scope: {
fields: ['componentFk', 'value'],
include: {
relation: 'componentRate',
scope: {
fields: ['componentTypeRate', 'name'],
include: {
relation: 'componentType',
scope: {
fields: ['type']
}
}
}
}
}
}]
};
}
total() {
let sum;
if (this.sales) {
sum = 0;
for (let sale of this.sales)
let sales = this.$scope.model.data;
let sum = 0;
if (!sales) return;
for (let sale of sales)
for (let component of sale.components)
sum += sale.quantity * component.value;
}
return sum;
}
base() {
let sum;
if (this.sales) {
sum = 0;
for (let sale of this.sales)
let sales = this.$scope.model.data;
let sum = 0;
if (!sales) return;
for (let sale of sales)
for (let component of sale.components)
if (component.componentRate.name == 'valor de compra')
sum += sale.quantity * component.value;
}
return sum;
}
profitMargin() {
let sum;
if (this.sales) {
sum = 0;
for (let sale of this.sales)
let sales = this.$scope.model.data;
let sum = 0;
if (!sales) return;
for (let sale of sales)
for (let component of sale.components)
if (component.componentRate.name != 'valor de compra')
sum += sale.quantity * component.value;
}
return sum;
}
@ -55,7 +98,7 @@ class Controller extends FilterTicketList {
}
}
Controller.$inject = ['$scope', '$timeout', '$state'];
Controller.$inject = ['$scope', '$stateParams'];
ngModule.component('vnTicketComponents', {
template: require('./index.html'),

View File

@ -1,25 +1,24 @@
import './index.js';
import {crudModel} from '../../../helpers/crudModelHelper';
describe('ticket', () => {
describe('Component vnTicketComponents', () => {
let $componentController;
let $state;
let $scope;
let controller;
beforeEach(() => {
angular.mock.module('ticket');
});
beforeEach(angular.mock.inject((_$componentController_, _$state_) => {
beforeEach(angular.mock.inject((_$componentController_, $rootScope, _$state_) => {
$componentController = _$componentController_;
$state = _$state_;
$state.params.id = '1';
controller = $componentController('vnTicketComponents');
}));
describe('total()', () => {
it('should return the sum from all componenets in each sale', () => {
controller.sales = [{
$scope = $rootScope.$new();
$scope.model = crudModel;
$scope.model.data = [{
components: [
{componentRate: {name: 'valor de compra'}, value: 5},
{componentRate: {name: 'reparto'}, value: 5},
@ -34,8 +33,12 @@ describe('ticket', () => {
{componentRate: {name: 'recobro'}, value: 1}
],
quantity: 5
}
];
}];
controller = $componentController('vnTicketComponents', {$scope});
}));
describe('total()', () => {
it('should return the sum from all componenets in each sale', () => {
let result = controller.total();
expect(result).toEqual(30);

View File

@ -1,9 +0,0 @@
import FilterList from 'core/src/lib/filter-list';
export default class FilterTicketList extends FilterList {
constructor($scope, $timeout, $state) {
super($scope, $timeout, $state);
this.modelName = 'ticketFk';
}
}
FilterTicketList.$inject = ['$scope', '$timeout', '$state'];

View File

@ -21,7 +21,7 @@
<vn-thead>
<vn-tr>
<vn-th></vn-th>
<vn-th field="ticketFk" number>Id</vn-th>
<vn-th field="id" number>Id</vn-th>
<vn-th field="salesPersonFk">Salesperson</vn-th>
<vn-th field="shipped">Date</vn-th>
<vn-th>Hour</vn-th>
@ -39,7 +39,7 @@
<vn-tbody>
<vn-tr ng-repeat="ticket in tickets"
class="{{::$ctrl.compareDate(ticket.shipped)}} clickable"
ui-sref="ticket.card.summary({id: {{::ticket.ticketFk}}})">
ui-sref="ticket.card.summary({id: {{::ticket.id}}})">
<vn-td>
<vn-icon ng-show="ticket.problem" class="bright"
vn-tooltip="{{ticket.problem}}"

View File

@ -2,57 +2,11 @@ import ngModule from '../module';
export default class Controller {
constructor($scope) {
this.$ = $scope;
this.$scope = $scope;
this.ticketSelected = null;
this.filter = {
include: [
{
relation: 'address',
scope: {
fields: ['provinceFk'],
include: {
relation: 'province',
scope: {
fields: ['name']
}
}
}
}, {
relation: 'warehouse',
scope: {
fields: ['name']
}
}, {
relation: 'agencyMode',
scope: {
fields: ['name']
}
}, {
relation: 'tracking',
scope: {
fields: ['stateFk'],
include: {
relation: 'state',
scope: {
fields: ['name']
}
}
}
}, {
relation: 'client',
scope: {
fields: ['salesPersonFk'],
include: {
relation: 'salesPerson',
scope: {
fields: ['name']
}
}
}
}
],
order: 'shipped DESC, ticketFk'
order: 'shipped DESC'
};
}
@ -61,13 +15,13 @@ export default class Controller {
case 'search':
return /^\d+$/.test(value)
? {id: value}
: {nickname: {regexp: value}};
: {nickname: {like: value}};
case 'from':
return {shipped: {gte: value}};
case 'to':
return {shipped: {lte: value}};
case 'nickname':
return {[param]: {regexp: value}};
return {[param]: {like: value}};
case 'id':
case 'clientFk':
case 'agencyModeFk':
@ -92,21 +46,21 @@ export default class Controller {
}
showDescriptor(event, clientFk) {
this.$.descriptor.clientFk = clientFk;
this.$.descriptor.parent = event.target;
this.$.descriptor.show();
this.$scope.descriptor.clientFk = clientFk;
this.$scope.descriptor.parent = event.target;
this.$scope.descriptor.show();
event.preventDefault();
event.stopImmediatePropagation();
}
onDescriptorLoad() {
this.$.popover.relocate();
this.$scope.popover.relocate();
}
preview(event, ticket) {
event.preventDefault();
event.stopImmediatePropagation();
this.$.dialogSummaryTicket.show();
this.$scope.dialogSummaryTicket.show();
this.ticketSelected = ticket;
}
}

View File

@ -28,7 +28,7 @@ describe('ticket', () => {
let value = 'Bruce';
let result = controller.exprBuilder(param, value);
expect(result).toEqual({nickname: {regexp: 'Bruce'}});
expect(result).toEqual({nickname: {like: 'Bruce'}});
});
it('should return a formated object with the date in case of from', () => {
@ -52,7 +52,7 @@ describe('ticket', () => {
let value = 'Bruce';
let result = controller.exprBuilder(param, value);
expect(result).toEqual({nickname: {regexp: 'Bruce'}});
expect(result).toEqual({nickname: {like: 'Bruce'}});
});
it('should return a formated object with the warehouseFk in case of warehouseFk', () => {
@ -84,14 +84,14 @@ describe('ticket', () => {
it('should call preventDefault and stopImmediatePropagation from event and show', () => {
let event = jasmine.createSpyObj('event', ['preventDefault', 'stopImmediatePropagation']);
controller.$ = {dialogSummaryTicket: {show: () => {}}};
spyOn(controller.$.dialogSummaryTicket, 'show');
controller.$scope = {dialogSummaryTicket: {show: () => {}}};
spyOn(controller.$scope.dialogSummaryTicket, 'show');
let ticket = {};
controller.preview(event, ticket);
expect(event.preventDefault).toHaveBeenCalledWith();
expect(event.stopImmediatePropagation).toHaveBeenCalledWith();
expect(controller.$.dialogSummaryTicket.show).toHaveBeenCalledWith();
expect(controller.$scope.dialogSummaryTicket.show).toHaveBeenCalledWith();
});
});
});

View File

@ -2,7 +2,8 @@
import Nightmare from 'nightmare';
export default function createNightmare(width = 1280, height = 720) {
const nightmare = new Nightmare({show: true, typeInterval: 10, x: 0, y: 0}).viewport(width, height);
const nightmare = new Nightmare({show: process.env.E2E_SHOW, typeInterval: 10, x: 0, y: 0})
.viewport(width, height);
nightmare.on('page', (type, message, error) => {
fail(error);

View File

@ -195,27 +195,22 @@ export default {
tagsButton: `vn-menu-item a[ui-sref="item.card.tags"]`,
firstRemoveTagButton: `vn-item-tags vn-horizontal:nth-child(2) vn-icon-button[icon="remove_circle_outline"]`,
firstTagSelect: `vn-item-tags vn-horizontal:nth-child(2) > vn-autocomplete[field="itemTag.tagFk"] input`,
firstTagDisabled: `vn-item-tags vn-horizontal:nth-child(2) > vn-autocomplete > div > div > input`,
firstTagSelectOptionOne: `vn-item-tags vn-horizontal:nth-child(2) > vn-autocomplete[field="itemTag.tagFk"] vn-drop-down ul > li:nth-child(1)`,
firstValueInput: `vn-item-tags vn-horizontal:nth-child(2) > vn-textfield[label="Value"] input`,
firstRelevancyInput: `vn-horizontal:nth-child(2) > vn-textfield[label="Relevancy"] input`,
secondTagSelect: `vn-item-tags vn-horizontal:nth-child(3) > vn-autocomplete[field="itemTag.tagFk"] input`,
secondTagDisabled: `vn-item-tags vn-horizontal:nth-child(3) > vn-autocomplete > div > div > input`,
secondTagSelectOptionOne: `vn-item-tags vn-horizontal:nth-child(3) > vn-autocomplete[field="itemTag.tagFk"] vn-drop-down ul > li:nth-child(1)`,
secondValueInput: `vn-item-tags vn-horizontal:nth-child(3) > vn-textfield[label="Value"] input`,
secondRelevancyInput: `vn-horizontal:nth-child(3) > vn-textfield[label="Relevancy"] input`,
thirdTagSelect: `vn-item-tags vn-horizontal:nth-child(4) > vn-autocomplete[field="itemTag.tagFk"] input`,
thirdTagDisabled: `vn-item-tags vn-horizontal:nth-child(4) > vn-autocomplete > div > div > input`,
thirdTagSelectOptionOne: `vn-item-tags vn-horizontal:nth-child(4) > vn-autocomplete[field="itemTag.tagFk"] vn-drop-down ul > li:nth-child(1)`,
thirdValueInput: `vn-item-tags vn-horizontal:nth-child(4) > vn-textfield[label="Value"] input`,
thirdRelevancyInput: `vn-horizontal:nth-child(4) > vn-textfield[label="Relevancy"] input`,
fourthTagSelect: `vn-item-tags vn-horizontal:nth-child(5) > vn-autocomplete[field="itemTag.tagFk"] input`,
fourthTagDisabled: `vn-item-tags vn-horizontal:nth-child(5) > vn-autocomplete > div > div > input`,
fourthTagSelectOptionOne: `vn-item-tags vn-horizontal:nth-child(5) > vn-autocomplete[field="itemTag.tagFk"] vn-drop-down ul > li:nth-child(1)`,
fourthValueInput: `vn-item-tags vn-horizontal:nth-child(5) > vn-textfield[label="Value"] input`,
fourthRelevancyInput: `vn-horizontal:nth-child(5) > vn-textfield[label="Relevancy"] input`,
fifthTagSelect: `vn-item-tags vn-horizontal:nth-child(6) > vn-autocomplete[field="itemTag.tagFk"] input`,
fifthTagDisabled: `vn-item-tags vn-horizontal:nth-child(6) > vn-autocomplete > div > div > input`,
fifthValueInput: `vn-item-tags vn-horizontal:nth-child(6) > vn-textfield[label="Value"] input`,
fifthRelevancyInput: `vn-horizontal:nth-child(6) > vn-textfield[label="Relevancy"] input`,
seventhTagSelectOptionFive: `vn-item-tags vn-horizontal:nth-child(8) > vn-autocomplete[field="itemTag.tagFk"] vn-drop-down ul > li:nth-child(5)`,
@ -285,9 +280,8 @@ export default {
notesButton: `vn-menu-item a[ui-sref="ticket.card.observation"]`,
firstNoteRemoveButton: `vn-icon[icon="remove_circle_outline"]`,
addNoteButton: `vn-icon[icon="add_circle"]`,
firstNoteSelect: `vn-autocomplete[field="ticketObservation.observationTypeFk"] input`,
firstNoteSelectSecondOption: `vn-autocomplete[field="ticketObservation.observationTypeFk"] vn-drop-down ul > li:nth-child(2)`,
firstNoteDisabled: `vn-textfield[label="Observation type"] input`,
firstNoteSelect: `vn-autocomplete[field="observation.observationTypeFk"] input`,
firstNoteSelectSecondOption: `vn-autocomplete[field="observation.observationTypeFk"] vn-drop-down ul > li:nth-child(2)`,
firstDescriptionInput: `vn-textfield[label="Description"] input`,
submitNotesButton: `${components.vnSubmit}`
},

View File

@ -50,8 +50,10 @@ describe('Client', () => {
return nightmare
.waitToClick(selectors.clientPayMethod.payMethodInput)
.waitToClick(selectors.clientPayMethod.payMethodIBANOption)
.waitForTextInInput(selectors.clientPayMethod.payMethodInput, 'PayMethod with IBAN')
.clearInput(selectors.clientPayMethod.dueDayInput)
.type(selectors.clientPayMethod.dueDayInput, '60')
.waitForTextInInput(selectors.clientPayMethod.dueDayInput, '60')
.waitToClick(selectors.clientPayMethod.receivedCoreLCRCheckbox)
.waitToClick(selectors.clientPayMethod.receivedCoreVNLCheckbox)
.waitToClick(selectors.clientPayMethod.receivedB2BVNLCheckbox)
@ -66,6 +68,7 @@ describe('Client', () => {
return nightmare
.clearInput(selectors.clientPayMethod.IBANInput)
.type(selectors.clientPayMethod.IBANInput, 'ES91 2100 0418 4502 0005 1332')
.waitForTextInInput(selectors.clientPayMethod.IBANInput, 'ES91 2100 0418 4502 0005 1332')
.waitToClick(selectors.clientPayMethod.saveButton)
.waitForSnackbar()
.then(result => {

View File

@ -63,7 +63,7 @@ describe('Client', () => {
.waitToClick(selectors.clientBasicData.basicDataButton)
.wait(selectors.clientBasicData.nameInput)
.waitToClick(selectors.clientWebAccess.webAccessButton)
.wait(selectors.clientWebAccess.enableWebAccessCheckbox) // ahora lo dejamos mejor
.wait(selectors.clientWebAccess.enableWebAccessCheckbox)
.evaluate(selector => {
return document.querySelector(selector).checked;
}, selectors.clientWebAccess.enableWebAccessCheckbox)

View File

@ -64,8 +64,8 @@ describe('Ticket', () => {
.click(selectors.ticketPackages.packagesButton)
.wait(selectors.ticketPackages.firstPackageSelect)
.click(selectors.ticketNotes.notesButton)
.waitForTextInInput(selectors.ticketNotes.firstNoteDisabled, 'observation two')
.getInputValue(selectors.ticketNotes.firstNoteDisabled)
.waitForTextInInput(selectors.ticketNotes.firstNoteSelect, 'observation two')
.getInputValue(selectors.ticketNotes.firstNoteSelect)
.then(result => {
expect(result).toEqual('observation two');
return nightmare

View File

@ -71,6 +71,9 @@ gulp.task('services-only', async () => {
* Runs the e2e tests, restoring the fixtures first.
*/
gulp.task('e2e', ['docker'], async () => {
if (argv.show || argv.s)
process.env.E2E_SHOW = true;
await runSequenceP('e2e-only');
});

7322
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,20 +0,0 @@
module.exports = Self => {
Self.installMethod('filter', filterParams);
function filterParams(params) {
return {
where: {
clientFk: params.clientFk
},
skip: (params.page - 1) * params.size,
limit: params.size,
order: params.order || 'created DESC',
include: {
relation: "worker",
scope: {
fields: ["id", "firstName", "name"]
}
}
};
}
};

View File

@ -98,7 +98,7 @@ BEGIN
-- El disponible es menor que 0
INSERT INTO tmp.ticketProblems(ticketFk, problem)
SELECT tt.ticketFk, i.name
FROM tmp.ticketGetProblems tt
FROM tmp.ticketListFiltered tt
JOIN vn.ticket t ON t.id = tt.ticketFk
LEFT JOIN vn.sale s ON s.ticketFk = t.id
JOIN vn.item i ON i.id = s.itemFk
@ -122,7 +122,7 @@ BEGIN
-- Amarillo: El disponible es mayor que cero y la cantidad supera el visible, estando aun sin preparar
INSERT INTO tmp.ticketProblems(ticketFk, problem)
SELECT tt.ticketFk, CONCAT('Delay', i.name)
FROM tmp.ticketGetProblems tt
FROM tmp.ticketListFiltered tt
JOIN vn.ticket t ON t.id = tt.ticketFk
LEFT JOIN vn.sale s ON s.ticketFk = t.id
JOIN vn.item i ON i.id = s.itemFk
@ -148,3 +148,4 @@ BEGIN
END$$
DELIMITER ;

View File

@ -0,0 +1,115 @@
USE `vn`;
DROP procedure IF EXISTS `itemDiary`;
DELIMITER $$
USE `vn`$$
CREATE DEFINER=`root`@`%` PROCEDURE `itemDiary`(IN vItemId INT, IN vWarehouse INT)
BEGIN
DECLARE vDateInventory DATETIME;
DECLARE vCurdate DATE DEFAULT CURDATE();
DECLARE vDayEnd DATETIME DEFAULT util.dayEnd(vCurdate);
-- traduccion: date, alertLevel, origin, reference, name, In, Out, Balance
SELECT Fechainventario INTO vDateInventory FROM vn2008.tblContadores;
SET @a = 0;
SELECT sql_no_cache DATE(date) AS date,
alertLevel,
stateName,
origin,
reference,
name,
`in`,
`out`,
@a := @a + IFNULL(`in`,0) - IFNULL(`out`,0) as balance,
isPicked,
isTicket
FROM
( SELECT tr.landed as date,
b.quantity as `in`,
NULL as `out`,
IF(tr.isReceived != FALSE,3, IF(tr.isDelivered,1,0)) as alertLevel,
st.name AS stateName,
s.name as name,
e.ref as reference,
e.id as origin,
TRUE isPicked,
FALSE AS isTicket
FROM vn.buy b
JOIN vn.entry e ON e.id = b.entryFk
JOIN vn.travel tr ON tr.id = e.travelFk
JOIN vn.supplier s ON s.id = e.supplierFk
JOIN vn.alertLevel al ON al.alertLevel =
CASE
WHEN tr.isReceived != FALSE THEN 3
WHEN tr.isDelivered THEN 1
ELSE 0
END
JOIN vn.state st ON st.code = al.code
WHERE tr.landed >= vDateInventory
AND vWarehouse = tr.warehouseInFk
AND b.itemFk = vItemId
AND e.isInventory = 0
UNION ALL
SELECT tr.shipped as date,
NULL as `in`,
b.quantity as `out`,
IF(tr.isReceived != FALSE,3, IF(tr.isDelivered,1,0)) as alertLevel,
st.name AS stateName,
s.name as name,
e.ref as reference,
e.id as origin,
TRUE isPicked,
FALSE AS isTicket
FROM vn.buy b
JOIN vn.entry e ON e.id = b.entryFk
JOIN vn.travel tr ON tr.id = e.travelFk
JOIN vn.warehouse w ON w.id = tr.warehouseOutFk
JOIN vn.supplier s ON s.id = e.supplierFk
JOIN vn.alertLevel al ON al.alertLevel =
CASE
WHEN tr.isReceived != FALSE THEN 3
WHEN tr.isDelivered THEN 1
ELSE 0
END
JOIN vn.state st ON st.code = al.code
WHERE tr.shipped >= vDateInventory
AND vWarehouse =tr.warehouseOutFk
AND s.id <> 4
AND b.itemFk = vItemId
AND e.isInventory = 0
AND w.isFeedStock = 0
UNION ALL
SELECT t.shipped as date,
NULL as `in`,
s.quantity as `out`,
al.alertLevel as alertLevel,
st.name AS stateName,
t.nickname as name,
t.refFk as reference,
t.id as origin,
TRUE as isPicked, -- stk.id as isPicked
TRUE as isTicket
FROM vn.sale s
JOIN vn.ticket t ON t.id = s.ticketFk
LEFT JOIN vn.ticketState ts ON ts.ticket = t.id
JOIN vn.client c ON c.id = t.clientFk
JOIN vn.alertLevel al ON al.alertLevel =
CASE
WHEN t.shipped < vCurdate THEN 3
WHEN t.shipped > vDayEnd THEN 0
ELSE IFNULL(ts.alertLevel, 0)
END
JOIN vn.state st ON st.code = al.code
-- LEFT JOIN vn.saleTracking stk ON stk.saleFk = s.id AND stk.stateFk = 14
WHERE t.shipped >= vDateInventory
AND s.itemFk = vItemId
AND vWarehouse =t.warehouseFk
) AS itemDiary
ORDER BY date, alertLevel DESC, isPicked DESC, `in` DESC, `out` DESC;
END$$
DELIMITER ;

View File

@ -47,7 +47,7 @@ INSERT INTO `vn`.`warehouse`(`id`, `name`, `isComparative`, `isInventory`, `hasA
(2, 'Warehouse Two', 0, 1, 1, 1),
(3, 'Warehouse Three', 1, 1, 1, 1),
(4, 'Warehouse Four', 1, 1, 1, 1),
(5, 'Warehouse Five', 1, 1, 1, 0);
(5, 'Warehouse Five', 1, 0, 1, 0);
INSERT INTO `vn`.`warehouseAlias`(`id`, `name`)
VALUES

View File

@ -1,3 +0,0 @@
module.exports = Self => {
Self.installCrudModel('crudItemBarcodes');
};

View File

@ -1,72 +0,0 @@
// const crudItemBarcodes = require('../crudItemBarcodes');
// const catchErrors = require('../../../../../../services/utils/jasmineHelpers').catchErrors;
// let mysql = require('mysql2');
// describe('Item crudItemBarcodes()', () => {
// let connection;
// beforeAll(() => {
// connection = mysql.createConnection({
// multipleStatements: true,
// host: 'localhost',
// user: 'root',
// password: '',
// database: 'salix'
// });
// });
// it('should call the destroyAll methodif there are ids in delete Array', done => {
// let self = jasmine.createSpyObj('self', ['remoteMethod', 'crudItemBarcodes', 'destroyAll', 'create', 'upsert']);
// crudItemBarcodes(self);
// self.crudItemBarcodes({
// delete: [1],
// create: [],
// update: []
// }).then(result => {
// expect(self.destroyAll).toHaveBeenCalledWith({id: {inq: [1]}});
// done();
// })
// .catch(catchErrors(done));
// });
// it('should call the create method if there are ids in create Array', done => {
// let self = jasmine.createSpyObj('self', ['remoteMethod', 'crudItemBarcodes', 'destroyAll', 'create', 'upsert']);
// crudItemBarcodes(self);
// self.crudItemBarcodes({
// delete: [],
// create: [1],
// update: []
// }).then(result => {
// expect(self.create).toHaveBeenCalledWith([1]);
// done();
// })
// .catch(catchErrors(done));
// });
// it('should call the upsert method as many times as ids in update Array', done => {
// let self = jasmine.createSpyObj('self', ['remoteMethod', 'crudItemBarcodes', 'destroyAll', 'create', 'upsert']);
// crudItemBarcodes(self);
// self.crudItemBarcodes({
// delete: [],
// create: [],
// update: [1, 2]
// }).then(result => {
// expect(self.upsert).toHaveBeenCalledWith(1);
// expect(self.upsert).toHaveBeenCalledWith(2);
// expect(self.upsert.calls.count()).toEqual(2);
// done();
// })
// .catch(catchErrors(done));
// });
// it('should return an error when attempting to save a duplicated barcode', done => {
// let callback = (err, res) => {
// expect(err.toString()).toBe("Error: Duplicate entry '4' for key 'PRIMARY'");
// done();
// };
// connection.query('INSERT INTO `vn`.`itemBarcode` VALUES (4, 2 ,4 );', callback);
// });
// });

View File

@ -1,3 +0,0 @@
module.exports = Self => {
Self.installCrudModel('crudItemNiches');
};

View File

@ -1,51 +0,0 @@
// const crudItemNiches = require('../crudItemNiches');
// const catchErrors = require('../../../../../../services/utils/jasmineHelpers').catchErrors;
// describe('Item crudItemNiches()', () => {
// it('should call the destroyAll method if there are ids in delete Array', done => {
// let self = jasmine.createSpyObj('self', ['remoteMethod', 'crudItemNiches', 'destroyAll', 'create', 'upsert']);
// crudItemNiches(self);
// self.crudItemNiches({
// delete: [1],
// create: [],
// update: []
// }).then(result => {
// expect(self.destroyAll).toHaveBeenCalledWith({id: {inq: [1]}});
// done();
// })
// .catch(catchErrors(done));
// });
// it('should call the create method if there are ids in create Array', done => {
// let self = jasmine.createSpyObj('self', ['remoteMethod', 'crudItemNiches', 'destroyAll', 'create', 'upsert']);
// crudItemNiches(self);
// self.crudItemNiches({
// delete: [],
// create: [1],
// update: []
// }).then(result => {
// expect(self.create).toHaveBeenCalledWith([1]);
// done();
// })
// .catch(catchErrors(done));
// });
// it('should call the upsert method as many times as ids in update Array', done => {
// let self = jasmine.createSpyObj('self', ['remoteMethod', 'crudItemNiches', 'destroyAll', 'create', 'upsert']);
// crudItemNiches(self);
// self.crudItemNiches({
// delete: [],
// create: [],
// update: [1, 2]
// }).then(result => {
// expect(self.upsert).toHaveBeenCalledWith(1);
// expect(self.upsert).toHaveBeenCalledWith(2);
// expect(self.upsert.calls.count()).toEqual(2);
// done();
// })
// .catch(catchErrors(done));
// });
// });

View File

@ -1,6 +1,4 @@
module.exports = Self => {
require('../methods/item-barcode/crudItemBarcodes')(Self);
Self.validatesUniquenessOf('code', {
message: `Barcode must be unique`
});

View File

@ -1,39 +0,0 @@
module.exports = Self => {
Self.installMethod('filter', filterParams);
function filterParams(params) {
return {
where: {
ticketFk: params.ticketFk
},
skip: (params.page - 1) * params.size,
limit: params.size,
order: params.order || 'concept ASC',
include: [{
relation: 'item',
scope: {
include: {
relation: 'tags',
scope: {
fields: ['tagFk', 'value'],
include: {
relation: 'tag',
scope: {
fields: ['name']
}
},
limit: 6
}
},
fields: ['itemFk', 'name']
}
},
{
relation: 'isChecked',
scope: {
fields: ['isChecked']
}
}]
};
}
};

View File

@ -1,51 +0,0 @@
module.exports = Self => {
Self.installMethod('saleComponentFilter', filterParams);
function filterParams(params) {
return {
where: {
ticketFk: params.ticketFk
},
skip: (params.page - 1) * params.size,
limit: params.size,
order: params.order || 'concept ASC',
include: [{
relation: 'item',
scope: {
include: {
relation: 'tags',
scope: {
fields: ['tagFk', 'value'],
include: {
relation: 'tag',
scope: {
fields: ['name']
}
},
limit: 6
}
},
fields: ['itemFk', 'name']
}
},
{
relation: 'components',
scope: {
fields: ['componentFk', 'value'],
include: {
relation: 'componentRate',
scope: {
fields: ['componentTypeRate', 'name'],
include: {
relation: 'componentType',
scope: {
fields: ['type']
}
}
}
}
}
}]
};
}
};

View File

@ -1,56 +0,0 @@
module.exports = function(Self) {
Self.remoteMethodCtx('changeState', {
description: 'Change state of tickets',
accepts: [
{
arg: 'state',
type: 'number',
required: true,
description: 'New state',
http: {source: 'path'}
}
],
returns: {
arg: 'response',
type: 'boolean'
},
http: {
verb: 'put',
path: '/:state/changeState'
}
});
Self.changeState = function(ctx, state, cb) {
var tickets = ctx.req.body.tickets;
Self.connectToService(ctx, 'client');
Self.app.models.Worker.findOne({where: {userFk: ctx.req.accessToken.userId}}, function(err, emp) {
if (err)
cb(err, null);
else
changeState(emp.id, tickets, state, cb);
});
Self.disconnectFromService('client');
};
function changeState(emp, tickets, state, cb) {
var inserts = [];
var FakeProduction = Self.app.models.FakeProduction;
tickets.forEach(function(t) {
inserts.push({ticketFk: t, stateFk: state, workerFk: emp});
}, this);
Self.create(inserts, function(err, res) {
if (err)
cb(err, null);
else {
FakeProduction.updateAll({ticketFk: {inq: tickets}}, {stateFk: state}, function(err, info) {
cb(err, info);
});
}
});
}
};

View File

@ -1,37 +0,0 @@
module.exports = function(Ticket) {
Ticket.remoteMethodCtx('changeTime', {
description: 'Change time of tickets',
accepts: [{
arg: 'time',
type: 'string',
required: true,
description: 'New time of tickets',
http: {source: 'path'}
}],
returns: {
arg: 'response',
type: 'boolean'
},
http: {
verb: 'put',
path: '/:time/changeTime'
}
});
Ticket.changeTime = function(ctx, time, cb) {
var tickets = ctx.req.body.tickets;
var FakeProduction = Ticket.app.models.FakeProduction;
var hour = `${time}:00`;
var query = `update Ticket set date = CONCAT(DATE(date), ' ', ?) where id in (?)`;
var params = [hour, tickets];
FakeProduction.updateAll({ticketFk: {inq: tickets}}, {hour: hour}, function(err, res) {
if (err)
cb(err, null);
else
Ticket.rawSql(query, params, cb).then(function(response) {
cb(null, response);
});
});
};
};

View File

@ -33,6 +33,7 @@ module.exports = Self => {
`CREATE TEMPORARY TABLE tmp.filter
(PRIMARY KEY (ticketFk)) ENGINE = MEMORY
SELECT
t.id,
t.id AS ticketFk,
t.shipped,
t.nickname,
@ -49,7 +50,7 @@ module.exports = Self => {
am.name AS agencyMode,
st.name AS state,
wk.name AS salesPerson,
0 AS total
CAST(0 AS DECIMAL(10, 2)) AS total
FROM ticket t
LEFT JOIN address a ON a.id = t.addressFk
LEFT JOIN province p ON p.id = a.provinceFk
@ -88,7 +89,7 @@ module.exports = Self => {
tp.problem
FROM tmp.filter f
LEFT JOIN tmp.ticketProblems tp ON tp.ticketFk = f.ticketFk`);
stmt.merge(Self.buildSuffix(filter, 'f'));
stmt.merge(Self.buildOrderBy(filter, 'f'));
let ticketsIndex = stmts.push(stmt) - 1;
stmts.push(

View File

@ -1,7 +1,5 @@
module.exports = Self => {
require('../methods/sale/filter')(Self);
require('../methods/sale/getClaimableFromTicket')(Self);
require('../methods/sale/saleComponentFilter')(Self);
require('../methods/sale/priceDifference')(Self);
require('../methods/sale/moveToTicket')(Self);
require('../methods/sale/reserve')(Self);

View File

@ -1,3 +0,0 @@
module.exports = Self => {
require('../methods/ticket-state/changeState')(Self);
};

View File

@ -1,5 +1,4 @@
module.exports = Self => {
require('../methods/ticket/changeTime')(Self);
require('../methods/ticket/changeWorker')(Self);
require('../methods/ticket/getVolume')(Self);
require('../methods/ticket/getTotalVolume')(Self);

View File

@ -31,5 +31,5 @@
"permission": "ALLOW"
}
],
"scope" : {"where": {"isManaged": {"neq": 0}}}
"scope" : {"where": {"isInventory": {"neq": 0}}}
}

View File

@ -1,5 +0,0 @@
FROM vn-loopback:latest
COPY production /app
WORKDIR /app
CMD ["pm2-docker", "./server/server.js"]

View File

@ -1,90 +0,0 @@
module.exports = function(Self) {
Self.defineScope();
Self.list = function(ctx, filter, callback) {
let daysTickets = 0;
let warehouseFk = filter.warehouseFk;
delete filter.limit;
delete filter.page;
delete filter.warehouseFk;
let call = `call salix.production_control_source(? , ?)`;
var params = [warehouseFk, daysTickets];
let conn;
Self.getConnection((err, connection) => {
if (err) {
onFinish(err);
}
conn = connection;
conn.query(call, params, getValue);
});
function getValue(err) {
if (err) {
onFinish(err);
}
buildWhereObject();
let where = Self.dataSource.connector.buildWhere(Self.modelName, filter.where);
let query = `SELECT * FROM tmp.production ${where.sql} GROUP BY RouteFk ORDER BY routeFk`;
conn.query(query, where.params, onFinish);
}
function buildWhereObject() {
let newFilter = {};
if (filter.q) {
let regexQ = new RegExp(filter.q);
delete filter.q;
newFilter = {
and: [
{
or: [
{agency: {regexp: regexQ}},
{state: {regexp: regexQ}}
]
}
]
};
if (Object.keys(filter).length) {
Object.keys(filter).forEach(
key => {
let field = {};
field[key] = filter[key];
newFilter.and.push(field);
}
);
}
} else if (Object.keys(filter).length) {
newFilter = filter;
}
filter.where = newFilter;
}
function onFinish(err, results) {
conn.query('DROP TEMPORARY TABLE IF EXISTS tmp.production');
conn.release();
if (err)
callback(err);
callback(null, sum(results));
}
function sum(tickets) {
let obj = {lines: 0, m3: 0};
if (tickets && tickets.length)
tickets.forEach(function(t, i) {
obj.lines += t.lines;
obj.m3 += t.m3;
if (tickets[i].problem)
tickets[i].problem = tickets[i].problem.trim();
}, this);
obj.m3 = obj.m3.toFixed(2);
obj.total = tickets ? tickets.length : 0;
obj.tickets = tickets || [];
return obj;
}
};
};

View File

@ -1,80 +0,0 @@
var uuid = require('uuid');
module.exports = function(FakeProduction) {
FakeProduction.remoteMethodCtx('messageSend', {
description: 'Send message to salesPerson of one array of tickets',
returns: {
arg: 'response',
type: 'message'
},
http: {
path: '/messageSend',
verb: 'post'
}
});
FakeProduction.messageSend = function(ctx, cb) {
var tickets = ctx.req.body.tickets;
var userId = ctx.req.accessToken.$userId;
var User = FakeProduction.app.models.User;
User.findById(userId, function(err, user) {
var elements = [];
tickets.forEach(function(t) {
elements.push({sender: user.username, salesPerson: t.salesPerson, message: `Revisa el tickete ${t.ticketFk}`});
}, this);
messageSend(elements, cb);
});
};
function messageSend(elements, cb) {
var messages = [];
var messagesInbox = [];
elements.forEach(function(e) {
var id = uuid.v1();
var message = {uuid: id, sender: e.sender, recipient: e.salesPerson, message: e.message};
var messageInbox = {uuid: id, sender: e.sender, recipient: e.salesPerson, finalRecipient: e.salesPerson, message: e.message};
messages.push(message);
messagesInbox.push(messageInbox);
}, this);
createMessage(messages, messagesInbox, cb);
}
function createMessage(messages, messagesInbox, cb) {
var Message = FakeProduction.app.models.Message;
FakeProduction.beginTransaction({isolationLevel: FakeProduction.Transaction.READ_COMMITTED}, function(err, tx) {
Message.create(messages, {transaction: tx}, function(err, res) {
if (err) {
tx.rollback(function(error) {
if (error)
cb(error, null);
else
cb(err, null);
});
} else {
createMessageInbox(messagesInbox, tx, cb);
}
});
});
}
function createMessageInbox(messagesInbox, tx, cb) {
var MessageInbox = FakeProduction.app.models.MessageInbox;
MessageInbox.create(messagesInbox, {transaction: tx}, function(err, res) {
if (err) {
tx.rollback(function(error) {
if (error)
cb(error, null);
else
cb(err, null);
});
} else {
tx.commit(function(err) {
if (err)
cb(err, null);
else
cb(null, res);
});
}
});
}
};

View File

@ -1,26 +0,0 @@
module.exports = function(FakeProduction) {
FakeProduction.remoteMethodCtx('routeList', {
description: 'Route list',
returns: {
arg: 'response',
type: 'message'
},
http: {
path: '/routeList',
verb: 'get'
}
});
FakeProduction.routeList = function(ctx, cb) {
// var query = `select routeFk from FakeProduction where routeFk is not null group by RouteFk order by routeFk`;
let query = `call salix.production_control_source(1,1)`;
var params = [];
FakeProduction.rawSql(query, params, cb)
.then(function(response) {
cb(null, response);
})
.catch(function(response) {
cb(response, null);
});
};
};

View File

@ -1,6 +0,0 @@
module.exports = function(Self) {
require('../methods/fake-production/list.js')(Self);
require('../methods/fake-production/message-send.js')(Self);
require('../methods/fake-production/route.js')(Self);
};

View File

@ -1,77 +0,0 @@
{
"name": "FakeProduction",
"base": "VnModel",
"properties": {
"id": {
"type": "Number",
"id": true,
"description": "Identifier"
},
"ticketFk": {
"type": "Number"
},
"clientFk": {
"type": "Number"
},
"client":{
"type": "String"
},
"date":{
"type": "Date"
},
"hour":{
"type": "String"
},
"city":{
"type": "String"
},
"province":{
"type": "String"
},
"provinceFk":{
"type": "Number"
},
"agency":{
"type": "String"
},
"agencyFk":{
"type": "Number"
},
"lines":{
"type": "Number"
},
"m3":{
"type": "Number"
},
"problems":{
"type": "Number"
},
"problem":{
"type": "String"
},
"state":{
"type": "String"
},
"stateFk":{
"type": "Number"
},
"worker":{
"type": "String"
},
"workerFk":{
"type": "Number"
},
"salesPerson":{
"type": "String"
},
"salesPersonFk":{
"type": "Number"
},
"boxes":{
"type": "Number"
},
"routeFk":{
"type": "Number"
}
}
}

View File

@ -1,34 +0,0 @@
{
"name": "MessageInbox",
"base": "VnModel",
"options": {
"mysql": {
"table": "messageInbox"
}
},
"properties": {
"id": {
"type": "Number",
"id": true,
"description": "Identifier"
},
"uuid":{
"type": "String"
},
"sender":{
"type": "String"
},
"recipient":{
"type": "String"
},
"finalRecipient":{
"type": "String"
},
"message":{
"type": "String"
},
"sendDate":{
"type": "date"
}
}
}

View File

@ -1,31 +0,0 @@
{
"name": "Message",
"base": "VnModel",
"options": {
"mysql": {
"table": "message"
}
},
"properties": {
"id": {
"type": "Number",
"id": true,
"description": "Identifier"
},
"uuid":{
"type": "String"
},
"sender":{
"type": "String"
},
"recipient":{
"type": "String"
},
"message":{
"type": "String"
},
"sendDate":{
"type": "date"
}
}
}

View File

@ -1,20 +0,0 @@
{
"name": "vn-production",
"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-production",
"dependencies": {
"uuid": "^3.1.0",
"vn-loopback": "file:../loopback"
}
}

View File

@ -1,11 +0,0 @@
{
"FakeProduction": {
"dataSource": "vn"
},
"Message": {
"dataSource": "vn"
},
"MessageInbox": {
"dataSource": "vn"
}
}

View File

@ -1,4 +0,0 @@
var vnLoopback = require('vn-loopback/server/server.js');
var app = module.exports = vnLoopback.loopback();
vnLoopback.boot(app, __dirname, module);

View File

@ -1,3 +0,0 @@
module.exports = Self => {
Self.installCrudModel('crudTicketObservation');
};

View File

@ -1,22 +1,17 @@
const app = require(`${servicesDir}/ticket/server/server`);
describe('ticket listSaleTracking()', () => {
it('should call the listSaleTracking method and return the response', done => {
it('should call the listSaleTracking method and return the response', async() => {
let filter = {where: {ticketFk: 1}};
app.models.SaleTracking.listSaleTracking(filter)
.then(response => {
expect(response[0].concept).toEqual('Gem of Time');
done();
});
let result = await app.models.SaleTracking.listSaleTracking(filter);
expect(result[0].concept).toEqual('Gem of Time');
});
it(`should call the listSaleTracking method and return zero if doesn't have lines`, done => {
it(`should call the listSaleTracking method and return zero if doesn't have lines`, async() => {
let filter = {where: {ticketFk: 2}};
app.models.SaleTracking.listSaleTracking(filter)
.then(response => {
expect(response.length).toEqual(0);
done();
});
let result = await app.models.SaleTracking.listSaleTracking(filter);
expect(result.length).toEqual(0);
});
});

View File

@ -1,6 +1,4 @@
module.exports = function(Self) {
require('../methods/notes/crudTicketObservation.js')(Self);
/* Self.validateAsync('observationTypeFk', validateObservationUniqueness, {
message: `The observation type can't be repeated`
});