diff --git a/db/changes/10491-august/00-aclInvoiceOut.sql b/db/changes/10491-august/00-aclInvoiceOut.sql new file mode 100644 index 000000000..b129b7201 --- /dev/null +++ b/db/changes/10491-august/00-aclInvoiceOut.sql @@ -0,0 +1,3 @@ +INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) + VALUES + ('InvoiceOut', 'clientToInvoice', 'WRITE', 'ALLOW', 'ROLE', 'invoicing'); \ No newline at end of file diff --git a/modules/invoiceOut/back/methods/invoiceOut/clientToInvoice.js b/modules/invoiceOut/back/methods/invoiceOut/clientToInvoice.js new file mode 100644 index 000000000..16c999e73 --- /dev/null +++ b/modules/invoiceOut/back/methods/invoiceOut/clientToInvoice.js @@ -0,0 +1,173 @@ +module.exports = Self => { + Self.remoteMethodCtx('clientToInvoice', { + description: 'Get the clients to make global invoicing', + accessType: 'WRITE', + accepts: [ + { + arg: 'invoiceDate', + type: 'date', + description: 'The invoice date' + }, + { + arg: 'maxShipped', + type: 'date', + description: 'The maximum shipped date' + }, + { + arg: 'fromClientId', + type: 'number', + description: 'The minimum client id' + }, + { + arg: 'toClientId', + type: 'number', + description: 'The maximum client id', + required: false + }, + { + arg: 'companyFk', + type: 'number', + description: 'The company id to invoice' + } + ], + returns: { + type: 'object', + root: true + }, + http: { + path: '/clientToInvoice', + verb: 'POST' + } + }); + + Self.clientToInvoice = async(ctx, options) => { + const args = ctx.args; + let tx; + const myOptions = {}; + + if (typeof options == 'object') + Object.assign(myOptions, options); + + if (!myOptions.transaction) { + tx = await Self.beginTransaction({}); + myOptions.transaction = tx; + } + + const clientToInvoideIds = []; + let query; + try { + query = ` + SELECT MAX(issued) issued + FROM vn.invoiceOut io + JOIN vn.time t ON t.dated = io.issued + WHERE io.serial = 'A' + AND t.year = YEAR(?) + AND io.companyFk = ?`; + const [maxIssued] = await Self.rawSql(query, [ + args.invoiceDate, + args.companyFk + ], myOptions); + + const maxSerialDate = maxIssued.issued || args.invoiceDate; + if (args.invoiceDate < maxSerialDate) + args.invoiceDate = maxSerialDate; + + if (args.invoiceDate < args.maxShipped) + args.maxShipped = args.invoiceDate; + + const minShipped = new Date(); + minShipped.setFullYear(minShipped.getFullYear() - 1); + minShipped.setMonth(1); + minShipped.setDate(1); + minShipped.setHours(0, 0, 0, 0); + + // Packaging liquidation + const vIsAllInvoiceable = false; + const clientsWithPackaging = await getClientsWithPackaging(ctx, myOptions); + for (let client of clientsWithPackaging) { + await Self.rawSql('CALL packageInvoicing(?, ?, ?, ?, @newTicket)', [ + client.id, + args.invoiceDate, + args.companyFk, + vIsAllInvoiceable + ], myOptions); + } + + const invoiceableClients = await getInvoiceableClients(ctx, myOptions); + + if (!invoiceableClients.length) return; + + const clientToInvoiceIds = invoiceableClients.map(invoiceableClient => invoiceableClient.id); + const dataArr = new Set(clientToInvoiceIds); + const clientNotRepeatedIds = [...dataArr]; + + if (tx) await tx.commit(); + + console.log(invoiceableClients, clientToInvoiceIds, clientNotRepeatedIds); + return clientNotRepeatedIds; + } catch (e) { + if (tx) await tx.rollback(); + throw e; + } + }; + + async function getClientsWithPackaging(ctx, options) { + const models = Self.app.models; + const args = ctx.args; + const query = `SELECT DISTINCT clientFk AS id + FROM ticket t + JOIN ticketPackaging tp ON t.id = tp.ticketFk + JOIN client c ON c.id = t.clientFk + WHERE t.shipped BETWEEN '2017-11-21' AND ? + AND t.clientFk >= ? + AND (t.clientFk <= ? OR ? IS NULL) + AND c.isActive`; + return models.InvoiceOut.rawSql(query, [ + args.maxShipped, + args.fromClientId, + args.toClientId, + args.toClientId + ], options); + } + + async function getInvoiceableClients(ctx, options) { + const models = Self.app.models; + const args = ctx.args; + const minShipped = new Date(); + minShipped.setFullYear(minShipped.getFullYear() - 1); + + const query = `SELECT + c.id, + SUM(IFNULL + ( + s.quantity * + s.price * (100-s.discount)/100, + 0) + + IFNULL(ts.quantity * ts.price,0) + ) AS sumAmount, + c.hasToInvoiceByAddress, + c.email, + c.isToBeMailed, + a.id addressFk + FROM ticket t + LEFT JOIN sale s ON s.ticketFk = t.id + LEFT JOIN ticketService ts ON ts.ticketFk = t.id + JOIN address a ON a.id = t.addressFk + JOIN client c ON c.id = t.clientFk + WHERE ISNULL(t.refFk) AND c.id >= ? + AND (t.clientFk <= ? OR ? IS NULL) + AND t.shipped BETWEEN ? AND util.dayEnd(?) + AND t.companyFk = ? AND c.hasToInvoice + AND c.isTaxDataChecked AND c.isActive + GROUP BY c.id, IF(c.hasToInvoiceByAddress,a.id,TRUE) HAVING sumAmount > 0`; + + return models.InvoiceOut.rawSql(query, [ + args.fromClientId, + args.toClientId, + args.toClientId, + minShipped, + args.maxShipped, + args.companyFk + ], options); + } +}; diff --git a/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js b/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js index dae6a0c33..bee79746a 100644 --- a/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js +++ b/modules/invoiceOut/back/methods/invoiceOut/globalInvoicing.js @@ -1,35 +1,13 @@ module.exports = Self => { Self.remoteMethodCtx('globalInvoicing', { - description: 'Make a global invoice', + description: 'Make a global invoice of a client', accessType: 'WRITE', - accepts: [ - { - arg: 'invoiceDate', - type: 'date', - description: 'The invoice date' - }, - { - arg: 'maxShipped', - type: 'date', - description: 'The maximum shipped date' - }, - { - arg: 'fromClientId', - type: 'number', - description: 'The minimum client id' - }, - { - arg: 'toClientId', - type: 'number', - description: 'The maximum client id', - required: false - }, - { - arg: 'companyFk', - type: 'number', - description: 'The company id to invoice' - } - ], + accepts: [{ + arg: 'clientId', + type: 'number', + description: 'The client id to invoice', + required: true + }], returns: { type: 'object', root: true @@ -40,10 +18,10 @@ module.exports = Self => { } }); - Self.globalInvoicing = async(ctx, options) => { - const args = ctx.args; - let tx; + Self.globalInvoicing = async(ctx, clientId, options) => { + const models = Self.app.models; const myOptions = {}; + let tx; if (typeof options == 'object') Object.assign(myOptions, options); @@ -55,108 +33,65 @@ module.exports = Self => { const invoicesIds = []; const failedClients = []; - let query; try { - query = ` - SELECT MAX(issued) issued - FROM vn.invoiceOut io - JOIN vn.time t ON t.dated = io.issued - WHERE io.serial = 'A' - AND t.year = YEAR(?) - AND io.companyFk = ?`; - const [maxIssued] = await Self.rawSql(query, [ - args.invoiceDate, - args.companyFk - ], myOptions); - - const maxSerialDate = maxIssued.issued || args.invoiceDate; - if (args.invoiceDate < maxSerialDate) - args.invoiceDate = maxSerialDate; - - if (args.invoiceDate < args.maxShipped) - args.maxShipped = args.invoiceDate; - - const minShipped = new Date(); - minShipped.setFullYear(minShipped.getFullYear() - 1); - minShipped.setMonth(1); - minShipped.setDate(1); - minShipped.setHours(0, 0, 0, 0); - - // Packaging liquidation - const vIsAllInvoiceable = false; - const clientsWithPackaging = await getClientsWithPackaging(ctx, myOptions); - for (let client of clientsWithPackaging) { - await Self.rawSql('CALL packageInvoicing(?, ?, ?, ?, @newTicket)', [ - client.id, - args.invoiceDate, - args.companyFk, - vIsAllInvoiceable - ], myOptions); - } - - const invoiceableClients = await getInvoiceableClients(ctx, myOptions); - - if (!invoiceableClients.length) return; - - for (let client of invoiceableClients) { - try { - if (client.hasToInvoiceByAddress) { - await Self.rawSql('CALL ticketToInvoiceByAddress(?, ?, ?, ?)', [ - minShipped, - args.maxShipped, - client.addressFk, - 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) - continue; - - query = `SELECT invoiceSerial(?, ?, ?) AS serial`; - const [invoiceSerial] = await Self.rawSql(query, [ + const client = await models.Client.findById(clientId, { + fields: ['id', 'hasToInvoiceByAddress', 'addressFk'] + }, myOptions); + try { + if (client.hasToInvoiceByAddress) { + await Self.rawSql('CALL ticketToInvoiceByAddress(?, ?, ?, ?)', [ + minShipped, + args.maxShipped, + client.addressFk, + args.companyFk + ], myOptions); + } else { + await Self.rawSql('CALL invoiceFromClient(?, ?, ?)', [ + args.maxShipped, client.id, - args.companyFk, - 'G' + args.companyFk ], 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); - - query = `INSERT IGNORE INTO invoiceOutQueue(invoiceFk) VALUES(?)`; - await Self.rawSql(query, [newInvoice.id], myOptions); - - invoicesIds.push(newInvoice.id); - } - } catch (e) { - failedClients.push({ - id: client.id, - stacktrace: e - }); - continue; } - } - if (failedClients.length > 0) - await notifyFailures(ctx, failedClients, myOptions); + // Make invoice + const isSpanishCompany = await getIsSpanishCompany(args.companyFk, myOptions); + + // Validates ticket nagative base + const hasAnyNegativeBase = await getNegativeBase(myOptions); + if (hasAnyNegativeBase && isSpanishCompany) + return notifyFailures(ctx, failedClients, myOptions); // continue + + 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); + + query = `INSERT IGNORE INTO invoiceOutQueue(invoiceFk) VALUES(?)`; + await Self.rawSql(query, [newInvoice.id], myOptions); + + invoicesIds.push(newInvoice.id); + } + } catch (e) { + failedClients.push({ + id: client.id, + stacktrace: e + }); + return notifyFailures(ctx, failedClients, myOptions); // continue + } + // } if (tx) await tx.commit(); } catch (e) { @@ -189,66 +124,6 @@ module.exports = Self => { return supplierCompany && supplierCompany.total; } - async function getClientsWithPackaging(ctx, options) { - const models = Self.app.models; - const args = ctx.args; - const query = `SELECT DISTINCT clientFk AS id - FROM ticket t - JOIN ticketPackaging tp ON t.id = tp.ticketFk - JOIN client c ON c.id = t.clientFk - WHERE t.shipped BETWEEN '2017-11-21' AND ? - AND t.clientFk >= ? - AND (t.clientFk <= ? OR ? IS NULL) - AND c.isActive`; - return models.InvoiceOut.rawSql(query, [ - args.maxShipped, - args.fromClientId, - args.toClientId, - args.toClientId - ], options); - } - - async function getInvoiceableClients(ctx, options) { - const models = Self.app.models; - const args = ctx.args; - const minShipped = new Date(); - minShipped.setFullYear(minShipped.getFullYear() - 1); - - const query = `SELECT - c.id, - SUM(IFNULL - ( - s.quantity * - s.price * (100-s.discount)/100, - 0) - + IFNULL(ts.quantity * ts.price,0) - ) AS sumAmount, - c.hasToInvoiceByAddress, - c.email, - c.isToBeMailed, - a.id addressFk - FROM ticket t - LEFT JOIN sale s ON s.ticketFk = t.id - LEFT JOIN ticketService ts ON ts.ticketFk = t.id - JOIN address a ON a.id = t.addressFk - JOIN client c ON c.id = t.clientFk - WHERE ISNULL(t.refFk) AND c.id >= ? - AND (t.clientFk <= ? OR ? IS NULL) - AND t.shipped BETWEEN ? AND util.dayEnd(?) - AND t.companyFk = ? AND c.hasToInvoice - AND c.isTaxDataChecked AND c.isActive - GROUP BY c.id, IF(c.hasToInvoiceByAddress,a.id,TRUE) HAVING sumAmount > 0`; - - return models.InvoiceOut.rawSql(query, [ - args.fromClientId, - args.toClientId, - args.toClientId, - minShipped, - args.maxShipped, - args.companyFk - ], options); - } - async function notifyFailures(ctx, failedClients, options) { const models = Self.app.models; const userId = ctx.req.accessToken.userId; diff --git a/modules/invoiceOut/back/models/invoice-out.js b/modules/invoiceOut/back/models/invoice-out.js index 5af64de2b..7ac1246cf 100644 --- a/modules/invoiceOut/back/models/invoice-out.js +++ b/modules/invoiceOut/back/models/invoice-out.js @@ -7,6 +7,7 @@ module.exports = Self => { require('../methods/invoiceOut/book')(Self); require('../methods/invoiceOut/createPdf')(Self); require('../methods/invoiceOut/createManualInvoice')(Self); + require('../methods/invoiceOut/clientToInvoice')(Self); require('../methods/invoiceOut/globalInvoicing')(Self); require('../methods/invoiceOut/refund')(Self); require('../methods/invoiceOut/invoiceEmail')(Self); diff --git a/modules/invoiceOut/front/index/global-invoicing/index.html b/modules/invoiceOut/front/index/global-invoicing/index.html index 3d245b8d8..dbb780b7c 100644 --- a/modules/invoiceOut/front/index/global-invoicing/index.html +++ b/modules/invoiceOut/front/index/global-invoicing/index.html @@ -20,6 +20,8 @@ Adding invoices to queue... + {{$ctrl.lastClientId}} + {{::$ctrl.lastClientId || 'VacĂ­o'}} diff --git a/modules/invoiceOut/front/index/global-invoicing/index.js b/modules/invoiceOut/front/index/global-invoicing/index.js index 1b1ae5ec9..66c2e698a 100644 --- a/modules/invoiceOut/front/index/global-invoicing/index.js +++ b/modules/invoiceOut/front/index/global-invoicing/index.js @@ -58,8 +58,18 @@ class Controller extends Dialog { throw new Error('Choose a valid clients range'); this.isInvoicing = true; - return this.$http.post(`InvoiceOuts/globalInvoicing`, this.invoice) - .then(() => super.responseHandler(response)) + return this.$http.post(`InvoiceOuts/clientToInvoice`, this.invoice) + .then(res => { + this.lastClientId = res.data[res.data.length - 1]; + console.log(this.lastClientId); + }) + // .then(() => { + // for (let clientId of res.data) { + // const params = {clientId: clientId}; + // this.$http.post(`InvoiceOuts/globalInvoicing`, params); + // } + // }) + // .then(() => super.responseHandler(response)) .then(() => this.vnApp.showSuccess(this.$t('Data saved!'))) .finally(() => this.isInvoicing = false); } catch (e) {