Item request refactor #1818
gitea/salix/dev This commit looks good Details
gitea/salix/test This commit looks good Details

This commit is contained in:
Joan Sanchez 2019-10-22 13:44:36 +02:00
parent 58a763acf5
commit 2ed4cf3e4a
21 changed files with 209 additions and 219 deletions

View File

@ -61,7 +61,7 @@ export default {
fiscalDataButton: 'vn-left-menu a[ui-sref="client.card.fiscalData"]', fiscalDataButton: 'vn-left-menu a[ui-sref="client.card.fiscalData"]',
socialNameInput: `vn-textfield input[name="socialName"]`, socialNameInput: `vn-textfield input[name="socialName"]`,
fiscalIdInput: `vn-textfield input[name="fi"]`, fiscalIdInput: `vn-textfield input[name="fi"]`,
equalizationTaxCheckbox: 'vn-check[label="Is equalizated"]', equalizationTaxCheckbox: 'vn-check[ng-model="$ctrl.client.isEqualizated"]',
acceptPropagationButton: 'vn-client-fiscal-data > vn-confirm button[response=ACCEPT]', acceptPropagationButton: 'vn-client-fiscal-data > vn-confirm button[response=ACCEPT]',
addressInput: `vn-textfield input[name="street"]`, addressInput: `vn-textfield input[name="street"]`,
postcodeInput: `vn-textfield input[name="postcode"]`, postcodeInput: `vn-textfield input[name="postcode"]`,
@ -482,7 +482,7 @@ export default {
addRequestButton: 'vn-ticket-request-index > a > vn-float-button > button', addRequestButton: 'vn-ticket-request-index > a > vn-float-button > button',
request: 'vn-ticket-request-index vn-table vn-tr', request: 'vn-ticket-request-index vn-table vn-tr',
descriptionInput: 'vn-ticket-request-create > form > div > vn-card > div > vn-horizontal:nth-child(1) > vn-textfield input', descriptionInput: 'vn-ticket-request-create > form > div > vn-card > div > vn-horizontal:nth-child(1) > vn-textfield input',
atenderAutocomplete: 'vn-ticket-request-create vn-autocomplete[ng-model="$ctrl.ticketRequest.atenderFk"]', atenderAutocomplete: 'vn-ticket-request-create vn-autocomplete[ng-model="$ctrl.ticketRequest.attenderFk"]',
quantityInput: 'vn-ticket-request-create vn-input-number input[name=quantity]', quantityInput: 'vn-ticket-request-create vn-input-number input[name=quantity]',
priceInput: 'vn-ticket-request-create vn-input-number input[name=price]', priceInput: 'vn-ticket-request-create vn-input-number input[name=price]',
firstRemoveRequestButton: 'vn-ticket-request-index vn-icon[icon="delete"]:nth-child(1)', firstRemoveRequestButton: 'vn-ticket-request-index vn-icon[icon="delete"]:nth-child(1)',
@ -534,7 +534,7 @@ export default {
itemDescriptorPopover: '.vn-popover.shown vn-item-descriptor', itemDescriptorPopover: '.vn-popover.shown vn-item-descriptor',
itemDescriptorPopoverItemDiaryButton: '.vn-popover.shown vn-item-descriptor a[href="#!/item/2/diary"]', itemDescriptorPopoverItemDiaryButton: '.vn-popover.shown vn-item-descriptor a[href="#!/item/2/diary"]',
firstDevelopmentWorker: 'vn-claim-summary vn-horizontal > vn-auto:nth-child(5) vn-table > div > vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(4) > span', firstDevelopmentWorker: 'vn-claim-summary vn-horizontal > vn-auto:nth-child(5) vn-table > div > vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(4) > span',
firstDevelopmentWorkerGoToClientButton: '.vn-popover.shown vn-worker-descriptor div.quicklinks > a[href="#!/client/21/summary"]', firstDevelopmentWorkerGoToClientButton: '.vn-popover.shown vn-worker-descriptor vn-quick-links > a[href="#!/client/21/summary"]',
firstActionTicketId: 'vn-claim-summary > vn-card > div > vn-horizontal > vn-auto:nth-child(6) vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(2) > span', firstActionTicketId: 'vn-claim-summary > vn-card > div > vn-horizontal > vn-auto:nth-child(6) vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(2) > span',
firstActionTicketDescriptor: '.vn-popover.shown vn-ticket-descriptor' firstActionTicketDescriptor: '.vn-popover.shown vn-ticket-descriptor'
}, },

View File

@ -3,7 +3,7 @@ import ngModule from '../module';
const regex = /Android|webOS|iPhone|iPad|iPod|BlackBerry|Windows Phone/i; const regex = /Android|webOS|iPhone|iPad|iPod|BlackBerry|Windows Phone/i;
export const isMobile = regex.test(navigator.userAgent); export const isMobile = regex.test(navigator.userAgent);
export function focus(input) { export function focus($scope, input) {
if (isMobile) return; if (isMobile) return;
const element = input; const element = input;
@ -23,9 +23,9 @@ export function focus(input) {
} }
input.focus(); input.focus();
$scope.$applyAsync(() => {
if (input.select)
input.select(); input.select();
});
} }
/** /**
@ -37,7 +37,7 @@ export function directive() {
return { return {
restrict: 'A', restrict: 'A',
link: function($scope, $element) { link: function($scope, $element) {
$scope.$watch('', () => focus($element[0])); $scope.$watch('', () => focus($scope, $element[0]));
} }
}; };
} }

View File

@ -40,6 +40,7 @@ describe('Directive focus', () => {
it('should call select function on the element', () => { it('should call select function on the element', () => {
let html = `<input vn-focus></input>`; let html = `<input vn-focus></input>`;
compile(html); compile(html);
$scope.$apply();
expect($element[0].select).toHaveBeenCalledWith(); expect($element[0].select).toHaveBeenCalledWith();
}); });

View File

@ -1,7 +1,7 @@
<a ng-if="$ctrl.links.btnOne" <a ng-if="$ctrl.links.btnOne"
vn-tooltip="{{::$ctrl.links.btnOne.tooltip}}" vn-tooltip="{{::$ctrl.links.btnOne.tooltip}}"
class="vn-button colored" class="vn-button colored"
ui-sref="{{::$ctrl.links.btnOne.state}}" target="_blank"> ui-sref="{{::$ctrl.links.btnOne.state}}">
<vn-icon <vn-icon
icon="{{::$ctrl.links.btnOne.icon}}"> icon="{{::$ctrl.links.btnOne.icon}}">
</vn-icon> </vn-icon>
@ -9,7 +9,7 @@
<a ng-if="$ctrl.links.btnTwo" <a ng-if="$ctrl.links.btnTwo"
vn-tooltip="{{::$ctrl.links.btnTwo.tooltip}}" vn-tooltip="{{::$ctrl.links.btnTwo.tooltip}}"
class="vn-button colored" class="vn-button colored"
ui-sref="{{::$ctrl.links.btnTwo.state}}" target="_blank"> ui-sref="{{::$ctrl.links.btnTwo.state}}">
<vn-icon <vn-icon
icon="{{::$ctrl.links.btnTwo.icon}}"> icon="{{::$ctrl.links.btnTwo.icon}}">
</vn-icon> </vn-icon>
@ -17,7 +17,7 @@
<a ng-if="$ctrl.links.btnThree" <a ng-if="$ctrl.links.btnThree"
vn-tooltip="{{::$ctrl.links.btnThree.tooltip}}" vn-tooltip="{{::$ctrl.links.btnThree.tooltip}}"
class="vn-button colored" class="vn-button colored"
ui-sref="{{::$ctrl.links.btnThree.state}}" target="_blank"> ui-sref="{{::$ctrl.links.btnThree.state}}">
<vn-icon <vn-icon
icon="{{::$ctrl.links.btnThree.icon}}"> icon="{{::$ctrl.links.btnThree.icon}}">
</vn-icon> </vn-icon>

View File

@ -82,17 +82,6 @@ describe('claim', () => {
}); });
}); });
describe('setClaimDestination(id, claimDestinationFk)', () => {
it('should make a patch and call refresh and showSuccess', () => {
spyOn(controller.vnApp, 'showSuccess');
$httpBackend.expectPATCH(`claim/api/ClaimEnds/`).respond({});
controller.setClaimDestination(1, 1);
$httpBackend.flush();
expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Data saved!');
});
});
describe('calculateTotals()', () => { describe('calculateTotals()', () => {
it('should calculate the total price of the items claimed', () => { it('should calculate the total price of the items claimed', () => {
controller.salesClaimed = [ controller.salesClaimed = [

View File

@ -8,12 +8,11 @@
<div class="content-block"> <div class="content-block">
<vn-card class="vn-pa-md vn-w-sm"> <vn-card class="vn-pa-md vn-w-sm">
<vn-horizontal style="align-items: center;"> <vn-horizontal style="align-items: center;">
<vn-searchbar <vn-searchbar vn-focus
panel="vn-item-search-panel" panel="vn-item-search-panel"
on-search="$ctrl.onSearch($params)" on-search="$ctrl.onSearch($params)"
info="Search items by id, name or barcode" info="Search items by id, name or barcode"
suggested-filter="{isActive: true}" suggested-filter="{isActive: true}">
vn-focus>
</vn-searchbar> </vn-searchbar>
<vn-icon-menu <vn-icon-menu
vn-id="more-button" vn-id="more-button"

View File

@ -16,7 +16,7 @@
</vn-textfield> </vn-textfield>
<vn-autocomplete <vn-autocomplete
vn-one vn-one
ng-model="filter.atenderFk" ng-model="filter.attenderFk"
url="/client/api/Clients/activeWorkersWithRole" url="/client/api/Clients/activeWorkersWithRole"
search-function="{firstName: $search}" search-function="{firstName: $search}"
value-field="id" value-field="id"

View File

@ -1,121 +1,116 @@
<vn-crud-model <vn-crud-model auto-load="true"
vn-id="model" vn-id="model"
url="/ticket/api/TicketRequests/filter" url="/ticket/api/TicketRequests/filter"
limit="20" limit="20"
data="requests" data="requests"
order="isOk ASC" order="shipped ASC, isOk ASC">
auto-load="false">
</vn-crud-model> </vn-crud-model>
<form name="form"> <form name="form">
<div class="vn-ma-md"> <div class="vn-ma-md">
<vn-card class="vn-pa-md vn-list"> <vn-card class="vn-pa-md vn-list">
<vn-horizontal> <vn-searchbar vn-one vn-focus
<vn-searchbar auto-load="false"
auto-load="false" panel="vn-request-search-panel"
panel="vn-request-search-panel" on-search="$ctrl.onSearch($params)"
on-search="$ctrl.onSearch($params)" info="Search request by id or alias"
info="Search request by id or alias" suggested-filter="$ctrl.filter.where">
vn-one </vn-searchbar>
vn-focus>
</vn-searchbar>
</vn-horizontal>
</vn-card> </vn-card>
<vn-card class="vn-my-md"> <vn-data-viewer model="model" class="vn-my-md">
<vn-table model="model" auto-load="false"> <vn-card>
<vn-thead> <vn-table model="model">
<vn-tr> <vn-thead>
<vn-th field="ticketFk" number>Ticket ID</vn-th> <vn-tr>
<vn-th field="shipped">Shipped</vn-th> <vn-th field="ticketFk" number>Ticket ID</vn-th>
<vn-th field="warehouse">Warehouse</vn-th> <vn-th field="shipped">Shipped</vn-th>
<vn-th field="salesPersonNickname">SalesPerson</vn-th> <vn-th field="warehouse">Warehouse</vn-th>
<vn-th field="description">Description</vn-th> <vn-th field="salesPersonNickname">SalesPerson</vn-th>
<vn-th field="quantity" number editable>Quantity</vn-th> <vn-th field="description">Description</vn-th>
<vn-th field="price" number>Price</vn-th> <vn-th field="quantity" number editable>Requested</vn-th>
<vn-th field="atenderNickname">Atender</vn-th> <vn-th field="price" number>Price</vn-th>
<vn-th field="itemFk">Item</vn-th> <vn-th field="atenderNickname">Atender</vn-th>
<vn-th field="description">Concept</vn-th> <vn-th field="itemFk">Item</vn-th>
<vn-th field="saleQuantity" number>Sale quantity</vn-th> <vn-th field="saleQuantity">Achieved</vn-th>
<vn-th field="isOk">State</vn-th> <vn-th field="description">Concept</vn-th>
</vn-tr> <vn-th field="isOk">State</vn-th>
</vn-thead> </vn-tr>
<vn-tbody> </vn-thead>
<vn-tr ng-repeat="request in requests"> <vn-tbody>
<vn-td number> <vn-tr ng-repeat="request in requests">
<span class="link" <vn-td number>
ng-click="$ctrl.showTicketDescriptor($event, request.ticketFk)"> <span class="link"
{{request.ticketFk}} ng-click="$ctrl.showTicketDescriptor($event, request.ticketFk)">
</span> {{request.ticketFk}}
</vn-td> </span>
<vn-td> </vn-td>
<span title="{{::request.shipped | date: 'dd/MM/yyyy'}}" <vn-td>
class="chip {{$ctrl.compareDate(request.shipped)}}"> <span title="{{::request.shipped | date: 'dd/MM/yyyy'}}"
{{::request.shipped | date: 'dd/MM/yyyy'}} class="chip {{$ctrl.compareDate(request.shipped)}}">
</span> {{::request.shipped | date: 'dd/MM/yyyy'}}
</vn-td> </span>
<vn-td>{{::request.warehouse}}</vn-td> </vn-td>
<vn-td> <vn-td>{{::request.warehouse}}</vn-td>
<span <vn-td>
<span
class="link"
ng-click="$ctrl.showWorkerDescriptor($event, request.salesPersonFk)">
{{::request.salesPersonNickname}}
</span>
</vn-td>
<vn-td title="{{::request.description}}">{{::request.description}}</vn-td>
<vn-td number>{{::request.quantity}}</vn-td>
<vn-td number>{{::request.price | currency: 'EUR':2}}</vn-td>
<vn-td>
<span
class="link" class="link"
ng-click="$ctrl.showWorkerDescriptor($event, request.salesPersonFk)"> ng-click="$ctrl.showWorkerDescriptor($event, request.attenderFk)">
{{::request.salesPersonNickname}} {{::request.atenderNickname}}
</span> </span>
</vn-td> </vn-td>
<vn-td title="{{::request.description}}">{{::request.description}}</vn-td> <vn-td-editable disabled="request.isOk != null" number>
<vn-td number>{{::request.quantity}}</vn-td> <text>{{request.itemFk}}</text>
<vn-td number>{{::request.price | currency: 'EUR':2}}</vn-td> <field>
<vn-td> <vn-input-number class="dense" vn-focus
<span ng-model="request.itemFk">
class="link" </vn-input-number>
ng-click="$ctrl.showWorkerDescriptor($event, request.atenderFk)"> </field>
{{::request.atenderNickname}} </vn-td-editable>
</span> <vn-td-editable disabled="!request.itemFk || request.isOk != null" number>
</vn-td> <text number>{{request.saleQuantity}}</text>
<vn-td-editable disabled="request.isOk === 0" number> <field>
<text>{{request.itemFk}}</text> <vn-input-number class="dense" vn-focus
<field> ng-model="request.saleQuantity"
<vn-input-number on-change="$ctrl.changeQuantity(request)">
ng-model="request.itemFk" </vn-input-number>
on-change="$ctrl.confirmRequest(request)"> </field>
</vn-input-number> </vn-td-editable>
</field> <vn-td>
</vn-td-editable> <span
<vn-td> class="link"
<span ng-click="$ctrl.showItemDescriptor($event, request.itemFk)"
class="link" title="{{request.itemDescription}}">
ng-click="$ctrl.showItemDescriptor($event, request.itemFk)" {{request.itemDescription}}
title="{{::request.itemDescription}}"> </span>
{{::request.itemDescription}} </vn-td>
</span> <vn-td>{{$ctrl.getState(request.isOk)}}</vn-td>
</vn-td> <vn-td>
<vn-td-editable disabled="request.isOk === 0" number> <vn-icon
<text number>{{request.saleQuantity}}</text> ng-if="request.response.length"
<field> ranslate-attr="{title: request.response}"
<vn-input-number icon="insert_drive_file">
ng-model="request.saleQuantity" </vn-icon>
on-change="$ctrl.changeQuantity(request)"> <vn-icon-button
</vn-input-number> ng-if="request.isOk != 0"
</field> icon="thumb_down"
</vn-td-editable> ng-click="$ctrl.showDenyReason($event, request)"
<vn-td>{{::$ctrl.getState(request.isOk)}}</vn-td> translate-attr="{title: 'Discard'}">
<vn-td> </vn-icon-button>
<vn-icon </vn-td>
ng-if="request.response.length" </vn-tr>
vn-tooltip="{{request.response}}" </vn-tbody>
icon="insert_drive_file"> </vn-table>
</vn-icon> </vn-card>
<vn-icon-button </vn-data-viewer>
ng-if="request.isOk != 0"
number
icon="thumb_down"
ng-click="$ctrl.showDenyReason($event, request.id)"
vn-tooltip="Discard">
</vn-icon-button>
</vn-td>
</vn-tr>
</vn-tbody>
</vn-table>
</vn-card>
<vn-pagination model="model"></vn-pagination>
</div> </div>
</form> </form>
<vn-worker-descriptor-popover <vn-worker-descriptor-popover
@ -129,21 +124,17 @@
</vn-item-descriptor-popover> </vn-item-descriptor-popover>
<vn-dialog <vn-dialog
vn-id="denyReason" vn-id="denyReason"
class="modal-form"> on-response="$ctrl.denyRequest(response)">
<tpl-body> <tpl-body>
<vn-horizontal class="header"> <h5 class="vn-pa-md" translate>Specify the reasons to deny this request</h5>
<h5><span translate>Indicate the reasons to deny this request</span></h5>
</vn-horizontal>
<vn-horizontal class="vn-pa-md"> <vn-horizontal class="vn-pa-md">
<vn-textarea <vn-textarea
ng-model="$ctrl.denyObservation"> ng-model="$ctrl.denyObservation">
</vn-textarea> </vn-textarea>
</vn-horizontal> </vn-horizontal>
<vn-horizontal class="vn-pa-md">
<vn-button
label="Save"
ng-click="$ctrl.denyRequest()">
</vn-button>
</vn-horizontal>
</tpl-body> </tpl-body>
<tpl-buttons>
<input type="button" response="CANCEL" translate-attr="{value: 'Cancel'}"/>
<button response="ACCEPT" translate>Save</button>
</tpl-buttons>
</vn-dialog> </vn-dialog>

View File

@ -9,8 +9,23 @@ export default class Controller {
this.$ = $; this.$ = $;
this.vnApp = vnApp; this.vnApp = vnApp;
this._ = $translate; this._ = $translate;
if (!$stateParams.q) if (!$stateParams.q) {
this.filter = {isOk: false, mine: true}; const today = new Date();
today.setHours(23, 59, 59, 59);
const lastWeek = new Date();
lastWeek.setHours(0, 0, 0, 0);
lastWeek.setDate(lastWeek.getDate() - 7);
this.filter = {
where: {
isOk: false,
mine: true,
from: lastWeek,
to: today
}
};
}
} }
$postLink() { $postLink() {
@ -21,7 +36,7 @@ export default class Controller {
getState(isOk) { getState(isOk) {
if (isOk === null) if (isOk === null)
return 'Nueva'; return 'Nueva';
else if (isOk === -1 || isOk === 1) else if (isOk === -1 || isOk)
return 'Aceptada'; return 'Aceptada';
else else
return 'Denegada'; return 'Denegada';
@ -34,14 +49,12 @@ export default class Controller {
quantity: request.saleQuantity quantity: request.saleQuantity
}; };
let endpoint = `/api/TicketRequests/${request.id}/confirm`; let query = `/api/TicketRequests/${request.id}/confirm`;
this.$http.post(query, params).then(res => {
request.itemDescription = res.data.concept;
request.isOk = true;
this.$http.post(endpoint, params).then(() => {
this.vnApp.showSuccess(this._.instant('Data saved!')); this.vnApp.showSuccess(this._.instant('Data saved!'));
this.$.model.refresh();
}).catch( e => {
this.$.model.refresh();
throw e;
}); });
} }
} }
@ -56,10 +69,7 @@ export default class Controller {
this.$http.patch(endpoint, params).then(() => { this.$http.patch(endpoint, params).then(() => {
this.vnApp.showSuccess(this._.instant('Data saved!')); this.vnApp.showSuccess(this._.instant('Data saved!'));
}).catch( e => { }).then(() => this.confirmRequest(request));
this.$.model.refresh();
throw e;
});
} else } else
this.confirmRequest(request); this.confirmRequest(request);
} }
@ -86,7 +96,7 @@ export default class Controller {
} }
showDenyReason(event, requestId) { showDenyReason(event, requestId) {
this.denyRequestId = requestId; this.selectedRequest = requestId;
this.$.denyReason.parent = event.target; this.$.denyReason.parent = event.target;
this.$.denyReason.show(); this.$.denyReason.show();
document.querySelector('vn-item-request vn-textarea textArea').focus(); document.querySelector('vn-item-request vn-textarea textArea').focus();
@ -96,17 +106,21 @@ export default class Controller {
delete this.denyRequestId; delete this.denyRequestId;
} }
denyRequest() { denyRequest(response) {
if (response !== 'ACCEPT') return;
let params = { let params = {
observation: this.denyObservation observation: this.denyObservation
}; };
let endpoint = `/api/TicketRequests/${this.denyRequestId}/deny`; let query = `/api/TicketRequests/${this.selectedRequest.id}/deny`;
this.$http.post(query, params).then(res => {
const request = res.data;
this.selectedRequest.isOk = request.isOk;
this.selectedRequest.attenderFk = request.attenderFk;
this.selectedRequest.response = request.response;
this.$http.post(endpoint, params).then(() => {
this.vnApp.showSuccess(this._.instant('Data saved!')); this.vnApp.showSuccess(this._.instant('Data saved!'));
this.$.model.refresh();
this.$.denyReason.hide();
this.denyObservation = null; this.denyObservation = null;
}); });
} }

View File

@ -53,15 +53,15 @@ describe('Item', () => {
let model = controller.$.model; let model = controller.$.model;
spyOn(model, 'refresh'); spyOn(model, 'refresh');
const expectedResult = {concept: 'Melee Weapon'};
let request = {itemFk: 1, saleQuantity: 1, id: 1}; let request = {itemFk: 1, saleQuantity: 1, id: 1};
$httpBackend.when('POST', `/api/TicketRequests/${request.id}/confirm`).respond(); $httpBackend.when('POST', `/api/TicketRequests/${request.id}/confirm`).respond(expectedResult);
$httpBackend.expect('POST', `/api/TicketRequests/${request.id}/confirm`).respond(); $httpBackend.expect('POST', `/api/TicketRequests/${request.id}/confirm`).respond(expectedResult);
controller.confirmRequest(request); controller.confirmRequest(request);
$httpBackend.flush(); $httpBackend.flush();
expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Data saved!'); expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Data saved!');
expect($scope.model.refresh).toHaveBeenCalledWith();
}); });
}); });
@ -110,20 +110,17 @@ describe('Item', () => {
describe('denyRequest()', () => { describe('denyRequest()', () => {
it(`should perform a query and call vnApp.showSuccess(), refresh(), hide() and set denyObservation to null in the controller`, () => { it(`should perform a query and call vnApp.showSuccess(), refresh(), hide() and set denyObservation to null in the controller`, () => {
spyOn(controller.vnApp, 'showSuccess'); spyOn(controller.vnApp, 'showSuccess');
let model = controller.$.model;
spyOn(model, 'refresh');
spyOn(controller.$.denyReason, 'hide');
controller.denyRequestId = 1; const request = {id: 1};
const expectedResult = {isOk: false, attenderFk: 106, response: 'Denied!'};
controller.selectedRequest = request;
$httpBackend.when('POST', `/api/TicketRequests/${controller.denyRequestId}/deny`).respond(); $httpBackend.when('POST', `/api/TicketRequests/${request.id}/deny`).respond(expectedResult);
$httpBackend.expect('POST', `/api/TicketRequests/${controller.denyRequestId}/deny`).respond(); $httpBackend.expect('POST', `/api/TicketRequests/${request.id}/deny`).respond(expectedResult);
controller.denyRequest(); controller.denyRequest('ACCEPT');
$httpBackend.flush(); $httpBackend.flush();
expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Data saved!'); expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Data saved!');
expect($scope.model.refresh).toHaveBeenCalledWith();
expect($scope.denyReason.hide).toHaveBeenCalledWith();
}); });
}); });
}); });

View File

@ -1,5 +1,6 @@
Discard: Descartar Discard: Descartar
Indicate the reasons to deny this request: Indique las razones para descartar esta peticion Specify the reasons to deny this request: Especifica las razones para descartar la petición
Buy requests: Peticiones de compra Buy requests: Peticiones de compra
Search request by id or alias: Buscar peticiones por identificador o alias Search request by id or alias: Buscar peticiones por identificador o alias
Sale quantity: C. conseguida Requested: Solicitado
Achieved: Conseguido

View File

@ -38,27 +38,27 @@ module.exports = Self => {
try { try {
let options = {transaction: tx}; let options = {transaction: tx};
let item = await models.Item.findById(ctx.args.itemFk); let item = await models.Item.findById(ctx.args.itemFk, null, options);
if (!item) if (!item)
throw new UserError(`That item doesn't exists`); throw new UserError(`That item doesn't exists`);
let request = await models.TicketRequest.findById(ctx.args.id, { let request = await models.TicketRequest.findById(ctx.args.id, {
include: {relation: 'ticket'} include: {relation: 'ticket'}
}); }, options);
let [[stock]] = await Self.rawSql(`CALL vn.getItemVisibleAvailable(?,?,?,?)`, [ let [[stock]] = await Self.rawSql(`CALL vn.getItemVisibleAvailable(?,?,?,?)`, [
ctx.args.itemFk, ctx.args.itemFk,
request.ticket().shipped, request.ticket().shipped,
request.ticket().warehouseFk, request.ticket().warehouseFk,
false false
]); ], options);
if (stock.available < 0) if (stock.available < 0)
throw new UserError(`This item is not available`); throw new UserError(`This item is not available`);
if (request.saleFk) { if (request.saleFk) {
sale = await models.Sale.findById(request.saleFk); sale = await models.Sale.findById(request.saleFk, null, options);
sale.updateAttributes({ sale.updateAttributes({
itemFk: ctx.args.itemFk, itemFk: ctx.args.itemFk,
quantity: ctx.args.quantity, quantity: ctx.args.quantity,
@ -71,7 +71,11 @@ module.exports = Self => {
quantity: ctx.args.quantity, quantity: ctx.args.quantity,
concept: item.name concept: item.name
}, options); }, options);
request.updateAttributes({saleFk: sale.id, itemFk: sale.itemFk, isOk: true}, options); request.updateAttributes({
saleFk: sale.id,
itemFk: sale.itemFk,
isOk: true
}, options);
} }
query = `CALL vn.ticketCalculateSale(?)`; query = `CALL vn.ticketCalculateSale(?)`;
@ -86,6 +90,8 @@ module.exports = Self => {
}, options); }, options);
await tx.commit(); await tx.commit();
return sale;
} catch (error) { } catch (error) {
await tx.rollback(); await tx.rollback();
throw error; throw error;

View File

@ -29,7 +29,7 @@ module.exports = Self => {
let params = { let params = {
isOk: false, isOk: false,
atenderFk: worker.id, attenderFk: worker.id,
response: ctx.args.observation, response: ctx.args.observation,
}; };

View File

@ -28,7 +28,7 @@ module.exports = Self => {
type: 'Number', type: 'Number',
description: `Search by warehouse` description: `Search by warehouse`
}, { }, {
arg: 'atenderFk', arg: 'attenderFk',
type: 'Number', type: 'Number',
description: `Search requests atended by the given worker` description: `Search requests atended by the given worker`
}, { }, {
@ -65,7 +65,7 @@ module.exports = Self => {
let worker = await Self.app.models.Worker.findOne({where: {userFk: userId}}); let worker = await Self.app.models.Worker.findOne({where: {userFk: userId}});
if (ctx.args.mine) if (ctx.args.mine)
ctx.args.atenderFk = worker.id; ctx.args.attenderFk = worker.id;
let where = buildFilter(ctx.args, (param, value) => { let where = buildFilter(ctx.args, (param, value) => {
switch (param) { switch (param) {
@ -75,7 +75,7 @@ module.exports = Self => {
: {'t.nickname': {like: `%${value}%`}}; : {'t.nickname': {like: `%${value}%`}};
case 'ticketFk': case 'ticketFk':
return {'t.id': value}; return {'t.id': value};
case 'atenderFk': case 'attenderFk':
return {'tr.atenderFk': value}; return {'tr.atenderFk': value};
case 'isOk': case 'isOk':
return {'tr.isOk': value}; return {'tr.isOk': value};
@ -106,13 +106,13 @@ module.exports = Self => {
tr.ticketFk, tr.ticketFk,
tr.quantity, tr.quantity,
tr.price, tr.price,
tr.atenderFk, tr.atenderFk attenderFk,
tr.description, tr.description,
tr.response, tr.response,
tr.saleFk, tr.saleFk,
tr.isOk, tr.isOk,
s.quantity AS saleQuantity, s.quantity AS saleQuantity,
s.itemFK, s.itemFk,
i.name AS itemDescription, i.name AS itemDescription,
t.shipped, t.shipped,
t.nickname, t.nickname,

View File

@ -1,27 +1,14 @@
const app = require('vn-loopback/server/server'); const app = require('vn-loopback/server/server');
describe('ticket-request confirm()', () => { describe('ticket-request confirm()', () => {
let request; let originalRequest;
let sale; let originalSale;
let createdSaleId; let createdSaleId;
afterAll(async done => { afterAll(async done => {
const paramsForRequest = { await originalRequest.updateAttributes(originalRequest);
saleFk: request.saleFk, await originalSale.updateAttributes(originalSale);
isOk: request.isOk, await app.models.Sale.destroyById(createdSaleId);
itemFk: request.itemFk,
ticketFk: request.ticketFk
};
const paramsForSale = {
itemFk: sale.itemFk,
quantity: sale.quantity,
concept: sale.concept,
};
await request.updateAttributes(paramsForRequest);
await sale.updateAttributes(paramsForSale);
app.models.Sale.destroyById(createdSaleId);
done(); done();
}); });
@ -65,10 +52,11 @@ describe('ticket-request confirm()', () => {
const itemId = 1; const itemId = 1;
const quantity = 10; const quantity = 10;
request = await app.models.TicketRequest.findById(requestId); originalRequest = await app.models.TicketRequest.findById(requestId);
sale = await app.models.Sale.findById(saleId); originalSale = await app.models.Sale.findById(saleId);
request.updateAttributes({saleFk: saleId}); const request = await app.models.TicketRequest.findById(requestId);
await request.updateAttributes({saleFk: saleId});
let ctx = {req: {accessToken: {userId: 9}}, args: { let ctx = {req: {accessToken: {userId: 9}}, args: {
itemFk: itemId, itemFk: itemId,
@ -89,7 +77,8 @@ describe('ticket-request confirm()', () => {
const itemId = 1; const itemId = 1;
const quantity = 10; const quantity = 10;
request.updateAttributes({saleFk: null}); const request = await app.models.TicketRequest.findById(requestId);
await request.updateAttributes({saleFk: null});
let ctx = {req: {accessToken: {userId: 9}}, args: { let ctx = {req: {accessToken: {userId: 9}}, args: {
itemFk: itemId, itemFk: itemId,

View File

@ -5,7 +5,7 @@ describe('ticket-request deny()', () => {
afterAll(async done => { afterAll(async done => {
let params = { let params = {
isOk: null, isOk: null,
atenderFk: request.atenderFk, attenderFk: request.attenderFk,
response: null, response: null,
}; };

View File

@ -37,7 +37,7 @@ describe('ticket-request filter()', () => {
}); });
it('should return the ticket request matching the atender ID', async() => { it('should return the ticket request matching the atender ID', async() => {
let ctx = {req: {accessToken: {userId: 9}}, args: {atenderFk: 35}}; let ctx = {req: {accessToken: {userId: 9}}, args: {attenderFk: 35}};
let result = await app.models.TicketRequest.filter(ctx); let result = await app.models.TicketRequest.filter(ctx);
let requestId = result[0].id; let requestId = result[0].id;

View File

@ -33,9 +33,12 @@
"isOk": { "isOk": {
"type": "Boolean" "type": "Boolean"
}, },
"atenderFk": { "attenderFk": {
"type": "Number", "type": "Number",
"required": true "required": true,
"mysql": {
"columnName": "atenderFk"
}
}, },
"response": { "response": {
"type": "String" "type": "String"
@ -55,7 +58,7 @@
"atender": { "atender": {
"type": "belongsTo", "type": "belongsTo",
"model": "Worker", "model": "Worker",
"foreignKey": "atenderFk" "foreignKey": "attenderFk"
}, },
"requester": { "requester": {
"type": "belongsTo", "type": "belongsTo",

View File

@ -176,7 +176,7 @@ class Controller {
links.btnTwo = { links.btnTwo = {
icon: 'icon-stowaway', icon: 'icon-stowaway',
state: `ticket.card.summary({id: ${value.stowaway.shipFk}})`, state: `ticket.card.summary({id: ${value.stowaway.shipFk}})`,
tooltip: 'Ship' tooltip: 'Ship stowaways'
}; };
} }

View File

@ -18,7 +18,7 @@
</vn-textfield> </vn-textfield>
<vn-autocomplete <vn-autocomplete
vn-one vn-one
ng-model="$ctrl.ticketRequest.atenderFk" ng-model="$ctrl.ticketRequest.attenderFk"
url="/client/api/Clients/activeWorkersWithRole" url="/client/api/Clients/activeWorkersWithRole"
show-field="nickname" show-field="nickname"
search-function="{firstName: $search}" search-function="{firstName: $search}"

View File

@ -1,7 +1,7 @@
<vn-crud-model <vn-crud-model
vn-id="model" vn-id="model"
url="/ticket/api/TicketRequests" url="/ticket/api/TicketRequests"
fields="['id', 'description', 'created', 'requesterFk', 'atenderFk', 'quantity', 'price', 'saleFk', 'isOk']" fields="['id', 'description', 'created', 'requesterFk', 'attenderFk', 'quantity', 'price', 'saleFk', 'isOk']"
order="created ASC" order="created ASC"
link="{ticketFk: $ctrl.$stateParams.id}" link="{ticketFk: $ctrl.$stateParams.id}"
filter="::$ctrl.filter" filter="::$ctrl.filter"
@ -43,7 +43,7 @@
<vn-td expand> <vn-td expand>
<span <span
class="link" class="link"
ng-click="$ctrl.showWorkerDescriptor($event, request.atenderFk)"> ng-click="$ctrl.showWorkerDescriptor($event, request.attenderFk)">
{{::request.atender.user.nickname | dashIfEmpty}} {{::request.atender.user.nickname | dashIfEmpty}}
</span> </span>
</vn-td> </vn-td>