Merge pull request '2391 - Editable description(done) + e2e' (#359) from 2391-client_balance_description into dev
gitea/salix/pipeline/head This commit looks good Details

Reviewed-on: #359
Reviewed-by: Carlos Jimenez <carlosjr@verdnatura.es>
This commit is contained in:
Carlos Jimenez Ruiz 2020-08-31 13:05:12 +00:00
commit f797fdce94
14 changed files with 268 additions and 70 deletions

View File

@ -2,6 +2,9 @@
"Account": { "Account": {
"dataSource": "vn" "dataSource": "vn"
}, },
"AccountingType": {
"dataSource": "vn"
},
"Bank": { "Bank": {
"dataSource": "vn" "dataSource": "vn"
}, },

View File

@ -0,0 +1,30 @@
{
"name": "AccountingType",
"base": "VnModel",
"options": {
"mysql": {
"table": "accountingType"
}
},
"properties": {
"id": {
"type": "Number",
"id": true,
"description": "Identifier"
},
"description": {
"type": "String",
"required": true
},
"receiptDescription": {
"type": "String",
"required": true
}
},
"acls": [{
"accessType": "READ",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW"
}]
}

View File

@ -2,39 +2,49 @@
"name": "Bank", "name": "Bank",
"base": "VnModel", "base": "VnModel",
"options": { "options": {
"mysql": { "mysql": {
"table": "bank" "table": "bank"
} }
}, },
"properties": { "properties": {
"id": { "id": {
"type": "Number", "type": "Number",
"id": true, "id": true,
"description": "Identifier" "description": "Identifier"
}, },
"bank": { "bank": {
"type": "string", "type": "String",
"required": true "required": true
}, },
"account": { "account": {
"type": "string", "type": "String",
"required": true "required": true
}, },
"cash": { "accountingTypeFk": {
"type": "string", "type": "Number",
"required": true "required": true,
}, "mysql": {
"entityFk": { "columnName": "cash"
"type": "string", }
"required": true },
}, "entityFk": {
"isActive": { "type": "Number",
"type": "string", "required": true
"required": true },
}, "isActive": {
"currencyFk": { "type": "Boolean",
"type": "string", "required": true
"required": true },
} "currencyFk": {
"type": "Number",
"required": true
}
},
"relations": {
"accountingType": {
"type": "belongsTo",
"model": "AccountingType",
"foreignKey": "accountingTypeFk"
}
} }
} }

View File

@ -0,0 +1,2 @@
ALTER TABLE `vn`.`accountingType`
ADD COLUMN `receiptDescription` VARCHAR(50) NULL AFTER `description`;

View File

