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

This commit is contained in:
Juan 2018-09-13 15:22:42 +02:00
commit fad2b78cc3
56 changed files with 1759 additions and 278 deletions

View File

@ -16,7 +16,7 @@
"state": "claim.index", "state": "claim.index",
"component": "vn-claim-index", "component": "vn-claim-index",
"description": "List", "description": "List",
"acl": ["salesAssistant"] "acl": ["salesAssistant", "salesPerson"]
}, },
{ {
"url": "/:id", "url": "/:id",

View File

@ -80,7 +80,7 @@
<vn-dialog <vn-dialog
vn-id="addSales"> vn-id="addSales">
<tpl-body> <tpl-body>
<h3 translate>Claimable sales from ticket</h3><h3> {{$ctrl.claim.ticketFk}}</h3> <h3><span translate>Claimable sales from ticket</span> {{$ctrl.claim.ticketFk}}</h3>
<vn-table> <vn-table>
<vn-thead> <vn-thead>
<vn-tr> <vn-tr>

View File

@ -3,6 +3,7 @@ Client Id: Id cliente
Observation: Observación Observation: Observación
Responsible: Responsable Responsible: Responsable
Claim Id: Id reclamación Claim Id: Id reclamación
Created: Creado
#sections #sections
Claims: Reclamaciones Claims: Reclamaciones

View File

@ -19,7 +19,8 @@
<vn-horizontal> <vn-horizontal>
<vn-textfield vn-one label="Postcode" field="$ctrl.address.postalCode"></vn-textfield> <vn-textfield vn-one label="Postcode" field="$ctrl.address.postalCode"></vn-textfield>
<vn-textfield vn-one label="Town/City" field="$ctrl.address.city"></vn-textfield> <vn-textfield vn-one label="Town/City" field="$ctrl.address.city"></vn-textfield>
<vn-autocomplete vn-one <vn-autocomplete
vn-one
field="$ctrl.address.provinceFk" field="$ctrl.address.provinceFk"
url="/client/api/Provinces" url="/client/api/Provinces"
show-field="name" show-field="name"
@ -28,7 +29,8 @@
</vn-autocomplete> </vn-autocomplete>
</vn-horizontal> </vn-horizontal>
<vn-horizontal> <vn-horizontal>
<vn-autocomplete vn-one <vn-autocomplete
vn-one
field="$ctrl.address.agencyModeFk" field="$ctrl.address.agencyModeFk"
url="/client/api/AgencyModes/" url="/client/api/AgencyModes/"
show-field="name" show-field="name"

View File

@ -0,0 +1,53 @@
import './icon-menu.js';
describe('Component vnIconMenu', () => {
let $componentController;
let controller;
let $element;
beforeEach(() => {
angular.mock.module('ticket');
});
beforeEach(angular.mock.inject(_$componentController_ => {
$componentController = _$componentController_;
$element = angular.element(`<div class="shown"></div>`);
controller = $componentController('vnIconMenu', {$element: $element, $transclude: null});
}));
describe('getFields()', () => {
it(`should return an array with the fields selectables`, () => {
let fields = controller.getFields();
expect(fields).toEqual(['id', 'name']);
});
});
describe('onClick(event)', () => {
it(`should call preventDefault, onOpen and showDropdown`, () => {
let event = {preventDefault: () => {}};
controller.onOpen = () => {};
spyOn(event, 'preventDefault');
spyOn(controller, 'showDropDown');
spyOn(controller, 'onOpen');
controller.onClick(event);
expect(event.preventDefault).toHaveBeenCalledWith();
expect(controller.showDropDown).toHaveBeenCalledWith();
expect(controller.onOpen).toHaveBeenCalledWith();
});
});
describe('onDropDownSelect(value)', () => {
it(`should set field to a given value and call onChange`, () => {
controller.onChange = () => {};
spyOn(controller, 'onChange');
controller.onDropDownSelect('mariano');
expect(controller.field).toBe('mariano');
expect(controller.onChange).toHaveBeenCalledWith({value: 'mariano'});
});
});
});

View File

@ -40,3 +40,4 @@ import './table';
import './th'; import './th';
import './input-range'; import './input-range';
import './chip'; import './chip';
import './input-number';

View File

@ -0,0 +1,42 @@
<div class="container"
ng-class="{selected: $ctrl.hasFocus}">
<div class="textField">
<div class="leftIcons">
<vn-icon-button
icon="remove"
ng-click="$ctrl.remove()"
tabindex="-1"
title="Remove number">
</vn-icon-button>
</div>
<div class="infix">
<input
class="mdl-textfield__input"
type="number"
name="{{$ctrl.name}}"
ng-model="$ctrl.value"
ng-disabled="$ctrl.disabled"
ng-readonly="$ctrl.readonly"
ng-focus="$ctrl.hasFocus = true"
ng-blur="$ctrl.hasFocus = false"
tabindex="{{$ctrl.input.tabindex}}"/>
<label class="label" translate>{{::$ctrl.label}}</label>
</div>
<div class="underline"></div>
<div class="selected underline"></div>
<div class="suffix">
<vn-icon-button
icon="add"
ng-click="$ctrl.add()"
tabindex="-1"
title="Add number">
</vn-icon-button>
<i class="material-icons"
ng-if="$ctrl.hasInfo"
vn-tooltip="{{$ctrl.info}}">
info_outline
</i>
</div>
<div class="rightIcons"></div>
</div>
</div>

View File

@ -0,0 +1,104 @@
import ngModule from '../../module';
import Textfield from '../textfield/textfield';
import './style.scss';
export default class InputNumber extends Textfield {
constructor($element, $scope, $attrs, vnTemplate, $transclude) {
super($element, $scope, $attrs, vnTemplate, $transclude);
this.input.addEventListener('change', () => {
this.validateValue();
});
}
get value() {
return this._value;
}
set value(value) {
this._value = value;
this.hasValue = this._value !== null;
if (this.hasValue) this.element.classList.add('not-empty');
else this.element.classList.remove('not-empty');
this.element.querySelector('.infix').classList.remove('invalid', 'validated');
}
get max() {
return this.input.max;
}
set max(value) {
if (value)
this.input.max = value;
}
get min() {
return this.input.min;
}
set min(value) {
if (!value) value = 0;
this.input.min = value;
}
get step() {
return parseInt(this.input.step);
}
set step(value) {
this.input.step = value;
}
validateValue() {
if ((this.validate() !== undefined && !this.validate()) ||
(this.max && this.value > this.max) ||
(this.min && this.value < this.min) ||
(this.step && this.value % this.step != 0)) {
this.$element[0].querySelector('.infix').classList.add('invalid', 'validated');
}
if (this.onChange)
this.onChange();
}
add() {
if (this.step && this.value % this.step != 0) {
this.value += (this.step - this.value % this.step);
} else {
this.value += this.step;
}
this.validateValue();
}
remove() {
if (this.step && this.value % this.step != 0) {
this.value -= (this.step + this.value % this.step);
} else {
this.value -= this.step;
}
this.validateValue();
}
}
InputNumber.$inject = ['$element', '$scope', '$attrs', 'vnTemplate', '$transclude'];
ngModule.component('vnInputNumber', {
template: require('./index.html'),
controller: InputNumber,
bindings: {
label: '@?',
disabled: '<?',
min: '<?',
max: '<?',
step: '<?',
rule: '@?',
value: '=model',
validate: '&',
onChange: '&',
onClear: '&'
}
});

View File

@ -0,0 +1,160 @@
import './index.js';
describe('Component vnInputNumber', () => {
let $componentController;
let $scope;
let $attrs;
let $timeout;
let $element;
let controller;
beforeEach(() => {
angular.mock.module('claim');
});
beforeEach(angular.mock.inject((_$componentController_, $rootScope, _$httpBackend_, _$timeout_) => {
$componentController = _$componentController_;
$scope = $rootScope.$new();
$attrs = {};
$timeout = _$timeout_;
$element = angular.element('<div><input><div class="infix invalid validated"><div class="rightIcons"></div></div>');
controller = $componentController('vnInputNumber', {$element, $scope, $attrs, $timeout, $transclude: () => {}});
}));
describe('value() setter', () => {
it(`should set _value to a given value, add the class not-empty and remove invalid and validated`, () => {
controller.value = 'pepino';
let classes = controller.element.classList.toString();
expect(classes).toContain('not-empty');
expect(controller._value).toEqual('pepino');
classes = controller.element.querySelector('.infix').classList.toString();
expect(classes).not.toContain('invalid validated');
});
it(`should set _value to a given value and not add the class not-empty if the given value is null`, () => {
controller.value = null;
let classes = controller.element.classList.toString();
expect(classes).not.toContain('not-empty');
expect(controller._value).toEqual(null);
});
});
describe('max() setter', () => {
it(`should set input.max to a given value`, () => {
controller.max = 10;
expect(controller.input.max).toEqual('10');
});
});
describe('min() setter', () => {
it(`should set input.min if theres a given value`, () => {
controller.min = 1;
expect(controller.input.min).toEqual('1');
});
it(`should set input.min to 0 if theres not a given value`, () => {
controller.min = null;
expect(controller.input.min).toEqual('0');
});
});
describe('step() setter/getter', () => {
it(`should set input.step to a given value`, () => {
controller.step = 50;
expect(controller.input.step).toEqual('50');
});
it(`should return a number`, () => {
controller.step = 50;
expect(controller.step).toEqual(50);
expect(typeof controller.step).toEqual('number');
});
});
describe('validateValue()', () => {
it(`should add the classes invalid and validated if the value is less than min`, () => {
controller.validate = () => {};
controller.min = 0;
controller.value = -7;
let classes = controller.element.querySelector('.infix').classList.toString();
expect(classes).not.toContain('invalid validated');
expect(controller.value).toEqual(-7);
controller.validateValue();
classes = controller.element.querySelector('.infix').classList.toString();
expect(classes).toContain('infix invalid validated');
});
it(`should add the classes invalid and validated if the value is greater than max`, () => {
controller.validate = () => {};
controller.max = 10;
controller.value = 15;
let classes = controller.element.querySelector('.infix').classList.toString();
expect(classes).not.toContain('invalid validated');
expect(controller.value).toEqual(15);
controller.validateValue();
classes = controller.element.querySelector('.infix').classList.toString();
expect(classes).toContain('infix invalid validated');
});
it(`should add the classes invalid and validated if the value is not a valid step`, () => {
controller.validate = () => {};
controller.step = 5;
controller.value = 7;
let classes = controller.element.querySelector('.infix').classList.toString();
expect(classes).not.toContain('invalid validated');
expect(controller.value).toEqual(7);
controller.validateValue();
classes = controller.element.querySelector('.infix').classList.toString();
expect(classes).toContain('infix invalid validated');
});
it(`should add the classes invalid and validated if the function validate returns false`, () => {
controller.validate = () => {
return false;
};
controller.step = 5;
controller.value = 7;
let classes = controller.element.querySelector('.infix').classList.toString();
expect(classes).not.toContain('invalid validated');
expect(controller.value).toEqual(7);
controller.validateValue();
classes = controller.element.querySelector('.infix').classList.toString();
expect(classes).toContain('infix invalid validated');
});
});
describe('add()', () => {
it(`should set value to the next possible step and call validateValue`, () => {
spyOn(controller, 'validateValue');
controller.step = 50;
controller.value = -1;
controller.remove();
expect(controller.value).toEqual(-50);
expect(controller.validateValue).toHaveBeenCalledWith();
});
});
});

View File

@ -0,0 +1,21 @@
@import 'colors';
@import '../textfield/style.scss';
vn-input-number {
@extend vn-textfield;
input {
text-align: center!important;
}
vn-icon[icon=add],
vn-icon[icon=remove]{
&:not(:hover){
color: $secondary-font-color;
}
i {
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
}
}
}

View File

@ -56,7 +56,7 @@ vn-table {
display: table-footer-group display: table-footer-group
} }
vn-tr { vn-tr, a.vn-tr {
display: table-row display: table-row
} }
@ -67,10 +67,8 @@ vn-table {
padding: 10px padding: 10px
} }
vn-thead, vn-thead, vn-tbody, vn-tfoot {
vn-tbody, vn-tr, a.vn-tr {
vn-tfoot {
vn-tr {
display: table-row; display: table-row;
vn-th { vn-th {
@ -101,7 +99,7 @@ vn-table {
vn-thead, vn-tbody, vn-empty-rows { vn-thead, vn-tbody, vn-empty-rows {
border-bottom: 3px solid $lines; border-bottom: 3px solid $lines;
} }
vn-tbody > vn-tr { vn-tbody > vn-tr, vn-tbody > a.vn-tr {
border-bottom: 1px solid $lines; border-bottom: 1px solid $lines;
transition: background-color 200ms ease-in-out; transition: background-color 200ms ease-in-out;

View File

@ -1,6 +1,24 @@
@import 'colors';
vn-textarea { vn-textarea {
& > .mdl-textfield { & > .mdl-textfield {
width: initial; width: initial;
display: block; display: block;
} }
label {
position: absolute;
bottom: 0;
pointer-events: none;
color: $secondary-font-color;
transition-duration: .2s;
transition-timing-function: cubic-bezier(.4,0,.2,1);
}
& textarea.ng-not-empty+label.placeholder{
top: 5px;
color: $main-01;
padding: 0;
font-size: 12px;
visibility: visible!important;
content: normal!important;
}
} }

View File

@ -5,5 +5,5 @@
ng-disabled="$ctrl.disabled" ng-disabled="$ctrl.disabled"
ng-model="$ctrl.model"> ng-model="$ctrl.model">
</textarea> </textarea>
<label class="mdl-textfield__label" translate>{{$ctrl.label}}</label> <label class="mdl-textfield__label placeholder" translate>{{$ctrl.label}}</label>
</div> </div>

View File

@ -81,6 +81,7 @@ export default class Textfield extends Input {
clear() { clear() {
this.saveOldValue(); this.saveOldValue();
this.value = null; this.value = null;
if (this.onClear) this.onClear();
this.input.focus(); this.input.focus();
} }
} }
@ -102,6 +103,7 @@ ngModule.component('vnTextfield', {
rule: '@?', rule: '@?',
type: '@?', type: '@?',
vnTabIndex: '@?', vnTabIndex: '@?',
onChange: '&' onChange: '&',
onClear: '&'
} }
}); });

View File

@ -3,7 +3,7 @@
.icon-volume:before { content: '\e801'; } /* '' */ .icon-volume:before { content: '\e801'; } /* '' */
.icon-barcode:before { content: '\e802'; } /* '' */ .icon-barcode:before { content: '\e802'; } /* '' */
.icon-bucket:before { content: '\e803'; } /* '' */ .icon-bucket:before { content: '\e803'; } /* '' */
.icon-accessory:before { content: '\e804'; } /* '' */ .icon-accesory:before { content: '\e804'; } /* '' */
.icon-dfiscales:before { content: '\e805'; } /* '' */ .icon-dfiscales:before { content: '\e805'; } /* '' */
.icon-doc:before { content: '\e806'; } /* '' */ .icon-doc:before { content: '\e806'; } /* '' */
.icon-eye:before { content: '\e807'; } /* '' */ .icon-eye:before { content: '\e807'; } /* '' */
@ -13,6 +13,8 @@
.icon-disabled:before { content: '\e80b'; } /* '' */ .icon-disabled:before { content: '\e80b'; } /* '' */
.icon-invoices:before { content: '\e80c'; } /* '' */ .icon-invoices:before { content: '\e80c'; } /* '' */
.icon-frozen-1:before { content: '\e80d'; } /* '' */ .icon-frozen-1:before { content: '\e80d'; } /* '' */
.icon-actions:before { content: '\e80e'; } /* '' */
.icon-details:before { content: '\e80f'; } /* '' */
.icon-noweb:before { content: '\e812'; } /* '' */ .icon-noweb:before { content: '\e812'; } /* '' */
.icon-payment:before { content: '\e813'; } /* '' */ .icon-payment:before { content: '\e813'; } /* '' */
.icon-recovery:before { content: '\e815'; } /* '' */ .icon-recovery:before { content: '\e815'; } /* '' */
@ -33,8 +35,9 @@
.icon-solunion:before { content: '\e827'; } /* '' */ .icon-solunion:before { content: '\e827'; } /* '' */
.icon-reserva:before { content: '\e828'; } /* '' */ .icon-reserva:before { content: '\e828'; } /* '' */
.icon-entry:before { content: '\e829'; } /* '' */ .icon-entry:before { content: '\e829'; } /* '' */
.icon-traceability:before { content: '\e82a'; } /* '' */
.icon-transaction:before { content: '\e82b'; } /* '' */ .icon-transaction:before { content: '\e82b'; } /* '' */
.icon-greenery:before { content: '\e82c'; } /* '' */ .icon-verde:before { content: '\e82c'; } /* '' */
.icon-regentry:before { content: '\e82d'; } /* '' */ .icon-regentry:before { content: '\e82d'; } /* '' */
.icon-plant:before { content: '\e82e'; } /* '' */ .icon-plant:before { content: '\e82e'; } /* '' */
.icon-artificial:before { content: '\e82f'; } /* '' */ .icon-artificial:before { content: '\e82f'; } /* '' */

View File

@ -34,11 +34,11 @@
</vn-tr> </vn-tr>
</vn-thead> </vn-thead>
<vn-tbody> <vn-tbody>
<vn-tr ng-class="{'warning': $ctrl.isToday(sale.date)}" <vn-tr ng-class="::{'warning': $ctrl.isToday(sale.date)}"
ng-repeat="sale in sales" vn-repeat-last on-last="$ctrl.scrollToActive()"> ng-repeat="sale in sales" vn-repeat-last on-last="$ctrl.scrollToActive()">
<vn-td>{{::sale.date | date:'dd/MM/yyyy HH:mm' }}</vn-td> <vn-td>{{::sale.date | date:'dd/MM/yyyy HH:mm' }}</vn-td>
<vn-td number> <vn-td number>
<span ng-class="{'link pointer': sale.isTicket}" <span ng-class="::{'link pointer': sale.isTicket}"
ng-click="$ctrl.showDescriptor($event, sale)"> ng-click="$ctrl.showDescriptor($event, sale)">
{{::sale.origin | dashIfEmpty}} {{::sale.origin | dashIfEmpty}}
</span> </span>
@ -46,9 +46,9 @@
<vn-td>{{::sale.stateName | dashIfEmpty}}</vn-td> <vn-td>{{::sale.stateName | dashIfEmpty}}</vn-td>
<vn-td>{{::sale.reference | dashIfEmpty}}</vn-td> <vn-td>{{::sale.reference | dashIfEmpty}}</vn-td>
<vn-td> <vn-td>
<span ng-class="{'link pointer': sale.isTicket}" <span ng-class="::{'link pointer': sale.isTicket}"
ng-click="$ctrl.showClientDescriptor($event, sale)"> ng-click="$ctrl.showClientDescriptor($event, sale)">
{{sale.name | dashIfEmpty}} {{::sale.name | dashIfEmpty}}
</span> </span>
</vn-td> </vn-td>
<vn-td number>{{::sale.in | dashIfEmpty}}</vn-td> <vn-td number>{{::sale.in | dashIfEmpty}}</vn-td>

View File

@ -74,7 +74,7 @@ class Controller {
}; };
this.$http.post(`order/api/Orders/new`, params).then(res => { this.$http.post(`order/api/Orders/new`, params).then(res => {
this.vnApp.showSuccess(this.translate.instant('Data saved!')); this.vnApp.showSuccess(this.translate.instant('Data saved!'));
this.$state.go("order.card.catalogue", {id: res.data}); this.$state.go("order.card.catalog", {id: res.data});
}).catch(e => { }).catch(e => {
this.vnApp.showError(this.translate.instant(e.data.error.message)); this.vnApp.showError(this.translate.instant(e.data.error.message));
}); });

View File

@ -88,7 +88,7 @@ describe('Order', () => {
$httpBackend.flush(); $httpBackend.flush();
expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Data saved!'); expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Data saved!');
expect(controller.$state.go).toHaveBeenCalledWith("order.card.catalogue", {id: 1}); expect(controller.$state.go).toHaveBeenCalledWith("order.card.catalog", {id: 1});
}); });
}); });
}); });

