diff --git a/db/changes/10411-january/00-ticket_getMovable.sql b/db/changes/10420-valentines/00-ticket_getMovable.sql similarity index 77% rename from db/changes/10411-january/00-ticket_getMovable.sql rename to db/changes/10420-valentines/00-ticket_getMovable.sql index 5f5b0a93a..eb5c722c4 100644 --- a/db/changes/10411-january/00-ticket_getMovable.sql +++ b/db/changes/10420-valentines/00-ticket_getMovable.sql @@ -6,20 +6,23 @@ CREATE DEFINER=`root`@`%` PROCEDURE `vn`.`ticket_getMovable`(vTicketFk INT, vDat BEGIN /** * Cálcula el stock movible para los artículos de un ticket + * vDatedNew debe ser menor que vDatedOld, en los otros casos se + * asume que siempre es posible * * @param vTicketFk -> Ticket * @param vDatedNew -> Nueva fecha * @return Sales con Movible */ DECLARE vDatedOld DATETIME; - + SET vDatedNew = DATE_ADD(vDatedNew, INTERVAL 1 DAY); + SELECT t.shipped INTO vDatedOld FROM ticket t WHERE t.id = vTicketFk; - CALL itemStock(vWarehouseFk, DATE_SUB(vDatedNew, INTERVAL 1 DAY), NULL); - CALL item_getMinacum(vWarehouseFk, vDatedNew, DATEDIFF(vDatedOld, vDatedNew), NULL); - + CALL itemStock(vWarehouseFk, vDatedNew, NULL); + CALL item_getMinacum(vWarehouseFk, vDatedNew, DATEDIFF(DATE_SUB(vDatedOld, INTERVAL 1 DAY), vDatedNew), NULL); + SELECT s.id, s.itemFk, s.quantity, diff --git a/modules/account/back/models/role-config.js b/modules/account/back/models/role-config.js index b5cfb7b83..6051f2060 100644 --- a/modules/account/back/models/role-config.js +++ b/modules/account/back/models/role-config.js @@ -1,7 +1,13 @@ module.exports = Self => { Self.getSynchronizer = async function() { - return await Self.findOne({fields: ['id']}); + let NODE_ENV = process.env.NODE_ENV; + if (!NODE_ENV || NODE_ENV == 'development') + return null; + + return await Self.findOne({ + fields: ['id', 'rolePrefix', 'userPrefix', 'userHost'] + }); }; Object.assign(Self.prototype, { @@ -14,17 +20,16 @@ module.exports = Self => { }, async syncUser(userName, info, password) { - const mysqlHost = '%'; - let mysqlUser = userName; - if (this.dbType == 'MySQL') mysqlUser = `!${mysqlUser}`; + if (this.dbType == 'MySQL') + mysqlUser = this.userPrefix + mysqlUser; const [row] = await Self.rawSql( `SELECT COUNT(*) AS nRows FROM mysql.user WHERE User = ? AND Host = ?`, - [mysqlUser, mysqlHost] + [mysqlUser, this.userHost] ); let userExists = row.nRows > 0; @@ -35,11 +40,10 @@ module.exports = Self => { FROM mysql.global_priv WHERE User = ? AND Host = ?`, - [mysqlUser, mysqlHost] + [mysqlUser, this.userHost] ); const priv = row && JSON.parse(row.priv); - const role = priv && priv.default_role; - isUpdatable = !row || (role && role.startsWith('z-')); + isUpdatable = !row || (priv && priv.autogenerated); } if (!isUpdatable) { @@ -51,31 +55,27 @@ module.exports = Self => { if (password) { if (!userExists) { await Self.rawSql('CREATE USER ?@? IDENTIFIED BY ?', - [mysqlUser, mysqlHost, password] - ); + [mysqlUser, this.userHost, password]); userExists = true; } else { switch (this.dbType) { case 'MariaDB': await Self.rawSql('ALTER USER ?@? IDENTIFIED BY ?', - [mysqlUser, mysqlHost, password] - ); + [mysqlUser, this.userHost, password]); break; default: await Self.rawSql('SET PASSWORD FOR ?@? = PASSWORD(?)', - [mysqlUser, mysqlHost, password] - ); + [mysqlUser, this.userHost, password]); } } } if (userExists && this.dbType == 'MariaDB') { - let role = `z-${info.user.role().name}`; + let role = `${this.rolePrefix}${info.user.role().name}`; try { await Self.rawSql('REVOKE ALL, GRANT OPTION FROM ?@?', - [mysqlUser, mysqlHost] - ); + [mysqlUser, this.userHost]); } catch (err) { if (err.code == 'ER_REVOKE_GRANTS') console.warn(`${err.code}: ${err.sqlMessage}: ${err.sql}`); @@ -83,21 +83,18 @@ module.exports = Self => { throw err; } await Self.rawSql('GRANT ? TO ?@?', - [role, mysqlUser, mysqlHost] - ); + [role, mysqlUser, this.userHost]); if (role) { await Self.rawSql('SET DEFAULT ROLE ? FOR ?@?', - [role, mysqlUser, mysqlHost] - ); + [role, mysqlUser, this.userHost]); } else { await Self.rawSql('SET DEFAULT ROLE NONE FOR ?@?', - [mysqlUser, mysqlHost] - ); + [mysqlUser, this.userHost]); } } } else if (userExists) - await Self.rawSql('DROP USER ?@?', [mysqlUser, mysqlHost]); + await Self.rawSql('DROP USER ?@?', [mysqlUser, this.userHost]); } }); }; diff --git a/modules/account/back/models/role-config.json b/modules/account/back/models/role-config.json index c2abfcc38..f4138bea8 100644 --- a/modules/account/back/models/role-config.json +++ b/modules/account/back/models/role-config.json @@ -16,6 +16,18 @@ }, "mysqlPassword": { "type": "string" + }, + "rolePrefix": { + "type": "string" + }, + "userPrefix": { + "type": "string" + }, + "userHost": { + "type": "string" + }, + "tplUser": { + "type": "string" } } } diff --git a/modules/claim/front/search-panel/index.html b/modules/claim/front/search-panel/index.html index dbbc3a46b..22faf9ec4 100644 --- a/modules/claim/front/search-panel/index.html +++ b/modules/claim/front/search-panel/index.html @@ -28,7 +28,7 @@ url="Workers/activeWithRole" search-function="{firstName: $search}" value-field="id" - where="{role: {inq: ['salesPerson', 'officeBoss']}}" + where="{role: {inq: ['salesBoss', 'salesPerson', 'officeBoss']}}" label="Salesperson"> {{firstName}} {{name}} @@ -38,7 +38,7 @@ url="Workers/activeWithRole" search-function="{firstName: $search}" value-field="id" - where="{role: 'salesPerson'}" + where="{role: {inq: ['salesBoss', 'salesPerson']}}" label="Attended by"> {{firstName}} {{name}} diff --git a/modules/client/back/methods/client/specs/sendSms.spec.js b/modules/client/back/methods/client/specs/sendSms.spec.js index 121d427ce..54fe802e3 100644 --- a/modules/client/back/methods/client/specs/sendSms.spec.js +++ b/modules/client/back/methods/client/specs/sendSms.spec.js @@ -1,7 +1,8 @@ const models = require('vn-loopback/server/server').models; const soap = require('soap'); -describe('client sendSms()', () => { +// #3673 sendSms tests excluded +xdescribe('client sendSms()', () => { it('should now send a message and log it', async() => { spyOn(soap, 'createClientAsync').and.returnValue('a so fake client'); const tx = await models.Client.beginTransaction({}); diff --git a/modules/client/back/methods/sms/send.spec.js b/modules/client/back/methods/sms/send.spec.js index 7ca78b214..a81c24e96 100644 --- a/modules/client/back/methods/sms/send.spec.js +++ b/modules/client/back/methods/sms/send.spec.js @@ -1,6 +1,7 @@ const app = require('vn-loopback/server/server'); -describe('sms send()', () => { +// #3673 sendSms tests excluded +xdescribe('sms send()', () => { it('should not return status error', async() => { const ctx = {req: {accessToken: {userId: 1}}}; const result = await app.models.Sms.send(ctx, 1105, '123456789', 'My SMS Body'); diff --git a/modules/item/front/waste/index/index.html b/modules/item/front/waste/index/index.html index 7ad985ea8..c80733e9e 100644 --- a/modules/item/front/waste/index/index.html +++ b/modules/item/front/waste/index/index.html @@ -3,13 +3,21 @@ url="Items/getWasteByWorker" data="details"> - - -
- -
{{detail.buyer}}
-
+
+ +
{{detail.buyer}}
+ + + + +
+ @@ -21,7 +29,7 @@ + ui-sref="item.waste.detail({buyer: waste.buyer, family: waste.family})"> {{::waste.family}} {{::(waste.percentage / 100) | percentage: 2}} {{::waste.dwindle | currency: 'EUR'}} @@ -29,6 +37,6 @@ -
- - + +
+
\ No newline at end of file diff --git a/modules/item/front/waste/index/index.js b/modules/item/front/waste/index/index.js index 15e6b063f..b11f54b08 100644 --- a/modules/item/front/waste/index/index.js +++ b/modules/item/front/waste/index/index.js @@ -2,7 +2,34 @@ import ngModule from '../../module'; import Section from 'salix/components/section'; import './style.scss'; +export default class Controller extends Section { + constructor($element, $) { + super($element, $); + + this.getWasteConfig(); + } + + getWasteConfig() { + return this.wasteConfig = JSON.parse(localStorage.getItem('wasteConfig')) || {}; + } + + setWasteConfig() { + localStorage.setItem('wasteConfig', JSON.stringify(this.wasteConfig)); + } + + toggleHidePanel(detail) { + if (!this.wasteConfig[detail.buyer]) { + this.wasteConfig[detail.buyer] = { + hidden: true + }; + } else + this.wasteConfig[detail.buyer].hidden = !this.wasteConfig[detail.buyer].hidden; + + this.setWasteConfig(); + } +} + ngModule.vnComponent('vnItemWasteIndex', { template: require('./index.html'), - controller: Section + controller: Controller }); diff --git a/modules/item/front/waste/index/index.spec.js b/modules/item/front/waste/index/index.spec.js new file mode 100644 index 000000000..fd7332f68 --- /dev/null +++ b/modules/item/front/waste/index/index.spec.js @@ -0,0 +1,53 @@ +import './index.js'; +import crudModel from 'core/mocks/crud-model'; + +describe('Item', () => { + describe('Component vnItemWasteIndex', () => { + let $scope; + let controller; + + beforeEach(ngModule('item')); + + beforeEach(inject(($componentController, $rootScope) => { + $scope = $rootScope.$new(); + $scope.model = crudModel; + const $element = angular.element(''); + controller = $componentController('vnItemWasteIndex', {$element, $scope}); + })); + + describe('getWasteConfig / setWasteConfig', () => { + it('should return the local storage wasteConfig', () => { + const result = controller.getWasteConfig(); + + expect(result).toEqual({}); + }); + + it('should set and return the local storage wasteConfig', () => { + controller.wasteConfig = {salesPerson: {hidden: true}}; + controller.setWasteConfig(); + + const result = controller.getWasteConfig(); + + expect(result).toEqual(controller.wasteConfig); + }); + }); + + describe('toggleHidePanel()', () => { + it('should make details hidden by default', () => { + controller.wasteConfig = {}; + + controller.toggleHidePanel({buyer: 'salesPerson'}); + + expect(controller.wasteConfig.salesPerson.hidden).toEqual(true); + }); + + it('should toggle hidden false', () => { + controller.wasteConfig = {salesPerson: {hidden: true}}; + + controller.toggleHidePanel({buyer: 'salesPerson'}); + + expect(controller.wasteConfig.salesPerson.hidden).toEqual(false); + }); + }); + }); +}); diff --git a/modules/item/front/waste/index/style.scss b/modules/item/front/waste/index/style.scss index faac46139..8b44cb6f1 100644 --- a/modules/item/front/waste/index/style.scss +++ b/modules/item/front/waste/index/style.scss @@ -1,21 +1,24 @@ @import "variables"; +@import "effects"; vn-item-waste-index, vn-item-waste-detail { .header { - margin-bottom: 16px; - text-transform: uppercase; - font-size: 1.25rem; - line-height: 1; - padding: 7px; - padding-bottom: 7px; - padding-bottom: 4px; - font-weight: lighter; - background-color: $color-bg; - border-bottom: 1px solid #f7931e; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; + padding: 12px 0 5px 0; + color: gray; + font-size: 1.2rem; + border-bottom: $border; + margin-bottom: 10px; + + & > vn-none > vn-icon { + @extend %clickable-light; + color: $color-button; + font-size: 1.4rem; + } + + vn-none > .arrow { + transition: transform 200ms; + } } vn-table vn-th.waste-family, @@ -23,4 +26,12 @@ vn-item-waste-detail { max-width: 64px; width: 64px } + .hidden { + display: none; + + } + .header > vn-none > .arrow.hidden { + display: block; + transform: rotate(180deg); + } } \ No newline at end of file diff --git a/modules/item/front/waste/locale/es.yml b/modules/item/front/waste/locale/es.yml index 9f08e3a72..b9cd33dec 100644 --- a/modules/item/front/waste/locale/es.yml +++ b/modules/item/front/waste/locale/es.yml @@ -1,3 +1,4 @@ Family: Familia Percentage: Porcentaje -Dwindle: Mermas \ No newline at end of file +Dwindle: Mermas +Minimize/Maximize: Minimizar/Maximizar \ No newline at end of file diff --git a/modules/ticket/back/methods/ticket/specs/priceDifference.spec.js b/modules/ticket/back/methods/ticket/specs/priceDifference.spec.js index e9aa5030a..d8c785baa 100644 --- a/modules/ticket/back/methods/ticket/specs/priceDifference.spec.js +++ b/modules/ticket/back/methods/ticket/specs/priceDifference.spec.js @@ -86,8 +86,8 @@ describe('sale priceDifference()', () => { const firstItem = result.items[0]; const secondtItem = result.items[1]; - expect(firstItem.movable).toEqual(440); - expect(secondtItem.movable).toEqual(1980); + expect(firstItem.movable).toEqual(410); + expect(secondtItem.movable).toEqual(1870); await tx.rollback(); } catch (e) { diff --git a/modules/ticket/back/methods/ticket/specs/sendSms.spec.js b/modules/ticket/back/methods/ticket/specs/sendSms.spec.js index 8ec4ca487..46ae23702 100644 --- a/modules/ticket/back/methods/ticket/specs/sendSms.spec.js +++ b/modules/ticket/back/methods/ticket/specs/sendSms.spec.js @@ -1,7 +1,8 @@ const models = require('vn-loopback/server/server').models; const soap = require('soap'); -describe('ticket sendSms()', () => { +// #3673 sendSms tests excluded +xdescribe('ticket sendSms()', () => { it('should send a message and log it', async() => { const tx = await models.Ticket.beginTransaction({}); diff --git a/modules/ticket/front/basic-data/step-two/index.html b/modules/ticket/front/basic-data/step-two/index.html index 092c9e746..6be455fc9 100644 --- a/modules/ticket/front/basic-data/step-two/index.html +++ b/modules/ticket/front/basic-data/step-two/index.html @@ -18,7 +18,14 @@ - {{("000000"+sale.itemFk).slice(-6)}} + + + {{::sale.itemFk | zeroFill:6}} + +
{{::sale.item.name}} @@ -83,5 +90,9 @@
- + + diff --git a/print/methods/closure/closure.js b/print/methods/closure/closure.js index 8cce8237c..2b58205e3 100644 --- a/print/methods/closure/closure.js +++ b/print/methods/closure/closure.js @@ -12,8 +12,6 @@ module.exports = { const failedtickets = []; for (const ticket of tickets) { try { - await db.rawSql('START TRANSACTION'); - await db.rawSql(`CALL vn.ticket_closeByTicket(?)`, [ticket.id]); const invoiceOut = await db.findOne(` @@ -91,9 +89,7 @@ module.exports = { const email = new Email('delivery-note-link', args); await email.send(); } - await db.rawSql('COMMIT'); } catch (error) { - await db.rawSql('ROLLBACK'); // Domain not found if (error.responseCode == 450) return invalidEmail(ticket); diff --git a/print/templates/reports/invoice/assets/css/style.css b/print/templates/reports/invoice/assets/css/style.css index cd605db9b..9fda2a613 100644 --- a/print/templates/reports/invoice/assets/css/style.css +++ b/print/templates/reports/invoice/assets/css/style.css @@ -5,7 +5,7 @@ h2 { .table-title { margin-bottom: 15px; - font-size: 0.8rem + font-size: .8rem } .table-title h2 { @@ -16,9 +16,12 @@ h2 { font-size: 22px } + #nickname h2 { - max-width: 400px; - word-wrap: break-word + max-width: 400px; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; } #phytosanitary { diff --git a/print/templates/reports/invoice/invoice.html b/print/templates/reports/invoice/invoice.html index 8b13f2a15..1d646a0db 100644 --- a/print/templates/reports/invoice/invoice.html +++ b/print/templates/reports/invoice/invoice.html @@ -85,7 +85,7 @@ -
+

{{$t('deliveryNote')}}