2111 - Drop tickets to route ticket list
gitea/salix/pipeline/head This commit looks good Details

This commit is contained in:
Joan Sanchez 2020-03-06 13:06:01 +01:00
parent 97671fd4a1
commit 3c41c4656b
8 changed files with 127 additions and 35 deletions

View File

@ -127,5 +127,6 @@
"Sent units from ticket": "Envio *{{quantity}}* unidades de [{{concept}} (#{{itemId}})]({{{itemUrl}}}) a *\"{{nickname}}\"* provenientes del ticket id [#{{ticketId}}]({{{ticketUrl}}})", "Sent units from ticket": "Envio *{{quantity}}* unidades de [{{concept}} (#{{itemId}})]({{{itemUrl}}}) a *\"{{nickname}}\"* provenientes del ticket id [#{{ticketId}}]({{{ticketUrl}}})",
"Client checked as validated despite of duplication": "Cliente comprobado a pesar de que existe el cliente id {{clientId}}", "Client checked as validated despite of duplication": "Cliente comprobado a pesar de que existe el cliente id {{clientId}}",
"ORDER_ROW_UNAVAILABLE": "No hay disponibilidad de este producto", "ORDER_ROW_UNAVAILABLE": "No hay disponibilidad de este producto",
"Distance must be lesser than 1000": "La distancia debe ser inferior a 1000" "Distance must be lesser than 1000": "La distancia debe ser inferior a 1000",
"This ticket is deleted": "This ticket is deleted"
} }

View File

@ -45,7 +45,8 @@ export default class Controller extends Component {
this.$.confirmDuplicatedClient.show(); this.$.confirmDuplicatedClient.show();
}).catch(error => { }).catch(error => {
if (error.status == 404) if (error.status == 404)
this.save(); return this.save();
throw error;
}); });
} }

View File

@ -67,9 +67,8 @@ describe('Client', () => {
] ]
} }
}; };
const expectedClient = {id: 102};
const filter = encodeURIComponent(JSON.stringify(filterObj)); const filter = encodeURIComponent(JSON.stringify(filterObj));
$httpBackend.expect('GET', `Clients/findOne?filter=${filter}`).respond(expectedClient); $httpBackend.expect('GET', `Clients/findOne?filter=${filter}`).respond(404);
controller.checkExistingClient(); controller.checkExistingClient();
$httpBackend.flush(); $httpBackend.flush();
}); });

View File

@ -1,6 +1,6 @@
<vn-crud-model <vn-crud-model
vn-id="model" vn-id="model"
url="Routes/{{$ctrl.$stateParams.id}}/getTickets" url="Routes/{{$ctrl.$params.id}}/getTickets"
order="priority ASC" order="priority ASC"
data="$ctrl.tickets" data="$ctrl.tickets"
auto-load="true"> auto-load="true">
@ -23,7 +23,7 @@
</vn-tool-bar> </vn-tool-bar>
</vn-card> </vn-card>
<vn-card class="vn-mt-md"> <vn-card class="vn-mt-md">
<vn-table model="model" auto-load="false"> <vn-table model="model" auto-load="false" vn-droppable="$ctrl.onDrop($event)">
<vn-thead> <vn-thead>
<vn-tr> <vn-tr>
<vn-th shrink> <vn-th shrink>
@ -86,7 +86,7 @@
</vn-td> </vn-td>
<vn-td> <vn-td>
<vn-icon-button <vn-icon-button
translate-attr="::{title: 'Remove ticket'}" translate-attr="{title: 'Remove ticket'}"
icon="delete" icon="delete"
ng-click="$ctrl.showDeleteConfirm(ticket.id)" ng-click="$ctrl.showDeleteConfirm(ticket.id)"
tabindex="-1"> tabindex="-1">

View File

