const UserError = require('vn-loopback/util/user-error'); module.exports = Self => { Self.remoteMethodCtx('invoiceClient', { description: 'Make a invoice of a client', accessType: 'WRITE', accepts: [ { arg: 'clientId', type: 'number', description: 'The client id to invoice', required: true }, { arg: 'addressId', type: 'number', description: 'The address id to invoice', required: true }, { arg: 'invoiceDate', type: 'date', description: 'The invoice date', required: true }, { arg: 'maxShipped', type: 'date', description: 'The maximum shipped date', required: true }, { arg: 'companyFk', type: 'number', description: 'The company id to invoice', required: true }, { arg: 'printerFk', type: 'number', description: 'The printer to print', required: true } ], returns: { type: 'object', root: true }, http: { path: '/invoiceClient', verb: 'POST' } }); Self.invoiceClient = async(ctx, options) => { const args = ctx.args; const models = Self.app.models; const myOptions = {}; let tx; if (typeof options == 'object') Object.assign(myOptions, options); if (!myOptions.transaction) { tx = await Self.beginTransaction({}); myOptions.transaction = tx; } const minShipped = Date.vnNew(); minShipped.setFullYear(args.maxShipped.getFullYear() - 1); let invoiceId; let invoiceOut; try { const client = await models.Client.findById(args.clientId, { fields: ['id', 'hasToInvoiceByAddress'] }, myOptions); if (client.hasToInvoiceByAddress) { await Self.rawSql('CALL ticketToInvoiceByAddress(?, ?, ?, ?)', [ minShipped, args.maxShipped, args.addressId, args.companyFk ], myOptions); } else { await Self.rawSql('CALL invoiceFromClient(?, ?, ?)', [ args.maxShipped, client.id, args.companyFk ], myOptions); } // Make invoice const isSpanishCompany = await getIsSpanishCompany(args.companyFk, myOptions); // Validates ticket nagative base const hasAnyNegativeBase = await getNegativeBase(myOptions); if (hasAnyNegativeBase && isSpanishCompany) throw new UserError('Negative basis'); query = `SELECT invoiceSerial(?, ?, ?) AS serial`; const [invoiceSerial] = await Self.rawSql(query, [ client.id, args.companyFk, 'G' ], myOptions); const serialLetter = invoiceSerial.serial; query = `CALL invoiceOut_new(?, ?, NULL, @invoiceId)`; await Self.rawSql(query, [ serialLetter, args.invoiceDate ], myOptions); const [newInvoice] = await Self.rawSql(`SELECT @invoiceId id`, null, myOptions); if (newInvoice.id) { await Self.rawSql('CALL invoiceOutBooking(?)', [newInvoice.id], myOptions); invoiceOut = await models.InvoiceOut.findById(newInvoice.id, { include: { relation: 'client' } }, myOptions); invoiceId = newInvoice.id; } if (tx) await tx.commit(); } catch (e) { if (tx) await tx.rollback(); throw e; } if (invoiceId) { if (!invoiceOut.client().isToBeMailed) { const query = ` CALL vn.report_print( 'invoice', ?, account.myUser_getId(), JSON_OBJECT('refFk', ?), 'normal' );`; await models.InvoiceOut.rawSql(query, [args.printerFk, invoiceOut.ref]); } else { ctx.args = { reference: invoiceOut.ref, recipientId: invoiceOut.clientFk, recipient: invoiceOut.client().email }; await models.InvoiceOut.invoiceEmail(ctx, invoiceOut.ref); } } return invoiceId; }; async function getNegativeBase(options) { const models = Self.app.models; const query = 'SELECT hasAnyNegativeBase() AS base'; const [result] = await models.InvoiceOut.rawSql(query, null, options); return result && result.base; } async function getIsSpanishCompany(companyId, options) { const models = Self.app.models; const query = `SELECT COUNT(*) isSpanishCompany FROM supplier s JOIN country c ON c.id = s.countryFk AND c.code = 'ES' WHERE s.id = ?`; const [supplierCompany] = await models.InvoiceOut.rawSql(query, [ companyId ], options); return supplierCompany && supplierCompany.isSpanishCompany; } };