Merge branch '1919-ticket_service_type' of verdnatura/salix into dev
gitea/salix/dev This commit looks good Details

This commit is contained in:
Joan Sanchez 2019-12-13 11:49:52 +00:00 committed by Gitea
commit fb30c9b6a3
16 changed files with 86 additions and 43 deletions

View File

@ -237,7 +237,7 @@ export default {
nameInput: 'vn-textfield[label="Name"] input', nameInput: 'vn-textfield[label="Name"] input',
relevancyInput: 'vn-input-number[ng-model="$ctrl.item.relevancy"] input', relevancyInput: 'vn-input-number[ng-model="$ctrl.item.relevancy"] input',
originAutocomplete: 'vn-autocomplete[ng-model="$ctrl.item.originFk"]', originAutocomplete: 'vn-autocomplete[ng-model="$ctrl.item.originFk"]',
expenceAutocomplete: 'vn-autocomplete[ng-model="$ctrl.item.expenceFk"]', expenseAutocomplete: 'vn-autocomplete[ng-model="$ctrl.item.expenseFk"]',
longNameInput: 'vn-textfield[ng-model="$ctrl.item.longName"] input', longNameInput: 'vn-textfield[ng-model="$ctrl.item.longName"] input',
isActiveCheckbox: 'vn-check[label="Active"]', isActiveCheckbox: 'vn-check[label="Active"]',
priceInKgCheckbox: 'vn-check[label="Price in kg"]', priceInKgCheckbox: 'vn-check[label="Price in kg"]',
@ -501,16 +501,17 @@ export default {
}, },
ticketService: { ticketService: {
addServiceButton: 'vn-ticket-service vn-icon-button[vn-tooltip="Add service"] > button', addServiceButton: 'vn-ticket-service vn-icon-button[vn-tooltip="Add service"] > button',
firstAddDescriptionButton: 'vn-ticket-service vn-icon-button[vn-tooltip="New service type"]', firstAddServiceTypeButton: 'vn-ticket-service vn-icon-button[vn-tooltip="New service type"]',
firstDescriptionAutocomplete: 'vn-ticket-service vn-autocomplete[ng-model="service.description"]', firstServiceTypeAutocomplete: 'vn-ticket-service vn-autocomplete[ng-model="service.ticketServiceTypeFk"]',
firstQuantityInput: 'vn-ticket-service vn-input-number[label="Quantity"] input', firstQuantityInput: 'vn-ticket-service vn-input-number[label="Quantity"] input',
firstPriceInput: 'vn-ticket-service vn-input-number[label="Price"] input', firstPriceInput: 'vn-ticket-service vn-input-number[label="Price"] input',
firstVatTypeAutocomplete: 'vn-ticket-service vn-autocomplete[label="Tax class"]', firstVatTypeAutocomplete: 'vn-ticket-service vn-autocomplete[label="Tax class"]',
fistDeleteServiceButton: 'vn-ticket-service form vn-horizontal:nth-child(1) vn-icon-button[icon="delete"]', fistDeleteServiceButton: 'vn-ticket-service form vn-horizontal:nth-child(1) vn-icon-button[icon="delete"]',
newDescriptionInput: '.vn-dialog.shown vn-textfield[ng-model="$ctrl.newServiceType.name"] input', newServiceTypeNameInput: '.vn-dialog.shown vn-textfield[ng-model="$ctrl.newServiceType.name"] input',
newServiceTypeExpenseAutocomplete: '.vn-dialog.shown vn-autocomplete[ng-model="$ctrl.newServiceType.expenseFk"]',
serviceLine: 'vn-ticket-service > form > vn-card > vn-one:nth-child(2) > vn-horizontal', serviceLine: 'vn-ticket-service > form > vn-card > vn-one:nth-child(2) > vn-horizontal',
saveServiceButton: `button[type=submit]`, saveServiceButton: `button[type=submit]`,
saveDescriptionButton: '.vn-dialog.shown tpl-buttons > button' saveServiceTypeButton: '.vn-dialog.shown tpl-buttons > button'
}, },
createStateView: { createStateView: {
stateAutocomplete: 'vn-autocomplete[ng-model="$ctrl.stateFk"]', stateAutocomplete: 'vn-autocomplete[ng-model="$ctrl.stateFk"]',

View File

@ -27,7 +27,7 @@ describe('Item Edit basic data path', () => {
.clearInput(selectors.itemBasicData.relevancyInput) .clearInput(selectors.itemBasicData.relevancyInput)
.write(selectors.itemBasicData.relevancyInput, '1') .write(selectors.itemBasicData.relevancyInput, '1')
.autocompleteSearch(selectors.itemBasicData.originAutocomplete, 'Spain') .autocompleteSearch(selectors.itemBasicData.originAutocomplete, 'Spain')
.autocompleteSearch(selectors.itemBasicData.expenceAutocomplete, 'Alquiler VNH') .autocompleteSearch(selectors.itemBasicData.expenseAutocomplete, 'Alquiler VNH')
.clearInput(selectors.itemBasicData.longNameInput) .clearInput(selectors.itemBasicData.longNameInput)
.write(selectors.itemBasicData.longNameInput, 'RS Rose of Purity') .write(selectors.itemBasicData.longNameInput, 'RS Rose of Purity')
.waitToClick(selectors.itemBasicData.isActiveCheckbox) .waitToClick(selectors.itemBasicData.isActiveCheckbox)
@ -76,7 +76,7 @@ describe('Item Edit basic data path', () => {
it(`should confirm the item expence was edited`, async() => { it(`should confirm the item expence was edited`, async() => {
const result = await nightmare const result = await nightmare
.waitToGetProperty(`${selectors.itemBasicData.expenceAutocomplete} input`, 'value'); .waitToGetProperty(`${selectors.itemBasicData.expenseAutocomplete} input`, 'value');
expect(result).toEqual('Alquiler VNH'); expect(result).toEqual('Alquiler VNH');
}); });

View File

@ -15,10 +15,10 @@ describe('Ticket services path', () => {
it('should find the add descripton button disabled for this user role', async() => { it('should find the add descripton button disabled for this user role', async() => {
const result = await nightmare const result = await nightmare
.waitForClassPresent(selectors.ticketService.firstAddDescriptionButton, 'disabled') .waitForClassPresent(selectors.ticketService.firstAddServiceTypeButton, 'disabled')
.waitToClick(selectors.ticketService.addServiceButton) .waitToClick(selectors.ticketService.addServiceButton)
.wait(selectors.ticketService.firstAddDescriptionButton) .wait(selectors.ticketService.firstAddServiceTypeButton)
.isDisabled(selectors.ticketService.firstAddDescriptionButton); .isDisabled(selectors.ticketService.firstAddServiceTypeButton);
expect(result).toBeTruthy(); expect(result).toBeTruthy();
}, 100000); }, 100000);
@ -50,7 +50,7 @@ describe('Ticket services path', () => {
it('should click on the add button to prepare the form to create a new service', async() => { it('should click on the add button to prepare the form to create a new service', async() => {
const result = await nightmare const result = await nightmare
.waitToClick(selectors.ticketService.addServiceButton) .waitToClick(selectors.ticketService.addServiceButton)
.isVisible(selectors.ticketService.firstDescriptionAutocomplete); .isVisible(selectors.ticketService.firstServiceTypeAutocomplete);
expect(result).toBeTruthy(); expect(result).toBeTruthy();
}); });
@ -63,27 +63,28 @@ describe('Ticket services path', () => {
expect(result).toEqual(`can't be blank`); expect(result).toEqual(`can't be blank`);
}); });
it('should click on the add new description to open the dialog', async() => { it('should click on the add new service type to open the dialog', async() => {
const result = await nightmare const result = await nightmare
.waitToClick(selectors.ticketService.firstAddDescriptionButton) .waitToClick(selectors.ticketService.firstAddServiceTypeButton)
.wait('.vn-dialog.shown') .wait('.vn-dialog.shown')
.isVisible(selectors.ticketService.newDescriptionInput); .isVisible(selectors.ticketService.newServiceTypeNameInput);
expect(result).toBeTruthy(); expect(result).toBeTruthy();
}); });
it('should receive an error if description is empty on submit', async() => { it('should receive an error if service type is empty on submit', async() => {
const result = await nightmare const result = await nightmare
.waitToClick(selectors.ticketService.saveDescriptionButton) .waitToClick(selectors.ticketService.saveServiceTypeButton)
.waitForLastSnackbar(); .waitForLastSnackbar();
expect(result).toEqual(`Name can't be empty`); expect(result).toEqual(`Name can't be empty`);
}); });
it('should create a new description then add price then create the service', async() => { it('should create a new service type then add price then create the service', async() => {
const result = await nightmare const result = await nightmare
.write(selectors.ticketService.newDescriptionInput, 'accurate description') .write(selectors.ticketService.newServiceTypeNameInput, 'Documentos')
.waitToClick(selectors.ticketService.saveDescriptionButton) .autocompleteSearch(selectors.ticketService.newServiceTypeExpenseAutocomplete, 'Retencion')
.waitToClick(selectors.ticketService.saveServiceTypeButton)
.write(selectors.ticketService.firstPriceInput, 999) .write(selectors.ticketService.firstPriceInput, 999)
.waitToClick(selectors.ticketService.saveServiceButton) .waitToClick(selectors.ticketService.saveServiceButton)
.waitForLastSnackbar(); .waitForLastSnackbar();
@ -94,9 +95,9 @@ describe('Ticket services path', () => {
it('should confirm the service description was created correctly', async() => { it('should confirm the service description was created correctly', async() => {
const result = await nightmare const result = await nightmare
.reloadSection('ticket.card.service') .reloadSection('ticket.card.service')
.waitToGetProperty(`${selectors.ticketService.firstDescriptionAutocomplete} input`, 'value'); .waitToGetProperty(`${selectors.ticketService.firstServiceTypeAutocomplete} input`, 'value');
expect(result).toEqual('accurate description'); expect(result).toEqual('Documentos');
}); });
it('should confirm the service quantity was created correctly', async() => { it('should confirm the service quantity was created correctly', async() => {

View File

@ -46,7 +46,7 @@ module.exports = Self => {
}, },
{relation: 'intrastat'}, {relation: 'intrastat'},
{relation: 'itemBarcode'}, {relation: 'itemBarcode'},
{relation: 'expence'}, {relation: 'expense'},
{relation: 'origin'}, {relation: 'origin'},
{relation: 'taxes', {relation: 'taxes',
scope: { scope: {

View File

@ -1,5 +1,5 @@
{ {
"Expence": { "Expense": {
"dataSource": "vn" "dataSource": "vn"
}, },
"Genus": { "Genus": {

View File

@ -1,5 +1,5 @@
{ {
"name": "Expence", "name": "Expense",
"base": "VnModel", "base": "VnModel",
"options": { "options": {
"mysql": { "mysql": {

View File

@ -116,6 +116,12 @@
"hasKgPrice": { "hasKgPrice": {
"type": "Boolean", "type": "Boolean",
"description": "Price per Kg" "description": "Price per Kg"
},
"expenseFk": {
"type": "Number",
"mysql": {
"columnName": "expenceFk"
}
} }
}, },
"relations": { "relations": {
@ -144,10 +150,10 @@
"model": "Intrastat", "model": "Intrastat",
"foreignKey": "intrastatFk" "foreignKey": "intrastatFk"
}, },
"expence": { "expense": {
"type": "belongsTo", "type": "belongsTo",
"model": "Expence", "model": "Expense",
"foreignKey": "expenceFk" "foreignKey": "expenseFk"
}, },
"tags": { "tags": {
"type": "hasMany", "type": "hasMany",

View File

@ -1,7 +1,7 @@
<mg-ajax <mg-ajax
path="Items/{{patch.params.id}}" path="Items/{{patch.params.id}}"
options="vnPatch" options="vnPatch"
override="{filter: {include: [{relation: 'itemType'}, {relation: 'origin'}, {relation: 'ink'}, {relation: 'producer'}, {relation: 'expence'}]}}"> override="{filter: {include: [{relation: 'itemType'}, {relation: 'origin'}, {relation: 'ink'}, {relation: 'producer'}, {relation: 'expense'}]}}">
</mg-ajax> </mg-ajax>
<vn-watcher <vn-watcher
vn-id="watcher" vn-id="watcher"
@ -49,10 +49,10 @@
</tpl-item> </tpl-item>
</vn-autocomplete> </vn-autocomplete>
<vn-autocomplete vn-one <vn-autocomplete vn-one
url="Expences" url="Expenses"
label="Expence" label="Expense"
ng-model="$ctrl.item.expenceFk" ng-model="$ctrl.item.expenseFk"
initial-data="$ctrl.item.expence"> initial-data="$ctrl.item.expense">
</vn-autocomplete> </vn-autocomplete>
<vn-autocomplete vn-one <vn-autocomplete vn-one
url="Origins" url="Origins"

View File

@ -4,5 +4,5 @@ Full name calculates based on tags 1-3. Is not recommended to change it manually
basado en los tags 1-3. basado en los tags 1-3.
No se recomienda cambiarlo manualmente No se recomienda cambiarlo manualmente
Is active: Activo Is active: Activo
Expence: Gasto Expense: Gasto
Price in kg: Precio en kg Price in kg: Precio en kg

View File

@ -60,8 +60,8 @@
<vn-label-value label="Compression" <vn-label-value label="Compression"
value="{{$ctrl.summary.item.compression}}"> value="{{$ctrl.summary.item.compression}}">
</vn-label-value> </vn-label-value>
<vn-label-value label="Expence" <vn-label-value label="Expense"
value="{{$ctrl.summary.item.expence.name}}"> value="{{$ctrl.summary.item.expense.name}}">
</vn-label-value> </vn-label-value>
</vn-one> </vn-one>
<vn-one name="tags"> <vn-one name="tags">

View File

@ -14,6 +14,20 @@
"name": { "name": {
"type": "String", "type": "String",
"required": true "required": true
},
"expenseFk": {
"type": "Number",
"required": true,
"mysql": {
"columnName": "expenceFk"
}
}
},
"relations": {
"expenditure": {
"type": "belongsTo",
"model": "Expense",
"foreignKey": "expenseFk"
} }
} }
} }

View File

@ -12,6 +12,11 @@ module.exports = Self => {
let isEditable = await models.Ticket.isEditable(httpCtx, ticketId); let isEditable = await models.Ticket.isEditable(httpCtx, ticketId);
if (!isEditable) if (!isEditable)
throw new UserError(`The current ticket can't be modified`); throw new UserError(`The current ticket can't be modified`);
if (changes.ticketServiceTypeFk) {
const ticketServiceType = await models.TicketServiceType.findById(changes.ticketServiceTypeFk);
changes.description = ticketServiceType.name;
}
} }
}); });

View File

@ -36,6 +36,10 @@
"taxClassFk": { "taxClassFk": {
"type": "Number", "type": "Number",
"required": true "required": true
},
"ticketServiceTypeFk": {
"type": "Number",
"required": true
} }
}, },
"relations": { "relations": {
@ -48,6 +52,11 @@
"type": "belongsTo", "type": "belongsTo",
"model": "Ticket", "model": "Ticket",
"foreignKey": "ticketFk" "foreignKey": "ticketFk"
},
"ticketService": {
"type": "belongsTo",
"model": "TicketServiceType",
"foreignKey": "ticketServiceTypeFk"
} }
} }
} }

View File

@ -12,14 +12,12 @@
<form name="form" ng-submit="$ctrl.onSubmit()" class="vn-w-md"> <form name="form" ng-submit="$ctrl.onSubmit()" class="vn-w-md">
<vn-card class="vn-pa-lg"> <vn-card class="vn-pa-lg">
<vn-horizontal ng-repeat="service in $ctrl.services track by $index"> <vn-horizontal ng-repeat="service in $ctrl.services track by $index">
<vn-autocomplete <vn-autocomplete vn-two vn-focus
vn-one
vn-focus
url="TicketServiceTypes" url="TicketServiceTypes"
label="Description" label="Description"
show-field="name" show-field="name"
value-field="name" value-field="id"
ng-model="service.description"> ng-model="service.ticketServiceTypeFk">
<append> <append>
<vn-icon-button <vn-icon-button
icon="add_circle" icon="add_circle"
@ -87,6 +85,15 @@
vn-focus> vn-focus>
</vn-textfield> </vn-textfield>
</vn-horizontal> </vn-horizontal>
<vn-horizontal>
<vn-autocomplete vn-one vn-focus
url="Expenses"
label="Expense"
show-field="name"
value-field="id"
ng-model="$ctrl.newServiceType.expenseFk">
</vn-autocomplete>
</vn-horizontal>
</tpl-body> </tpl-body>
<tpl-buttons> <tpl-buttons>
<input type="button" response="cancel" translate-attr="{value: 'Cancel'}"/> <input type="button" response="cancel" translate-attr="{value: 'Cancel'}"/>

View File

@ -50,7 +50,7 @@ class Controller {
throw new UserError(`Name can't be empty`); throw new UserError(`Name can't be empty`);
this.$http.post(`TicketServiceTypes`, this.newServiceType).then(response => { this.$http.post(`TicketServiceTypes`, this.newServiceType).then(response => {
this.services[this.currentServiceIndex].description = response.data.name; this.services[this.currentServiceIndex].ticketServiceTypeFk = response.data.id;
}); });
} }
} }

View File

@ -54,11 +54,11 @@ describe('Ticket component vnTicketService', () => {
controller.newServiceType = {name: 'totally new stuff'}; controller.newServiceType = {name: 'totally new stuff'};
controller.currentServiceIndex = 0; controller.currentServiceIndex = 0;
$httpBackend.when('POST', 'TicketServiceTypes').respond({id: 4001, name: 'great service!'}); $httpBackend.when('POST', 'TicketServiceTypes').respond({id: 4001, name: 'totally new stuff'});
controller.onNewServiceTypeResponse('accept'); controller.onNewServiceTypeResponse('accept');
$httpBackend.flush(); $httpBackend.flush();
expect(controller.services[0].description).toEqual('great service!'); expect(controller.services[0].ticketServiceTypeFk).toEqual(4001);
}); });
}); });
}); });