@ -1,26 +1,24 @@
import ngModule from '../module'; import ngModule from '../module';
import Section from 'salix/components/section';
import './style.scss'; import './style.scss';
class Controller { class Controller extends Section {
constructor($stateParams, $scope, $translate, $http, vnApp, $filter) { constructor($element, $scope, $filter) {
this.$translate = $translate; super($element, $scope);
this.$stateParams = $stateParams;
this.$ = $scope;
this.$http = $http;
this.vnApp = vnApp;
this.$filter = $filter; this.$filter = $filter;
} }
get route() {
return this._route;
}
set route(value) { set route(value) {
this._route = value; this._route = value;
if (value) if (value)
this.buildPossibleTicketsFilter(); this.buildPossibleTicketsFilter();
} }
get route() {
return this._route;
}
get isChecked() { get isChecked() {
if (this.tickets) { if (this.tickets) {
for (let instance of this.tickets) for (let instance of this.tickets)
@ -104,7 +102,6 @@ class Controller {
}); });
} }
showDeleteConfirm(id) { showDeleteConfirm(id) {
this.selectedTicket = id; this.selectedTicket = id;
this.$.confirm.show(); this.$.confirm.show();
@ -122,7 +119,7 @@ class Controller {
} }
updateVolume() { updateVolume() {
let url = `Routes/${this.$stateParams.id}/updateVolume`; let url = `Routes/${this.$params.id}/updateVolume`;
this.$http.post(url).then(() => { this.$http.post(url).then(() => {
this.card.reload(); this.card.reload();
this.$.model.refresh(); this.$.model.refresh();
@ -130,7 +127,7 @@ class Controller {
} }
guessPriority() { guessPriority() {
let query = `Routes/${this.$stateParams.id}/guessPriority/`; let query = `Routes/${this.$params.id}/guessPriority/`;
this.$http.get(query).then(() => { this.$http.get(query).then(() => {
this.vnApp.showSuccess(this.$translate.instant('Order changed')); this.vnApp.showSuccess(this.$translate.instant('Order changed'));
this.$.model.refresh(); this.$.model.refresh();
@ -171,9 +168,39 @@ class Controller {
} }
return Promise.resolve(); return Promise.resolve();
} }
onDrop($event) {
const ticketId = $event.dataTransfer.getData('Text');
if (isNaN(ticketId)) {
const regexp = new RegExp(/\/ticket\/([0-9]+)\//i);
const matches = ticketId.match(regexp);
if (matches && matches.length)
this.insert(matches[1]);
else
this.vnApp.showError(this.$translate.instant('Ticket not found'));
}
if (!isNaN(ticketId))
this.insert(ticketId);
}
insert(id) {
const params = {routeFk: this.route.id};
this.$http.patch(`Tickets/${id}`, params).then(() => {
this.vnApp.showSuccess(this.$translate.instant('Data saved!'));
this.$.model.refresh();
this.card.reload();
}).catch(error => {
if (error.status == 404)
return this.vnApp.showError(this.$translate.instant('Ticket not found'));
throw error;
});
}
} }
Controller.$inject = ['$stateParams', '$scope', '$translate', '$http', 'vnApp', '$filter']; Controller.$inject = ['$element', '$scope', '$filter'];
ngModule.component('vnRouteTickets', { ngModule.component('vnRouteTickets', {
template: require('./index.html'), template: require('./index.html'),

View File

@ -1,14 +1,20 @@
import './index.js'; import './index';
describe('Route', () => { describe('Route', () => {
let controller; let controller;
let $httpBackend; let $httpBackend;
let $scope;
beforeEach(ngModule('route')); beforeEach(ngModule('route'));
beforeEach(angular.mock.inject(($componentController, _$httpBackend_) => { beforeEach(angular.mock.inject(($componentController, $rootScope, _$httpBackend_) => {
$httpBackend = _$httpBackend_; $httpBackend = _$httpBackend_;
controller = $componentController('vnRouteTickets'); $scope = $rootScope.$new();
const $element = angular.element('<vn-route-tickets></vn-route-tickets>');
controller = $componentController('vnRouteTickets', {$element, $scope});
controller.route = {id: 1};
controller.$.model = {refresh: () => {}};
controller.card = {reload: () => {}};
})); }));
describe('route setter/getter', () => { describe('route setter/getter', () => {
@ -86,7 +92,6 @@ describe('Route', () => {
describe('setPriority()', () => { describe('setPriority()', () => {
it('should set a ticket priority', () => { it('should set a ticket priority', () => {
controller.$.model = {refresh: () => {}};
jest.spyOn(controller.$.model, 'refresh'); jest.spyOn(controller.$.model, 'refresh');
jest.spyOn(controller.vnApp, 'showSuccess'); jest.spyOn(controller.vnApp, 'showSuccess');
const ticketId = 1; const ticketId = 1;
@ -175,16 +180,14 @@ describe('Route', () => {
describe('updateVolume()', () => { describe('updateVolume()', () => {
it('should perform a POST query then call both reload and refresh methods', () => { it('should perform a POST query then call both reload and refresh methods', () => {
controller.$.model = {refresh: () => {}}; controller.$params = {id: 999};
controller.card = {reload: () => {}};
controller.$stateParamds = {id: 999};
jest.spyOn(controller.$.model, 'refresh'); jest.spyOn(controller.$.model, 'refresh');
jest.spyOn(controller.card, 'reload'); jest.spyOn(controller.card, 'reload');
let ticketId = 1; let ticketId = 1;
controller.selectedTicket = ticketId; controller.selectedTicket = ticketId;
const url = `Routes/${controller.$stateParams.id}/updateVolume`; const url = `Routes/${controller.$params.id}/updateVolume`;
$httpBackend.expectPOST(url).respond('ok'); $httpBackend.expectPOST(url).respond('ok');
controller.updateVolume(); controller.updateVolume();
$httpBackend.flush(); $httpBackend.flush();
@ -196,12 +199,11 @@ describe('Route', () => {
describe('guessPriority()', () => { describe('guessPriority()', () => {
it('should perform a GET query then call both refresh and showSuccess methods', () => { it('should perform a GET query then call both refresh and showSuccess methods', () => {
controller.$.model = {refresh: () => {}};
jest.spyOn(controller.$.model, 'refresh'); jest.spyOn(controller.$.model, 'refresh');
jest.spyOn(controller.vnApp, 'showSuccess'); jest.spyOn(controller.vnApp, 'showSuccess');
controller.$stateParams = {id: 99}; controller.$params = {id: 99};
const url = `Routes/${controller.$stateParams.id}/guessPriority/`; const url = `Routes/${controller.$params.id}/guessPriority/`;
$httpBackend.expectGET(url).respond('ok'); $httpBackend.expectGET(url).respond('ok');
controller.guessPriority(); controller.guessPriority();
$httpBackend.flush(); $httpBackend.flush();
@ -288,4 +290,66 @@ describe('Route', () => {
expect(controller.setTicketsRoute('cancel')).toEqual(jasmine.any(Promise)); expect(controller.setTicketsRoute('cancel')).toEqual(jasmine.any(Promise));
}); });
}); });
describe('onDrop()', () => {
it('should call the insert method when dragging a ticket number', () => {
jest.spyOn(controller, 'insert');
const expectedTicketId = '11';
const draggedElement = '11';
const $event = {
dataTransfer: {
getData: () => draggedElement
}
};
controller.onDrop($event);
expect(controller.insert).toHaveBeenCalledWith(expectedTicketId);
});
it('should call the insert method when dragging a ticket link', () => {
jest.spyOn(controller, 'insert');
const expectedTicketId = '11';
const draggedElement = 'http://arkamcity.com/#!/ticket/11/summary';
const $event = {
dataTransfer: {
getData: () => draggedElement
}
};
controller.onDrop($event);
expect(controller.insert).toHaveBeenCalledWith(expectedTicketId);
});
it('should throw an error when dragging an invalid ticket link', () => {
jest.spyOn(controller.vnApp, 'showError');
const draggedElement = 'http://arkamcity.com/#!/item/11/summary';
const $event = {
dataTransfer: {
getData: () => draggedElement
}
};
controller.onDrop($event);
expect(controller.vnApp.showError).toHaveBeenCalledWith('Ticket not found');
});
});
describe('insert()', () => {
it('should make a HTTP patch query and then call both refresh and showSuccess methods', () => {
jest.spyOn(controller.$.model, 'refresh').mockReturnThis();
jest.spyOn(controller.vnApp, 'showSuccess');
const ticketId = 11;
$httpBackend.expect('PATCH', `Tickets/11`).respond({id: 11});
controller.insert(ticketId);
$httpBackend.flush();
expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Data saved!');
expect(controller.$.model.refresh).toHaveBeenCalledWith();
});
});
}); });

View File

@ -5,4 +5,5 @@ Order changed: Orden cambiado
Delete ticket from route?: ¿Quitar el ticket de la ruta? Delete ticket from route?: ¿Quitar el ticket de la ruta?
Sort routes: Ordenar rutas Sort routes: Ordenar rutas
Add ticket: Añadir ticket Add ticket: Añadir ticket
Tickets to add: Tickets a añadir Tickets to add: Tickets a añadir
Ticket not found: No se ha encontrado el ticket

View File

@ -26,7 +26,6 @@ describe('component vnTravelSummary', () => {
jest.spyOn(controller, 'getThermographs'); jest.spyOn(controller, 'getThermographs');
controller.travel = {id: 99}; controller.travel = {id: 99};
expect(controller._travel.id).toEqual(99); expect(controller._travel.id).toEqual(99);
expect(controller.getTravel).toHaveBeenCalledWith(); expect(controller.getTravel).toHaveBeenCalledWith();
expect(controller.getEntries).toHaveBeenCalledWith(); expect(controller.getEntries).toHaveBeenCalledWith();