From f2bd0253e28222d2ab5f90931742a6f1a9c12af1 Mon Sep 17 00:00:00 2001 From: alexandre Date: Mon, 6 Mar 2023 09:27:53 +0100 Subject: [PATCH 01/13] refs #5092 added unbilled tickets section --- db/changes/231001/.gitkeep | 0 db/changes/231001/00-unbilledTickets.sql | 3 + .../09-invoice-in/05_unbilled_tickets.spec.js | 29 +++++ loopback/locale/en.json | 8 +- loopback/locale/es.json | 3 +- modules/client/front/locale/es.yml | 3 +- .../invoice-in/specs/unbilledTickets.spec.js | 47 ++++++++ .../methods/invoice-in/unbilledTickets.js | 112 ++++++++++++++++++ modules/invoiceIn/back/models/invoice-in.js | 1 + modules/invoiceIn/front/index.js | 1 + modules/invoiceIn/front/routes.json | 17 ++- .../front/unbilled-tickets/index.html | 104 ++++++++++++++++ .../invoiceIn/front/unbilled-tickets/index.js | 66 +++++++++++ .../front/unbilled-tickets/locale/es.yml | 1 + .../front/unbilled-tickets/style.scss | 7 ++ 15 files changed, 392 insertions(+), 10 deletions(-) delete mode 100644 db/changes/231001/.gitkeep create mode 100644 db/changes/231001/00-unbilledTickets.sql create mode 100644 e2e/paths/09-invoice-in/05_unbilled_tickets.spec.js create mode 100644 modules/invoiceIn/back/methods/invoice-in/specs/unbilledTickets.spec.js create mode 100644 modules/invoiceIn/back/methods/invoice-in/unbilledTickets.js create mode 100644 modules/invoiceIn/front/unbilled-tickets/index.html create mode 100644 modules/invoiceIn/front/unbilled-tickets/index.js create mode 100644 modules/invoiceIn/front/unbilled-tickets/locale/es.yml create mode 100644 modules/invoiceIn/front/unbilled-tickets/style.scss diff --git a/db/changes/231001/.gitkeep b/db/changes/231001/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/db/changes/231001/00-unbilledTickets.sql b/db/changes/231001/00-unbilledTickets.sql new file mode 100644 index 000000000..d0c3fbbcb --- /dev/null +++ b/db/changes/231001/00-unbilledTickets.sql @@ -0,0 +1,3 @@ +INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) + VALUES + ('InvoiceIn', 'unbilledTickets', 'READ', 'ALLOW', 'ROLE', 'administrative'); diff --git a/e2e/paths/09-invoice-in/05_unbilled_tickets.spec.js b/e2e/paths/09-invoice-in/05_unbilled_tickets.spec.js new file mode 100644 index 000000000..dd75d0b49 --- /dev/null +++ b/e2e/paths/09-invoice-in/05_unbilled_tickets.spec.js @@ -0,0 +1,29 @@ +import getBrowser from '../../helpers/puppeteer'; + +describe('InvoiceIn unbilled tickets path', () => { + let browser; + let page; + const httpRequests = []; + + beforeAll(async() => { + browser = await getBrowser(); + page = browser.page; + page.on('request', req => { + if (req.url().includes(`InvoiceIns/unbilledTickets`)) + httpRequests.push(req.url()); + }); + await page.loginAndModule('administrative', 'invoiceIn'); + await page.accessToSection('invoiceIn.unbilled-tickets'); + }); + + afterAll(async() => { + await browser.close(); + }); + + it('should show unbilled tickets in a date range', async() => { + const request = httpRequests.find(req => + req.includes(`from`) && req.includes(`to`)); + + expect(request).toBeDefined(); + }); +}); diff --git a/loopback/locale/en.json b/loopback/locale/en.json index eeb25f75d..dbe25dea3 100644 --- a/loopback/locale/en.json +++ b/loopback/locale/en.json @@ -147,8 +147,10 @@ "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", - "Tickets with associated refunds": "Tickets with associated refunds can't be deleted. This ticket is associated with refund Nº {{id}}", + "Tickets with associated refunds": "Tickets with associated refunds can't be deleted. This ticket is associated with refund Nº {{id}}", "It is not possible to modify tracked sales": "It is not possible to modify tracked sales", "It is not possible to modify sales that their articles are from Floramondo": "It is not possible to modify sales that their articles are from Floramondo", - "It is not possible to modify cloned sales": "It is not possible to modify cloned sales" -} + "It is not possible to modify cloned sales": "It is not possible to modify cloned sales", + "Valid priorities: 1,2,3": "Valid priorities: 1,2,3", + "Tickets with associated refunds can't be deleted. This ticket is associated with refund Nº 2": "Tickets with associated refunds can't be deleted. This ticket is associated with refund Nº 2" +} \ No newline at end of file diff --git a/loopback/locale/es.json b/loopback/locale/es.json index 507cc9003..563c24c05 100644 --- a/loopback/locale/es.json +++ b/loopback/locale/es.json @@ -266,5 +266,6 @@ "There is no assigned email for this client": "No hay correo asignado para este cliente", "This locker has already been assigned": "Esta taquilla ya ha sido asignada", "Tickets with associated refunds": "No se pueden borrar tickets con abonos asociados. Este ticket está asociado al abono Nº {{id}}", - "Not exist this branch": "La rama no existe" + "Not exist this branch": "La rama no existe", + "Insert a date range": "Inserte un rango de fechas" } diff --git a/modules/client/front/locale/es.yml b/modules/client/front/locale/es.yml index de4b91e0b..fe87b2362 100644 --- a/modules/client/front/locale/es.yml +++ b/modules/client/front/locale/es.yml @@ -63,4 +63,5 @@ Consumption: Consumo Compensation Account: Cuenta para compensar Amount to return: Cantidad a devolver Delivered amount: Cantidad entregada -Unpaid: Impagado \ No newline at end of file +Unpaid: Impagado +Unbilled tickets: Tickets sin facturar diff --git a/modules/invoiceIn/back/methods/invoice-in/specs/unbilledTickets.spec.js b/modules/invoiceIn/back/methods/invoice-in/specs/unbilledTickets.spec.js new file mode 100644 index 000000000..07e320a9f --- /dev/null +++ b/modules/invoiceIn/back/methods/invoice-in/specs/unbilledTickets.spec.js @@ -0,0 +1,47 @@ +const models = require('vn-loopback/server/server').models; + +describe('invoiceIn unbilledTickets()', () => { + it('should return all unbilled tickets in a date range', async() => { + const tx = await models.InvoiceIn.beginTransaction({}); + const options = {transaction: tx}; + const ctx = { + args: { + from: new Date().setMonth(new Date().getMonth() - 12), + to: new Date(), + filter: {} + } + }; + + try { + const result = await models.InvoiceIn.unbilledTickets(ctx, options); + + expect(result.length).toBeGreaterThan(0); + + await tx.rollback(); + } catch (e) { + await tx.rollback(); + throw e; + } + }); + + it('should throw an error if a date range is not in args', async() => { + let error; + const tx = await models.InvoiceIn.beginTransaction({}); + const options = {transaction: tx}; + const ctx = { + args: { + filter: {} + } + }; + + try { + await models.InvoiceIn.unbilledTickets(ctx, options); + await tx.rollback(); + } catch (e) { + error = e; + await tx.rollback(); + } + + expect(error.message).toEqual(`Insert a date range`); + }); +}); diff --git a/modules/invoiceIn/back/methods/invoice-in/unbilledTickets.js b/modules/invoiceIn/back/methods/invoice-in/unbilledTickets.js new file mode 100644 index 000000000..3c33c8337 --- /dev/null +++ b/modules/invoiceIn/back/methods/invoice-in/unbilledTickets.js @@ -0,0 +1,112 @@ +const UserError = require('vn-loopback/util/user-error'); +const ParameterizedSQL = require('loopback-connector').ParameterizedSQL; + +module.exports = Self => { + Self.remoteMethodCtx('unbilledTickets', { + description: 'Find all unbilled tickets', + accessType: 'READ', + accepts: [ + { + arg: 'from', + type: 'date', + description: 'From date' + }, + { + arg: 'to', + type: 'date', + description: 'To date' + }, + { + arg: 'filter', + type: 'object', + description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string' + }, + ], + returns: { + type: ['object'], + root: true + }, + http: { + path: `/unbilledTickets`, + verb: 'GET' + } + }); + + Self.unbilledTickets = async(ctx, options) => { + const conn = Self.dataSource.connector; + const args = ctx.args; + + if (!args.from || !args.to) + throw new UserError(`Insert a date range`); + + const myOptions = {}; + + if (typeof options == 'object') + Object.assign(myOptions, options); + + const stmts = []; + let stmt; + stmts.push(`DROP TEMPORARY TABLE IF EXISTS tmp.ticket`); + + stmts.push(new ParameterizedSQL( + `CREATE TEMPORARY TABLE tmp.ticket + (KEY (ticketFk)) + ENGINE = MEMORY + SELECT id ticketFk + FROM ticket t + WHERE shipped BETWEEN ? AND ? + AND refFk IS NULL`, [args.from, args.to])); + stmts.push(`CALL vn.ticket_getTax(NULL)`); + stmts.push(`DROP TEMPORARY TABLE IF EXISTS tmp.filter`); + stmts.push(new ParameterizedSQL( + `CREATE TEMPORARY TABLE tmp.filter + ENGINE = MEMORY + SELECT + co.code company, + cou.country, + c.id clientId, + c.socialName clientSocialName, + SUM(s.quantity * s.price * ( 100 - s.discount ) / 100) amount, + negativeBase.taxableBase, + negativeBase.ticketFk, + c.isActive, + c.hasToInvoice, + c.isTaxDataChecked, + w.id comercialId, + CONCAT(w.firstName, ' ', w.lastName) comercialName + FROM vn.ticket t + JOIN vn.company co ON co.id = t.companyFk + JOIN vn.sale s ON s.ticketFk = t.id + JOIN vn.client c ON c.id = t.clientFk + JOIN vn.country cou ON cou.id = c.countryFk + LEFT JOIN vn.worker w ON w.id = c.salesPersonFk + LEFT JOIN ( + SELECT ticketFk, taxableBase + FROM tmp.ticketAmount + GROUP BY ticketFk + HAVING taxableBase < 0 + ) negativeBase ON negativeBase.ticketFk = t.id + WHERE t.shipped BETWEEN ? AND ? + AND t.refFk IS NULL + AND c.typeFk IN ('normal','trust') + GROUP BY t.clientFk + HAVING amount <> 0`, [args.from, args.to])); + + stmt = new ParameterizedSQL(` + SELECT f.* + FROM tmp.filter f`); + + stmt.merge(conn.makeWhere(args.filter.where)); + stmt.merge(conn.makeOrderBy(args.filter.order)); + + const ticketsIndex = stmts.push(stmt) - 1; + + stmts.push(`DROP TEMPORARY TABLE tmp.filter, tmp.ticket, tmp.ticketTax, tmp.ticketAmount`); + + const sql = ParameterizedSQL.join(stmts, ';'); + const result = await conn.executeStmt(sql, myOptions); + + return ticketsIndex === 0 ? result : result[ticketsIndex]; + }; +}; + diff --git a/modules/invoiceIn/back/models/invoice-in.js b/modules/invoiceIn/back/models/invoice-in.js index 95ccc7b20..05909680c 100644 --- a/modules/invoiceIn/back/models/invoice-in.js +++ b/modules/invoiceIn/back/models/invoice-in.js @@ -6,4 +6,5 @@ module.exports = Self => { require('../methods/invoice-in/getTotals')(Self); require('../methods/invoice-in/invoiceInPdf')(Self); require('../methods/invoice-in/invoiceInEmail')(Self); + require('../methods/invoice-in/unbilledTickets')(Self); }; diff --git a/modules/invoiceIn/front/index.js b/modules/invoiceIn/front/index.js index 7b6d6a77c..00a8d2c58 100644 --- a/modules/invoiceIn/front/index.js +++ b/modules/invoiceIn/front/index.js @@ -13,3 +13,4 @@ import './dueDay'; import './intrastat'; import './create'; import './log'; +import './unbilled-tickets'; diff --git a/modules/invoiceIn/front/routes.json b/modules/invoiceIn/front/routes.json index 4867b7db9..1fe1b3255 100644 --- a/modules/invoiceIn/front/routes.json +++ b/modules/invoiceIn/front/routes.json @@ -9,10 +9,8 @@ ], "menus": { "main": [ - { - "state": "invoiceIn.index", - "icon": "icon-invoice-in" - } + { "state": "invoiceIn.index", "icon": "icon-invoice-in"}, + { "state": "invoiceIn.unbilled-tickets", "icon": "icon-ticket"} ], "card": [ { @@ -54,6 +52,15 @@ "administrative" ] }, + { + "url": "/unbilled-tickets", + "state": "invoiceIn.unbilled-tickets", + "component": "vn-unbilled-tickets", + "description": "Unbilled tickets", + "acl": [ + "administrative" + ] + }, { "url": "/:id", "state": "invoiceIn.card", @@ -133,4 +140,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/modules/invoiceIn/front/unbilled-tickets/index.html b/modules/invoiceIn/front/unbilled-tickets/index.html new file mode 100644 index 000000000..57cfa5138 --- /dev/null +++ b/modules/invoiceIn/front/unbilled-tickets/index.html @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Company + + Country + + Id Client + + Client + + Amount + + Base + + Id Ticket + + Active + + Has To Invoice + + Verified data + + Id Comercial + + Comercial +
{{ticket.company | dashIfEmpty}}{{ticket.country | dashIfEmpty}}{{ticket.clientId | dashIfEmpty}}{{ticket.clientSocialName | dashIfEmpty}}{{ticket.amount | currency: 'EUR':2 | dashIfEmpty}}{{ticket.taxableBase | dashIfEmpty}}{{ticket.ticketFk | dashIfEmpty}} + + + + + + + + + {{ticket.comercialId | dashIfEmpty}}{{ticket.comercialName | dashIfEmpty}}
+
+
+
diff --git a/modules/invoiceIn/front/unbilled-tickets/index.js b/modules/invoiceIn/front/unbilled-tickets/index.js new file mode 100644 index 000000000..f71fd35b3 --- /dev/null +++ b/modules/invoiceIn/front/unbilled-tickets/index.js @@ -0,0 +1,66 @@ +import ngModule from '../module'; +import Section from 'salix/components/section'; +import './style.scss'; + +export default class Controller extends Section { + constructor($element, $) { + super($element, $); + const now = new Date(); + const firstDayOfMonth = new Date(now.getFullYear(), now.getMonth(), 1); + const lastDayOfMonth = new Date(now.getFullYear(), now.getMonth() + 1, 0); + this.params = { + from: firstDayOfMonth, + to: lastDayOfMonth + }; + this.$checkAll = false; + + this.smartTableOptions = { + activeButtons: { + search: true, + }, columns: [ + { + field: 'isActive', + searchable: false + }, + { + field: 'hasToInvoice', + searchable: false + }, + { + field: 'isTaxDataChecked', + searchable: false + }, + ] + }; + } + + exprBuilder(param, value) { + switch (param) { + case 'company': + return {'company': value}; + case 'country': + return {'country': value}; + case 'clientId': + return {'clientId': value}; + case 'clientSocialName': + return {'clientSocialName': value}; + case 'amount': + return {'amount': value}; + case 'taxableBase': + return {'taxableBase': value}; + case 'ticketFk': + return {'ticketFk': value}; + case 'comercialId': + return {'comercialId': value}; + case 'comercialName': + return {'comercialName': value}; + } + } +} + +Controller.$inject = ['$element', '$scope']; + +ngModule.vnComponent('vnUnbilledTickets', { + template: require('./index.html'), + controller: Controller +}); diff --git a/modules/invoiceIn/front/unbilled-tickets/locale/es.yml b/modules/invoiceIn/front/unbilled-tickets/locale/es.yml new file mode 100644 index 000000000..9c6c3d735 --- /dev/null +++ b/modules/invoiceIn/front/unbilled-tickets/locale/es.yml @@ -0,0 +1 @@ +Has To Invoice: Facturar diff --git a/modules/invoiceIn/front/unbilled-tickets/style.scss b/modules/invoiceIn/front/unbilled-tickets/style.scss new file mode 100644 index 000000000..ad74a0071 --- /dev/null +++ b/modules/invoiceIn/front/unbilled-tickets/style.scss @@ -0,0 +1,7 @@ +@import "./variables"; + +vn-unbilled-tickets { + vn-date-picker{ + padding-right: 5%; + } +} From 4e800a7a454022a58714da645a56e4fbf95283d9 Mon Sep 17 00:00:00 2001 From: alexandre Date: Mon, 6 Mar 2023 09:30:14 +0100 Subject: [PATCH 02/13] . --- loopback/locale/en.json | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/loopback/locale/en.json b/loopback/locale/en.json index dbe25dea3..32b5e0168 100644 --- a/loopback/locale/en.json +++ b/loopback/locale/en.json @@ -150,7 +150,5 @@ "Tickets with associated refunds": "Tickets with associated refunds can't be deleted. This ticket is associated with refund Nº {{id}}", "It is not possible to modify tracked sales": "It is not possible to modify tracked sales", "It is not possible to modify sales that their articles are from Floramondo": "It is not possible to modify sales that their articles are from Floramondo", - "It is not possible to modify cloned sales": "It is not possible to modify cloned sales", - "Valid priorities: 1,2,3": "Valid priorities: 1,2,3", - "Tickets with associated refunds can't be deleted. This ticket is associated with refund Nº 2": "Tickets with associated refunds can't be deleted. This ticket is associated with refund Nº 2" -} \ No newline at end of file + "It is not possible to modify cloned sales": "It is not possible to modify cloned sales" +} From c4d6a19666f5ebdfe8af2390ca4574d777fc606e Mon Sep 17 00:00:00 2001 From: alexandre Date: Fri, 10 Mar 2023 12:49:20 +0100 Subject: [PATCH 03/13] refs #5092 download as csv button --- db/changes/231001/00-unbilledTickets.sql | 3 +- .../methods/invoice-in/unbilledTicketsCsv.js | 53 +++++++++++++++++++ modules/invoiceIn/back/models/invoice-in.js | 1 + .../front/unbilled-tickets/index.html | 28 ++++++---- .../invoiceIn/front/unbilled-tickets/index.js | 24 ++++++++- .../front/unbilled-tickets/locale/es.yml | 13 +++++ .../front/unbilled-tickets/style.scss | 3 ++ 7 files changed, 111 insertions(+), 14 deletions(-) create mode 100644 modules/invoiceIn/back/methods/invoice-in/unbilledTicketsCsv.js diff --git a/db/changes/231001/00-unbilledTickets.sql b/db/changes/231001/00-unbilledTickets.sql index d0c3fbbcb..3d2bc562b 100644 --- a/db/changes/231001/00-unbilledTickets.sql +++ b/db/changes/231001/00-unbilledTickets.sql @@ -1,3 +1,4 @@ INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES - ('InvoiceIn', 'unbilledTickets', 'READ', 'ALLOW', 'ROLE', 'administrative'); + ('InvoiceIn', 'unbilledTickets', 'READ', 'ALLOW', 'ROLE', 'administrative'), + ('InvoiceIn', 'unbilledTicketsCsv', 'READ', 'ALLOW', 'ROLE', 'administrative'); diff --git a/modules/invoiceIn/back/methods/invoice-in/unbilledTicketsCsv.js b/modules/invoiceIn/back/methods/invoice-in/unbilledTicketsCsv.js new file mode 100644 index 000000000..bd6bb8d36 --- /dev/null +++ b/modules/invoiceIn/back/methods/invoice-in/unbilledTicketsCsv.js @@ -0,0 +1,53 @@ +const {toCSV} = require('vn-loopback/util/csv'); + +module.exports = Self => { + Self.remoteMethodCtx('unbilledTicketsCsv', { + description: 'Returns the unbilled tickets as .csv', + accessType: 'READ', + accepts: [{ + arg: 'unbilledTickets', + type: ['object'], + required: true + }, + { + arg: 'from', + type: 'date', + description: 'From date' + }, + { + arg: 'to', + type: 'date', + description: 'To date' + }], + returns: [ + { + arg: 'body', + type: 'file', + root: true + }, { + arg: 'Content-Type', + type: 'String', + http: {target: 'header'} + }, { + arg: 'Content-Disposition', + type: 'String', + http: {target: 'header'} + } + ], + http: { + path: '/unbilledTicketsCsv', + verb: 'GET' + } + }); + + Self.unbilledTicketsCsv = async ctx => { + const args = ctx.args; + const content = toCSV(args.unbilledTickets); + + return [ + content, + 'text/csv', + `attachment; filename="unbilled-tickets-${new Date(args.from).toLocaleDateString()}-${new Date(args.to).toLocaleDateString()}.csv"` + ]; + }; +}; diff --git a/modules/invoiceIn/back/models/invoice-in.js b/modules/invoiceIn/back/models/invoice-in.js index 05909680c..bdd9e1b11 100644 --- a/modules/invoiceIn/back/models/invoice-in.js +++ b/modules/invoiceIn/back/models/invoice-in.js @@ -7,4 +7,5 @@ module.exports = Self => { require('../methods/invoice-in/invoiceInPdf')(Self); require('../methods/invoice-in/invoiceInEmail')(Self); require('../methods/invoice-in/unbilledTickets')(Self); + require('../methods/invoice-in/unbilledTicketsCsv')(Self); }; diff --git a/modules/invoiceIn/front/unbilled-tickets/index.html b/modules/invoiceIn/front/unbilled-tickets/index.html index 57cfa5138..eb669a015 100644 --- a/modules/invoiceIn/front/unbilled-tickets/index.html +++ b/modules/invoiceIn/front/unbilled-tickets/index.html @@ -13,17 +13,23 @@ expr-builder="$ctrl.exprBuilder(param, value)"> - - - + vn-one + label="From" + ng-model="$ctrl.params.from" + on-change="model.refresh()"> + + + + + diff --git a/modules/invoiceIn/front/unbilled-tickets/index.js b/modules/invoiceIn/front/unbilled-tickets/index.js index f71fd35b3..4d99257a7 100644 --- a/modules/invoiceIn/front/unbilled-tickets/index.js +++ b/modules/invoiceIn/front/unbilled-tickets/index.js @@ -3,8 +3,10 @@ import Section from 'salix/components/section'; import './style.scss'; export default class Controller extends Section { - constructor($element, $) { + constructor($element, $, vnReport) { super($element, $); + + this.vnReport = vnReport; const now = new Date(); const firstDayOfMonth = new Date(now.getFullYear(), now.getMonth(), 1); const lastDayOfMonth = new Date(now.getFullYear(), now.getMonth() + 1, 0); @@ -56,9 +58,27 @@ export default class Controller extends Section { return {'comercialName': value}; } } + + downloadCSV() { + const data = []; + this.$.model._orgData.forEach(element => { + data.push(Object.keys(element).map(key => { + return {newName: this.$t(key), value: element[key]}; + }).filter(item => item !== null) + .reduce((result, item) => { + result[item.newName] = item.value; + return result; + }, {})); + }); + this.vnReport.show('InvoiceIns/unbilledTicketsCsv', { + unbilledTickets: data, + from: this.params.from, + to: this.params.to + }); + } } -Controller.$inject = ['$element', '$scope']; +Controller.$inject = ['$element', '$scope', 'vnReport']; ngModule.vnComponent('vnUnbilledTickets', { template: require('./index.html'), diff --git a/modules/invoiceIn/front/unbilled-tickets/locale/es.yml b/modules/invoiceIn/front/unbilled-tickets/locale/es.yml index 9c6c3d735..9095eee22 100644 --- a/modules/invoiceIn/front/unbilled-tickets/locale/es.yml +++ b/modules/invoiceIn/front/unbilled-tickets/locale/es.yml @@ -1 +1,14 @@ Has To Invoice: Facturar +Download as CSV: Descargar como CSV +company: Compañía +country: País +clientId: Id Cliente +clientSocialName: Cliente +amount: Importe +taxableBase: Base +ticketFk: Id Ticket +isActive: Activo +hasToInvoice: Facturar +isTaxDataChecked: Datos comprobados +comercialId: Id Comercial +comercialName: Comercial diff --git a/modules/invoiceIn/front/unbilled-tickets/style.scss b/modules/invoiceIn/front/unbilled-tickets/style.scss index ad74a0071..555b25fa9 100644 --- a/modules/invoiceIn/front/unbilled-tickets/style.scss +++ b/modules/invoiceIn/front/unbilled-tickets/style.scss @@ -4,4 +4,7 @@ vn-unbilled-tickets { vn-date-picker{ padding-right: 5%; } + slot-actions{ + align-items: center; + } } From c46e15c8e463368135adff134285f2a287935e34 Mon Sep 17 00:00:00 2001 From: alexandre Date: Thu, 16 Mar 2023 09:35:00 +0100 Subject: [PATCH 04/13] refs #5092 changed section name --- db/changes/231201/.gitkeep | 0 .../00-unbilledClients.sql} | 4 +-- ...ts.spec.js => 05_unbilled_clients.spec.js} | 8 +++--- modules/client/front/locale/es.yml | 1 - ...ickets.spec.js => unbilledClients.spec.js} | 8 +++--- ...{unbilledTickets.js => unbilledClients.js} | 12 ++++---- ...ledTicketsCsv.js => unbilledClientsCsv.js} | 14 +++++----- modules/invoiceIn/back/models/invoice-in.js | 4 +-- modules/invoiceIn/front/index.js | 2 +- modules/invoiceIn/front/locale/es.yml | 1 + modules/invoiceIn/front/routes.json | 10 +++---- .../index.html | 28 +++++++++---------- .../index.js | 6 ++-- .../locale/es.yml | 0 .../style.scss | 2 +- 15 files changed, 50 insertions(+), 50 deletions(-) delete mode 100644 db/changes/231201/.gitkeep rename db/changes/{231001/00-unbilledTickets.sql => 231201/00-unbilledClients.sql} (56%) rename e2e/paths/09-invoice-in/{05_unbilled_tickets.spec.js => 05_unbilled_clients.spec.js} (71%) rename modules/invoiceIn/back/methods/invoice-in/specs/{unbilledTickets.spec.js => unbilledClients.spec.js} (82%) rename modules/invoiceIn/back/methods/invoice-in/{unbilledTickets.js => unbilledClients.js} (92%) rename modules/invoiceIn/back/methods/invoice-in/{unbilledTicketsCsv.js => unbilledClientsCsv.js} (75%) rename modules/invoiceIn/front/{unbilled-tickets => unbilled-clients}/index.html (80%) rename modules/invoiceIn/front/{unbilled-tickets => unbilled-clients}/index.js (94%) rename modules/invoiceIn/front/{unbilled-tickets => unbilled-clients}/locale/es.yml (100%) rename modules/invoiceIn/front/{unbilled-tickets => unbilled-clients}/style.scss (85%) diff --git a/db/changes/231201/.gitkeep b/db/changes/231201/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/db/changes/231001/00-unbilledTickets.sql b/db/changes/231201/00-unbilledClients.sql similarity index 56% rename from db/changes/231001/00-unbilledTickets.sql rename to db/changes/231201/00-unbilledClients.sql index 3d2bc562b..16127dd18 100644 --- a/db/changes/231001/00-unbilledTickets.sql +++ b/db/changes/231201/00-unbilledClients.sql @@ -1,4 +1,4 @@ INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES - ('InvoiceIn', 'unbilledTickets', 'READ', 'ALLOW', 'ROLE', 'administrative'), - ('InvoiceIn', 'unbilledTicketsCsv', 'READ', 'ALLOW', 'ROLE', 'administrative'); + ('InvoiceIn', 'unbilledClients', 'READ', 'ALLOW', 'ROLE', 'administrative'), + ('InvoiceIn', 'unbilledClientsCsv', 'READ', 'ALLOW', 'ROLE', 'administrative'); diff --git a/e2e/paths/09-invoice-in/05_unbilled_tickets.spec.js b/e2e/paths/09-invoice-in/05_unbilled_clients.spec.js similarity index 71% rename from e2e/paths/09-invoice-in/05_unbilled_tickets.spec.js rename to e2e/paths/09-invoice-in/05_unbilled_clients.spec.js index dd75d0b49..629f24404 100644 --- a/e2e/paths/09-invoice-in/05_unbilled_tickets.spec.js +++ b/e2e/paths/09-invoice-in/05_unbilled_clients.spec.js @@ -1,6 +1,6 @@ import getBrowser from '../../helpers/puppeteer'; -describe('InvoiceIn unbilled tickets path', () => { +describe('InvoiceIn unbilled clients path', () => { let browser; let page; const httpRequests = []; @@ -9,18 +9,18 @@ describe('InvoiceIn unbilled tickets path', () => { browser = await getBrowser(); page = browser.page; page.on('request', req => { - if (req.url().includes(`InvoiceIns/unbilledTickets`)) + if (req.url().includes(`InvoiceIns/unbilledClients`)) httpRequests.push(req.url()); }); await page.loginAndModule('administrative', 'invoiceIn'); - await page.accessToSection('invoiceIn.unbilled-tickets'); + await page.accessToSection('invoiceIn.unbilled-clients'); }); afterAll(async() => { await browser.close(); }); - it('should show unbilled tickets in a date range', async() => { + it('should show unbilled clients in a date range', async() => { const request = httpRequests.find(req => req.includes(`from`) && req.includes(`to`)); diff --git a/modules/client/front/locale/es.yml b/modules/client/front/locale/es.yml index fe87b2362..adbca8dbf 100644 --- a/modules/client/front/locale/es.yml +++ b/modules/client/front/locale/es.yml @@ -64,4 +64,3 @@ Compensation Account: Cuenta para compensar Amount to return: Cantidad a devolver Delivered amount: Cantidad entregada Unpaid: Impagado -Unbilled tickets: Tickets sin facturar diff --git a/modules/invoiceIn/back/methods/invoice-in/specs/unbilledTickets.spec.js b/modules/invoiceIn/back/methods/invoice-in/specs/unbilledClients.spec.js similarity index 82% rename from modules/invoiceIn/back/methods/invoice-in/specs/unbilledTickets.spec.js rename to modules/invoiceIn/back/methods/invoice-in/specs/unbilledClients.spec.js index 07e320a9f..fcb3173ab 100644 --- a/modules/invoiceIn/back/methods/invoice-in/specs/unbilledTickets.spec.js +++ b/modules/invoiceIn/back/methods/invoice-in/specs/unbilledClients.spec.js @@ -1,7 +1,7 @@ const models = require('vn-loopback/server/server').models; -describe('invoiceIn unbilledTickets()', () => { - it('should return all unbilled tickets in a date range', async() => { +describe('invoiceIn unbilledClients()', () => { + it('should return all unbilled clients in a date range', async() => { const tx = await models.InvoiceIn.beginTransaction({}); const options = {transaction: tx}; const ctx = { @@ -13,7 +13,7 @@ describe('invoiceIn unbilledTickets()', () => { }; try { - const result = await models.InvoiceIn.unbilledTickets(ctx, options); + const result = await models.InvoiceIn.unbilledClients(ctx, options); expect(result.length).toBeGreaterThan(0); @@ -35,7 +35,7 @@ describe('invoiceIn unbilledTickets()', () => { }; try { - await models.InvoiceIn.unbilledTickets(ctx, options); + await models.InvoiceIn.unbilledClients(ctx, options); await tx.rollback(); } catch (e) { error = e; diff --git a/modules/invoiceIn/back/methods/invoice-in/unbilledTickets.js b/modules/invoiceIn/back/methods/invoice-in/unbilledClients.js similarity index 92% rename from modules/invoiceIn/back/methods/invoice-in/unbilledTickets.js rename to modules/invoiceIn/back/methods/invoice-in/unbilledClients.js index 3c33c8337..ad39bc547 100644 --- a/modules/invoiceIn/back/methods/invoice-in/unbilledTickets.js +++ b/modules/invoiceIn/back/methods/invoice-in/unbilledClients.js @@ -2,8 +2,8 @@ const UserError = require('vn-loopback/util/user-error'); const ParameterizedSQL = require('loopback-connector').ParameterizedSQL; module.exports = Self => { - Self.remoteMethodCtx('unbilledTickets', { - description: 'Find all unbilled tickets', + Self.remoteMethodCtx('unbilledClients', { + description: 'Find all unbilled clients', accessType: 'READ', accepts: [ { @@ -27,12 +27,12 @@ module.exports = Self => { root: true }, http: { - path: `/unbilledTickets`, + path: `/unbilledClients`, verb: 'GET' } }); - Self.unbilledTickets = async(ctx, options) => { + Self.unbilledClients = async(ctx, options) => { const conn = Self.dataSource.connector; const args = ctx.args; @@ -99,14 +99,14 @@ module.exports = Self => { stmt.merge(conn.makeWhere(args.filter.where)); stmt.merge(conn.makeOrderBy(args.filter.order)); - const ticketsIndex = stmts.push(stmt) - 1; + const clientsIndex = stmts.push(stmt) - 1; stmts.push(`DROP TEMPORARY TABLE tmp.filter, tmp.ticket, tmp.ticketTax, tmp.ticketAmount`); const sql = ParameterizedSQL.join(stmts, ';'); const result = await conn.executeStmt(sql, myOptions); - return ticketsIndex === 0 ? result : result[ticketsIndex]; + return clientsIndex === 0 ? result : result[clientsIndex]; }; }; diff --git a/modules/invoiceIn/back/methods/invoice-in/unbilledTicketsCsv.js b/modules/invoiceIn/back/methods/invoice-in/unbilledClientsCsv.js similarity index 75% rename from modules/invoiceIn/back/methods/invoice-in/unbilledTicketsCsv.js rename to modules/invoiceIn/back/methods/invoice-in/unbilledClientsCsv.js index bd6bb8d36..f9b30d83b 100644 --- a/modules/invoiceIn/back/methods/invoice-in/unbilledTicketsCsv.js +++ b/modules/invoiceIn/back/methods/invoice-in/unbilledClientsCsv.js @@ -1,11 +1,11 @@ const {toCSV} = require('vn-loopback/util/csv'); module.exports = Self => { - Self.remoteMethodCtx('unbilledTicketsCsv', { - description: 'Returns the unbilled tickets as .csv', + Self.remoteMethodCtx('unbilledClientsCsv', { + description: 'Returns the unbilled clients as .csv', accessType: 'READ', accepts: [{ - arg: 'unbilledTickets', + arg: 'unbilledClients', type: ['object'], required: true }, @@ -35,19 +35,19 @@ module.exports = Self => { } ], http: { - path: '/unbilledTicketsCsv', + path: '/unbilledClientsCsv', verb: 'GET' } }); - Self.unbilledTicketsCsv = async ctx => { + Self.unbilledClientsCsv = async ctx => { const args = ctx.args; - const content = toCSV(args.unbilledTickets); + const content = toCSV(args.unbilledClients); return [ content, 'text/csv', - `attachment; filename="unbilled-tickets-${new Date(args.from).toLocaleDateString()}-${new Date(args.to).toLocaleDateString()}.csv"` + `attachment; filename="unbilled-clients-${new Date(args.from).toLocaleDateString()}-${new Date(args.to).toLocaleDateString()}.csv"` ]; }; }; diff --git a/modules/invoiceIn/back/models/invoice-in.js b/modules/invoiceIn/back/models/invoice-in.js index bdd9e1b11..ebb2981e1 100644 --- a/modules/invoiceIn/back/models/invoice-in.js +++ b/modules/invoiceIn/back/models/invoice-in.js @@ -6,6 +6,6 @@ module.exports = Self => { require('../methods/invoice-in/getTotals')(Self); require('../methods/invoice-in/invoiceInPdf')(Self); require('../methods/invoice-in/invoiceInEmail')(Self); - require('../methods/invoice-in/unbilledTickets')(Self); - require('../methods/invoice-in/unbilledTicketsCsv')(Self); + require('../methods/invoice-in/unbilledClients')(Self); + require('../methods/invoice-in/unbilledClientsCsv')(Self); }; diff --git a/modules/invoiceIn/front/index.js b/modules/invoiceIn/front/index.js index 00a8d2c58..7576848bf 100644 --- a/modules/invoiceIn/front/index.js +++ b/modules/invoiceIn/front/index.js @@ -13,4 +13,4 @@ import './dueDay'; import './intrastat'; import './create'; import './log'; -import './unbilled-tickets'; +import './unbilled-clients'; diff --git a/modules/invoiceIn/front/locale/es.yml b/modules/invoiceIn/front/locale/es.yml index 35b43f9f6..2b444f75b 100644 --- a/modules/invoiceIn/front/locale/es.yml +++ b/modules/invoiceIn/front/locale/es.yml @@ -22,3 +22,4 @@ Total stems: Total tallos Show agricultural receipt as PDF: Ver recibo agrícola como PDF Send agricultural receipt as PDF: Enviar recibo agrícola como PDF New InvoiceIn: Nueva Factura +Unbilled clients: Clientes sin facturar diff --git a/modules/invoiceIn/front/routes.json b/modules/invoiceIn/front/routes.json index 1fe1b3255..567323571 100644 --- a/modules/invoiceIn/front/routes.json +++ b/modules/invoiceIn/front/routes.json @@ -10,7 +10,7 @@ "menus": { "main": [ { "state": "invoiceIn.index", "icon": "icon-invoice-in"}, - { "state": "invoiceIn.unbilled-tickets", "icon": "icon-ticket"} + { "state": "invoiceIn.unbilled-clients", "icon": "person"} ], "card": [ { @@ -53,10 +53,10 @@ ] }, { - "url": "/unbilled-tickets", - "state": "invoiceIn.unbilled-tickets", - "component": "vn-unbilled-tickets", - "description": "Unbilled tickets", + "url": "/unbilled-clients", + "state": "invoiceIn.unbilled-clients", + "component": "vn-unbilled-clients", + "description": "Unbilled clients", "acl": [ "administrative" ] diff --git a/modules/invoiceIn/front/unbilled-tickets/index.html b/modules/invoiceIn/front/unbilled-clients/index.html similarity index 80% rename from modules/invoiceIn/front/unbilled-tickets/index.html rename to modules/invoiceIn/front/unbilled-clients/index.html index eb669a015..514f1e8ff 100644 --- a/modules/invoiceIn/front/unbilled-tickets/index.html +++ b/modules/invoiceIn/front/unbilled-clients/index.html @@ -1,6 +1,6 @@ @@ -74,34 +74,34 @@ - - - - - - - - + + + + + + + + - - + +
{{ticket.company | dashIfEmpty}}{{ticket.country | dashIfEmpty}}{{ticket.clientId | dashIfEmpty}}{{ticket.clientSocialName | dashIfEmpty}}{{ticket.amount | currency: 'EUR':2 | dashIfEmpty}}{{ticket.taxableBase | dashIfEmpty}}{{ticket.ticketFk | dashIfEmpty}}
{{client.company | dashIfEmpty}}{{client.country | dashIfEmpty}}{{client.clientId | dashIfEmpty}}{{client.clientSocialName | dashIfEmpty}}{{client.amount | currency: 'EUR':2 | dashIfEmpty}}{{client.taxableBase | dashIfEmpty}}{{client.ticketFk | dashIfEmpty}} + ng-model="client.isActive"> + ng-model="client.hasToInvoice"> + ng-model="client.isTaxDataChecked"> {{ticket.comercialId | dashIfEmpty}}{{ticket.comercialName | dashIfEmpty}}{{client.comercialId | dashIfEmpty}}{{client.comercialName | dashIfEmpty}}
diff --git a/modules/invoiceIn/front/unbilled-tickets/index.js b/modules/invoiceIn/front/unbilled-clients/index.js similarity index 94% rename from modules/invoiceIn/front/unbilled-tickets/index.js rename to modules/invoiceIn/front/unbilled-clients/index.js index 4d99257a7..a53872f8b 100644 --- a/modules/invoiceIn/front/unbilled-tickets/index.js +++ b/modules/invoiceIn/front/unbilled-clients/index.js @@ -70,8 +70,8 @@ export default class Controller extends Section { return result; }, {})); }); - this.vnReport.show('InvoiceIns/unbilledTicketsCsv', { - unbilledTickets: data, + this.vnReport.show('InvoiceIns/unbilledClientsCsv', { + unbilledClients: data, from: this.params.from, to: this.params.to }); @@ -80,7 +80,7 @@ export default class Controller extends Section { Controller.$inject = ['$element', '$scope', 'vnReport']; -ngModule.vnComponent('vnUnbilledTickets', { +ngModule.vnComponent('vnUnbilledClients', { template: require('./index.html'), controller: Controller }); diff --git a/modules/invoiceIn/front/unbilled-tickets/locale/es.yml b/modules/invoiceIn/front/unbilled-clients/locale/es.yml similarity index 100% rename from modules/invoiceIn/front/unbilled-tickets/locale/es.yml rename to modules/invoiceIn/front/unbilled-clients/locale/es.yml diff --git a/modules/invoiceIn/front/unbilled-tickets/style.scss b/modules/invoiceIn/front/unbilled-clients/style.scss similarity index 85% rename from modules/invoiceIn/front/unbilled-tickets/style.scss rename to modules/invoiceIn/front/unbilled-clients/style.scss index 555b25fa9..dbed8b967 100644 --- a/modules/invoiceIn/front/unbilled-tickets/style.scss +++ b/modules/invoiceIn/front/unbilled-clients/style.scss @@ -1,6 +1,6 @@ @import "./variables"; -vn-unbilled-tickets { +vn-unbilled-clients { vn-date-picker{ padding-right: 5%; } From 3f356335db93ac0945f034294bfdf03fbdac145d Mon Sep 17 00:00:00 2001 From: alexandre Date: Thu, 16 Mar 2023 09:47:58 +0100 Subject: [PATCH 05/13] refs #5092 added popovers --- .../front/unbilled-clients/index.html | 49 ++++++++++++++----- .../invoiceIn/front/unbilled-clients/index.js | 2 - 2 files changed, 36 insertions(+), 15 deletions(-) diff --git a/modules/invoiceIn/front/unbilled-clients/index.html b/modules/invoiceIn/front/unbilled-clients/index.html index 514f1e8ff..c4c561191 100644 --- a/modules/invoiceIn/front/unbilled-clients/index.html +++ b/modules/invoiceIn/front/unbilled-clients/index.html @@ -56,18 +56,15 @@ Id Ticket - + Active - + Has To Invoice - + Verified data - - Id Comercial - Comercial @@ -77,34 +74,60 @@ {{client.company | dashIfEmpty}} {{client.country | dashIfEmpty}} - {{client.clientId | dashIfEmpty}} + + + {{::client.clientId | dashIfEmpty}} + + {{client.clientSocialName | dashIfEmpty}} {{client.amount | currency: 'EUR':2 | dashIfEmpty}} {{client.taxableBase | dashIfEmpty}} - {{client.ticketFk | dashIfEmpty}} - + + + {{::client.ticketFk | dashIfEmpty}} + + + - + - + - {{client.comercialId | dashIfEmpty}} - {{client.comercialName | dashIfEmpty}} + + + {{::client.comercialName | dashIfEmpty}} + +
+ + + + + + diff --git a/modules/invoiceIn/front/unbilled-clients/index.js b/modules/invoiceIn/front/unbilled-clients/index.js index a53872f8b..b1f55abac 100644 --- a/modules/invoiceIn/front/unbilled-clients/index.js +++ b/modules/invoiceIn/front/unbilled-clients/index.js @@ -52,8 +52,6 @@ export default class Controller extends Section { return {'taxableBase': value}; case 'ticketFk': return {'ticketFk': value}; - case 'comercialId': - return {'comercialId': value}; case 'comercialName': return {'comercialName': value}; } From 61a0d8bcb204b75d54069da7eb5af3c63b6bbb35 Mon Sep 17 00:00:00 2001 From: alexandre Date: Mon, 20 Mar 2023 10:15:18 +0100 Subject: [PATCH 06/13] refs #5092 showing clients with multiple negative bases --- modules/invoiceIn/back/methods/invoice-in/unbilledClients.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/invoiceIn/back/methods/invoice-in/unbilledClients.js b/modules/invoiceIn/back/methods/invoice-in/unbilledClients.js index ad39bc547..790185d25 100644 --- a/modules/invoiceIn/back/methods/invoice-in/unbilledClients.js +++ b/modules/invoiceIn/back/methods/invoice-in/unbilledClients.js @@ -89,8 +89,8 @@ module.exports = Self => { WHERE t.shipped BETWEEN ? AND ? AND t.refFk IS NULL AND c.typeFk IN ('normal','trust') - GROUP BY t.clientFk - HAVING amount <> 0`, [args.from, args.to])); + GROUP BY t.clientFk, negativeBase.taxableBase + HAVING amount < 0`, [args.from, args.to])); stmt = new ParameterizedSQL(` SELECT f.* From 700151b500853f9d4065fb089c4f9221163dbad2 Mon Sep 17 00:00:00 2001 From: alexandre Date: Wed, 22 Mar 2023 08:18:56 +0100 Subject: [PATCH 07/13] refs #5092 amount <> 0 --- modules/invoiceIn/back/methods/invoice-in/unbilledClients.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/invoiceIn/back/methods/invoice-in/unbilledClients.js b/modules/invoiceIn/back/methods/invoice-in/unbilledClients.js index 790185d25..216af4d48 100644 --- a/modules/invoiceIn/back/methods/invoice-in/unbilledClients.js +++ b/modules/invoiceIn/back/methods/invoice-in/unbilledClients.js @@ -90,7 +90,7 @@ module.exports = Self => { AND t.refFk IS NULL AND c.typeFk IN ('normal','trust') GROUP BY t.clientFk, negativeBase.taxableBase - HAVING amount < 0`, [args.from, args.to])); + HAVING amount <> 0`, [args.from, args.to])); stmt = new ParameterizedSQL(` SELECT f.* From 87d0dc3cece9d674ff70e65894bf70d02932e7d8 Mon Sep 17 00:00:00 2001 From: alexandre Date: Tue, 28 Mar 2023 08:25:41 +0200 Subject: [PATCH 08/13] refs #5092 changed name to negative bases --- db/changes/231201/00-negativeBases.sql | 4 ++++ db/changes/231201/00-unbilledClients.sql | 4 ---- ...d_clients.spec.js => 05_negative_bases.spec.js} | 8 ++++---- .../{unbilledClients.js => negativeBases.js} | 12 ++++++------ .../{unbilledClientsCsv.js => negativeBasesCsv.js} | 14 +++++++------- ...billedClients.spec.js => negativeBases.spec.js} | 8 ++++---- modules/invoiceIn/back/models/invoice-in.js | 4 ++-- modules/invoiceIn/front/index.js | 2 +- modules/invoiceIn/front/locale/es.yml | 2 +- .../index.html | 2 +- .../{unbilled-clients => negative-bases}/index.js | 6 +++--- .../locale/es.yml | 0 .../style.scss | 2 +- modules/invoiceIn/front/routes.json | 10 +++++----- 14 files changed, 39 insertions(+), 39 deletions(-) create mode 100644 db/changes/231201/00-negativeBases.sql delete mode 100644 db/changes/231201/00-unbilledClients.sql rename e2e/paths/09-invoice-in/{05_unbilled_clients.spec.js => 05_negative_bases.spec.js} (70%) rename modules/invoiceIn/back/methods/invoice-in/{unbilledClients.js => negativeBases.js} (92%) rename modules/invoiceIn/back/methods/invoice-in/{unbilledClientsCsv.js => negativeBasesCsv.js} (69%) rename modules/invoiceIn/back/methods/invoice-in/specs/{unbilledClients.spec.js => negativeBases.spec.js} (79%) rename modules/invoiceIn/front/{unbilled-clients => negative-bases}/index.html (99%) rename modules/invoiceIn/front/{unbilled-clients => negative-bases}/index.js (94%) rename modules/invoiceIn/front/{unbilled-clients => negative-bases}/locale/es.yml (100%) rename modules/invoiceIn/front/{unbilled-clients => negative-bases}/style.scss (85%) diff --git a/db/changes/231201/00-negativeBases.sql b/db/changes/231201/00-negativeBases.sql new file mode 100644 index 000000000..0bdc6f2dc --- /dev/null +++ b/db/changes/231201/00-negativeBases.sql @@ -0,0 +1,4 @@ +INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) + VALUES + ('InvoiceIn', 'negativeBases', 'READ', 'ALLOW', 'ROLE', 'administrative'), + ('InvoiceIn', 'negativeBasesCsv', 'READ', 'ALLOW', 'ROLE', 'administrative'); diff --git a/db/changes/231201/00-unbilledClients.sql b/db/changes/231201/00-unbilledClients.sql deleted file mode 100644 index 16127dd18..000000000 --- a/db/changes/231201/00-unbilledClients.sql +++ /dev/null @@ -1,4 +0,0 @@ -INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) - VALUES - ('InvoiceIn', 'unbilledClients', 'READ', 'ALLOW', 'ROLE', 'administrative'), - ('InvoiceIn', 'unbilledClientsCsv', 'READ', 'ALLOW', 'ROLE', 'administrative'); diff --git a/e2e/paths/09-invoice-in/05_unbilled_clients.spec.js b/e2e/paths/09-invoice-in/05_negative_bases.spec.js similarity index 70% rename from e2e/paths/09-invoice-in/05_unbilled_clients.spec.js rename to e2e/paths/09-invoice-in/05_negative_bases.spec.js index 629f24404..4c9fe651f 100644 --- a/e2e/paths/09-invoice-in/05_unbilled_clients.spec.js +++ b/e2e/paths/09-invoice-in/05_negative_bases.spec.js @@ -1,6 +1,6 @@ import getBrowser from '../../helpers/puppeteer'; -describe('InvoiceIn unbilled clients path', () => { +describe('InvoiceIn negative bases path', () => { let browser; let page; const httpRequests = []; @@ -9,18 +9,18 @@ describe('InvoiceIn unbilled clients path', () => { browser = await getBrowser(); page = browser.page; page.on('request', req => { - if (req.url().includes(`InvoiceIns/unbilledClients`)) + if (req.url().includes(`InvoiceIns/negativeBases`)) httpRequests.push(req.url()); }); await page.loginAndModule('administrative', 'invoiceIn'); - await page.accessToSection('invoiceIn.unbilled-clients'); + await page.accessToSection('invoiceIn.negative-bases'); }); afterAll(async() => { await browser.close(); }); - it('should show unbilled clients in a date range', async() => { + it('should show negative bases in a date range', async() => { const request = httpRequests.find(req => req.includes(`from`) && req.includes(`to`)); diff --git a/modules/invoiceIn/back/methods/invoice-in/unbilledClients.js b/modules/invoiceIn/back/methods/invoice-in/negativeBases.js similarity index 92% rename from modules/invoiceIn/back/methods/invoice-in/unbilledClients.js rename to modules/invoiceIn/back/methods/invoice-in/negativeBases.js index 216af4d48..4d5975fab 100644 --- a/modules/invoiceIn/back/methods/invoice-in/unbilledClients.js +++ b/modules/invoiceIn/back/methods/invoice-in/negativeBases.js @@ -2,8 +2,8 @@ const UserError = require('vn-loopback/util/user-error'); const ParameterizedSQL = require('loopback-connector').ParameterizedSQL; module.exports = Self => { - Self.remoteMethodCtx('unbilledClients', { - description: 'Find all unbilled clients', + Self.remoteMethodCtx('negativeBases', { + description: 'Find all negative bases', accessType: 'READ', accepts: [ { @@ -27,12 +27,12 @@ module.exports = Self => { root: true }, http: { - path: `/unbilledClients`, + path: `/negativeBases`, verb: 'GET' } }); - Self.unbilledClients = async(ctx, options) => { + Self.negativeBases = async(ctx, options) => { const conn = Self.dataSource.connector; const args = ctx.args; @@ -99,14 +99,14 @@ module.exports = Self => { stmt.merge(conn.makeWhere(args.filter.where)); stmt.merge(conn.makeOrderBy(args.filter.order)); - const clientsIndex = stmts.push(stmt) - 1; + const negativeBasesIndex = stmts.push(stmt) - 1; stmts.push(`DROP TEMPORARY TABLE tmp.filter, tmp.ticket, tmp.ticketTax, tmp.ticketAmount`); const sql = ParameterizedSQL.join(stmts, ';'); const result = await conn.executeStmt(sql, myOptions); - return clientsIndex === 0 ? result : result[clientsIndex]; + return negativeBasesIndex === 0 ? result : result[negativeBasesIndex]; }; }; diff --git a/modules/invoiceIn/back/methods/invoice-in/unbilledClientsCsv.js b/modules/invoiceIn/back/methods/invoice-in/negativeBasesCsv.js similarity index 69% rename from modules/invoiceIn/back/methods/invoice-in/unbilledClientsCsv.js rename to modules/invoiceIn/back/methods/invoice-in/negativeBasesCsv.js index f9b30d83b..963151b7d 100644 --- a/modules/invoiceIn/back/methods/invoice-in/unbilledClientsCsv.js +++ b/modules/invoiceIn/back/methods/invoice-in/negativeBasesCsv.js @@ -1,11 +1,11 @@ const {toCSV} = require('vn-loopback/util/csv'); module.exports = Self => { - Self.remoteMethodCtx('unbilledClientsCsv', { - description: 'Returns the unbilled clients as .csv', + Self.remoteMethodCtx('negativeBasesCsv', { + description: 'Returns the negative bases as .csv', accessType: 'READ', accepts: [{ - arg: 'unbilledClients', + arg: 'negativeBases', type: ['object'], required: true }, @@ -35,19 +35,19 @@ module.exports = Self => { } ], http: { - path: '/unbilledClientsCsv', + path: '/negativeBasesCsv', verb: 'GET' } }); - Self.unbilledClientsCsv = async ctx => { + Self.negativeBasesCsv = async ctx => { const args = ctx.args; - const content = toCSV(args.unbilledClients); + const content = toCSV(args.negativeBases); return [ content, 'text/csv', - `attachment; filename="unbilled-clients-${new Date(args.from).toLocaleDateString()}-${new Date(args.to).toLocaleDateString()}.csv"` + `attachment; filename="negative-bases-${new Date(args.from).toLocaleDateString()}-${new Date(args.to).toLocaleDateString()}.csv"` ]; }; }; diff --git a/modules/invoiceIn/back/methods/invoice-in/specs/unbilledClients.spec.js b/modules/invoiceIn/back/methods/invoice-in/specs/negativeBases.spec.js similarity index 79% rename from modules/invoiceIn/back/methods/invoice-in/specs/unbilledClients.spec.js rename to modules/invoiceIn/back/methods/invoice-in/specs/negativeBases.spec.js index fcb3173ab..a5c6e3102 100644 --- a/modules/invoiceIn/back/methods/invoice-in/specs/unbilledClients.spec.js +++ b/modules/invoiceIn/back/methods/invoice-in/specs/negativeBases.spec.js @@ -1,7 +1,7 @@ const models = require('vn-loopback/server/server').models; -describe('invoiceIn unbilledClients()', () => { - it('should return all unbilled clients in a date range', async() => { +describe('invoiceIn negativeBases()', () => { + it('should return all negative bases in a date range', async() => { const tx = await models.InvoiceIn.beginTransaction({}); const options = {transaction: tx}; const ctx = { @@ -13,7 +13,7 @@ describe('invoiceIn unbilledClients()', () => { }; try { - const result = await models.InvoiceIn.unbilledClients(ctx, options); + const result = await models.InvoiceIn.negativeBases(ctx, options); expect(result.length).toBeGreaterThan(0); @@ -35,7 +35,7 @@ describe('invoiceIn unbilledClients()', () => { }; try { - await models.InvoiceIn.unbilledClients(ctx, options); + await models.InvoiceIn.negativeBases(ctx, options); await tx.rollback(); } catch (e) { error = e; diff --git a/modules/invoiceIn/back/models/invoice-in.js b/modules/invoiceIn/back/models/invoice-in.js index ebb2981e1..d87b8c111 100644 --- a/modules/invoiceIn/back/models/invoice-in.js +++ b/modules/invoiceIn/back/models/invoice-in.js @@ -6,6 +6,6 @@ module.exports = Self => { require('../methods/invoice-in/getTotals')(Self); require('../methods/invoice-in/invoiceInPdf')(Self); require('../methods/invoice-in/invoiceInEmail')(Self); - require('../methods/invoice-in/unbilledClients')(Self); - require('../methods/invoice-in/unbilledClientsCsv')(Self); + require('../methods/invoice-in/negativeBases')(Self); + require('../methods/invoice-in/negativeBasesCsv')(Self); }; diff --git a/modules/invoiceIn/front/index.js b/modules/invoiceIn/front/index.js index 7576848bf..69593dd5b 100644 --- a/modules/invoiceIn/front/index.js +++ b/modules/invoiceIn/front/index.js @@ -13,4 +13,4 @@ import './dueDay'; import './intrastat'; import './create'; import './log'; -import './unbilled-clients'; +import './negative-bases'; diff --git a/modules/invoiceIn/front/locale/es.yml b/modules/invoiceIn/front/locale/es.yml index 2b444f75b..71fd3b87b 100644 --- a/modules/invoiceIn/front/locale/es.yml +++ b/modules/invoiceIn/front/locale/es.yml @@ -22,4 +22,4 @@ Total stems: Total tallos Show agricultural receipt as PDF: Ver recibo agrícola como PDF Send agricultural receipt as PDF: Enviar recibo agrícola como PDF New InvoiceIn: Nueva Factura -Unbilled clients: Clientes sin facturar +Negative bases: Bases negativas diff --git a/modules/invoiceIn/front/unbilled-clients/index.html b/modules/invoiceIn/front/negative-bases/index.html similarity index 99% rename from modules/invoiceIn/front/unbilled-clients/index.html rename to modules/invoiceIn/front/negative-bases/index.html index c4c561191..368f44461 100644 --- a/modules/invoiceIn/front/unbilled-clients/index.html +++ b/modules/invoiceIn/front/negative-bases/index.html @@ -1,6 +1,6 @@ diff --git a/modules/invoiceIn/front/unbilled-clients/index.js b/modules/invoiceIn/front/negative-bases/index.js similarity index 94% rename from modules/invoiceIn/front/unbilled-clients/index.js rename to modules/invoiceIn/front/negative-bases/index.js index b1f55abac..0f6f04692 100644 --- a/modules/invoiceIn/front/unbilled-clients/index.js +++ b/modules/invoiceIn/front/negative-bases/index.js @@ -68,8 +68,8 @@ export default class Controller extends Section { return result; }, {})); }); - this.vnReport.show('InvoiceIns/unbilledClientsCsv', { - unbilledClients: data, + this.vnReport.show('InvoiceIns/negativeBasesCsv', { + negativeBases: data, from: this.params.from, to: this.params.to }); @@ -78,7 +78,7 @@ export default class Controller extends Section { Controller.$inject = ['$element', '$scope', 'vnReport']; -ngModule.vnComponent('vnUnbilledClients', { +ngModule.vnComponent('vnNegativeBases', { template: require('./index.html'), controller: Controller }); diff --git a/modules/invoiceIn/front/unbilled-clients/locale/es.yml b/modules/invoiceIn/front/negative-bases/locale/es.yml similarity index 100% rename from modules/invoiceIn/front/unbilled-clients/locale/es.yml rename to modules/invoiceIn/front/negative-bases/locale/es.yml diff --git a/modules/invoiceIn/front/unbilled-clients/style.scss b/modules/invoiceIn/front/negative-bases/style.scss similarity index 85% rename from modules/invoiceIn/front/unbilled-clients/style.scss rename to modules/invoiceIn/front/negative-bases/style.scss index dbed8b967..2d628cb94 100644 --- a/modules/invoiceIn/front/unbilled-clients/style.scss +++ b/modules/invoiceIn/front/negative-bases/style.scss @@ -1,6 +1,6 @@ @import "./variables"; -vn-unbilled-clients { +vn-negative-bases { vn-date-picker{ padding-right: 5%; } diff --git a/modules/invoiceIn/front/routes.json b/modules/invoiceIn/front/routes.json index 567323571..0d95c7e80 100644 --- a/modules/invoiceIn/front/routes.json +++ b/modules/invoiceIn/front/routes.json @@ -10,7 +10,7 @@ "menus": { "main": [ { "state": "invoiceIn.index", "icon": "icon-invoice-in"}, - { "state": "invoiceIn.unbilled-clients", "icon": "person"} + { "state": "invoiceIn.negative-bases", "icon": "icon-ticket"} ], "card": [ { @@ -53,10 +53,10 @@ ] }, { - "url": "/unbilled-clients", - "state": "invoiceIn.unbilled-clients", - "component": "vn-unbilled-clients", - "description": "Unbilled clients", + "url": "/negative-bases", + "state": "invoiceIn.negative-bases", + "component": "vn-negative-bases", + "description": "Negative bases", "acl": [ "administrative" ] From 02a1bcbfd30737b6c0fc26ff763fc5f887f28693 Mon Sep 17 00:00:00 2001 From: joan Date: Mon, 3 Apr 2023 08:54:15 +0200 Subject: [PATCH 09/13] fix(setPassword): proper access type Refs #5471 --- back/methods/account/change-password.js | 1 + back/methods/account/set-password.js | 1 + 2 files changed, 2 insertions(+) diff --git a/back/methods/account/change-password.js b/back/methods/account/change-password.js index c0956b193..b8f9de341 100644 --- a/back/methods/account/change-password.js +++ b/back/methods/account/change-password.js @@ -2,6 +2,7 @@ module.exports = Self => { Self.remoteMethod('changePassword', { description: 'Changes the user password', + accessType: 'WRITE', accepts: [ { arg: 'id', diff --git a/back/methods/account/set-password.js b/back/methods/account/set-password.js index ab4d3b3fe..093935948 100644 --- a/back/methods/account/set-password.js +++ b/back/methods/account/set-password.js @@ -1,6 +1,7 @@ module.exports = Self => { Self.remoteMethod('setPassword', { description: 'Sets the user password', + accessType: 'WRITE', accepts: [ { arg: 'id', From 32df51eccaf965523de58c3dbc3a2e29bee4f801 Mon Sep 17 00:00:00 2001 From: alexandre Date: Tue, 4 Apr 2023 08:40:51 +0200 Subject: [PATCH 10/13] refs #5092 moved sql --- db/changes/231401/.gitkeep | 0 db/changes/{231201 => 231401}/00-negativeBases.sql | 0 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 db/changes/231401/.gitkeep rename db/changes/{231201 => 231401}/00-negativeBases.sql (100%) diff --git a/db/changes/231401/.gitkeep b/db/changes/231401/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/db/changes/231201/00-negativeBases.sql b/db/changes/231401/00-negativeBases.sql similarity index 100% rename from db/changes/231201/00-negativeBases.sql rename to db/changes/231401/00-negativeBases.sql From 98f61ecfdbfc34b6aa596ed03adafd31e5cecbe2 Mon Sep 17 00:00:00 2001 From: alexandre Date: Tue, 4 Apr 2023 08:47:56 +0200 Subject: [PATCH 11/13] refs #5092 changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 25c1fc2fe..c5ee05fe4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [2314.01] - 2023-04-20 ### Added -- +- (Facturas recibidas -> Bases negativas) Nueva sección ### Changed - From e8f0a49f0c2dd223a9e6672b324d2b362076d9e2 Mon Sep 17 00:00:00 2001 From: joan Date: Tue, 4 Apr 2023 13:51:44 +0200 Subject: [PATCH 12/13] fix(resetPassword): increased token TTL for password recovery Refs #5474 --- back/models/user.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/back/models/user.json b/back/models/user.json index 921362e0e..d992fd9db 100644 --- a/back/models/user.json +++ b/back/models/user.json @@ -4,7 +4,8 @@ "options": { "mysql": { "table": "salix.User" - } + }, + "resetPasswordTokenTTL": "604800" }, "properties": { "id": { From c126c6044acb635a1373305ea1a4fc901d023f9b Mon Sep 17 00:00:00 2001 From: joan Date: Tue, 4 Apr 2023 13:55:44 +0200 Subject: [PATCH 13/13] Updated format --- .../back/methods/item-image-queue/download.js | 22 ++-- .../item-image-queue/downloadImages.js | 105 ------------------ 2 files changed, 11 insertions(+), 116 deletions(-) delete mode 100644 modules/item/back/methods/item-image-queue/downloadImages.js diff --git a/modules/item/back/methods/item-image-queue/download.js b/modules/item/back/methods/item-image-queue/download.js index cdc0fe049..5f1b460fc 100644 --- a/modules/item/back/methods/item-image-queue/download.js +++ b/modules/item/back/methods/item-image-queue/download.js @@ -1,7 +1,7 @@ const axios = require('axios'); const uuid = require('uuid'); const fs = require('fs/promises'); -const { createWriteStream } = require('fs'); +const {createWriteStream} = require('fs'); const path = require('path'); const gm = require('gm'); @@ -15,7 +15,7 @@ module.exports = Self => { }, }); - Self.download = async () => { + Self.download = async() => { const models = Self.app.models; const tempContainer = await models.TempContainer.container( 'salix-image' @@ -32,13 +32,13 @@ module.exports = Self => { let tempFilePath; let queueRow; try { - const myOptions = { transaction: tx }; + const myOptions = {transaction: tx}; queueRow = await Self.findOne( { fields: ['id', 'itemFk', 'url', 'attempts'], where: { - url: { neq: null }, + url: {neq: null}, attempts: { lt: maxAttempts, }, @@ -59,7 +59,7 @@ module.exports = Self => { 'model', 'property', ], - where: { name: collectionName }, + where: {name: collectionName}, include: { relation: 'sizes', scope: { @@ -116,16 +116,16 @@ module.exports = Self => { const collectionDir = path.join(rootPath, collectionName); // To max size - const { maxWidth, maxHeight } = collection; + const {maxWidth, maxHeight} = collection; const fullSizePath = path.join(collectionDir, 'full'); const toFullSizePath = `${fullSizePath}/${fileName}`; - await fs.mkdir(fullSizePath, { recursive: true }); + await fs.mkdir(fullSizePath, {recursive: true}); await new Promise((resolve, reject) => { gm(tempFilePath) .resize(maxWidth, maxHeight, '>') .setFormat('png') - .write(toFullSizePath, function (err) { + .write(toFullSizePath, function(err) { if (err) reject(err); if (!err) resolve(); }); @@ -133,12 +133,12 @@ module.exports = Self => { // To collection sizes for (const size of collection.sizes()) { - const { width, height } = size; + const {width, height} = size; const sizePath = path.join(collectionDir, `${width}x${height}`); const toSizePath = `${sizePath}/${fileName}`; - await fs.mkdir(sizePath, { recursive: true }); + await fs.mkdir(sizePath, {recursive: true}); await new Promise((resolve, reject) => { const gmInstance = gm(tempFilePath); @@ -153,7 +153,7 @@ module.exports = Self => { gmInstance .setFormat('png') - .write(toSizePath, function (err) { + .write(toSizePath, function(err) { if (err) reject(err); if (!err) resolve(); }); diff --git a/modules/item/back/methods/item-image-queue/downloadImages.js b/modules/item/back/methods/item-image-queue/downloadImages.js deleted file mode 100644 index 7f53df95a..000000000 --- a/modules/item/back/methods/item-image-queue/downloadImages.js +++ /dev/null @@ -1,105 +0,0 @@ -const https = require('https'); -const fs = require('fs-extra'); -const path = require('path'); -const uuid = require('uuid'); - -module.exports = Self => { - Self.remoteMethod('downloadImages', { - description: 'Returns last entries', - accessType: 'WRITE', - returns: { - type: ['Object'], - root: true - }, - http: { - path: `/downloadImages`, - verb: 'POST' - } - }); - - Self.downloadImages = async() => { - const models = Self.app.models; - const container = await models.TempContainer.container('salix-image'); - const tempPath = path.join(container.client.root, container.name); - const maxAttempts = 3; - - const images = await Self.find({ - where: {attempts: {eq: maxAttempts}} - }); - - for (let image of images) { - const currentStamp = Date.vnNew().getTime(); - const updatedStamp = image.updated.getTime(); - const graceTime = Math.abs(currentStamp - updatedStamp); - const maxTTL = 3600 * 48 * 1000; // 48 hours in ms; - - if (graceTime >= maxTTL) - await Self.destroyById(image.itemFk); - } - - download(); - - async function download() { - const image = await Self.findOne({ - where: {url: {neq: null}, attempts: {lt: maxAttempts}}, - order: 'priority, attempts, updated' - }); - - if (!image) return; - - const fileName = `${uuid.v4()}.png`; - const filePath = path.join(tempPath, fileName); - const imageUrl = image.url.replace('http://', 'https://'); - - https.get(imageUrl, async response => { - if (response.statusCode != 200) { - const error = new Error(`Could not download the image. Status code ${response.statusCode}`); - - return await errorHandler(image.itemFk, error, filePath); - } - - const writeStream = fs.createWriteStream(filePath); - writeStream.on('open', () => response.pipe(writeStream)); - writeStream.on('error', async error => - await errorHandler(image.itemFk, error, filePath)); - writeStream.on('finish', () => writeStream.end()); - - writeStream.on('close', async function() { - try { - await models.Image.registerImage('catalog', filePath, fileName, image.itemFk); - await image.destroy(); - - download(); - } catch (error) { - await errorHandler(image.itemFk, error, filePath); - } - }); - }).on('error', async error => { - await errorHandler(image.itemFk, error, filePath); - }); - } - - async function errorHandler(rowId, error, filePath) { - try { - const row = await Self.findById(rowId); - - if (!row) return; - - if (row.attempts < maxAttempts) { - await row.updateAttributes({ - error: error, - attempts: row.attempts + 1, - updated: Date.vnNew() - }); - } - - if (filePath && fs.existsSync(filePath)) - await fs.unlink(filePath); - - download(); - } catch (err) { - throw new Error(`Image download failed: ${err}`); - } - } - }; -};