fixes #4547 check compensation and tests #1161

Merged
alexandre merged 6 commits from 4547-fix-compensation into dev 2022-11-24 08:48:42 +00:00
12 changed files with 106 additions and 33 deletions

View File

@ -0,0 +1,4 @@
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
VALUES
('Receipt', 'balanceCompensationEmail', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
('Receipt', 'balanceCompensationPdf', 'READ', 'ALLOW', 'ROLE', 'employee');

View File

@ -1859,7 +1859,8 @@ INSERT INTO `vn`.`receipt`(`id`, `invoiceFk`, `amountPaid`, `payed`, `workerFk`,
(1, 'Cobro web', 100.50, util.VN_CURDATE(), 9, 1, 1101, util.VN_CURDATE(), 442, 1), (1, 'Cobro web', 100.50, util.VN_CURDATE(), 9, 1, 1101, util.VN_CURDATE(), 442, 1),
(2, 'Cobro web', 200.50, DATE_ADD(util.VN_CURDATE(), INTERVAL -5 DAY), 9, 1, 1101, DATE_ADD(util.VN_CURDATE(), INTERVAL -5 DAY), 442, 1), (2, 'Cobro web', 200.50, DATE_ADD(util.VN_CURDATE(), INTERVAL -5 DAY), 9, 1, 1101, DATE_ADD(util.VN_CURDATE(), INTERVAL -5 DAY), 442, 1),
(3, 'Cobro en efectivo', 300.00, DATE_ADD(util.VN_CURDATE(), INTERVAL -10 DAY), 9, 1, 1102, DATE_ADD(util.VN_CURDATE(), INTERVAL -10 DAY), 442, 0), (3, 'Cobro en efectivo', 300.00, DATE_ADD(util.VN_CURDATE(), INTERVAL -10 DAY), 9, 1, 1102, DATE_ADD(util.VN_CURDATE(), INTERVAL -10 DAY), 442, 0),
(4, 'Cobro en efectivo', 400.00, DATE_ADD(util.VN_CURDATE(), INTERVAL -15 DAY), 9, 1, 1103, DATE_ADD(util.VN_CURDATE(), INTERVAL -15 DAY), 442, 0); (4, 'Cobro en efectivo', 400.00, DATE_ADD(util.VN_CURDATE(), INTERVAL -15 DAY), 9, 1, 1103, DATE_ADD(util.VN_CURDATE(), INTERVAL -15 DAY), 442, 0),
(5, 'Compensación', 400.00, DATE_ADD(util.VN_CURDATE(), INTERVAL -15 DAY), 9, 3, 1103, DATE_ADD(util.VN_CURDATE(), INTERVAL -15 DAY), 442, 0);
INSERT INTO `vn`.`workerTeam`(`id`, `team`, `workerFk`) INSERT INTO `vn`.`workerTeam`(`id`, `team`, `workerFk`)
VALUES VALUES

View File

@ -324,7 +324,8 @@ export default {
anyBalanceLine: 'vn-client-balance-index vn-tbody > vn-tr', anyBalanceLine: 'vn-client-balance-index vn-tbody > vn-tr',
firstLineBalance: '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', 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' firstLineReferenceInput: 'vn-client-balance-index vn-tbody > vn-tr:nth-child(1) > vn-td-editable > div > field > vn-textfield',
compensationButton: 'vn-client-balance-index vn-icon-button[vn-dialog="send_compensation"]'
}, },
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

@ -0,0 +1,27 @@
import selectors from '../../helpers/selectors';
import getBrowser from '../../helpers/puppeteer';
describe('Client Send balance compensation', () => {
let browser;
let page;
beforeAll(async() => {
browser = await getBrowser();
page = browser.page;
await page.loginAndModule('employee', 'client');
await page.accessToSearchResult('Clark Kent');
await page.accessToSection('client.card.balance.index');
});
afterAll(async() => {
await browser.close();
});
it(`should click on send compensation button`, async() => {
await page.autocompleteSearch(selectors.clientBalance.company, 'VNL');
await page.waitToClick(selectors.clientBalance.compensationButton);
await page.waitToClick(selectors.clientBalance.saveButton);
const message = await page.waitForSnackbar();
expect(message.text).toContain('Notification sent!');
});
});

View File

@ -138,5 +138,8 @@
"You don't have grant privilege": "You don't have grant privilege", "You don't have grant privilege": "You don't have grant privilege",
"You don't own the role and you can't assign it to another user": "You don't own the role and you can't assign it to another user", "You don't own the role and you can't assign it to another user": "You don't own the role and you can't assign it to another user",
"Ticket merged": "Ticket [{{id}}]({{{fullPath}}}) ({{{originDated}}}) merged with [{{tfId}}]({{{fullPathFuture}}}) ({{{futureDated}}})", "Ticket merged": "Ticket [{{id}}]({{{fullPath}}}) ({{{originDated}}}) merged with [{{tfId}}]({{{fullPathFuture}}}) ({{{futureDated}}})",
"Sale(s) blocked, please contact production": "Sale(s) blocked, please contact production" "Sale(s) blocked, please contact production": "Sale(s) blocked, please contact production",
"Receipt's bank was not found": "Receipt's bank was not found",
"This receipt was not compensated": "This receipt was not compensated",
"Client's email was not found": "Client's email was not found"
} }