@ -116,13 +116,13 @@ INSERT INTO `vn`.`shelving` (`code`, `parkingFk`, `isPrinted`, `priority`, `park
('GVC', '1', '0', '1', '0', '106'), ('GVC', '1', '0', '1', '0', '106'),
('HEJ', '2', '0', '1', '0', '106'); ('HEJ', '2', '0', '1', '0', '106');
INSERT INTO `vn`.`accountingType`(`id`, `description`) INSERT INTO `vn`.`accountingType`(`id`, `description`, `receiptDescription`)
VALUES VALUES
(1, 'Digital money'), (1, 'Digital money', ''),
(2, 'Cash'), (2, 'Cash', 'Cash'),
(3, 'Card'), (3, 'Card', 'Pay on receipt'),
(4, 'Stolen Money'), (4, 'Stolen Money', ''),
(5, 'Miscellaneous'); (5, 'Miscellaneous', '');
INSERT INTO `vn`.`currency`(`id`, `code`, `name`, `ratio`) INSERT INTO `vn`.`currency`(`id`, `code`, `name`, `ratio`)
VALUES VALUES
@ -133,8 +133,8 @@ INSERT INTO `vn`.`currency`(`id`, `code`, `name`, `ratio`)
INSERT INTO `vn`.`bank`(`id`, `bank`, `account`, `cash`, `entityFk`, `isActive`, `currencyFk`) INSERT INTO `vn`.`bank`(`id`, `bank`, `account`, `cash`, `entityFk`, `isActive`, `currencyFk`)
VALUES VALUES
(1, 'Pay on receipt', '0000000000', 4, 0, 1, 1), (1, 'Pay on receipt', '0000000000', 3, 0, 1, 1),
(2, 'Cash', '1111111111', 1, 0, 1, 1); (2, 'Cash', '1111111111', 2, 0, 1, 1);
INSERT INTO `vn`.`deliveryMethod`(`id`, `code`, `description`) INSERT INTO `vn`.`deliveryMethod`(`id`, `code`, `description`)
VALUES VALUES

View File

@ -189,8 +189,9 @@ export default {
newPaymentBank: '.vn-dialog.shown vn-autocomplete[ng-model="$ctrl.receipt.bankFk"]', newPaymentBank: '.vn-dialog.shown vn-autocomplete[ng-model="$ctrl.receipt.bankFk"]',
newPaymentAmount: '.vn-dialog.shown vn-input-number[ng-model="$ctrl.receipt.amountPaid"]', newPaymentAmount: '.vn-dialog.shown vn-input-number[ng-model="$ctrl.receipt.amountPaid"]',
saveButton: '.vn-dialog.shown [response="accept"]', saveButton: '.vn-dialog.shown [response="accept"]',
firstBalanceLine: 'vn-client-balance-index vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(8)' firstLineBalance: 'vn-client-balance-index vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(8)',
firstLineReference: 'vn-client-balance-index vn-tbody > vn-tr:nth-child(1) > vn-td-editable',
firstLineReferenceInput: 'vn-client-balance-index vn-tbody > vn-tr:nth-child(1) > vn-td-editable > div > field > vn-textfield'
}, },
webPayment: { webPayment: {
confirmFirstPaymentButton: 'vn-client-web-payment vn-tr:nth-child(1) vn-icon-button[icon="done_all"]', confirmFirstPaymentButton: 'vn-client-web-payment vn-tr:nth-child(1) vn-icon-button[icon="done_all"]',

View File

@ -53,15 +53,28 @@ describe('Client balance path', () => {
expect(message.type).toBe('success'); expect(message.type).toBe('success');
}); });
it('should check balance is now 0 and the company is now VNL becouse the user local settings were removed', async() => { it('should edit the 1st line reference', async() => {
await page.waitToClick(selectors.clientBalance.firstLineReference);
await page.write(selectors.clientBalance.firstLineReferenceInput, 'Miscellaneous payment');
await page.keyboard.press('Enter');
const message = await page.waitForSnackbar();
expect(message.type).toBe('success');
});
it('should check balance is now 0, the reference was saved and the company is now VNL becouse the user local settings were removed', async() => {
await page.waitForSpinnerLoad(); await page.waitForSpinnerLoad();
let company = await page let company = await page
.waitToGetProperty(selectors.clientBalance.company, 'value'); .waitToGetProperty(selectors.clientBalance.company, 'value');
let reference = await page
.waitToGetProperty(selectors.clientBalance.firstLineReference, 'innerText');
let firstBalanceLine = await page let firstBalanceLine = await page
.waitToGetProperty(selectors.clientBalance.firstBalanceLine, 'innerText'); .waitToGetProperty(selectors.clientBalance.firstLineBalance, 'innerText');
expect(company).toEqual('VNL'); expect(company).toEqual('VNL');
expect(reference).toEqual('Miscellaneous payment');
expect(firstBalanceLine).toContain('0.00'); expect(firstBalanceLine).toContain('0.00');
}); });
@ -76,7 +89,7 @@ describe('Client balance path', () => {
it('should check balance is now -100', async() => { it('should check balance is now -100', async() => {
let result = await page let result = await page
.waitToGetProperty(selectors.clientBalance.firstBalanceLine, 'innerText'); .waitToGetProperty(selectors.clientBalance.firstLineBalance, 'innerText');
expect(result).toContain('-€100.00'); expect(result).toContain('-€100.00');
}); });
@ -92,7 +105,7 @@ describe('Client balance path', () => {
it('should check balance is now 50', async() => { it('should check balance is now 50', async() => {
let result = await page let result = await page
.waitToGetProperty(selectors.clientBalance.firstBalanceLine, 'innerText'); .waitToGetProperty(selectors.clientBalance.firstLineBalance, 'innerText');
expect(result).toEqual('€50.00'); expect(result).toEqual('€50.00');
}); });

View File

@ -42,11 +42,11 @@ module.exports = Self => {
r.workerFk, r.workerFk,
c.code company, c.code company,
r.created, r.created,
r.invoiceFk ref, r.invoiceFk description,
NULL debit, NULL debit,
r.amountPaid credit, r.amountPaid credit,
r.bankFk, r.bankFk,
u.nickname userNickname, u.name userName,
r.clientFk, r.clientFk,
FALSE hasPdf, FALSE hasPdf,
FALSE isInvoice FALSE isInvoice

View File

@ -17,11 +17,17 @@
</vn-horizontal> </vn-horizontal>
<vn-horizontal> <vn-horizontal>
<vn-autocomplete <vn-autocomplete
url="Banks"
label="Bank" label="Bank"
url="Banks"
show-field="bank" show-field="bank"
value-field="id" value-field="id"
ng-model="$ctrl.receipt.bankFk"> fields="['accountingTypeFk']"
include="{relation: 'accountingType'}"
order="id"
ng-model="$ctrl.receipt.bankFk"
search-function="{or: [{id: $search}, {bank: {like: '%'+ $search +'%'}}]}"
selection="$ctrl.bankSelection">
<tpl-item>{{id}}: {{bank}}</tpl-item>
</vn-autocomplete> </vn-autocomplete>
<vn-input-number <vn-input-number
vn-focus vn-focus
@ -31,6 +37,13 @@
rule> rule>
</vn-input-number> </vn-input-number>
</vn-horizontal> </vn-horizontal>
<vn-horizontal>
<vn-textfield
label="Reference"
ng-model="$ctrl.receipt.description"
rule>
</vn-textfield>
</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,6 +50,19 @@ class Controller extends Dialog {
return this.receipt.description; return this.receipt.description;
} }
get bankSelection() {
return this._bankSelection;
}
set bankSelection(value) {
this._bankSelection = value;
if (value) {
const accountingType = value.accountingType;
this.receipt.description = accountingType && accountingType.receiptDescription;
}
}
getAmountPaid() { getAmountPaid() {
const filter = { const filter = {
where: { where: {

View File

@ -0,0 +1,76 @@
import './index';
describe('Client', () => {
describe('Component vnClientBalancCreate', () => {
let controller;
let $httpBackend;
let $httpParamSerializer;
beforeEach(ngModule('client'));
beforeEach(inject(($componentController, $rootScope, _$httpBackend_, _$httpParamSerializer_) => {
$httpBackend = _$httpBackend_;
$httpParamSerializer = _$httpParamSerializer_;
let $scope = $rootScope.$new();
const $element = angular.element('<vn-client-balance-create></vn-client-balance-create>');
const $transclude = {
$$boundTransclude: {
$$slots: []
}
};
controller = $componentController('vnClientBalanceCreate', {$element, $scope, $transclude});
controller.receipt = {
clientFk: 101,
companyFk: 442
};
}));
describe('bankSelection() setter', () => {
it('should set the receipt description property', () => {
controller.bankSelection = {
id: 1,
bank: 'Cash',
accountingType: {
id: 2,
receiptDescription: 'Cash'
}
};
expect(controller.receipt.description).toEqual('Cash');
});
});
describe('getAmountPaid()', () => {
it('should make an http GET query and then set the receipt amountPaid property', () => {
controller.$params = {id: 101};
const receipt = controller.receipt;
const filter = {
where: {
clientFk: 101,
companyFk: 442
}
};
const serializedParams = $httpParamSerializer({filter});
$httpBackend.expect('GET', `ClientRisks?${serializedParams}`,).respond([{amount: 20}]);
controller.getAmountPaid();
$httpBackend.flush();
expect(receipt.amountPaid).toEqual(20);
});
});
describe('responseHandler()', () => {
it('should make an http POST query and then call to the parent responseHandler() method', () => {
jest.spyOn(controller.vnApp, 'showSuccess');
controller.$params = {id: 101};
$httpBackend.expect('POST', `Receipts`,).respond({id: 1});
controller.responseHandler('accept');
$httpBackend.flush();
expect(controller.vnApp.showSuccess).toHaveBeenCalled();
});
});
});
});

View File

@ -68,25 +68,33 @@
<span <span
vn-click-stop="workerDescriptor.show($event, balance.workerFk)" vn-click-stop="workerDescriptor.show($event, balance.workerFk)"
class="link"> class="link">
{{::balance.userNickname}} {{::balance.userName}}
</span> </span>
</vn-td> </vn-td>
<vn-td expand> <vn-td-editable disabled="balance.isInvoice || !$ctrl.isAdministrative" expand>
<div ng-show="::balance.ref"> <text>
<span <div ng-show="::balance.description">
ng-if="balance.isInvoice" <span
title="{{'BILL' | translate: {ref: balance.ref} }}" ng-if="balance.isInvoice"
vn-click-stop="$ctrl.showInvoiceOutDescriptor($event, balance)" title="{{'BILL' | translate: {ref: balance.description} }}"
class="link"> vn-click-stop="$ctrl.showInvoiceOutDescriptor($event, balance)"
{{'BILL' | translate: {ref: balance.ref} }} class="link">
</span> {{'BILL' | translate: {ref: balance.description} }}
<span </span>
ng-if="!balance.isInvoice" <span
title="{{::balance.ref}}"> ng-if="!balance.isInvoice"
{{::balance.ref}} title="{{::balance.description}}">
</span> {{balance.description}}
</div> </span>
</vn-td> </div>
</text>
<field>
<vn-textfield vn-acl="administrative" class="dense" vn-focus
ng-model="balance.description"
on-change="$ctrl.changeDescription(balance)">
</vn-textfield>
</field>
</vn-td-editable>
<vn-td number>{{::balance.bankFk}}</vn-td> <vn-td number>{{::balance.bankFk}}</vn-td>
<vn-td number expand>{{::balance.debit | currency: 'EUR':2}}</vn-td> <vn-td number expand>{{::balance.debit | currency: 'EUR':2}}</vn-td>
<vn-td number expand>{{::balance.credit | currency: 'EUR':2}}</vn-td> <vn-td number expand>{{::balance.credit | currency: 'EUR':2}}</vn-td>

View File

@ -39,6 +39,10 @@ class Controller extends Section {
this.getBalances(); this.getBalances();
} }
get isAdministrative() {
return this.aclService.hasAny(['administrative']);
}
getData() { getData() {
return this.$.model.applyFilter(null, { return this.$.model.applyFilter(null, {
clientId: this.$params.id, clientId: this.$params.id,
@ -58,7 +62,7 @@ class Controller extends Section {
return balance.companyFk === selectedCompany; return balance.companyFk === selectedCompany;
}); });
return currentBalance.amount; return currentBalance && currentBalance.amount;
} }
getBalances() { getBalances() {
@ -79,6 +83,13 @@ class Controller extends Section {
this.$.invoiceOutDescriptor.show(event.target, balance.id); this.$.invoiceOutDescriptor.show(event.target, balance.id);
} }
changeDescription(balance) {
const params = {description: balance.description};
const endpoint = `Receipts/${balance.id}`;
this.$http.patch(endpoint, params)
.then(() => this.vnApp.showSuccess(this.$t('Data saved!')));
}
} }
Controller.$inject = ['$element', '$scope']; Controller.$inject = ['$element', '$scope'];

View File

@ -3,10 +3,12 @@ import './index';
describe('Client', () => { describe('Client', () => {
describe('Component vnClientBalanceIndex', () => { describe('Component vnClientBalanceIndex', () => {
let controller; let controller;
let $httpBackend;
beforeEach(ngModule('client')); beforeEach(ngModule('client'));
beforeEach(inject(($componentController, $rootScope) => { beforeEach(inject(($componentController, $rootScope, _$httpBackend_) => {
$httpBackend = _$httpBackend_;
let $scope = $rootScope.$new(); let $scope = $rootScope.$new();
const $element = angular.element('<vn-client-balance-index></vn-client-balance-index>'); const $element = angular.element('<vn-client-balance-index></vn-client-balance-index>');
controller = $componentController('vnClientBalanceIndex', {$element, $scope}); controller = $componentController('vnClientBalanceIndex', {$element, $scope});
@ -133,5 +135,21 @@ describe('Client', () => {
expect(controller.getBalances).toHaveBeenCalledWith(); expect(controller.getBalances).toHaveBeenCalledWith();
}); });
}); });
describe('changeDescription()', () => {
it('should make an http PATCH query', () => {
const expectedParams = {description: 'Web'};
$httpBackend.expect('PATCH', `Receipts/1`, expectedParams).respond(200);
controller.changeDescription({
id: 1,
description: 'Web',
accountingType: {
description: 'Cash'
}
});
$httpBackend.flush();
});
});
}); });
}); });