WIP: #7134 SupplierBalance #3173

Draft
jsegarra wants to merge 6 commits from 7134-supplierBalance into dev
5 changed files with 260 additions and 8 deletions

View File

@ -2629,9 +2629,9 @@ REPLACE INTO `vn`.`invoiceIn`(`id`, `serialNumber`,`serial`, `supplierFk`, `issu
(9, 1009, 'R', 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 1242, 0, 442, 1,util.VN_CURDATE()), (9, 1009, 'R', 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 1242, 0, 442, 1,util.VN_CURDATE()),
(10, 1010, 'R', 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 1243, 0, 442, 1,util.VN_CURDATE()); (10, 1010, 'R', 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 1243, 0, 442, 1,util.VN_CURDATE());
INSERT INTO `vn`.`invoiceInConfig` (`id`, `retentionRate`, `retentionName`, `sageFarmerWithholdingFk`, `daysAgo`) INSERT INTO `vn`.`invoiceInConfig` (`id`, `retentionRate`, `retentionName`, `sageFarmerWithholdingFk`, `daysAgo`, `balanceStartingDate`)
VALUES VALUES
(1, -2, '2% retention', 2, 45); (1, -2, '2% retention', 2, 45, '2000-01-01');
INSERT INTO `vn`.`invoiceInDueDay`(`invoiceInFk`, `dueDated`, `bankFk`, `amount`) INSERT INTO `vn`.`invoiceInDueDay`(`invoiceInFk`, `dueDated`, `bankFk`, `amount`)
VALUES VALUES
@ -4012,10 +4012,10 @@ INSERT INTO vn.routeAction (id, name, price, isMainlineDelivered) VALUES(1, 'Pin
INSERT INTO vn.routeComplement (id, dated, workerFk, price, routeActionFk) VALUES(1, util.VN_CURDATE(), 9, 50.00, 1); INSERT INTO vn.routeComplement (id, dated, workerFk, price, routeActionFk) VALUES(1, util.VN_CURDATE(), 9, 50.00, 1);
INSERT INTO srt.buffer (id, x, y, `size`, `length`, stateFk, typeFk, isActive, code, stratus, hasWorkerWaiting, reserve, routeFk, dayMinute, lastUnloaded, hasStrapper, typeDefaultFk, motors, editorFk) INSERT INTO srt.buffer (id, x, y, `size`, `length`, stateFk, typeFk, isActive, code, stratus, hasWorkerWaiting, reserve, routeFk, dayMinute, lastUnloaded, hasStrapper, typeDefaultFk, motors, editorFk)
VALUES (0, 0, 0, 0, NULL, 3, 1, 0, 'ENT', 0, 0, NULL, NULL, NULL, NULL, 0, 1, 1, NULL), VALUES (0, 0, 0, 0, NULL, 3, 1, 0, 'ENT', 0, 0, NULL, NULL, NULL, NULL, 0, 1, 1, NULL),
(1, 0, 9900, 0, NULL, 1, 0, 0, 'NOK', 0, 0, NULL, NULL, NULL, NULL, 0, 1, 1, NULL), (1, 0, 9900, 0, NULL, 1, 0, 0, 'NOK', 0, 0, NULL, NULL, NULL, NULL, 0, 1, 1, NULL),
(2, 0, 0, 450, 13000, 1, 0, 1, '01A', 1, 1, NULL, NULL, NULL, NULL, 0, 1, 1, NULL), (2, 0, 0, 450, 13000, 1, 0, 1, '01A', 1, 1, NULL, NULL, NULL, NULL, 0, 1, 1, NULL),
(3, 1400, 0, 450, 13000, 1, 0, 1, '01B', 1, 0, NULL, NULL, NULL, NULL, 0, 1, 1, NULL), (3, 1400, 0, 450, 13000, 1, 0, 1, '01B', 1, 0, NULL, NULL, NULL, NULL, 0, 1, 1, NULL),
(4, 0, 500, 500, 13000, 1, 4, 1, '02A', 2, 1, NULL, NULL, NULL, NULL, 1, 4, 13, NULL), (4, 0, 500, 500, 13000, 1, 4, 1, '02A', 2, 1, NULL, NULL, NULL, NULL, 1, 4, 13, NULL),
(5, 1400, 500, 500, 13000, 1, 4, 1, '02B', 2, 1, NULL, NULL, NULL, NULL, 1, 4, 13, NULL), (5, 1400, 500, 500, 13000, 1, 4, 1, '02B', 2, 1, NULL, NULL, NULL, NULL, 1, 4, 13, NULL),
@ -4026,9 +4026,13 @@ INSERT INTO srt.buffer (id, x, y, `size`, `length`, stateFk, typeFk, isActive, c
(10, 0, 2000, 500, 13000, 1, 1, 1, '05A', 5, 0, NULL, NULL, NULL, NULL, 0, 1, 1, NULL); (10, 0, 2000, 500, 13000, 1, 1, 1, '05A', 5, 0, NULL, NULL, NULL, NULL, 0, 1, 1, NULL);
INSERT IGNORE INTO vn.saySimpleCountry (countryFk, channel) INSERT IGNORE INTO vn.saySimpleCountry (countryFk, channel)
VALUES (19, '1169'), VALUES (19, '1169'),
(8, '1183'); (8, '1183');
INSERT IGNORE INTO vn.saySimpleConfig (url, defaultChannel) INSERT IGNORE INTO vn.saySimpleConfig (url, defaultChannel)
VALUES ('saysimle-url-mock', 1320); VALUES ('saysimle-url-mock', 1320);
INSERT INTO vn.payment (received,supplierFk,amount,currencyFk,divisa,bankFk,payMethodFk,bankingFees,concept,companyFk,created,isConciliated,dueDated,workerFk) VALUES
('2024-09-15',1,1000.00,1,NULL,1,1,0.0,'n/pago',442,'2024-11-20 13:06:02.000',1,'2024-09-15',9);

View File

@ -154,7 +154,7 @@ BEGIN
JOIN travel tr ON tr.id = e.travelFk JOIN travel tr ON tr.id = e.travelFk
JOIN currency c ON c.id = e.currencyFk JOIN currency c ON c.id = e.currencyFk
WHERE e.supplierFk = vSupplierFk WHERE e.supplierFk = vSupplierFk
AND tr.landed >= CURDATE() AND tr.landed >= util.VN_CURDATE()
AND e.invoiceInFk IS NULL AND e.invoiceInFk IS NULL
AND vHasEntries AND vHasEntries
ORDER BY (dated IS NULL AND NOT isBooked), ORDER BY (dated IS NULL AND NOT isBooked),

View File

@ -0,0 +1,173 @@
const UserError = require('vn-loopback/util/user-error');
// Insert payment
// divisa = solo en caso que la moneda sea distinta a €,
module.exports = function(Self) {
Self.remoteMethodCtx('createReceipt', {
description: 'Creates receipt and its compensation if necessary',
accessType: 'READ',
accepts: [{
arg: 'supplierFk',
type: 'number',
description: 'The supplier id',
http: {source: 'path'}
},
{
arg: 'received',
type: 'Date',
required: true
},
{
arg: 'dueDate',
type: 'Date',
required: true
},
{
arg: 'companyFk',
type: 'number',
required: true
},
{
arg: 'currencyFk',
type: 'number',
required: true
},
{
arg: 'bankFk',
type: 'number',
required: true
},
{
arg: 'payMethodFk',
type: 'number',
required: true
},
{
arg: 'amount',
type: 'number',
required: true
},
{
arg: 'concept',
type: 'string',
required: true
},
{
arg: 'divisa',
type: 'number'
},
{
arg: 'compensationAccount',
type: 'any'
}],
returns: {
root: true,
type: 'Object'
},
http: {
verb: 'post',
path: '/:supplierFk/createReceipt'
},
accessScopes: ['DEFAULT', 'read:multimedia']
});
Self.createReceipt = async(ctx, options) => {
const models = Self.app.models;
const args = ctx.args;
const date = Date.vnNew();
date.setHours(0, 0, 0, 0);
let tx;
const myOptions = {userId: ctx.req.accessToken.userId};
if (typeof options == 'object')
Object.assign(myOptions, options);
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
try {
delete args.ctx; // Remove unwanted properties
const originalSupplier = await models.Supplier.findById(args.supplierFk, null, myOptions);
const bank = await models.Accounting.findById(args.bankFk, null, myOptions);
const accountingType = await models.AccountingType.findById(bank.accountingTypeFk, null, myOptions);
if (accountingType.code == 'compensation') {
if (!args.compensationAccount)
throw new UserError('Compensation account is empty');
// Check compensation account exists
await models.Supplier.getClientOrSupplierReference(args.compensationAccount, myOptions);
await Self.rawSql(
`CALL vn.ledger_doCompensation(?, ?, ?, ?, ?, ?, ?)`,
[
date,
args.compensationAccount,
args.bankFk,
accountingType.receiptDescription + originalSupplier.accountingAccount,
args.amountPaid,
args.companyFk,
originalSupplier.accountingAccount
],
myOptions
);
} else if (accountingType.isAutoConciliated == true) {
const description =
`${originalSupplier.id} : ${originalSupplier.socialName} - ${accountingType.receiptDescription}`;
const [, [xdiarioNew]] = await Self.rawSql(
`CALL xdiario_new(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, @xdiarioNew);
SELECT @xdiarioNew ledger;`,
[
null,
date,
bank.account,
originalSupplier.accountingAccount,
description,
args.amountPaid,
0,
0,
'',
'',
null,
null,
false,
args.companyFk
],
myOptions
);
await Self.rawSql(
`CALL xdiario_new(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, @xdiarioNew);`,
[
xdiarioNew.ledger,
date,
originalSupplier.accountingAccount,
bank.account,
description,
0,
args.amountPaid,
0,
'',
'',
null,
null,
false,
args.companyFk
],
myOptions
);
}
const newReceipt = await models.Receipt.create(args, myOptions);
if (tx) await tx.commit();
return newReceipt;
} catch (e) {
if (tx) await tx.rollback();
throw e;
}
};
};

View File

@ -0,0 +1,73 @@
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
module.exports = Self => {
Self.remoteMethodCtx('receipts', {
description: 'Find all clients matched by the filter',
accessType: 'READ',
accepts: [
{
arg: 'supplierId',
type: 'number',
description: 'The supplier id',
},
{
arg: 'companyId',
type: 'number',
description: 'The company id',
},
{
arg: 'currencyFk',
type: 'number',
description: 'The currency',
default: 1,
},
{
arg: 'orderBy',
type: 'string',
description: 'The client fiscal id',
enum: ['issued', ' bookEntried', ' booked', ' dueDate'],
},
{
arg: 'isConciliated',
default: false,
type: 'boolean',
},
],
returns: {
type: ['object'],
root: true
},
http: {
path: `/receipts`,
verb: 'GET'
}
});
Self.receipts = async(ctx, filter, options) => {
const conn = Self.dataSource.connector;
const myOptions = {userId: ctx.req.accessToken.userId};
const args = ctx.args;
if (typeof options == 'object')
Object.assign(myOptions, options);
let stmts = [];
stmts.push(new ParameterizedSQL('CALL vn.supplier_statementWithEntries(?,?,?,?,?,?)', [
args.supplierId,
args.currencyFk ?? 1,
args.companyId,
args.orderBy ?? 'issued',
args.isConciliated ?? false,
false
]));
stmts.push(`
SELECT *
FROM tmp.supplierStatement`);
stmts.push(`DROP TEMPORARY TABLE tmp.supplierStatement`);
const sql = ParameterizedSQL.join(stmts, ';');
const results = await conn.executeStmt(sql);
const resultsIndex = stmts.length - 2;
const result = results[resultsIndex];
return result;
};
};

View File

@ -8,6 +8,8 @@ module.exports = Self => {
require('../methods/supplier/updateFiscalData')(Self); require('../methods/supplier/updateFiscalData')(Self);
require('../methods/supplier/consumption')(Self); require('../methods/supplier/consumption')(Self);
require('../methods/supplier/freeAgencies')(Self); require('../methods/supplier/freeAgencies')(Self);
require('../methods/supplier/createReceipt')(Self);
require('../methods/supplier/receipts')(Self);
require('../methods/supplier/campaignMetricsPdf')(Self); require('../methods/supplier/campaignMetricsPdf')(Self);
require('../methods/supplier/campaignMetricsEmail')(Self); require('../methods/supplier/campaignMetricsEmail')(Self);
require('../methods/supplier/newSupplier')(Self); require('../methods/supplier/newSupplier')(Self);