View File

@ -244,5 +244,8 @@
"Ticket merged": "Ticket [{{id}}]({{{fullPath}}}) ({{{originDated}}}) fusionado con [{{tfId}}]({{{fullPathFuture}}}) ({{{futureDated}}})", "Ticket merged": "Ticket [{{id}}]({{{fullPath}}}) ({{{originDated}}}) fusionado con [{{tfId}}]({{{fullPathFuture}}}) ({{{futureDated}}})",
"Already has this status": "Ya tiene este estado", "Already has this status": "Ya tiene este estado",
"There aren't records for this week": "No existen registros para esta semana", "There aren't records for this week": "No existen registros para esta semana",
"Empty data source": "Origen de datos vacio" "Empty data source": "Origen de datos vacio",
"Receipt's bank was not found": "No se encontró el banco del recibo",
"This receipt was not compensated": "Este recibo no ha sido compensado",
"Client's email was not found": "No se encontró el email del cliente"
} }

View File

@ -1,4 +1,5 @@
const {Email} = require('vn-print'); const {Email} = require('vn-print');
const UserError = require('vn-loopback/util/user-error');
module.exports = Self => { module.exports = Self => {
Self.remoteMethodCtx('balanceCompensationEmail', { Self.remoteMethodCtx('balanceCompensationEmail', {
@ -10,7 +11,7 @@ module.exports = Self => {
type: 'Number', type: 'Number',
required: true, required: true,
description: 'The receipt id', description: 'The receipt id',
http: { source: 'path' } http: {source: 'path'}
} }
], ],
returns: { returns: {
@ -23,18 +24,29 @@ module.exports = Self => {
} }
}); });
Self.balanceCompensationEmail = async (ctx, id) => { Self.balanceCompensationEmail = async(ctx, id) => {
const models = Self.app.models; const models = Self.app.models;
const receipt = await models.Receipt.findById(id, {fields: ['clientFk']}); const receipt = await models.Receipt.findById(id, {fields: ['clientFk', 'bankFk']});
const client = await models.Client.findById(receipt.clientFk, {fields:['email']});
const email = new Email('balance-compensation', { const bank = await models.Bank.findById(receipt.bankFk);
Outdated
Review

No es necesario el null si no se le pasa el tercer argumento.

No es necesario el null si no se le pasa el tercer argumento.
lang: ctx.req.getLocale(), if (!bank)
recipient: client.email+',administracion@verdnatura.es', throw new UserError(`Receipt's bank was not found`);
Outdated
Review

Para evitar escapar las comillas se puede poner la cadena entre template strings

Receipt's bank was not found

Para evitar escapar las comillas se puede poner la cadena entre template strings Receipt's bank was not found
id
});
return email.send(); const accountingType = await models.AccountingType.findById(bank.accountingTypeFk);
if (!(accountingType && accountingType.code == 'compensation'))
throw new UserError(`This receipt was not compensated`);
Outdated
Review

This receipt was not compensated?

This receipt was not compensated?
const client = await models.Client.findById(receipt.clientFk, {fields: ['email']});
if (!client.email)
throw new UserError(`Client's email was not found`);
Outdated
Review

Faltan las traducciones en la carpeta loopback

Faltan las traducciones en la carpeta loopback
else {
const email = new Email('balance-compensation', {
lang: ctx.req.getLocale(),
recipient: client.email + ',administracion@verdnatura.es',
id
});
return email.send();
}
}; };
}; };