View File

@ -17,6 +17,12 @@ input[type=reset]::-moz-focus-inner
{ {
border: none; border: none;
} }
.unselectable {
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
}
.link{ .link{
text-decoration: underline; text-decoration: underline;
cursor: pointer; cursor: pointer;

View File

@ -37,8 +37,9 @@
</vn-tr> </vn-tr>
</vn-thead> </vn-thead>
<vn-tbody> <vn-tbody>
<vn-tr ng-repeat="ticket in tickets" <a
class="{{::$ctrl.compareDate(ticket.shipped)}} clickable" ng-repeat="ticket in tickets"
class="{{::$ctrl.compareDate(ticket.shipped)}} clickable vn-tr"
ui-sref="ticket.card.summary({id: {{::ticket.id}}})"> ui-sref="ticket.card.summary({id: {{::ticket.id}}})">
<vn-td> <vn-td>
<vn-icon ng-show="ticket.problem" class="bright" <vn-icon ng-show="ticket.problem" class="bright"
@ -71,7 +72,7 @@
icon="desktop_windows"> icon="desktop_windows">
</vn-icon-button> </vn-icon-button>
</vn-td> </vn-td>
</vn-tr> </a>
</vn-tbody> </vn-tbody>
</vn-table> </vn-table>
</vn-card> </vn-card>

View File

@ -48,7 +48,7 @@
<vn-table model="model"> <vn-table model="model">
<vn-thead> <vn-thead>
<vn-tr> <vn-tr>
<vn-th number ng-show="$ctrl.isEditable"> <vn-th number>
<vn-multi-check <vn-multi-check
data="$ctrl.sales"> data="$ctrl.sales">
</vn-multi-check> </vn-multi-check>
@ -65,7 +65,7 @@
</vn-thead> </vn-thead>
<vn-tbody> <vn-tbody>
<vn-tr ng-repeat="sale in sales"> <vn-tr ng-repeat="sale in sales">
<vn-td number ng-show="$ctrl.isEditable"> <vn-td number >
<vn-check <vn-check
field="sale.checked"> field="sale.checked">
</vn-check> </vn-check>

View File

@ -16,7 +16,8 @@ class Controller {
{callback: this.showDeleteTicketDialog, name: "Delete ticket", always: true}, {callback: this.showDeleteTicketDialog, name: "Delete ticket", always: true},
{callback: this.markAsReserved, name: 'Mark as reserved'}, {callback: this.markAsReserved, name: 'Mark as reserved'},
{callback: this.unmarkAsReserved, name: 'Unmark as reserved'}, {callback: this.unmarkAsReserved, name: 'Unmark as reserved'},
{callback: this.showEditDialog, name: 'Update discount'} {callback: this.showEditDialog, name: 'Update discount'},
{callback: this.createClaim, name: 'Add claim'}
]; ];
} }
@ -78,7 +79,6 @@ class Controller {
for (let i = 0; i < data.length; i++) for (let i = 0; i < data.length; i++)
if (data[i].checked) if (data[i].checked)
lines.push({id: data[i].id, instance: i}); lines.push({id: data[i].id, instance: i});
return lines; return lines;
} }
@ -177,7 +177,6 @@ class Controller {
}); });
} }
// In Progress
linesToNewTicket() { linesToNewTicket() {
let ticket = { let ticket = {
oldTicketFk: this.ticket.id, oldTicketFk: this.ticket.id,
@ -197,6 +196,22 @@ class Controller {
}); });
} }
createClaim() {
let claim = {
ticketFk: this.ticket.id,
clientFk: this.ticket.clientFk,
ticketCreated: this.ticket.shipped,
workerFk: this.ticket.client.salesPersonFk
};
let sales = this.getCheckedLines();
for (let i = 0; i < sales.length; i++)
sales[i].quantity = this.sales[sales[i].instance].quantity;
this.$http.post(`claim/api/Claims/createFromSales`, {claim: claim, sales: sales}).then(res => {
let url = this.$state.href("claim.card.basicData", {id: res.data.id}, {absolute: true});
window.open(url, '_blank');
});
}
goToTicket(ticketID) { goToTicket(ticketID) {
this.$state.go("ticket.card.sale", {id: ticketID}); this.$state.go("ticket.card.sale", {id: ticketID});
} }

View File