View File

@ -42,7 +42,7 @@ module.exports = Self => {
const stmt = new ParameterizedSQL( const stmt = new ParameterizedSQL(
`SELECT * FROM ( `SELECT * FROM (
SELECT SELECT
r.id, r.id,
r.isConciliate, r.isConciliate,
r.payed, r.payed,
@ -56,13 +56,16 @@ module.exports = Self => {
u.name userName, u.name userName,
r.clientFk, r.clientFk,
FALSE hasPdf, FALSE hasPdf,
FALSE isInvoice FALSE isInvoice,
CASE WHEN at2.code LIKE 'compensation' THEN True ELSE False END as isCompensation
FROM vn.receipt r FROM vn.receipt r
LEFT JOIN vn.worker w ON w.id = r.workerFk LEFT JOIN vn.worker w ON w.id = r.workerFk
LEFT JOIN account.user u ON u.id = w.userFk LEFT JOIN account.user u ON u.id = w.userFk
JOIN vn.company c ON c.id = r.companyFk JOIN vn.company c ON c.id = r.companyFk
JOIN vn.accounting a ON a.id = r.bankFk
JOIN vn.accountingType at2 ON at2.id = a.accountingTypeFk
WHERE r.clientFk = ? AND r.companyFk = ? WHERE r.clientFk = ? AND r.companyFk = ?
UNION ALL UNION ALL
SELECT SELECT
i.id, i.id,
TRUE, TRUE,
@ -77,9 +80,12 @@ module.exports = Self => {
NULL, NULL,
i.clientFk, i.clientFk,
i.hasPdf, i.hasPdf,
TRUE isInvoice TRUE isInvoice,
CASE WHEN at2.code LIKE 'compensation' THEN True ELSE False END as isCompensation
FROM vn.invoiceOut i FROM vn.invoiceOut i
JOIN vn.company c ON c.id = i.companyFk JOIN vn.company c ON c.id = i.companyFk
JOIN vn.accounting a ON a.id = i.bankFk
JOIN vn.accountingType at2 ON at2.id = a.accountingTypeFk
WHERE i.clientFk = ? AND i.companyFk = ? WHERE i.clientFk = ? AND i.companyFk = ?
ORDER BY payed DESC, created DESC ORDER BY payed DESC, created DESC
) t ORDER BY payed DESC, created DESC`, ) t ORDER BY payed DESC, created DESC`,

View File

@ -121,7 +121,7 @@
</vn-icon-button> </vn-icon-button>
</a> </a>
</vn-td> </vn-td>
<vn-td center shrink ng-if="!balance.isInvoice"> <vn-td center shrink ng-if="balance.isCompensation">
<vn-icon-button <vn-icon-button
vn-dialog="send_compensation" vn-dialog="send_compensation"
icon="outgoing_mail" icon="outgoing_mail"
@ -144,7 +144,7 @@
vn-acl="salesAssistant" vn-acl="salesAssistant"
vn-acl-action="remove" vn-acl-action="remove"
icon="add" icon="add"
vn-tooltip="New payment" vn-tooltip="New payment"
vn-bind="+" vn-bind="+"
fixed-bottom-right fixed-bottom-right
ng-click="balanceCreate.show()"> ng-click="balanceCreate.show()">
@ -155,9 +155,9 @@
company-fk="$ctrl.companyId" company-fk="$ctrl.companyId"
client-fk="$ctrl.$params.id"> client-fk="$ctrl.$params.id">
</vn-client-balance-create> </vn-client-balance-create>
<vn-worker-descriptor-popover <vn-worker-descriptor-popover
vn-id="workerDescriptor"> vn-id="workerDescriptor">
</vn-worker-descriptor-popover> </vn-worker-descriptor-popover>
<vn-invoice-out-descriptor-popover <vn-invoice-out-descriptor-popover
vn-id="invoiceOutDescriptor"> vn-id="invoiceOutDescriptor">
</vn-invoice-out-descriptor-popover> </vn-invoice-out-descriptor-popover>

View File

@ -55,41 +55,41 @@ class Controller extends Section {
} }
})).then(() => this.getBalances()); })).then(() => this.getBalances());
} }
getCurrentBalance() { getCurrentBalance() {
const clientRisks = this.$.riskModel.data; const clientRisks = this.$.riskModel.data;
const selectedCompany = this.companyId; const selectedCompany = this.companyId;
const currentBalance = clientRisks.find(balance => { const currentBalance = clientRisks.find(balance => {
return balance.companyFk === selectedCompany; return balance.companyFk === selectedCompany;
}); });
return currentBalance && currentBalance.amount; return currentBalance && currentBalance.amount;
} }
getBalances() { getBalances() {
const balances = this.$.model.data; const balances = this.$.model.data;
balances.forEach((balance, index) => { balances.forEach((balance, index) => {
if (index === 0) if (index === 0)
balance.balance = this.getCurrentBalance(); balance.balance = this.getCurrentBalance();
if (index > 0) { if (index > 0) {
let previousBalance = balances[index - 1]; let previousBalance = balances[index - 1];
balance.balance = previousBalance.balance - (previousBalance.debit - previousBalance.credit); balance.balance = previousBalance.balance - (previousBalance.debit - previousBalance.credit);
} }
}); });
} }
showInvoiceOutDescriptor(event, balance) { showInvoiceOutDescriptor(event, balance) {
if (!balance.isInvoice) return; if (!balance.isInvoice) return;
if (event.defaultPrevented) return; if (event.defaultPrevented) return;
this.$.invoiceOutDescriptor.show(event.target, balance.id); this.$.invoiceOutDescriptor.show(event.target, balance.id);
} }
changeDescription(balance) { changeDescription(balance) {
const params = {description: balance.description}; const params = {description: balance.description};
const endpoint = `Receipts/${balance.id}`; const endpoint = `Receipts/${balance.id}`;
this.$http.patch(endpoint, params) this.$http.patch(endpoint, params)
.then(() => this.vnApp.showSuccess(this.$t('Data saved!'))); .then(() => this.vnApp.showSuccess(this.$t('Data saved!')));
} }
sendEmail(balance) { sendEmail(balance) {

View File

@ -151,5 +151,19 @@ describe('Client', () => {
$httpBackend.flush(); $httpBackend.flush();
}); });
}); });
describe('sendEmail()', () => {
it('should send an email', () => {
jest.spyOn(controller.vnEmail, 'send');
const $data = {id: 1103};
controller.sendEmail($data);
const expectedPath = `Receipts/${$data.id}/balance-compensation-email`;
expect(controller.vnEmail.send).toHaveBeenCalledWith(expectedPath);
});
});
}); });
}); });

View File

@ -1 +1,3 @@
BILL: N/INV {{ref}} BILL: N/INV {{ref}}
Notify compensation: Do you want to report compensation to the client by mail?
Send compensation: Send compensation