@ -33,14 +33,28 @@ describe('Ticket', () => {
quantity: 20, quantity: 20,
price: 5.5, price: 5.5,
discount: 0, discount: 0,
checked: true checked: false
} }
]}; ]};
$scope.addTurn = {show: () => {}}; $scope.addTurn = {show: () => {}};
controller = $componentController('vnTicketSale', {$scope: $scope}, {$state: $state}); controller = $componentController('vnTicketSale', {$scope: $scope}, {$state: $state});
controller.ticket = {id: 1}; controller.ticket = {id: 1, clientFk: 1, shipped: 1, client: {salesPersonFk: 1}};
spyOn(window, 'open');
})); }));
describe('createClaim()', () => {
it('should perfrom a query and call windows open', () => {
controller.sales = controller.$scope.model.data;
let res = {id: 1};
$httpBackend.expectPOST(`claim/api/Claims/createFromSales`).respond(res);
controller.createClaim();
$httpBackend.flush();
let urlMock = null;
expect(window.open).toHaveBeenCalledWith(urlMock, '_blank');
});
});
describe('getSales()', () => { describe('getSales()', () => {
it('should make a query and call getTaxes()', () => { it('should make a query and call getTaxes()', () => {
let data = [ let data = [
@ -56,7 +70,7 @@ describe('Ticket', () => {
quantity: 20, quantity: 20,
price: 5.5, price: 5.5,
discount: 0, discount: 0,
checked: true checked: false
} }
]; ];
@ -113,9 +127,10 @@ describe('Ticket', () => {
describe('getCheckedLines()', () => { describe('getCheckedLines()', () => {
it('should make an array of the instances with the property checked true()', () => { it('should make an array of the instances with the property checked true()', () => {
controller.sales = [{id: 1, checked: true}, {id: 2, checked: false}, {id: 3, checked: true}]; let expectedResult = [{id: 1, instance: 0}];
controller.sales = controller.$scope.model.data;
expect(controller.getCheckedLines()).toEqual([{id: 1, instance: 0}, {id: 3, instance: 2}]); expect(controller.getCheckedLines()).toEqual(expectedResult);
}); });
}); });

View File

@ -23,5 +23,6 @@ Thursday: Jueves
Friday: Viernes Friday: Viernes
Saturday: Sábado Saturday: Sábado
Sunday: Domingo Sunday: Domingo
Add claim: Crear reclamación
Transfer lines: Transferir líneas Transfer lines: Transferir líneas
Change ticket state to 'Ok': Cambiar estado del ticket a 'Ok' Change ticket state to 'Ok': Cambiar estado del ticket a 'Ok'

View File

@ -167,7 +167,7 @@ export default {
itemCreateView: { itemCreateView: {
name: `${components.vnTextfield}[name="name"]`, name: `${components.vnTextfield}[name="name"]`,
typeSelect: `vn-autocomplete[field="$ctrl.item.typeFk"] input`, typeSelect: `vn-autocomplete[field="$ctrl.item.typeFk"] input`,
typeSelectOptionOne: `vn-autocomplete[field="$ctrl.item.typeFk"] vn-drop-down ul > li:nth-child(2)`, typeSelectOptionThree: `vn-autocomplete[field="$ctrl.item.typeFk"] vn-drop-down ul > li:nth-child(3)`,
intrastatSelect: `vn-autocomplete[field="$ctrl.item.intrastatFk"] input`, intrastatSelect: `vn-autocomplete[field="$ctrl.item.intrastatFk"] input`,
intrastatSelectOptionOne: `vn-autocomplete[field="$ctrl.item.intrastatFk"] vn-drop-down ul > li:nth-child(2)`, intrastatSelectOptionOne: `vn-autocomplete[field="$ctrl.item.intrastatFk"] vn-drop-down ul > li:nth-child(2)`,
originSelect: `vn-autocomplete[field="$ctrl.item.originFk"] input`, originSelect: `vn-autocomplete[field="$ctrl.item.originFk"] input`,
@ -180,7 +180,7 @@ export default {
goToItemIndexButton: 'vn-item-descriptor [ui-sref="item.index"]', goToItemIndexButton: 'vn-item-descriptor [ui-sref="item.index"]',
basicDataButton: `vn-menu-item a[ui-sref="item.card.data"]`, basicDataButton: `vn-menu-item a[ui-sref="item.card.data"]`,
typeSelect: `vn-autocomplete[field="$ctrl.item.typeFk"] input`, typeSelect: `vn-autocomplete[field="$ctrl.item.typeFk"] input`,
typeSelectOptionTwo: `vn-autocomplete[field="$ctrl.item.typeFk"] vn-drop-down ul > li:nth-child(2)`, typeSelectOptionThree: `vn-autocomplete[field="$ctrl.item.typeFk"] vn-drop-down ul > li:nth-child(3)`,
intrastatSelect: `vn-autocomplete[field="$ctrl.item.intrastatFk"] input`, intrastatSelect: `vn-autocomplete[field="$ctrl.item.intrastatFk"] input`,
intrastatSelectOptionOne: `vn-autocomplete[field="$ctrl.item.intrastatFk"] vn-drop-down ul > li:nth-child(1)`, intrastatSelectOptionOne: `vn-autocomplete[field="$ctrl.item.intrastatFk"] vn-drop-down ul > li:nth-child(1)`,
nameInput: `vn-horizontal:nth-child(2) > ${components.vnTextfield}`, nameInput: `vn-horizontal:nth-child(2) > ${components.vnTextfield}`,
@ -274,7 +274,9 @@ export default {
}, },
ticketsIndex: { ticketsIndex: {
createTicketButton: `vn-ticket-index ${components.vnFloatButton}`, createTicketButton: `vn-ticket-index ${components.vnFloatButton}`,
searchResult: `vn-ticket-index vn-card > div > vn-table > div > vn-tbody > vn-tr`, searchResult: `vn-ticket-index vn-card > div > vn-table > div > vn-tbody > a.vn-tr`,
searchResultDate: `vn-ticket-index vn-table vn-tbody > a:nth-child(1) > vn-td:nth-child(4)`,
searchResultAddress: `vn-ticket-index vn-table vn-tbody > a:nth-child(1) > vn-td:nth-child(6)`,
searchTicketInput: `vn-ticket-index ${components.vnTextfield}`, searchTicketInput: `vn-ticket-index ${components.vnTextfield}`,
searchButton: `vn-ticket-index vn-searchbar vn-icon-button[icon="search"]` searchButton: `vn-ticket-index vn-searchbar vn-icon-button[icon="search"]`
}, },
@ -295,10 +297,10 @@ export default {
ticketPackages: { ticketPackages: {
packagesButton: `vn-menu-item a[ui-sref="ticket.card.package.index"]`, packagesButton: `vn-menu-item a[ui-sref="ticket.card.package.index"]`,
firstPackageSelect: `vn-autocomplete[label="Package"] > div > div > input`, firstPackageSelect: `vn-autocomplete[label="Package"] > div > div > input`,
firstPackageSelectOptionThree: `vn-autocomplete[label="Package"] vn-drop-down ul > li:nth-child(3)`, firstPackageSelectOptionTwo: `vn-autocomplete[label="Package"] vn-drop-down ul > li:nth-child(2)`,
firstQuantityInput: `vn-textfield[label="Quantity"] > div > input`, firstQuantityInput: `vn-textfield[label="Quantity"] input`,
firstRemovePackageButton: `vn-icon[vn-tooltip="Remove package"]`, firstRemovePackageButton: `vn-icon[vn-tooltip="Remove package"]`,
addPackageButton: `vn-icon[vn-tooltip="Add package"]`, addPackageButton: `vn-icon-button[vn-tooltip="Add package"]`,
clearPackageSelectButton: `vn-autocomplete[label="Package"] > div > div > div > vn-icon > i`, clearPackageSelectButton: `vn-autocomplete[label="Package"] > div > div > div > vn-icon > i`,
savePackagesButton: `${components.vnSubmit}` savePackagesButton: `${components.vnSubmit}`
}, },
@ -319,10 +321,17 @@ export default {
firstSaleDiscount: 'vn-ticket-sale:nth-child(1) vn-td:nth-child(8)', firstSaleDiscount: 'vn-ticket-sale:nth-child(1) vn-td:nth-child(8)',
firstSaleDiscountInput: 'vn-ticket-sale:nth-child(1) vn-ticket-sale-edit-discount > div > vn-textfield > div > div > div.infix > input.ng-not-empty', firstSaleDiscountInput: 'vn-ticket-sale:nth-child(1) vn-ticket-sale-edit-discount > div > vn-textfield > div > div > div.infix > input.ng-not-empty',
firstSaleImport: 'vn-ticket-sale:nth-child(1) vn-td:nth-child(9)', firstSaleImport: 'vn-ticket-sale:nth-child(1) vn-td:nth-child(9)',
totalImport: 'vn-ticket-sale vn-tfoot > vn-tr > vn-td:nth-child(9) > section > p:nth-child(3) > strong', firstSaleReservedIcon: 'vn-ticket-sale vn-tr:nth-child(1) > vn-td:nth-child(2) > vn-icon:nth-child(2)',
secondSaleText: `vn-table div > vn-tbody > vn-tr:nth-child(2)`, firstSaleColour: `vn-ticket-sale vn-tr:nth-child(1) vn-td:nth-child(5) section:nth-child(5)`,
selectAllSalesCheckbox: `vn-ticket-sale vn-thead vn-check label`, firstSaleLength: `vn-ticket-sale vn-tr:nth-child(1) vn-td:nth-child(5) section:nth-child(3)`,
firstSaleCheckbox: `vn-ticket-sale vn-tr:nth-child(1) vn-check[field="sale.checked"] label`, firstSaleCheckbox: `vn-ticket-sale vn-tr:nth-child(1) vn-check[field="sale.checked"] label`,
secondSaleColour: `vn-ticket-sale vn-tr:nth-child(2) vn-td:nth-child(5) section:nth-child(5)`,
secondSalePrice: `vn-ticket-sale vn-tr:nth-child(2) vn-td:nth-child(7)`,
secondSaleDiscount: `vn-ticket-sale vn-tr:nth-child(2) vn-td:nth-child(8)`,
secondSaleImport: `vn-ticket-sale vn-tr:nth-child(2) vn-td:nth-child(9)`,
secondSaleText: `vn-table div > vn-tbody > vn-tr:nth-child(2)`,
totalImport: 'vn-ticket-sale vn-tfoot > vn-tr > vn-td:nth-child(9) > section > p:nth-child(3) > strong',
selectAllSalesCheckbox: `vn-ticket-sale vn-thead vn-check label`,
secondSaleCheckbox: `vn-ticket-sale vn-tr:nth-child(2) vn-check[field="sale.checked"] label`, secondSaleCheckbox: `vn-ticket-sale vn-tr:nth-child(2) vn-check[field="sale.checked"] label`,
thirdSaleCheckbox: `vn-ticket-sale vn-tr:nth-child(3) vn-check[field="sale.checked"] label`, thirdSaleCheckbox: `vn-ticket-sale vn-tr:nth-child(3) vn-check[field="sale.checked"] label`,
deleteSaleButton: 'vn-ticket-sale vn-tool-bar > vn-button[icon="delete"]', deleteSaleButton: 'vn-ticket-sale vn-tool-bar > vn-button[icon="delete"]',
@ -331,7 +340,8 @@ export default {
moveToTicketInputClearButton: 'vn-popover.shown i[title="Clear"]', moveToTicketInputClearButton: 'vn-popover.shown i[title="Clear"]',
moveToTicketButton: 'vn-ticket-sale vn-popover.transfer vn-icon[icon="arrow_forward_ios"]', moveToTicketButton: 'vn-ticket-sale vn-popover.transfer vn-icon[icon="arrow_forward_ios"]',
moveToNewTicketButton: 'vn-ticket-sale vn-popover.transfer vn-button[label="New ticket"]', moveToNewTicketButton: 'vn-ticket-sale vn-popover.transfer vn-button[label="New ticket"]',
acceptDeleteButton: `vn-ticket-sale > vn-confirm[vn-id="delete-lines"] button[response=ACCEPT]`, acceptDeleteLineButton: `vn-ticket-sale > vn-confirm[vn-id="delete-lines"] button[response=ACCEPT]`,
acceptDeleteTicketButton: `vn-ticket-sale > vn-confirm[vn-id="deleteConfirmation"] button[response=ACCEPT]`,
stateMenuButton: 'vn-ticket-sale vn-tool-bar > vn-icon-menu[label="State"] button', stateMenuButton: 'vn-ticket-sale vn-tool-bar > vn-icon-menu[label="State"] button',
stateMenuOptions: 'vn-ticket-sale vn-drop-down > vn-popover ul > li:nth-child(1)', stateMenuOptions: 'vn-ticket-sale vn-drop-down > vn-popover ul > li:nth-child(1)',
moreMenuButton: 'vn-ticket-sale vn-tool-bar > vn-icon-menu[label="More"] button', moreMenuButton: 'vn-ticket-sale vn-tool-bar > vn-icon-menu[label="More"] button',
@ -340,7 +350,7 @@ export default {
moreMenuUnmarkResevedOption: 'vn-ticket-sale vn-drop-down > vn-popover ul > li:nth-child(4)', moreMenuUnmarkResevedOption: 'vn-ticket-sale vn-drop-down > vn-popover ul > li:nth-child(4)',
moreMenuUpdateDiscount: 'vn-ticket-sale vn-drop-down > vn-popover ul > li:nth-child(5)', moreMenuUpdateDiscount: 'vn-ticket-sale vn-drop-down > vn-popover ul > li:nth-child(5)',
moreMenuUpdateDiscountInput: 'vn-ticket-sale vn-dialog.shown vn-ticket-sale-edit-discount input', moreMenuUpdateDiscountInput: 'vn-ticket-sale vn-dialog.shown vn-ticket-sale-edit-discount input',
firstSaleReservedIcon: 'vn-ticket-sale vn-tr:nth-child(1) > vn-td:nth-child(2) > vn-icon:nth-child(2)' moreMenuCreateClaim: 'vn-ticket-sale vn-drop-down > vn-popover ul > li:nth-child(6)'
}, },
ticketTracking: { ticketTracking: {
trackingButton: `vn-left-menu a[ui-sref="ticket.card.tracking.index"]`, trackingButton: `vn-left-menu a[ui-sref="ticket.card.tracking.index"]`,

View File

@ -1,106 +1,104 @@
import selectors from '../../helpers/selectors.js'; import selectors from '../../helpers/selectors.js';
import createNightmare from '../../helpers/helpers.js'; import createNightmare from '../../helpers/helpers.js';
describe('Claim', () => { describe('Claim edit basic data path', () => {
describe('Edit basic data path', () => { const nightmare = createNightmare();
const nightmare = createNightmare();
beforeAll(() => { beforeAll(() => {
return nightmare return nightmare
.waitForLogin('developer'); .waitForLogin('salesAssistant');
});
it('should click on the Claims button of the top bar menu', () => {
return nightmare
.waitToClick(selectors.globalItems.applicationsMenuButton)
.wait(selectors.globalItems.applicationsMenuVisible)
.waitToClick(selectors.globalItems.claimsButton)
.wait(selectors.claimsIndex.searchClaimInput)
.parsedUrl()
.then(url => {
expect(url.hash).toEqual('#!/claim/index');
}); });
});
it('should click on the Claims button of the top bar menu', () => { it('should search for the claim with id 1', () => {
return nightmare return nightmare
.waitToClick(selectors.globalItems.applicationsMenuButton) .wait(selectors.claimsIndex.searchResult)
.wait(selectors.globalItems.applicationsMenuVisible) .type(selectors.claimsIndex.searchClaimInput, '1')
.waitToClick(selectors.globalItems.claimsButton) .click(selectors.claimsIndex.searchButton)
.wait(selectors.claimsIndex.searchClaimInput) .waitForNumberOfElements(selectors.claimsIndex.searchResult, 1)
.parsedUrl() .countElement(selectors.claimsIndex.searchResult)
.then(url => { .then(result => {
expect(url.hash).toEqual('#!/claim/index'); expect(result).toEqual(1);
});
}); });
});
it('should search for the claim with id 1', () => { it(`should click on the search result to access to the claim Basic Data`, () => {
return nightmare return nightmare
.wait(selectors.claimsIndex.searchResult) .waitToClick(selectors.claimsIndex.searchResult)
.type(selectors.claimsIndex.searchClaimInput, '1') .waitToClick(selectors.claimBasicData.basicDataButton)
.click(selectors.claimsIndex.searchButton) .waitForURL('basic-data')
.waitForNumberOfElements(selectors.claimsIndex.searchResult, 1) .url()
.countElement(selectors.claimsIndex.searchResult) .then(url => {
.then(result => { expect(url).toContain('basic-data');
expect(result).toEqual(1);
});
}); });
});
it(`should click on the search result to access to the ticket Basic Data`, () => { it(`should edit claim state, is paid with mana and observation fields`, () => {
return nightmare return nightmare
.waitToClick(selectors.claimsIndex.searchResult) .waitToClick(selectors.claimBasicData.claimStateSelect)
.waitToClick(selectors.claimBasicData.basicDataButton) .waitToClick(selectors.claimBasicData.claimStateSelectThirdOption)
.waitForURL('basic-data') .waitToClick(selectors.claimBasicData.isPaidWithManaCheckbox)
.url() .clearInput(selectors.claimBasicData.observationInput)
.then(url => { .type(selectors.claimBasicData.observationInput, 'edited observation')
expect(url).toContain('basic-data'); .click(selectors.claimBasicData.saveButton)
}); .waitForSnackbar()
.then(result => {
expect(result).toEqual(jasmine.arrayContaining(['Data saved!']));
}); });
});
it(`should edit claim state, is paid with mana and observation fields`, () => { it('should confirm the claim state was edited', () => {
return nightmare return nightmare
.waitToClick(selectors.claimBasicData.claimStateSelect) .click(selectors.claimDetails.detailsButton)
.waitToClick(selectors.claimBasicData.claimStateSelectThirdOption) .wait(selectors.claimDetails.addItemButton)
.waitToClick(selectors.claimBasicData.isPaidWithManaCheckbox) .click(selectors.claimBasicData.basicDataButton)
.clearInput(selectors.claimBasicData.observationInput) .wait(selectors.claimBasicData.claimStateSelect)
.type(selectors.claimBasicData.observationInput, 'edited observation') .getInputValue(selectors.claimBasicData.claimStateSelect)
.click(selectors.claimBasicData.saveButton) .then(result => {
.waitForSnackbar() expect(result).toEqual('Gestionado');
.then(result => {
expect(result).toEqual(jasmine.arrayContaining(['Data saved!']));
});
}); });
});
it('should confirm the claim state was edited', () => { it('should confirm the Is paid with mana checkbox is checked', () => {
return nightmare return nightmare
.click(selectors.claimDetails.detailsButton) .evaluate(selector => {
.wait(selectors.claimDetails.addItemButton) return document.querySelector(selector).checked;
.click(selectors.claimBasicData.basicDataButton) }, selectors.claimBasicData.isPaidWithManaCheckbox)
.wait(selectors.claimBasicData.claimStateSelect) .then(value => {
.getInputValue(selectors.claimBasicData.claimStateSelect) expect(value).toBeTruthy();
.then(result => {
expect(result).toEqual('Gestionado');
});
}); });
});
it('should confirm the Is paid with mana checkbox is checked', () => { it('should confirm the claim observation was edited', () => {
return nightmare return nightmare
.evaluate(selector => { .getInputValue(selectors.claimBasicData.observationInput)
return document.querySelector(selector).checked; .then(result => {
}, selectors.claimBasicData.isPaidWithManaCheckbox) expect(result).toEqual('edited observation');
.then(value => {
expect(value).toBeTruthy();
});
}); });
});
it('should confirm the claim observation was edited', () => { it(`should edit the claim to leave it untainted`, () => {
return nightmare return nightmare
.getInputValue(selectors.claimBasicData.observationInput) .waitToClick(selectors.claimBasicData.claimStateSelect)
.then(result => { .waitToClick(selectors.claimBasicData.claimStateSelectFourthOption)
expect(result).toEqual('edited observation'); .waitToClick(selectors.claimBasicData.isPaidWithManaCheckbox)
}); .clearInput(selectors.claimBasicData.observationInput)
}); .type(selectors.claimBasicData.observationInput, 'Observation one')
.click(selectors.claimBasicData.saveButton)
it(`should edit the claim to leave it untainted`, () => { .waitForSnackbar()
return nightmare .then(result => {
.waitToClick(selectors.claimBasicData.claimStateSelect) expect(result).toEqual(jasmine.arrayContaining(['Data saved!']));
.waitToClick(selectors.claimBasicData.claimStateSelectFourthOption)
.waitToClick(selectors.claimBasicData.isPaidWithManaCheckbox)
.clearInput(selectors.claimBasicData.observationInput)
.type(selectors.claimBasicData.observationInput, 'Observation one')
.click(selectors.claimBasicData.saveButton)
.waitForSnackbar()
.then(result => {
expect(result).toEqual(jasmine.arrayContaining(['Data saved!']));
});
}); });
}); });
}); });

View File

@ -49,7 +49,7 @@ describe('Item', () => {
.clearInput(selectors.itemBasicData.nameInput) .clearInput(selectors.itemBasicData.nameInput)
.type(selectors.itemBasicData.nameInput, 'Rose of Purity') .type(selectors.itemBasicData.nameInput, 'Rose of Purity')
.waitToClick(selectors.itemBasicData.typeSelect) .waitToClick(selectors.itemBasicData.typeSelect)
.waitToClick(selectors.itemBasicData.typeSelectOptionTwo) .waitToClick(selectors.itemBasicData.typeSelectOptionThree)
.waitToClick(selectors.itemBasicData.intrastatSelect) .waitToClick(selectors.itemBasicData.intrastatSelect)
.waitToClick(selectors.itemBasicData.intrastatSelectOptionOne) .waitToClick(selectors.itemBasicData.intrastatSelectOptionOne)
.clearInput(selectors.itemBasicData.relevancyInput) .clearInput(selectors.itemBasicData.relevancyInput)

View File

@ -20,7 +20,7 @@ describe('Item', () => {
}); });
}); });
it('should search for the item Gem of Time', () => { it('should search for the item Mjolnir', () => {
return nightmare return nightmare
.wait(selectors.itemsIndex.searchResult) .wait(selectors.itemsIndex.searchResult)
.type(selectors.itemsIndex.searchItemInput, 'Mjolnir') .type(selectors.itemsIndex.searchItemInput, 'Mjolnir')

View File

@ -65,7 +65,7 @@ describe('Item', () => {
return nightmare return nightmare
.type(selectors.itemCreateView.name, 'Infinity Gauntlet') .type(selectors.itemCreateView.name, 'Infinity Gauntlet')
.waitToClick(selectors.itemCreateView.typeSelect) .waitToClick(selectors.itemCreateView.typeSelect)
.waitToClick(selectors.itemCreateView.typeSelectOptionOne) .waitToClick(selectors.itemCreateView.typeSelectOptionThree)
.waitToClick(selectors.itemCreateView.intrastatSelect) .waitToClick(selectors.itemCreateView.intrastatSelect)
.waitToClick(selectors.itemCreateView.intrastatSelectOptionOne) .waitToClick(selectors.itemCreateView.intrastatSelectOptionOne)
.waitToClick(selectors.itemCreateView.originSelect) .waitToClick(selectors.itemCreateView.originSelect)

View File

@ -1,74 +1,128 @@
import selectors from '../../helpers/selectors.js'; import selectors from '../../helpers/selectors.js';
import createNightmare from '../../helpers/helpers'; import createNightmare from '../../helpers/helpers';
describe('Ticket', () => { describe('Ticket List sale path', () => {
describe('List sale path', () => { const nightmare = createNightmare();
const nightmare = createNightmare();
beforeAll(() => { beforeAll(() => {
return nightmare return nightmare
.waitForLogin('developer'); .waitForLogin('developer');
});
it('should click on the Tickets button of the top bar menu', () => {
return nightmare
.waitToClick(selectors.globalItems.applicationsMenuButton)
.wait(selectors.globalItems.applicationsMenuVisible)
.waitToClick(selectors.globalItems.ticketsButton)
.wait(selectors.ticketsIndex.createTicketButton)
.parsedUrl()
.then(url => {
expect(url.hash).toEqual('#!/ticket/index');
}); });
});
it('should click on the Tickets button of the top bar menu', () => { it('should search for the ticket 1', () => {
return nightmare return nightmare
.waitToClick(selectors.globalItems.applicationsMenuButton) .wait(selectors.ticketsIndex.searchResult)
.wait(selectors.globalItems.applicationsMenuVisible) .type(selectors.ticketsIndex.searchTicketInput, 'id:1')
.waitToClick(selectors.globalItems.ticketsButton) .click(selectors.ticketsIndex.searchButton)
.wait(selectors.ticketsIndex.createTicketButton) .waitForNumberOfElements(selectors.ticketsIndex.searchResult, 1)
.parsedUrl() .countElement(selectors.ticketsIndex.searchResult)
.then(url => { .then(result => {
expect(url.hash).toEqual('#!/ticket/index'); expect(result).toEqual(1);
});
}); });
});
it('should search for the ticket 1', () => { it(`should click on the search result to access to the ticket's sale`, () => {
return nightmare return nightmare
.wait(selectors.ticketsIndex.searchResult) .waitForTextInElement(selectors.ticketsIndex.searchResult, 'address 21')
.type(selectors.ticketsIndex.searchTicketInput, 'id:1') .waitToClick(selectors.ticketsIndex.searchResult)
.click(selectors.ticketsIndex.searchButton) .waitToClick(selectors.ticketSales.saleButton)
.waitForNumberOfElements(selectors.ticketsIndex.searchResult, 1) .waitForURL('sale')
.countElement(selectors.ticketsIndex.searchResult) .url()
.then(result => { .then(url => {
expect(result).toEqual(1); expect(url).toContain('sale');
});
}); });
});
it(`should click on the search result to access to the ticket's sale`, () => { it('should confirm the first ticket sale contains the colour', () => {
return nightmare return nightmare
.waitForTextInElement(selectors.ticketsIndex.searchResult, 'address 21') .wait(selectors.ticketSales.firstSaleText)
.waitToClick(selectors.ticketsIndex.searchResult) .getInnerText(selectors.ticketSales.firstSaleColour)
.waitToClick(selectors.ticketSales.saleButton) .then(value => {
.waitForURL('sale') expect(value).toContain('Yellow');
.url()
.then(url => {
expect(url).toContain('sale');
});
}); });
});
it('should confirm the first ticket sale is the expected one', () => { it('should confirm the first ticket sale contains the lenght', () => {
return nightmare return nightmare
.wait(selectors.ticketSales.firstSaleText) .wait(selectors.ticketSales.firstSaleText)
.getInnerText(selectors.ticketSales.firstSaleText) .getInnerText(selectors.ticketSales.firstSaleText)
.then(value => { .then(value => {
expect(value).toContain('Yellow'); expect(value).toContain('5');
expect(value).toContain('5');
expect(value).toContain('€9.60');
expect(value).toContain('0 %');
expect(value).toContain('€48.00');
});
}); });
});
it('should confirm the second ticket sale is the expected one', () => { it('should confirm the first ticket sale contains the price', () => {
return nightmare return nightmare
.wait(selectors.ticketSales.secondSaleText) .wait(selectors.ticketSales.firstSaleText)
.getInnerText(selectors.ticketSales.secondSaleText) .getInnerText(selectors.ticketSales.firstSalePrice)
.then(value => { .then(value => {
expect(value).toContain('Red'); expect(value).toContain('€11.42');
expect(value).toContain('€4.21'); });
expect(value).toContain('0 %'); });
expect(value).toContain('€42.10');
}); it('should confirm the first ticket sale contains the discount', () => {
return nightmare
.wait(selectors.ticketSales.firstSaleText)
.getInnerText(selectors.ticketSales.firstSaleDiscount)
.then(value => {
expect(value).toContain('0 %');
});
});
it('should confirm the first ticket sale contains the total import', () => {
return nightmare
.wait(selectors.ticketSales.firstSaleText)
.getInnerText(selectors.ticketSales.firstSaleImport)
.then(value => {
expect(value).toContain('57.10');
});
});
it('should confirm the second ticket sale contains the colour', () => {
return nightmare
.wait(selectors.ticketSales.secondSaleText)
.getInnerText(selectors.ticketSales.secondSaleColour)
.then(value => {
expect(value).toContain('Red');
});
});
it('should confirm the second ticket sale contains the price', () => {
return nightmare
.wait(selectors.ticketSales.secondSaleText)
.getInnerText(selectors.ticketSales.secondSalePrice)
.then(value => {
expect(value).toContain('€1.30');
});
});
it('should confirm the second ticket sale contains the discount', () => {
return nightmare
.wait(selectors.ticketSales.secondSaleText)
.getInnerText(selectors.ticketSales.secondSaleDiscount)
.then(value => {
expect(value).toContain('0 %');
});
});
it('should confirm the second ticket sale contains the total import', () => {
return nightmare
.wait(selectors.ticketSales.secondSaleText)
.getInnerText(selectors.ticketSales.secondSaleImport)
.then(value => {
expect(value).toContain('13.00');
}); });
}); });
}); });

View File

@ -1,8 +1,7 @@
import selectors from '../../helpers/selectors.js'; import selectors from '../../helpers/selectors.js';
import createNightmare from '../../helpers/helpers'; import createNightmare from '../../helpers/helpers';
// #640 Ticket Create packages path is excluded describe('Ticket Create packages path', () => {
xdescribe('Ticket Create packages path', () => {
const nightmare = createNightmare(); const nightmare = createNightmare();
beforeAll(() => { beforeAll(() => {
@ -36,7 +35,7 @@ xdescribe('Ticket Create packages path', () => {
it(`should click on the search result to access to the ticket packages`, () => { it(`should click on the search result to access to the ticket packages`, () => {
return nightmare return nightmare
.waitForTextInElement(selectors.ticketsIndex.searchResult, 'Batman') .waitForTextInElement(selectors.ticketsIndex.searchResultAddress, 'address 21')
.waitToClick(selectors.ticketsIndex.searchResult) .waitToClick(selectors.ticketsIndex.searchResult)
.waitToClick(selectors.ticketPackages.packagesButton) .waitToClick(selectors.ticketPackages.packagesButton)
.waitForURL('package/index') .waitForURL('package/index')
@ -51,11 +50,11 @@ xdescribe('Ticket Create packages path', () => {
.waitToClick(selectors.ticketPackages.firstRemovePackageButton) .waitToClick(selectors.ticketPackages.firstRemovePackageButton)
.waitToClick(selectors.ticketPackages.addPackageButton) .waitToClick(selectors.ticketPackages.addPackageButton)
.waitToClick(selectors.ticketPackages.firstPackageSelect) .waitToClick(selectors.ticketPackages.firstPackageSelect)
.waitToClick(selectors.ticketPackages.firstPackageSelectOptionThree) .waitToClick(selectors.ticketPackages.firstPackageSelectOptionTwo)
.click(selectors.ticketPackages.savePackagesButton) .click(selectors.ticketPackages.savePackagesButton)
.waitForSnackbar() .waitForLastSnackbar()
.then(result => { .then(result => {
expect(result).toEqual(jasmine.arrayContaining(['Some fields are invalid'])); expect(result).toEqual('Some fields are invalid');
}); });
}); });
@ -63,44 +62,44 @@ xdescribe('Ticket Create packages path', () => {
return nightmare return nightmare
.type(selectors.ticketPackages.firstQuantityInput, 'ninety 9') .type(selectors.ticketPackages.firstQuantityInput, 'ninety 9')
.click(selectors.ticketPackages.savePackagesButton) .click(selectors.ticketPackages.savePackagesButton)
.waitForSnackbar() .waitForLastSnackbar()
.then(result => { .then(result => {
expect(result).toEqual(jasmine.arrayContaining(['Some fields are invalid'])); expect(result).toEqual('Some fields are invalid');
}); });
}); });
it(`should attempt create a new package but receive an error if quantity is 0`, () => { it(`should attempt create a new package but receive an error if quantity is 0`, () => {
return nightmare return nightmare
.clearInput(selectors.ticketPackages.firstQuantityInput) .clearInput(selectors.ticketPackages.firstQuantityInput)
.type(selectors.ticketPackages.firstQuantityInput, '0') .type(selectors.ticketPackages.firstQuantityInput, 0)
.click(selectors.ticketPackages.savePackagesButton) .click(selectors.ticketPackages.savePackagesButton)
.waitForSnackbar() .waitForLastSnackbar()
.then(result => { .then(result => {
expect(result).toEqual(jasmine.arrayContaining(['Some fields are invalid'])); expect(result).toEqual('Some fields are invalid');
}); });
}); });
it(`should attempt create a new package but receive an error if package is blank`, () => { it(`should attempt create a new package but receive an error if package is blank`, () => {
return nightmare return nightmare
.clearInput(selectors.ticketPackages.firstQuantityInput) .clearInput(selectors.ticketPackages.firstQuantityInput)
.type(selectors.ticketPackages.firstQuantityInput, '99') .type(selectors.ticketPackages.firstQuantityInput, 99)
.click(selectors.ticketPackages.clearPackageSelectButton) .click(selectors.ticketPackages.clearPackageSelectButton)
.click(selectors.ticketPackages.savePackagesButton) .click(selectors.ticketPackages.savePackagesButton)
.waitForSnackbar() .waitForLastSnackbar()
.then(result => { .then(result => {
expect(result).toEqual(jasmine.arrayContaining(['Package cannot be blank'])); expect(result).toEqual('The package cannot be blank');
}); });
}); });
it(`should create a new package with correct data`, () => { it(`should create a new package with correct data`, () => {
return nightmare return nightmare
.waitToClick(selectors.ticketPackages.firstPackageSelect) .waitToClick(selectors.ticketPackages.firstPackageSelect)
.waitToClick(selectors.ticketPackages.firstPackageSelectOptionThree) .waitToClick(selectors.ticketPackages.firstPackageSelectOptionTwo)
.waitForTextInInput(selectors.ticketPackages.firstPackageSelect, 'Iron Patriot') .waitForTextInInput(selectors.ticketPackages.firstPackageSelect, 'Legendary Box')
.click(selectors.ticketPackages.savePackagesButton) .click(selectors.ticketPackages.savePackagesButton)
.waitForSnackbar() .waitForLastSnackbar()
.then(result => { .then(result => {
expect(result).toEqual(jasmine.arrayContaining(['Data saved!'])); expect(result).toEqual('Data saved!');
}); });
}); });
@ -109,10 +108,10 @@ xdescribe('Ticket Create packages path', () => {
.click(selectors.ticketSales.saleButton) .click(selectors.ticketSales.saleButton)
.wait(selectors.ticketSales.firstPackageSelect) .wait(selectors.ticketSales.firstPackageSelect)
.click(selectors.ticketPackages.packagesButton) .click(selectors.ticketPackages.packagesButton)
.waitForTextInInput(selectors.ticketPackages.firstPackageSelect, 'Iron Patriot') .waitForTextInInput(selectors.ticketPackages.firstPackageSelect, 'Legendary Box')
.getInputValue(selectors.ticketPackages.firstPackageSelect) .getInputValue(selectors.ticketPackages.firstPackageSelect)
.then(result => { .then(result => {
expect(result).toEqual('Iron Patriot'); expect(result).toEqual('Legendary Box');
}); });
}); });

View File

@ -120,7 +120,7 @@ describe('Ticket', () => {
return nightmare return nightmare
.getInnerText(selectors.ticketBasicData.stepTwoTotalPriceDif) .getInnerText(selectors.ticketBasicData.stepTwoTotalPriceDif)
.then(result => { .then(result => {
expect(result).toContain('-€206.60'); expect(result).toContain('-€20.65');
}); });
}); });

View File

@ -0,0 +1,772 @@
import selectors from '../../helpers/selectors.js';
import createNightmare from '../../helpers/helpers';
describe('Ticket Edit sale path', () => {
const nightmare = createNightmare();
beforeAll(() => {
return nightmare
.waitForLogin('salesPerson');
});
it('should click on the Tickets button of the top bar menu', () => {
return nightmare
.waitToClick(selectors.globalItems.applicationsMenuButton)
.wait(selectors.globalItems.applicationsMenuVisible)
.waitToClick(selectors.globalItems.ticketsButton)
.wait(selectors.ticketsIndex.createTicketButton)
.parsedUrl()
.then(url => {
expect(url.hash).toEqual('#!/ticket/index');
});
});
it('should search for a specific ticket', () => {
return nightmare
.wait(selectors.ticketsIndex.searchResult)
.type(selectors.ticketsIndex.searchTicketInput, 'id:16')
.click(selectors.ticketsIndex.searchButton)
.waitForNumberOfElements(selectors.ticketsIndex.searchResult, 1)
.countElement(selectors.ticketsIndex.searchResult)
.then(result => {
expect(result).toEqual(1);
});
});
it(`should click on the search result to access to the ticket Sale`, () => {
return nightmare
.waitForTextInElement(selectors.ticketsIndex.searchResult, 'address 21')
.waitToClick(selectors.ticketsIndex.searchResult)
.waitToClick(selectors.ticketSales.saleButton)
.waitForURL('/sale')
.url()
.then(url => {
expect(url).toContain('/sale');
});
});
describe('Before tests begings', () => {
it(`should check the quantity in the 1st line which we will be using in the further tests`, () => {
return nightmare
.wait(selectors.ticketSales.firstSaleText)
.getInputValue(selectors.ticketSales.firstSaleQuantity)
.then(value => {
expect(value).toEqual('5');
});
});
it(`should check the Price in the 1st line which we will be using in the further tests`, () => {
return nightmare
.wait(selectors.ticketSales.firstSaleText)
.getInnerText(selectors.ticketSales.firstSalePrice)
.then(value => {
expect(value).toEqual('€11.42');
});
});
it(`should check the Discount in the 1st line which we will be using in the further tests`, () => {
return nightmare
.wait(selectors.ticketSales.firstSaleText)
.getInnerText(selectors.ticketSales.firstSaleDiscount)
.then(value => {
expect(value).toEqual('0 %');
});
});
it(`should check the Import in the 1st line which we will be using in the further tests`, () => {
return nightmare
.wait(selectors.ticketSales.firstSaleText)
.getInnerText(selectors.ticketSales.firstSaleImport)
.then(value => {
expect(value).toEqual('€57.10');
});
});
it(`should count the ticket lines to verify there are 4 for further testing`, () => {
return nightmare
.countElement(selectors.ticketSales.saleLine)
.then(result => {
expect(result).toEqual(4);
});
});
});
it(`should check the zoomed image isnt present`, () => {
return nightmare
.countElement(selectors.ticketSales.firstSaleZoomedImage)
.then(result => {
expect(result).toEqual(0);
});
});
it(`should click on the thumbnail image of the 1st sale and see the zoomed image`, () => {
return nightmare
.waitToClick(selectors.ticketSales.firstSaleThumbnailImage)
.countElement(selectors.ticketSales.firstSaleZoomedImage)
.then(result => {
expect(result).toEqual(1);
});
});
it(`should click on the zoomed image to close it`, () => {
return nightmare
.waitToClick(selectors.ticketSales.firstSaleZoomedImage)
.countElement(selectors.ticketSales.firstSaleZoomedImage)
.then(result => {
expect(result).toEqual(0);
});
});
it(`should confirm the item descriptor insnt visible yet`, () => {
return nightmare
.isVisible(selectors.ticketSales.saleDescriptorPopover)
.then(result => {
expect(result).toBeFalsy();
});
});
it(`should click on the first sale ID making the item descriptor visible`, () => {
return nightmare
.waitToClick(selectors.ticketSales.firstSaleID)
.isVisible(selectors.ticketSales.saleDescriptorPopover)
.then(result => {
expect(result).toBeTruthy();
});
});
it(`should click on the descriptor image of the 1st sale and see the zoomed image`, () => {
return nightmare
.waitToClick('vn-item-descriptor img')
.countElement(selectors.ticketSales.firstSaleZoomedImage)
.then(result => {
expect(result).toEqual(1);
});
});
it(`should click on the zoomed image to close it`, () => {
return nightmare
.waitToClick(selectors.ticketSales.firstSaleZoomedImage)
.countElement(selectors.ticketSales.firstSaleZoomedImage)
.then(result => {
expect(result).toEqual(0);
});
});
it(`should click on the summary icon of the item-descriptor to access to the item summary`, () => {
return nightmare
.waitToClick(selectors.ticketSales.saleDescriptorPopoverSummaryButton)
.waitForURL('/summary')
.url()
.then(url => {
expect(url).toContain('/summary');
});
});
it('should return to ticket sales section', () => {
return nightmare
.waitToClick(selectors.globalItems.applicationsMenuButton)
.wait(selectors.globalItems.applicationsMenuVisible)
.waitToClick(selectors.globalItems.ticketsButton)
.wait(selectors.ticketsIndex.createTicketButton)
.wait(selectors.ticketsIndex.searchResult)
.type(selectors.ticketsIndex.searchTicketInput, 'id:16')
.click(selectors.ticketsIndex.searchButton)
.waitForNumberOfElements(selectors.ticketsIndex.searchResult, 1)
.waitForTextInElement(selectors.ticketsIndex.searchResult, 'address 21')
.waitToClick(selectors.ticketsIndex.searchResult)
.waitToClick(selectors.ticketSales.saleButton)
.waitForURL('/sale')
.url()
.then(url => {
expect(url).toContain('/sale');
});
});
it('should try to add a higher quantity value and then receive an error', () => {
return nightmare
.waitToClick(selectors.ticketSales.firstSaleQuantityClearInput)
.type(selectors.ticketSales.firstSaleQuantity, '9\u000d')
.waitForLastSnackbar()
.then(result => {
expect(result).toEqual('The new quantity should be smaller than the old one');
});
});
it('should remove 1 from quantity', () => {
return nightmare
.waitToClick(selectors.ticketSales.firstSaleQuantityClearInput)
.type(selectors.ticketSales.firstSaleQuantity, '4\u000d')
.waitForLastSnackbar()
.then(result => {
expect(result).toEqual('Data saved!');
});
});
it('should update the price', () => {
return nightmare
.waitToClick(selectors.ticketSales.firstSalePrice)
.wait(selectors.ticketSales.firstSalePriceInput)
.type(selectors.ticketSales.firstSalePriceInput, 5)
.type('body', '\u000d') // simulates enter
.waitForLastSnackbar()
.then(result => {
expect(result).toEqual('Data saved!');
});
});
it('should confirm the price have been updated', () => {
return nightmare
.getInnerText(selectors.ticketSales.firstSalePrice)
.then(result => {
expect(result).toContain('€5.00');
});
});
it('should confirm the total price for that item have been updated', () => {
return nightmare
.getInnerText(selectors.ticketSales.firstSaleImport)
.then(result => {
expect(result).toContain('€20.00');
});
});
it('should update the discount', () => {
return nightmare
.waitToClick(selectors.ticketSales.firstSaleDiscount)
.wait('vn-textfield[label="Discount"] > div[class="container selected"]') // a function selects the text after it's loaded
.type(selectors.ticketSales.firstSaleDiscountInput, 50)
.type('body', '\u000d') // simulates enter
.waitForLastSnackbar()
.then(result => {
expect(result).toEqual('Data saved!');
});
});
it('should confirm the discount have been updated', () => {
return nightmare
.waitForTextInElement(selectors.ticketSales.firstSaleDiscount, '50 %')
.getInnerText(selectors.ticketSales.firstSaleDiscount)
.then(result => {
expect(result).toContain('50 %');
});
});
it('should confirm the total import for that item have been updated', () => {
return nightmare
.waitForTextInElement(selectors.ticketSales.firstSaleImport, '€10.00')
.getInnerText(selectors.ticketSales.firstSaleImport)
.then(result => {
expect(result).toContain('€10.00');
});
});
it('should select the third sale and create a claim of it', () => {
return nightmare
.waitToClick(selectors.ticketSales.firstSaleCheckbox)
.waitToClick(selectors.ticketSales.moreMenuButton)
.waitToClick(selectors.ticketSales.moreMenuCreateClaim)
.waitForLogin('Developer')
.waitToClick(selectors.globalItems.applicationsMenuButton)
.wait(selectors.globalItems.applicationsMenuVisible)
.waitToClick(selectors.globalItems.claimsButton)
.wait(selectors.claimsIndex.searchResult)
.parsedUrl()
.then(url => {
expect(url.hash).toEqual('#!/claim/index');
});
});
it('should click on the Claims button of the top bar menu', () => {
return nightmare
.waitToClick(selectors.globalItems.applicationsMenuButton)
.wait(selectors.globalItems.applicationsMenuVisible)
.waitToClick(selectors.globalItems.claimsButton)
.wait(selectors.claimsIndex.searchClaimInput)
.parsedUrl()
.then(url => {
expect(url.hash).toEqual('#!/claim/index');
});
});
it('should search for the claim with id 4', () => {
return nightmare
.wait(selectors.claimsIndex.searchResult)
.type(selectors.claimsIndex.searchClaimInput, 4)
.click(selectors.claimsIndex.searchButton)
.waitForNumberOfElements(selectors.claimsIndex.searchResult, 1)
.countElement(selectors.claimsIndex.searchResult)
.then(result => {
expect(result).toEqual(1);
});
});
it('should click the Tickets button of the top bar menu', () => {
return nightmare
.waitToClick(selectors.globalItems.applicationsMenuButton)
.wait(selectors.globalItems.applicationsMenuVisible)
.waitToClick(selectors.globalItems.ticketsButton)
.wait(selectors.ticketsIndex.createTicketButton)
.parsedUrl()
.then(url => {
expect(url.hash).toEqual('#!/ticket/index');
});
});
it('should search the ticket', () => {
return nightmare
.wait(selectors.ticketsIndex.searchResult)
.type(selectors.ticketsIndex.searchTicketInput, 'id:16')
.click(selectors.ticketsIndex.searchButton)
.waitForNumberOfElements(selectors.ticketsIndex.searchResult, 1)
.countElement(selectors.ticketsIndex.searchResult)
.then(result => {
expect(result).toEqual(1);
});
});
it(`should click on the result to access to the ticket Sale`, () => {
return nightmare
.waitForTextInElement(selectors.ticketsIndex.searchResult, 'address 21')
.waitToClick(selectors.ticketsIndex.searchResult)
.waitToClick(selectors.ticketSales.saleButton)
.waitForURL('/sale')
.url()
.then(url => {
expect(url).toContain('/sale');
});
});
it('should select the third sale and delete it', () => {
return nightmare
.waitToClick(selectors.ticketSales.thirdSaleCheckbox)
.waitToClick(selectors.ticketSales.deleteSaleButton)
.waitToClick(selectors.ticketSales.acceptDeleteLineButton)
.waitForLastSnackbar()
.then(result => {
expect(result).toEqual('Data saved!');
});
});
it(`should confirm the third sale was deleted`, () => {
return nightmare
.countElement(selectors.ticketSales.saleLine)
.then(result => {
expect(result).toEqual(3);
});
});
it('should select the third sale and attempt to send it to a frozen client ticket', () => {
return nightmare
.waitToClick(selectors.ticketSales.thirdSaleCheckbox)
.waitToClick(selectors.ticketSales.transferSaleButton)
.wait(selectors.ticketSales.moveToTicketInput)
.type(selectors.ticketSales.moveToTicketInput, 2)
.waitToClick(selectors.ticketSales.moveToTicketButton)
.waitForLastSnackbar()
.then(result => {
expect(result).toEqual(`The sales of that ticket can't be modified`);
});
});
it('should transfer the sale to a valid ticket', () => {
return nightmare
.waitToClick(selectors.ticketSales.moveToTicketInputClearButton)
.type(selectors.ticketSales.moveToTicketInput, 12)
.waitToClick(selectors.ticketSales.moveToTicketButton)
.waitForURL('ticket/12/sale')
.url()
.then(result => {
expect(result).toContain(`ticket/12/sale`);
});
});
it('should confirm the transfered line is the correct one', () => {
return nightmare
.wait(selectors.ticketSales.firstSaleText)
.getInnerText(selectors.ticketSales.firstSaleText)
.then(result => {
expect(result).toContain(`Mark I`);
});
});
it('should go back to the original ticket sales section', () => {
return nightmare
.waitToClick(selectors.itemsIndex.goBackToModuleIndexButton)
.wait(selectors.ticketsIndex.searchResult)
.type(selectors.ticketsIndex.searchTicketInput, 'id:16')
.click(selectors.ticketsIndex.searchButton)
.waitForNumberOfElements(selectors.ticketsIndex.searchResult, 1)
.waitForTextInElement(selectors.ticketsIndex.searchResult, 'address 21')
.waitToClick(selectors.ticketsIndex.searchResult)
.waitToClick(selectors.ticketSales.saleButton)
.waitForURL('/sale')
.url()
.then(url => {
expect(url).toContain('/sale');
});
});
it(`should confirm the original ticket has only two lines now`, () => {
return nightmare
.wait(selectors.ticketSales.saleLine)
.countElement(selectors.ticketSales.saleLine)
.then(result => {
expect(result).toEqual(2);
});
});
it('should go back to the receiver ticket sales section', () => {
return nightmare
.waitToClick(selectors.itemsIndex.goBackToModuleIndexButton)
.wait(selectors.ticketsIndex.searchResult)
.type(selectors.ticketsIndex.searchTicketInput, 'id:12')
.click(selectors.ticketsIndex.searchButton)
.waitForNumberOfElements(selectors.ticketsIndex.searchResult, 1)
.waitForTextInElement(selectors.ticketsIndex.searchResult, 'address 21')
.waitToClick(selectors.ticketsIndex.searchResult)
.waitToClick(selectors.ticketSales.saleButton)
.waitForURL('/sale')
.url()
.then(url => {
expect(url).toContain('/sale');
});
});
it('should transfer the sale back to the original ticket', () => {
return nightmare
.waitToClick(selectors.ticketSales.firstSaleCheckbox)
.waitToClick(selectors.ticketSales.transferSaleButton)
.wait(selectors.ticketSales.moveToTicketInput)
.type(selectors.ticketSales.moveToTicketInput, 16)
.waitToClick(selectors.ticketSales.moveToTicketButton)
.waitForURL('ticket/16/sale')
.url()
.then(result => {
expect(result).toContain(`ticket/16/sale`);
});
});
it('should confirm the original ticket received the line', () => {
return nightmare
.wait(selectors.ticketSales.saleLine)
.countElement(selectors.ticketSales.saleLine)
.then(result => {
expect(result).toEqual(3);
});
});
it('should select the second and third sale and tranfer them to a new ticket then get to the ticket index', () => {
return nightmare
.waitToClick(selectors.ticketSales.secondSaleCheckbox)
.waitToClick(selectors.ticketSales.thirdSaleCheckbox)
.waitToClick(selectors.ticketSales.transferSaleButton)
.waitToClick(selectors.ticketSales.moveToNewTicketButton)
.waitForLogin('salesPerson')
.waitToClick(selectors.globalItems.applicationsMenuButton)
.wait(selectors.globalItems.applicationsMenuVisible)
.waitToClick(selectors.globalItems.ticketsButton)
.wait(selectors.ticketsIndex.createTicketButton)
.parsedUrl()
.then(url => {
expect(url.hash).toEqual('#!/ticket/index');
});
});
it('should search for a specific created ticket', () => {
return nightmare
.wait(selectors.ticketsIndex.searchResult)
.type(selectors.ticketsIndex.searchTicketInput, 'id:22')
.click(selectors.ticketsIndex.searchButton)
.waitForNumberOfElements(selectors.ticketsIndex.searchResult, 1)
.countElement(selectors.ticketsIndex.searchResult)
.then(result => {
expect(result).toEqual(1);
});
});
it(`should click on the search result to access to the ticket Sale`, () => {
return nightmare
.waitForTextInElement(selectors.ticketsIndex.searchResult, 'address 21')
.waitToClick(selectors.ticketsIndex.searchResult)
.waitToClick(selectors.ticketSales.saleButton)
.waitForURL('/sale')
.url()
.then(url => {
expect(url).toContain('/sale');
});
});
it('should confirm the new ticket received both lines', () => {
return nightmare
.countElement(selectors.ticketSales.saleLine)
.then(result => {
expect(result).toEqual(2);
});
});
it('should check the first sale reserved icon isnt visible', () => {
return nightmare
.isVisible(selectors.ticketSales.firstSaleReservedIcon)
.then(result => {
expect(result).toBeFalsy();
});
});
it('should mark the first sale as reserved', () => {
return nightmare
.waitToClick(selectors.ticketSales.firstSaleCheckbox)
.waitToClick(selectors.ticketSales.moreMenuButton)
.waitToClick(selectors.ticketSales.moreMenuReseveOption)
.waitForClassNotPresent(selectors.ticketSales.firstSaleReservedIcon, 'ng-hide')
.isVisible(selectors.ticketSales.firstSaleReservedIcon)
.then(result => {
expect(result).toBeTruthy();
});
});
it('should unmark the first sale as reserved', () => {
return nightmare
.waitToClick(selectors.ticketSales.firstSaleCheckbox)
.waitToClick(selectors.ticketSales.moreMenuButton)
.waitToClick(selectors.ticketSales.moreMenuUnmarkResevedOption)
.waitForClassPresent(selectors.ticketSales.firstSaleReservedIcon, 'ng-hide')
.isVisible(selectors.ticketSales.firstSaleReservedIcon)
.then(result => {
expect(result).toBeFalsy();
});
});
it('should update all sales discount', () => {
return nightmare
.waitToClick(selectors.ticketSales.selectAllSalesCheckbox)
.waitToClick(selectors.ticketSales.moreMenuButton)
.waitToClick(selectors.ticketSales.moreMenuUpdateDiscount)
.wait(selectors.ticketSales.moreMenuUpdateDiscountInput)
.type(selectors.ticketSales.moreMenuUpdateDiscountInput, 100)
.type('body', '\u000d') // simulates enter
.waitForTextInElement(selectors.ticketSales.totalImport, '€0.00')
.getInnerText(selectors.ticketSales.totalImport)
.then(result => {
expect(result).toEqual('€0.00');
});
});
it('should log in as Production role and go to the ticket index', () => {
return nightmare
.waitToClick(selectors.globalItems.logOutButton)
.waitForLogin('production')
.waitToClick(selectors.globalItems.applicationsMenuButton)
.wait(selectors.globalItems.applicationsMenuVisible)
.waitToClick(selectors.globalItems.ticketsButton)
.wait(selectors.ticketsIndex.createTicketButton)
.parsedUrl()
.then(url => {
expect(url.hash).toEqual('#!/ticket/index');
});
});
it('should now search for a specific ticket', () => {
return nightmare
.wait(selectors.ticketsIndex.searchResult)
.type(selectors.ticketsIndex.searchTicketInput, 'id:16')
.click(selectors.ticketsIndex.searchButton)
.waitForNumberOfElements(selectors.ticketsIndex.searchResult, 1)
.countElement(selectors.ticketsIndex.searchResult)
.then(result => {
expect(result).toEqual(1);
});
});
it(`should now click on the search result to access to the ticket Tracking`, () => {
return nightmare
.waitForTextInElement(selectors.ticketsIndex.searchResult, 'address 21')
.waitToClick(selectors.ticketsIndex.searchResult)
.waitToClick(selectors.ticketTracking.trackingButton)
.waitForURL('/tracking/index')
.url()
.then(url => {
expect(url).toContain('/tracking/index');
});
});
it(`should click on the edit ticket tracking state button`, () => {
return nightmare
.waitToClick(selectors.ticketTracking.createStateButton)
.waitForURL('/tracking/edit')
.url()
.then(url => {
expect(url).toContain('/tracking/edit');
});
});
it(`should set the state of the ticket to preparation`, () => {
return nightmare
.waitToClick(selectors.ticketTracking.stateSelect)
.wait(selectors.ticketTracking.stateSelectInput)
.type(selectors.ticketTracking.stateSelectInput, 'Preparación')
.waitToClick(selectors.ticketTracking.stateSelectFirstResult)
.waitForTextInInput(selectors.ticketTracking.stateSelectInput, 'Preparación')
.click(selectors.ticketTracking.saveButton)
.waitForURL('/tracking/index')
.url()
.then(url => {
expect(url).toContain('/tracking/index');
});
});
it(`should click on the ticket Sale menu button`, () => {
return nightmare
.waitToClick(selectors.ticketSales.saleButton)
.waitForURL('/sale')
.url()
.then(url => {
expect(url).toContain('/sale');
});
});
describe('when state is preparation and loged as Production', () => {
it(`should not be able to edit the sale price`, () => {
return nightmare
.waitToClick(selectors.ticketSales.firstSalePrice)
.exists(selectors.ticketSales.firstSalePriceInput)
.then(result => {
expect(result).toBeFalsy();
});
});
it(`should not be able to edit the sale discount`, () => {
return nightmare
.waitToClick(selectors.ticketSales.firstSaleDiscount)
.exists(selectors.ticketSales.firstSaleDiscountInput)
.then(result => {
expect(result).toBeFalsy();
});
});
it(`should not be able to edit the sale state`, () => {
return nightmare
.waitToClick(selectors.ticketSales.stateMenuButton)
.exists(selectors.ticketSales.stateMenuOptions)
.then(result => {
expect(result).toBeFalsy();
});
});
it('should log in as salesPerson role and go to the ticket index', () => {
return nightmare
.waitToClick(selectors.globalItems.logOutButton)
.waitForLogin('salesPerson')
.waitToClick(selectors.globalItems.applicationsMenuButton)
.wait(selectors.globalItems.applicationsMenuVisible)
.waitToClick(selectors.globalItems.ticketsButton)
.wait(selectors.ticketsIndex.createTicketButton)
.parsedUrl()
.then(url => {
expect(url.hash).toEqual('#!/ticket/index');
});
});
it('should again search for a specific ticket', () => {
return nightmare
.wait(selectors.ticketsIndex.searchResult)
.type(selectors.ticketsIndex.searchTicketInput, 'id:16')
.click(selectors.ticketsIndex.searchButton)
.waitForNumberOfElements(selectors.ticketsIndex.searchResult, 1)
.countElement(selectors.ticketsIndex.searchResult)
.then(result => {
expect(result).toEqual(1);
});
});
it(`should again click on the search result to access to the ticket Sales`, () => {
return nightmare
.waitForTextInElement(selectors.ticketsIndex.searchResult, 'address 21')
.waitToClick(selectors.ticketsIndex.searchResult)
.waitToClick(selectors.ticketSales.saleButton)
.waitForURL('/sale')
.url()
.then(url => {
expect(url).toContain('/sale');
});
});
});
describe('when state is preparation and loged as salesPerson', () => {
it(`shouldnt be able to edit the sale price`, () => {
return nightmare
.waitToClick(selectors.ticketSales.firstSalePrice)
.exists(selectors.ticketSales.firstSalePriceInput)
.then(result => {
expect(result).toBeFalsy();
});
});
it(`shouldnt be able to edit the sale discount`, () => {
return nightmare
.waitToClick(selectors.ticketSales.firstSaleDiscount)
.exists(selectors.ticketSales.firstSaleDiscountInput)
.then(result => {
expect(result).toBeFalsy();
});
});
it(`shouldnt be able to edit the sale state`, () => {
return nightmare
.waitToClick(selectors.ticketSales.stateMenuButton)
.exists(selectors.ticketSales.stateMenuOptions)
.then(result => {
expect(result).toBeFalsy();
});
});
it('should go to another ticket sales section', () => {
return nightmare
.waitToClick(selectors.itemsIndex.goBackToModuleIndexButton)
.wait(selectors.ticketsIndex.searchResult)
.type(selectors.ticketsIndex.searchTicketInput, 'id:17')
.click(selectors.ticketsIndex.searchButton)
.waitForNumberOfElements(selectors.ticketsIndex.searchResult, 1)
.waitForTextInElement(selectors.ticketsIndex.searchResult, 'address 26')
.waitToClick(selectors.ticketsIndex.searchResult)
.waitToClick(selectors.ticketSales.saleButton)
.waitForURL('/sale')
.url()
.then(url => {
expect(url).toContain('/sale');
});
});
it(`should be able to delete the ticket`, () => {
return nightmare
.waitToClick(selectors.ticketSales.moreMenuButton)
.waitToClick(selectors.ticketSales.moreMenuDeleteOption)
.waitToClick(selectors.ticketSales.acceptDeleteTicketButton)
.waitForURL('/ticket/index')
.url()
.then(url => {
expect(url).toContain('/ticket/index');
});
});
it(`should search for the deleted ticket`, () => {
return nightmare
.wait(selectors.ticketsIndex.searchResult)
.type(selectors.ticketsIndex.searchTicketInput, 'id:17')
.click(selectors.ticketsIndex.searchButton)
.waitForNumberOfElements(selectors.ticketsIndex.searchResult, 1)
.countElement(selectors.ticketsIndex.searchResult)
.then(result => {
expect(result).toEqual(1);
});
});
it(`should search for the deleted ticket`, () => {
return nightmare
.wait(selectors.ticketsIndex.searchResultDate)
.getInnerText(selectors.ticketsIndex.searchResultDate)
.then(result => {
expect(result).toContain(2000);
});
});
});
});

View File

@ -0,0 +1,50 @@
module.exports = Self => {
Self.remoteMethod('createFromSales', {
description: 'Create a claim',
accessType: '',
accepts: [{
arg: 'claim',
type: 'object',
required: true,
description: ' newTicketFk, clientFk, ticketCreated',
http: {source: 'body'}
}, {
arg: 'sales',
type: 'object',
required: true,
description: '[sales IDs]',
http: {source: 'body'}
}],
returns: {
type: 'object',
root: true
},
http: {
path: `/createFromSales`,
verb: 'post'
}
});
Self.createFromSales = async params => {
let model = Self.app.models;
let transaction = await Self.beginTransaction({});
try {
let newClaim = await Self.create(params.claim, {transaction});
let promises = [];
for (let i = 0; i < params.sales.length; i++) {
promises.push(model.ClaimBeginning.create(
{saleFk: params.sales[i].id,
claimFk: newClaim.id,
quantity: params.sales[i].quantity},
{transaction}));
}
await Promise.all(promises);
await transaction.commit();
return newClaim;
} catch (e) {
transaction.rollback();
throw e;
}
};
};

View File

@ -0,0 +1,53 @@
const app = require(`${servicesDir}/claim/server/server`);
describe('Claim Create', () => {
let newDate = new Date();
let createdClaimFk;
afterAll(async() => {
await app.models.Claim.destroyById(createdClaimFk);
});
let newClaim = {
ticketFk: 2,
clientFk: 101,
ticketCreated: newDate,
workerFk: 18
};
let newSale = [{
id: 3,
instance: 0,
quantity: 10
}];
let params = {claim: newClaim, sales: newSale};
it('should create a new claim', async() => {
let claim = await app.models.Claim.createFromSales(params);
expect(claim.ticketFk).toEqual(newClaim.ticketFk);
expect(claim.clientFk).toEqual(newClaim.clientFk);
expect(claim.ticketCreated).toEqual(newClaim.ticketCreated);
expect(claim.workerFk).toEqual(newClaim.workerFk);
let claimBeginning = await app.models.ClaimBeginning.findOne({where: {claimFk: claim.id}});
expect(claimBeginning.saleFk).toEqual(newSale[0].id);
expect(claimBeginning.quantity).toEqual(newSale[0].quantity);
createdClaimFk = claim.id;
});
it('should not be able to create a claim if exists that sale', async() => {
let error;
await app.models.Claim.createFromSales(params)
.catch(e => {
error = e;
});
expect(error.toString()).toContain(`A claim with that sale already exists`);
});
});

View File

@ -1,3 +1,4 @@
module.exports = Self => { module.exports = Self => {
require('../methods/claim/getSummary')(Self); require('../methods/claim/getSummary')(Self);
require('../methods/claim/createFromSales')(Self);
}; };

View File

@ -21,16 +21,16 @@
"required": true "required": true
}, },
"isChargedToMana": { "isChargedToMana": {
"type": "boolean", "type": "boolean"
"required": true
}, },
"created": { "created": {
"type": "date", "type": "date"
"required": true
}, },
"responsibility": { "responsibility": {
"type": "Number", "type": "Number"
"required": true },
"ticketFk": {
"type": "Number"
} }
}, },
"relations": { "relations": {

View File

@ -0,0 +1,70 @@
USE `vn`;
DROP procedure IF EXISTS `ticketGetTax`;
DELIMITER $$
USE `vn`$$
CREATE DEFINER=`root`@`%` PROCEDURE `ticketGetTax`()
READS SQL DATA
BEGIN
/**
* Calcula la base imponible, el IVA y el recargo de equivalencia para
* un conjunto de tickets.
*
* @table tmp.ticket(ticketFk) Identificadores de los tickets a calcular
* @return tmp.ticketTax Impuesto desglosado para cada ticket
* @return tmp.ticketAmount
*/
DROP TEMPORARY TABLE IF EXISTS tmp.addressCompany;
CREATE TEMPORARY TABLE tmp.addressCompany
(INDEX (addressFk, companyFk))
ENGINE = MEMORY
SELECT DISTINCT t.addressFk, t.companyFk
FROM tmp.ticket tmpTicket
JOIN ticket t ON t.id = tmpTicket.ticketFk;
CALL addressTaxArea ();
DROP TEMPORARY TABLE IF EXISTS tmp.ticketTax;
CREATE TEMPORARY TABLE tmp.ticketTax
(INDEX (ticketFk))
ENGINE = MEMORY
SELECT tmpTicket.ticketFk,
bp.pgcFk,
ROUND(SUM(s.quantity * s.price * (100 - s.discount)/100
),2) AS taxableBase,
ROUND(SUM(s.quantity * s.price * (100 - s.discount)/100
) * pgc.rate / 100,2) AS tax,
tc.code
FROM tmp.ticket tmpTicket
JOIN sale s ON s.ticketFk = tmpTicket.ticketFk
JOIN item i ON i.id = s.itemFk
JOIN ticket t ON t.id = tmpTicket.ticketFk
JOIN supplier su ON su.id = t.companyFk
JOIN tmp.addressTaxArea ata
ON ata.addressFk = t.addressFk AND ata.companyFk = t.companyFk
JOIN itemTaxCountry itc
ON itc.itemFk = i.id AND itc.countryFk = su.countryFk
JOIN bookingPlanner bp
ON bp.countryFk = su.countryFk
AND bp.taxAreaFk = ata.areaFk
AND bp.taxClassFk = itc.taxClassFk
JOIN pgc ON pgc.code = bp.pgcFk
JOIN taxClass tc ON tc.id = bp.taxClassFk
GROUP BY tmpTicket.ticketFk, pgc.code
HAVING taxableBase != 0;
DROP TEMPORARY TABLE IF EXISTS tmp.ticketAmount;
CREATE TEMPORARY TABLE tmp.ticketAmount
(INDEX (ticketFk))
ENGINE = MEMORY
SELECT ticketFk, taxableBase, SUM(tax) tax
FROM tmp.ticketTax
GROUP BY ticketFk, code;
DROP TEMPORARY TABLE IF EXISTS tmp.addressCompany;
DROP TEMPORARY TABLE IF EXISTS tmp.addressTaxArea;
END$$
DELIMITER ;

View File

@ -0,0 +1,7 @@
UPDATE `salix`.`ACL` SET `model`='ClaimEnd' WHERE `id`='96';
UPDATE `salix`.`ACL` SET `model`='ClaimEnd' WHERE `id`='97';
UPDATE `salix`.`ACL` SET `model`='ClaimBeginning', `accessType`='*' WHERE `id`='98';
UPDATE `salix`.`ACL` SET `model`='ClaimDevelopment' WHERE `id`='99';
UPDATE `salix`.`ACL` SET `model`='ClaimDevelopment' WHERE `id`='100';
INSERT INTO `salix`.`ACL` (`id`, `model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES (101, 'Claim', '*', '*', 'ALLOW', 'ROLE', 'employee');
INSERT INTO `salix`.`ACL` (`id`, `model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES (102, 'Claim', 'createFromSales', '*', 'ALLOW', 'ROLE', 'employee');

View File

@ -441,10 +441,11 @@ INSERT INTO `vn`.`itemCategory`(`id`, `name`, `display`, `color`, `icon`)
INSERT INTO `vn`.`itemType`(`id`, `code`, `name`, `categoryFk`, `life`,`workerFk`, `isPackaging`) INSERT INTO `vn`.`itemType`(`id`, `code`, `name`, `categoryFk`, `life`,`workerFk`, `isPackaging`)
VALUES VALUES
(1, 'CRI', 'Crisantemo' , 2, 31, 5, 0), (1, 'CRI', 'Crisantemo', 2, 31, 5, 0),
(2, 'ITG', 'Anthurium' , 1, 31, 5, 0), (2, 'ITG', 'Anthurium', 1, 31, 5, 0),
(3, 'WPN', 'Paniculata' , 2, 31, 5, 0), (3, 'WPN', 'Paniculata', 2, 31, 5, 0),
(4, 'PRT', 'Delivery ports', 3, 31, 5, 1); (4, 'PRT', 'Delivery ports', 3, NULL, 5, 1),
(5, 'CON', 'Container', 3, NULL, 5, 1);
INSERT INTO `vn`.`ink`(`id`, `name`, `picture`, `showOrder`) INSERT INTO `vn`.`ink`(`id`, `name`, `picture`, `showOrder`)
VALUES VALUES
@ -487,12 +488,14 @@ INSERT INTO `vn`.`intrastat`(`id`, `description`, `taxClassFk`, `taxCodeFk`)
INSERT INTO `vn`.`item`(`id`, `name`,`typeFk`,`size`,`inkFk`,`category`,`stems`,`originFk`,`description`,`producerFk`,`intrastatFk`,`isOnOffer`,`expenceFk`,`isBargain`,`comment`,`relevancy`,`image`,`taxClassFk`,`longName`,`subName`,`tag5`,`value5`,`tag6`,`value6`,`tag7`,`value7`,`tag8`,`value8`) INSERT INTO `vn`.`item`(`id`, `name`,`typeFk`,`size`,`inkFk`,`category`,`stems`,`originFk`,`description`,`producerFk`,`intrastatFk`,`isOnOffer`,`expenceFk`,`isBargain`,`comment`,`relevancy`,`image`,`taxClassFk`,`longName`,`subName`,`tag5`,`value5`,`tag6`,`value6`,`tag7`,`value7`,`tag8`,`value8`)
VALUES VALUES
(1 , 'Gem of Time', 2, 70, 'AMA', 'EXT', 1 , 1, 'One of the infinity gems' , 1 , 06021010, 0, 2000000000, 0, NULL, 0, 66540, 1, 'Gem of Time' , NULL, 'Medida', '70', 'Color', 'Amarillo' , 'Categoria', 'EXT', 'Tallos', '1'), (1 , 'Gem of Time', 2, 70, 'AMA', 'EXT', 1 , 1, 'One of the infinity gems', 1, 06021010, 0, 2000000000, 0, NULL, 0, 66540, 1, 'Gem of Time', NULL, 'Medida', '70', 'Color', 'Amarillo' , 'Categoria', 'EXT', 'Tallos', '1'),
(2 , 'Gem of Mind', 2, 70, 'AZL', 'EXT', 1 , 2, 'One of the infinity gems' , 1 , 06021010, 0, 2000000000, 0, NULL, 0, 65540, 1, 'Gem of Mind' , NULL, 'Medida', '70', 'Color', 'Azul' , 'Categoria', 'EXT', 'Tallos', '1'), (2 , 'Gem of Mind', 2, 70, 'AZL', 'EXT', 1 , 2, 'One of the infinity gems', 1, 06021010, 0, 2000000000, 0, NULL, 0, 65540, 1, 'Gem of Mind', NULL, 'Medida', '70', 'Color', 'Azul' , 'Categoria', 'EXT', 'Tallos', '1'),
(3 , 'Iron Patriot', 1, 60, 'AMR', 'EXT', 1 , 3, 'Rhodeys armor' , 1 , 05080000, 0, 4751000000, 0, NULL, 0, 61692, 1, 'Iron Patriot', NULL, 'Medida', '60', 'Color', 'Rosa/Amarillo', 'Categoria', 'EXT', 'Tallos', '1'), (3 , 'Iron Patriot', 1, 60, 'AMR', 'EXT', 1 , 3, 'Rhodeys armor', 1, 05080000, 0, 4751000000, 0, NULL, 0, 61692, 1, 'Iron Patriot', NULL, 'Medida', '60', 'Color', 'Rosa/Amarillo', 'Categoria', 'EXT', 'Tallos', '1'),
(4 , 'Mark I', 1, 60, 'AMR', 'EXT', 1 , 1, 'Iron Mans first armor' , 1 , 05080000, 1, 4751000000, 0, NULL, 0, 66090, 2, 'Mark I' , NULL, 'Medida', '60', 'Color', 'Rosa/Amarillo', 'Categoria', 'EXT', 'Tallos', '1'), (4 , 'Mark I', 1, 60, 'AMR', 'EXT', 1 , 1, 'Iron Mans first armor', 1, 05080000, 1, 4751000000, 0, NULL, 0, 66090, 2, 'Mark I', NULL, 'Medida', '60', 'Color', 'Rosa/Amarillo', 'Categoria', 'EXT', 'Tallos', '1'),
(5 , 'Mjolnir', 3, 30, 'AZL', 'EXT', 1 , 2, 'Thors hammer!' , 2 , 06021010, 1, 4751000000, 0, NULL, 0, 67350, 2, 'Mjolnir' , NULL, 'Medida', '30', 'Color', 'Azul' , 'Categoria', 'EXT', 'Tallos', '1'), (5 , 'Mjolnir', 3, 30, 'GRE', 'EXT', 1 , 2, 'Thors hammer!', 2, 06021010, 1, 4751000000, 0, NULL, 0, 67350, 2, 'Mjolnir', NULL, 'Medida', '30', 'Color', 'Azul' , 'Categoria', 'EXT', 'Tallos', '1'),
(71, 'ShippingCost', 4, NULL, NULL, NULL, NULL, 1, NULL , NULL, 06021010, 1, 4751000000, 0, NULL, 0, NULL, 2, 'ShippingCost', NULL, NULL , NULL, NULL , NULL , NULL, NULL , NULL , NULL); (6 , 'Broken Box', 5, 30, 'GRE', 'EXT', 1 , 2, NULL, NULL, 06021010, 0, 4751000000, 0, NULL, 0, 67350, 2, 'Legendary Box', NULL, 'Medida', '30', 'Color', 'Gris' , NULL, NULL, NULL, NULL),
(7 , 'Legendary Box', 5, 90, 'AZL', 'EXT', 1 , 2, NULL, NULL, 06021010, 0, 4751000000, 0, NULL, 0, 67350, 2, 'Broken Box', NULL, 'Medida', '90', 'Color', 'Gris' , NULL, NULL, NULL, NULL),
(71, 'ShippingCost', 4, NULL, NULL, NULL, NULL, 1, NULL, NULL, 06021010, 1, 4751000000, 0, NULL, 0, NULL, 2, 'ShippingCost', NULL, NULL , NULL, NULL , NULL , NULL, NULL, NULL, NULL);
INSERT INTO `vn`.`expedition`(`id`, `agencyModeFk`, `ticketFk`, `isBox`, `created`, `itemFk`, `counter`, `checked`, `workerFk`) INSERT INTO `vn`.`expedition`(`id`, `agencyModeFk`, `ticketFk`, `isBox`, `created`, `itemFk`, `counter`, `checked`, `workerFk`)
VALUES VALUES
@ -505,30 +508,29 @@ INSERT INTO `vn`.`expedition`(`id`, `agencyModeFk`, `ticketFk`, `isBox`, `create
INSERT INTO `vn`.`packaging`(`id`, `volume`, `width`, `height`, `depth`, `isPackageReturnable`, `created`, `itemFk`, `price`) INSERT INTO `vn`.`packaging`(`id`, `volume`, `width`, `height`, `depth`, `isPackageReturnable`, `created`, `itemFk`, `price`)
VALUES VALUES
(1, 0.00, 10, 10, 0, 0, CURDATE(), 1, 1.50), (1, 0.00, 10, 10, 0, 0, CURDATE(), 6, 1.50),
(2, 100.00, 20, 20, 0, 0, CURDATE(), 2, 1.00), (2, 100.00, 20, 20, 0, 0, CURDATE(), 7, 1.00);
('a', 50.00, 30, 30, 0, 1, CURDATE(), 3, 0.00);
INSERT INTO `vn`.`ticketPackaging`(`id`, `ticketFk`, `packagingFk`, `quantity`, `created`, `pvp`) INSERT INTO `vn`.`ticketPackaging`(`id`, `ticketFk`, `packagingFk`, `quantity`, `created`, `pvp`)
VALUES VALUES
( 1, 1, 1, 2, CURDATE(), NULL), ( 1, 1, 2, 2, CURDATE(), NULL),
( 2, 2, 2, 1, CURDATE(), NULL), ( 2, 2, 2, 1, CURDATE(), NULL),
( 3, 3, 'a', 4, CURDATE(), NULL); ( 3, 3, 2, 4, CURDATE(), NULL);
INSERT INTO `vn`.`sale`(`id`, `itemFk`, `ticketFk`, `concept`, `quantity`, `price`, `discount`, `reserved`, `isPicked`, `created`) INSERT INTO `vn`.`sale`(`id`, `itemFk`, `ticketFk`, `concept`, `quantity`, `price`, `discount`, `reserved`, `isPicked`, `created`)
VALUES VALUES
( 1, 1, 1 , 'Gem of Time', 5 , 9.60, 0, 0, 0, CURDATE()), ( 1, 1, 1 , 'Gem of Time', 5 , 11.42, 0, 0, 0, CURDATE()),
( 2, 2, 1 , 'Gem of Mind', 10 , 4.21, 0, 0, 0, CURDATE()), ( 2, 2, 1 , 'Gem of Mind', 10 , 1.30, 0, 0, 0, CURDATE()),
( 3, 1, 1 , 'Gem of Time', 2 , 9.60, 0, 0, 0, CURDATE()), ( 3, 1, 1 , 'Gem of Time', 2 , 11.42, 0, 0, 0, CURDATE()),
( 4, 4, 1 , 'Mark I' , 20 , 7.06, 0, 0, 0, CURDATE()), ( 4, 4, 1 , 'Mark I' , 20 , 3.26, 0, 0, 0, CURDATE()),
( 5, 1, 2 , 'Gem of Time', 10 , 9.60, 0, 0, 0, CURDATE()), ( 5, 1, 2 , 'Gem of Time', 10 , 11.42, 0, 0, 0, CURDATE()),
( 6, 1, 3 , 'Gem of Time', 15 , 9.60, 0, 0, 0, CURDATE()), ( 6, 1, 3 , 'Gem of Time', 15 , 11.42, 0, 0, 0, CURDATE()),
( 7, 2, 11, 'Gem of Mind', 15 , 4.21, 0, 0, 0, CURDATE()), ( 7, 2, 11, 'Gem of Mind', 15 , 1.30, 0, 0, 0, CURDATE()),
( 8, 4, 11, 'Mark I' , 10 , 7.06, 0, 0, 0, CURDATE()), ( 8, 4, 11, 'Mark I' , 10 , 3.26, 0, 0, 0, CURDATE()),
( 9, 1, 16, 'Gem of Time', 5 , 9.60, 0, 0, 0, CURDATE()), ( 9, 1, 16, 'Gem of Time', 5 , 11.42, 0, 0, 0, CURDATE()),
( 10, 2, 16, 'Gem of Mind', 10 , 4.21, 0, 0, 0, CURDATE()), ( 10, 2, 16, 'Gem of Mind', 10 , 1.30, 0, 0, 0, CURDATE()),
( 11, 1, 16, 'Gem of Time', 2 , 9.60, 0, 0, 0, CURDATE()), ( 11, 1, 16, 'Gem of Time', 2 , 11.42, 0, 0, 0, CURDATE()),
( 12, 4, 16, 'Mark I' , 20 , 7.06, 0, 0, 0, CURDATE()); ( 12, 4, 16, 'Mark I' , 20 , 3.26, 0, 0, 0, CURDATE());
INSERT INTO `vn`.`saleChecked`(`saleFk`, `isChecked`) INSERT INTO `vn`.`saleChecked`(`saleFk`, `isChecked`)
VALUES VALUES
@ -785,12 +787,12 @@ INSERT INTO `bi`.`claims_ratio`(`id_Cliente`, `Consumo`, `Reclamaciones`, `Ratio
INSERT INTO `vn`.`buy`(`id`,`entryFk`,`itemFk`,`buyingValue`,`quantity`,`packageFk`,`stickers`,`freightValue`,`packageValue`,`comissionValue`,`packing`,`grouping`,`groupingMode`,`location`,`price1`,`price2`,`price3`,`minPrice`,`producer`,`printedStickers`,`isChecked`,`isIgnored`, `created`) INSERT INTO `vn`.`buy`(`id`,`entryFk`,`itemFk`,`buyingValue`,`quantity`,`packageFk`,`stickers`,`freightValue`,`packageValue`,`comissionValue`,`packing`,`grouping`,`groupingMode`,`location`,`price1`,`price2`,`price3`,`minPrice`,`producer`,`printedStickers`,`isChecked`,`isIgnored`, `created`)
VALUES VALUES
(1, 1, 1, 2.5, 5000 , 1, 1, 0.350, 0.050, 0.000, 1, 1, 0, NULL, 1.50, 1.25, 1.30, 2.00, NULL, 0, 1, 0, DATE_ADD(CURDATE(), INTERVAL -2 MONTH)), (1, 1, 1, 2.5, 5000 , 1, 1, 0.350, 0.050, 0.000, 10, 10, 1, NULL, 0.00, 1.30, 1.25, 1.00, NULL, 0, 1, 0, DATE_ADD(CURDATE(), INTERVAL -2 MONTH)),
(2, 2, 1, 20 , 100 , 1, 1, 0.700, 0.020, 0.000, 1, 1, 0, NULL, 2.50, 1.00, 2.50, 2.00, NULL, 0, 1, 0, DATE_ADD(CURDATE(), INTERVAL -1 MONTH)), (2, 2, 1, 20 , 100 , 1, 1, 0.700, 0.020, 0.000, 5, 5, 1, NULL, 0.00, 2.50, 2.00, 0.50, NULL, 0, 1, 0, DATE_ADD(CURDATE(), INTERVAL -1 MONTH)),
(3, 3, 1, 20 , 100 , 1, 1, 0.700, 0.020, 0.000, 1, 1, 0, NULL, 2.50, 1.00, 2.50, 2.00, NULL, 0, 1, 0, CURDATE()), (3, 3, 1, 20 , 100 , 1, 1, 0.700, 0.020, 0.000, 1, 1, 0, NULL, 0.00, 2.50, 2.00, 0.50, NULL, 0, 1, 0, CURDATE()),
(4, 2, 2, 5 , 450 , 1, 1, 0.500, 0.100, 0.000, 1, 1, 0, NULL, 2, 1.00, 1.30, 2.00, NULL, 0, 1, 0, CURDATE()), (4, 2, 2, 5 , 450 , 1, 1, 0.500, 0.100, 0.000, 10, 10, 0, NULL, 0.00, 1.30, 1.00, 0.00, NULL, 0, 1, 0, CURDATE()),
(5, 3, 3, 10 , 500 , 1, 1, 1.000, 0.050, 0.000, 1, 1, 0, NULL, 2.50, 1.00, 2.50, 2.00, NULL, 0, 1, 0, CURDATE()), (5, 3, 3, 10 , 500 , 1, 1, 1.000, 0.050, 0.000, 10, 10, 0, NULL, 0.00, 2.50, 1.00, 0.00, NULL, 0, 1, 0, CURDATE()),
(6, 4, 4, 20 , 100 , 1, 1, 0.700, 0.020, 0.000, 1, 1, 0, NULL, 2.50, 1.00, 2.50, 2.00, NULL, 0, 1, 0, CURDATE()); (6, 4, 4, 20 , 100 , 1, 1, 0.700, 0.020, 0.000, 10, 10, 1, NULL, 0.00, 2.50, 1.00, 0.00, NULL, 0, 1, 0, CURDATE());
INSERT INTO `vn2008`.`tblContadores`(`id`,`FechaInventario`) INSERT INTO `vn2008`.`tblContadores`(`id`,`FechaInventario`)
VALUES VALUES

View File

@ -46,5 +46,6 @@
"Barcode must be unique": "El código de barras debe ser único", "Barcode must be unique": "El código de barras debe ser único",
"The warehouse can't be repeated": "El almacén no puede repetirse", "The warehouse can't be repeated": "El almacén no puede repetirse",
"The tag can't be repeated": "El tag no puede repetirse", "The tag can't be repeated": "El tag no puede repetirse",
"The observation type can't be repeated": "El tipo de observación no puede repetirse" "The observation type can't be repeated": "El tipo de observación no puede repetirse",
"A claim with that sale already exists": "Ya existe una reclamación para esta línea"
} }

View File

@ -4,7 +4,7 @@ describe('client getDebt()', () => {
it('should return the client debt', async() => { it('should return the client debt', async() => {
let result = await app.models.Client.getDebt(101); let result = await app.models.Client.getDebt(101);
expect(result.debt).toEqual(1342.66); expect(result.debt).toEqual(1048.76);
}); });
}); });

View File

@ -17,7 +17,7 @@ describe('client summary()', () => {
it('should return a summary object containing debt', async() => { it('should return a summary object containing debt', async() => {
let result = await app.models.Client.summary(101); let result = await app.models.Client.summary(101);
expect(result.debt.debt).toEqual(1342.66); expect(result.debt.debt).toEqual(1048.76);
}); });
it('should return a summary object containing averageInvoiced', async() => { it('should return a summary object containing averageInvoiced', async() => {

View File

@ -2,7 +2,7 @@ let UserError = require('../../helpers').UserError;
module.exports = Self => { module.exports = Self => {
Self.remoteMethod('moveToTicket', { Self.remoteMethod('moveToTicket', {
description: 'Change the state of a ticket', description: 'Moves a line to a given ticket',
accessType: '', accessType: '',
accepts: [{ accepts: [{
arg: 'params', arg: 'params',

View File

@ -10,8 +10,8 @@ describe('sale priceDifference()', () => {
}; };
let result = await app.models.Sale.priceDifference(1, data); let result = await app.models.Sale.priceDifference(1, data);
expect(result.totalUnitPrice).toEqual(30.469999999999995); expect(result.totalUnitPrice).toEqual(27.4);
expect(result.totalNewPrice).toEqual(26.12); expect(result.totalNewPrice).toEqual(22.33);
expect(result.totalDifference).toEqual(63.8); expect(result.totalDifference).toEqual(22.54);
}); });
}); });

View File

@ -1,5 +1,5 @@
module.exports = Self => { module.exports = Self => {
Self.remoteMethod('deleted', { Self.remoteMethodCtx('deleted', {
description: 'Sets the isDeleted value of a ticket to 1', description: 'Sets the isDeleted value of a ticket to 1',
accessType: '', accessType: '',
accepts: [{ accepts: [{
@ -19,7 +19,15 @@ module.exports = Self => {
} }
}); });
Self.deleted = async params => { Self.deleted = async(ctx, params) => {
return await Self.app.models.Ticket.update({id: params.id}, {isDeleted: '1'}); await Self.app.models.Ticket.update({id: params.id}, {isDeleted: '1'});
if (ctx.req.accessToken) {
let token = ctx.req.accessToken;
let currentUserId = token && token.userId;
let worker = await Self.app.models.Worker.findOne({where: {userFk: currentUserId}});
params.workerFk = worker.id;
}
return await Self.app.models.TicketTracking.create({ticketFk: params.id, stateFk: 17, workerFk: params.workerFk});
}; };
}; };

View File

@ -27,6 +27,6 @@ module.exports = Self => {
totalTax += tax.tax; totalTax += tax.tax;
}); });
return totalTax; return Math.round(totalTax * 100) / 100;
}; };
}; };

View File

@ -1,15 +1,25 @@
const app = require(`${servicesDir}/ticket/server/server`); const app = require(`${servicesDir}/ticket/server/server`);
describe('ticket deleted()', () => { describe('ticket deleted()', () => {
it('should call the getShipped method', async() => { let ticket;
let oldTicket = await app.models.Ticket.findOne({where: {id: 1}});
expect(oldTicket.isDeleted).toEqual(false); afterAll(async() => {
await app.models.Ticket.deleted({id: 1}); await app.models.Ticket.upsert(ticket);
let ticket = await app.models.Ticket.findOne({where: {id: 1}, fields: ['isDeleted']}); await app.models.TicketTracking.create({ticketFk: ticket.id, stateFk: 3});
});
expect(ticket.isDeleted).toEqual(true); it('should change the state of a ticket to deleted, and set the property isDeleted true', async() => {
oldTicket.isDeleted = 0; ticket = await app.models.Ticket.findOne({where: {id: 1}});
await app.models.Ticket.upsert(oldTicket);
expect(ticket.isDeleted).toEqual(false);
ctx = {req: {accessToken: {userId: 9}}};
params = {id: 1};
await app.models.Ticket.deleted(ctx, params);
let deletedTicket = await app.models.Ticket.findOne({where: {id: 1}, fields: ['isDeleted']});
let changedState = await app.models.TicketState.findOne({where: {id: 1}});
expect(deletedTicket.isDeleted).toEqual(true);
expect(changedState.stateFk).toEqual(17);
}); });
}); });

View File

@ -4,6 +4,6 @@ describe('ticket getTaxes()', () => {
it('should return the tax of a given ticket', async() => { it('should return the tax of a given ticket', async() => {
let result = await app.models.Ticket.getTaxes(1); let result = await app.models.Ticket.getTaxes(1);
expect(result[0].tax).toEqual(10.93); expect(result[0].tax).toEqual(9.29);
}); });
}); });

View File

@ -4,7 +4,7 @@ describe('ticket getTotal()', () => {
it('should return the total of a ticket', async() => { it('should return the total of a ticket', async() => {
let result = await app.models.Ticket.getTotal(1); let result = await app.models.Ticket.getTotal(1);
expect(result).toEqual(291.08); expect(result).toEqual(181.12);
}); });
it(`should return zero if the ticket doesn't have lines`, async() => { it(`should return zero if the ticket doesn't have lines`, async() => {

View File

@ -4,7 +4,7 @@ describe('ticket getTotalVolume()', () => {
it('should return the total volume of a ticket', async() => { it('should return the total volume of a ticket', async() => {
let ticketFk = 1; let ticketFk = 1;
let expectedResult = 0.276; let expectedResult = 0.078;
let result = await app.models.Ticket.getTotalVolume(ticketFk); let result = await app.models.Ticket.getTotalVolume(ticketFk);

View File

@ -4,7 +4,7 @@ describe('ticket getVAT()', () => {
it('should call the getVAT method and return the response', async() => { it('should call the getVAT method and return the response', async() => {
await app.models.Ticket.getVAT(1) await app.models.Ticket.getVAT(1)
.then(response => { .then(response => {
expect(response).toEqual(40.58); expect(response).toEqual(22.98);
}); });
}); });

View File

@ -17,18 +17,19 @@ describe('ticket summary()', () => {
it('should return a summary object containing subTotal for 1 ticket', async() => { it('should return a summary object containing subTotal for 1 ticket', async() => {
let result = await app.models.Ticket.summary(1); let result = await app.models.Ticket.summary(1);
expect(result.subTotal).toEqual(250.5); expect(result.subTotal).toEqual(158.14);
}); });
it('should return a summary object containing VAT for 1 ticket', async() => { it('should return a summary object containing VAT for 1 ticket', async() => {
let result = await app.models.Ticket.summary(1); let result = await app.models.Ticket.summary(1);
expect(result.VAT).toEqual(40.58); expect(Math.round(result.VAT * 100) / 100).toEqual(22.98);
}); });
it('should return a summary object containing total for 1 ticket', async() => { it('should return a summary object containing total for 1 ticket', async() => {
let result = await app.models.Ticket.summary(1); let result = await app.models.Ticket.summary(1);
let expectedTotal = result.subTotal + result.VAT; let total = result.subTotal + result.VAT;
let expectedTotal = Math.round(total * 100) / 100;
expect(result.total).toEqual(expectedTotal); expect(result.total).toEqual(expectedTotal);
}); });

View File

@ -86,6 +86,8 @@ module.exports = Self => {
tcp.itemFk, tcp.itemFk,
tcp.grouping, tcp.grouping,
tcp.price, tcp.price,
tcp.rate,
tcp.warehouseFk,
w.name AS warehouse w.name AS warehouse
FROM tmp.ticketComponentPrice tcp FROM tmp.ticketComponentPrice tcp
JOIN vn.warehouse w ON w.id = tcp.warehouseFk` JOIN vn.warehouse w ON w.id = tcp.warehouseFk`

View File

@ -6,7 +6,7 @@ describe('ticket listPackaging()', () => {
let response = await app.models.Packaging.listPackaging(filter); let response = await app.models.Packaging.listPackaging(filter);
expect(response[0].name).toBeDefined(); expect(response[0].name).toBeDefined();
expect(response[0].name).toEqual('Gem of Time'); expect(response[0].name).toEqual('Broken Box');
}); });
}); });