diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 000000000..bafedc760
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,17 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## [2302.01] - 2023-01-12
+
+### Added
+- [General](Inicio) Permite recuperar la contraseña
+
+### Changed
+
+
+### Removed
+- [Tickets](Control clientes) Eliminada sección
diff --git a/back/methods/campaign/latest.js b/back/methods/campaign/latest.js
index 20dda8a26..a418f1267 100644
--- a/back/methods/campaign/latest.js
+++ b/back/methods/campaign/latest.js
@@ -29,8 +29,12 @@ module.exports = Self => {
filter = mergeFilters(filter, {where});
const stmt = new ParameterizedSQL(
- `SELECT * FROM campaign`);
+ `SELECT * FROM (`);
+ stmt.merge('SELECT * FROM campaign');
stmt.merge(conn.makeWhere(filter.where));
+ stmt.merge('ORDER BY dated ASC');
+ stmt.merge('LIMIT 10000000000000000000');
+ stmt.merge(') sub');
stmt.merge('GROUP BY code');
stmt.merge(conn.makePagination(filter));
diff --git a/back/methods/collection/setSaleQuantity.js b/back/methods/collection/setSaleQuantity.js
index 644c44a60..b6c56ddc4 100644
--- a/back/methods/collection/setSaleQuantity.js
+++ b/back/methods/collection/setSaleQuantity.js
@@ -26,11 +26,30 @@ module.exports = Self => {
Self.setSaleQuantity = async(saleId, quantity) => {
const models = Self.app.models;
+ const myOptions = {};
+ let tx;
- const sale = await models.Sale.findById(saleId);
- return await sale.updateAttributes({
- originalQuantity: sale.quantity,
- quantity: quantity
- });
+ if (typeof options == 'object')
+ Object.assign(myOptions, options);
+
+ if (!myOptions.transaction) {
+ tx = await Self.beginTransaction({});
+ myOptions.transaction = tx;
+ }
+
+ try {
+ const sale = await models.Sale.findById(saleId, null, myOptions);
+ const saleUpdated = await sale.updateAttributes({
+ originalQuantity: sale.quantity,
+ quantity: quantity
+ }, myOptions);
+
+ if (tx) await tx.commit();
+
+ return saleUpdated;
+ } catch (e) {
+ if (tx) await tx.rollback();
+ throw e;
+ }
};
};
diff --git a/back/methods/collection/spec/setSaleQuantity.spec.js b/back/methods/collection/spec/setSaleQuantity.spec.js
index 5d06a4383..63dc3bd2d 100644
--- a/back/methods/collection/spec/setSaleQuantity.spec.js
+++ b/back/methods/collection/spec/setSaleQuantity.spec.js
@@ -2,15 +2,26 @@ const models = require('vn-loopback/server/server').models;
describe('setSaleQuantity()', () => {
it('should change quantity sale', async() => {
- const saleId = 30;
- const newQuantity = 10;
+ const tx = await models.Ticket.beginTransaction({});
- const originalSale = await models.Sale.findById(saleId);
+ try {
+ const options = {transaction: tx};
- await models.Collection.setSaleQuantity(saleId, newQuantity);
- const updateSale = await models.Sale.findById(saleId);
+ const saleId = 30;
+ const newQuantity = 10;
- expect(updateSale.originalQuantity).toEqual(originalSale.quantity);
- expect(updateSale.quantity).toEqual(newQuantity);
+ const originalSale = await models.Sale.findById(saleId, null, options);
+
+ await models.Collection.setSaleQuantity(saleId, newQuantity, options);
+ const updateSale = await models.Sale.findById(saleId, null, options);
+
+ expect(updateSale.originalQuantity).toEqual(originalSale.quantity);
+ expect(updateSale.quantity).toEqual(newQuantity);
+
+ await tx.rollback();
+ } catch (e) {
+ await tx.rollback();
+ throw e;
+ }
});
});
diff --git a/back/methods/dms/saveSign.js b/back/methods/dms/saveSign.js
new file mode 100644
index 000000000..f668c5ed2
--- /dev/null
+++ b/back/methods/dms/saveSign.js
@@ -0,0 +1,215 @@
+const md5 = require('md5');
+const fs = require('fs-extra');
+
+module.exports = Self => {
+ Self.remoteMethodCtx('saveSign', {
+ description: 'Save sign',
+ accessType: 'WRITE',
+ accepts:
+ [
+ {
+ arg: 'signContent',
+ type: 'string',
+ required: true,
+ description: 'The sign content'
+ }, {
+ arg: 'tickets',
+ type: ['number'],
+ required: true,
+ description: 'The tickets'
+ }, {
+ arg: 'signedTime',
+ type: 'date',
+ description: 'The signed time'
+ }, {
+ arg: 'addressFk',
+ type: 'number',
+ required: true,
+ description: 'The address fk'
+ }
+ ],
+ returns: {
+ type: 'Object',
+ root: true
+ },
+ http: {
+ path: `/saveSign`,
+ verb: 'POST'
+ }
+ });
+
+ async function createGestDoc(ticketId, userFk) {
+ const models = Self.app.models;
+ if (!await gestDocExists(ticketId)) {
+ const result = await models.Ticket.findOne({
+ where: {
+ id: ticketId
+ },
+ include: [
+ {
+ relation: 'warehouse',
+ scope: {
+ fields: ['id']
+ }
+ }, {
+ relation: 'client',
+ scope: {
+ fields: ['name']
+ }
+ }, {
+ relation: 'route',
+ scope: {
+ fields: ['id']
+ }
+ }
+ ]
+ });
+
+ const warehouseFk = result.warehouseFk;
+ const companyFk = result.companyFk;
+ const client = result.client.name;
+ const route = result.route.id;
+
+ const resultDmsType = await models.DmsType.findOne({
+ where: {
+ code: 'Ticket'
+ }
+ });
+
+ const resultDms = await models.Dms.create({
+ dmsTypeFk: resultDmsType.id,
+ reference: ticketId,
+ description: `Ticket ${ticketId} Cliente ${client} Ruta ${route}`,
+ companyFk: companyFk,
+ warehouseFk: warehouseFk,
+ workerFk: userFk
+ });
+
+ return resultDms.insertId;
+ }
+ }
+
+ async function gestDocExists(ticket) {
+ const models = Self.app.models;
+ const result = await models.TicketDms.findOne({
+ where: {
+ ticketFk: ticket
+ },
+ fields: ['dmsFk']
+ });
+
+ if (result == null)
+ return false;
+
+ const isSigned = await models.Ticket.findOne({
+ where: {
+ id: ticket
+ },
+ fields: ['isSigned']
+ });
+
+ if (isSigned)
+ return true;
+ else
+ await models.Dms.destroyById(ticket);
+ }
+
+ async function dmsRecover(ticket, signContent) {
+ const models = Self.app.models;
+ await models.DmsRecover.create({
+ ticketFk: ticket,
+ sign: signContent
+ });
+ }
+
+ async function ticketGestdoc(ticket, dmsFk) {
+ const models = Self.app.models;
+ models.TicketDms.replaceOrCreate({
+ ticketFk: ticket,
+ dmsFk: dmsFk
+ });
+
+ const queryVnTicketSetState = `CALL vn.ticket_setState(?, ?)`;
+
+ await Self.rawSql(queryVnTicketSetState, [ticket, 'DELIVERED']);
+ }
+
+ async function updateGestdoc(file, ticket) {
+ const models = Self.app.models;
+ models.Dms.updateOne({
+ where: {
+ id: ticket
+ },
+ file: file,
+ contentType: 'image/png'
+ });
+ }
+
+ Self.saveSign = async(ctx, signContent, tickets, signedTime) => {
+ const models = Self.app.models;
+ let tx = await Self.beginTransaction({});
+ try {
+ const userId = ctx.req.accessToken.userId;
+
+ const dmsDir = `storage/dms`;
+
+ let image = null;
+
+ for (let i = 0; i < tickets.length; i++) {
+ const alertLevel = await models.TicketState.findOne({
+ where: {
+ ticketFk: tickets[i]
+ },
+ fields: ['alertLevel']
+ });
+
+ signedTime ? signedTime != undefined : signedTime = new Date();
+
+ if (alertLevel >= 2) {
+ let dir;
+ let id = null;
+ let fileName = null;
+
+ if (!await gestDocExists(tickets[i])) {
+ id = await createGestDoc(tickets[i], userId);
+
+ const hashDir = md5(id).substring(0, 3);
+ dir = `${dmsDir}/${hashDir}`;
+
+ if (!fs.existsSync(dir))
+ fs.mkdirSync(dir);
+
+ fileName = `${id}.png`;
+ image = `${dir}/${fileName}`;
+ } else
+
+ if (image != null) {
+ if (!fs.existsSync(dir))
+ dmsRecover(tickets[i], signContent);
+ else {
+ fs.writeFile(image, signContent, 'base64', async function(err) {
+ if (err) {
+ await tx.rollback();
+ return err.message;
+ }
+ });
+ }
+ } else
+ dmsRecover(tickets[i], signContent);
+
+ if (id != null && fileName.length > 0) {
+ ticketGestdoc(tickets[i], id);
+ updateGestdoc(id, fileName);
+ }
+ }
+ }
+
+ if (tx) await tx.commit();
+
+ return 'OK';
+ } catch (err) {
+ await tx.rollback();
+ throw err.message;
+ }
+ };
+};
diff --git a/back/models/dms.js b/back/models/dms.js
index 24c072f56..fc586201f 100644
--- a/back/models/dms.js
+++ b/back/models/dms.js
@@ -6,6 +6,7 @@ module.exports = Self => {
require('../methods/dms/removeFile')(Self);
require('../methods/dms/updateFile')(Self);
require('../methods/dms/deleteTrashFiles')(Self);
+ require('../methods/dms/saveSign')(Self);
Self.checkRole = async function(ctx, id) {
const models = Self.app.models;
diff --git a/db/changes/224702/00-notificationProc.sql b/db/changes/224702/00-notificationProc.sql
index 475b2e389..2cf11b4f1 100644
--- a/db/changes/224702/00-notificationProc.sql
+++ b/db/changes/224702/00-notificationProc.sql
@@ -12,14 +12,9 @@ BEGIN
* @param vAuthorFk The notification author or %NULL if there is no author
* @return The notification id
*/
- DECLARE vNotificationFk INT;
-
- SELECT id INTO vNotificationFk
- FROM `notification`
- WHERE `name` = vNotificationName;
INSERT INTO notificationQueue
- SET notificationFk = vNotificationFk,
+ SET notificationFk = vNotificationName,
params = vParams,
authorFk = vAuthorFk;
diff --git a/db/changes/225001/.gitkeep b/db/changes/225001/.gitkeep
new file mode 100644
index 000000000..e69de29bb
diff --git a/db/changes/225001/00-aclMdbApp.sql b/db/changes/225001/00-aclMdbApp.sql
new file mode 100644
index 000000000..b5b60546c
--- /dev/null
+++ b/db/changes/225001/00-aclMdbApp.sql
@@ -0,0 +1,4 @@
+INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
+ VALUES
+ ('MdbApp', 'lock', 'WRITE', 'ALLOW', 'ROLE', 'developer'),
+ ('MdbApp', 'unlock', 'WRITE', 'ALLOW', 'ROLE', 'developer');
diff --git a/db/changes/225201/00-ACL_saveSign.sql b/db/changes/225201/00-ACL_saveSign.sql
new file mode 100644
index 000000000..16f9931c4
--- /dev/null
+++ b/db/changes/225201/00-ACL_saveSign.sql
@@ -0,0 +1 @@
+INSERT INTO `salix`.`ACL` (`model`,`property`,`accessType`,`permission`,`principalId`) VALUES ('Dms','saveSign','*','ALLOW','employee');
diff --git a/db/changes/225201/00-accountingMovements_add.sql b/db/changes/225201/00-accountingMovements_add.sql
new file mode 100644
index 000000000..12dc176bc
--- /dev/null
+++ b/db/changes/225201/00-accountingMovements_add.sql
@@ -0,0 +1,438 @@
+DROP PROCEDURE IF EXISTS `sage`.`accountingMovements_add`;
+
+DELIMITER $$
+$$
+CREATE DEFINER=`root`@`localhost` PROCEDURE `sage`.`accountingMovements_add`(vYear INT, vCompanyFk INT)
+BEGIN
+/**
+ * Traslada la info de contabilidad generada en base a vn.XDiario a la tabla sage.movConta para poder ejecutar posteriormente el proceso de importación de datos de SQL Server
+ * Solo traladará los asientos marcados con el campo vn.XDiario.enlazadoSage = FALSE
+ * @vYear Año contable del que se quiere trasladar la información
+ * @vCompanyFk Empresa de la que se quiere trasladar datos
+ */
+ DECLARE vDatedFrom DATETIME;
+ DECLARE vDatedTo DATETIME;
+ DECLARE vDuaTransactionFk INT;
+ DECLARE vTaxImportFk INT;
+ DECLARE vTaxImportReducedFk INT;
+ DECLARE vTaxImportSuperReducedFk INT;
+ DECLARE vTransactionExportFk INT;
+ DECLARE vTransactionExportTaxFreeFk INT;
+ DECLARE vSerialDua VARCHAR(1) DEFAULT 'D';
+ DECLARE vInvoiceTypeInformativeCode VARCHAR(1);
+ DECLARE vCountryCanariasCode, vCountryCeutaMelillaCode VARCHAR(2) ;
+ DECLARE vBookEntries TEXT;
+
+ SELECT SiglaNacion INTO vCountryCanariasCode
+ FROM Naciones
+ WHERE Nacion ='ISLAS CANARIAS';
+
+ SELECT SiglaNacion INTO vCountryCeutaMelillaCode
+ FROM Naciones
+ WHERE Nacion ='CEUTA Y MELILLA';
+
+ SELECT CodigoTransaccion INTO vDuaTransactionFk
+ FROM TiposTransacciones
+ WHERE Transaccion = 'Import. bienes y serv. corrientes pdte. liquidar';
+
+ SELECT CodigoIva INTO vTaxImportFk
+ FROM TiposIva
+ WHERE Iva = 'IVA 21% importaciones';
+
+ SELECT CodigoIva INTO vTaxImportReducedFk
+ FROM TiposIva
+ WHERE Iva = 'IVA 10% importaciones';
+
+ SELECT CodigoIva INTO vTaxImportSuperReducedFk
+ FROM TiposIva
+ WHERE Iva = 'H.P. IVA Soportado Impor 4%';
+
+ SELECT CodigoTransaccion INTO vTransactionExportFk
+ FROM TiposTransacciones
+ WHERE Transaccion = 'Exportaciones definitivas';
+
+ SELECT CodigoTransaccion INTO vTransactionExportTaxFreeFk
+ FROM TiposTransacciones
+ WHERE Transaccion = 'Envíos definitivos a Canarias, Ceuta y Melilla';
+
+ SELECT codeSage INTO vInvoiceTypeInformativeCode
+ FROM invoiceType WHERE code ='informative';
+
+ SELECT CAST(CONCAT(vYear, '-01-01') AS DATETIME), util.dayEnd(CAST(CONCAT(vYear, '-12-31') AS DATE))
+ INTO vDatedFrom, vDatedTo;
+
+ TRUNCATE movContaIVA;
+
+ DELETE FROM movConta
+ WHERE enlazadoSage = FALSE
+ AND Asiento <> 1 ;
+
+ CALL clientSupplier_add(vCompanyFk);
+ CALL pgc_add(vCompanyFk);
+ CALL invoiceOut_manager(vYear, vCompanyFk);
+ CALL invoiceIn_manager(vYear, vCompanyFk);
+
+ INSERT INTO movConta(TipoEntrada,
+ Ejercicio,
+ CodigoEmpresa,
+ Asiento,
+ CargoAbono,
+ CodigoCuenta,
+ Contrapartida,
+ FechaAsiento,
+ Comentario,
+ ImporteAsiento,
+ NumeroPeriodo,
+ FechaGrabacion,
+ CodigoDivisa,
+ ImporteCambio,
+ ImporteDivisa,
+ FactorCambio,
+ IdProcesoIME,
+ TipoCarteraIME,
+ TipoAnaliticaIME,
+ StatusTraspasadoIME,
+ TipoImportacionIME,
+ Metalico347,
+ BaseIva1,
+ PorBaseCorrectora1,
+ PorIva1,
+ CuotaIva1,
+ PorRecargoEquivalencia1,
+ RecargoEquivalencia1,
+ CodigoTransaccion1,
+ BaseIva2,
+ PorBaseCorrectora2,
+ PorIva2,
+ CuotaIva2,
+ PorRecargoEquivalencia2,
+ RecargoEquivalencia2,
+ CodigoTransaccion2,
+ BaseIva3,
+ PorBaseCorrectora3,
+ PorIva3,
+ CuotaIva3,
+ PorRecargoEquivalencia3,
+ RecargoEquivalencia3,
+ CodigoTransaccion3,
+ BaseIva4,
+ PorBaseCorrectora4,
+ PorIva4,
+ CuotaIva4,
+ PorRecargoEquivalencia4,
+ RecargoEquivalencia4,
+ CodigoTransaccion4,
+ Año,
+ Serie,
+ Factura,
+ SuFacturaNo,
+ FechaFactura,
+ ImporteFactura,
+ TipoFactura,
+ CodigoCuentaFactura,
+ CifDni,
+ Nombre,
+ CodigoRetencion,
+ BaseRetencion,
+ PorRetencion,
+ ImporteRetencion,
+ SiglaNacion,
+ EjercicioFactura,
+ FechaOperacion,
+ Exclusion347,
+ MantenerAsiento,
+ ClaveOperacionFactura_,
+ TipoRectificativa,
+ FechaFacturaOriginal,
+ BaseImponibleOriginal,
+ CuotaIvaOriginal,
+ ClaseAbonoRectificativas,
+ RecargoEquivalenciaOriginal,
+ LibreA1,
+ CodigoIva1,
+ CodigoIva2,
+ CodigoIva3,
+ CodigoIva4,
+ IvaDeducible1,
+ IvaDeducible2,
+ IvaDeducible3,
+ IvaDeducible4,
+ Intracomunitaria
+ )
+ SELECT 'EN' TipoEntrada,
+ YEAR(x.FECHA) Ejercicio,
+ company_getCode(vCompanyFk) AS CodigoEmpresa,
+ x.ASIEN Asiento,
+ IF(EURODEBE <> 0 OR (EURODEBE = 0 AND EUROHABER IS NULL), 'D', 'H') CargoAbono,
+ x.SUBCTA CodigoCuenta,
+ x.CONTRA Contrapartida,
+ x.FECHA FechaAsiento,
+ x.CONCEPTO Comentario,
+ IF(x.EURODEBE, x.EURODEBE, x.EUROHABER) ImporteAsiento,
+ MONTH(x.FECHA) NumeroPeriodo,
+ IF(sub2.FECREGCON IS NULL, sub2.FECHA_EX, sub2.FECREGCON) FechaGrabacion,
+ IF(x.CAMBIO, IFNULL(mci.CodigoDivisa, sub3.code), '') CodigoDivisa,
+ x.CAMBIO ImporteCambio,
+ IFNULL(x.DEBEME, x.HABERME) ImporteDivisa,
+ IF(x.CAMBIO, TRUE, FALSE) FactorCambio,
+ NULL IdProcesoIME,
+ 0 TipoCarteraIME,
+ 0 TipoAnaliticaIME,
+ 0 StatusTraspasadoIME,
+ 0 TipoImportacionIME,
+ x.METAL Metalico347,
+ mci.BaseIva1,
+ mci.PorBaseCorrectora1,
+ mci.PorIva1,
+ mci.CuotaIva1,
+ mci.PorRecargoEquivalencia1,
+ mci.RecargoEquivalencia1,
+ mci.CodigoTransaccion1,
+ mci.BaseIva2,
+ mci.PorBaseCorrectora2,
+ mci.PorIva2,
+ mci.CuotaIva2,
+ mci.PorRecargoEquivalencia2,
+ mci.RecargoEquivalencia2,
+ mci.CodigoTransaccion2,
+ mci.BaseIva3,
+ mci.PorBaseCorrectora3,
+ mci.PorIva3,
+ mci.CuotaIva3,
+ mci.PorRecargoEquivalencia3,
+ mci.RecargoEquivalencia3,
+ mci.CodigoTransaccion3,
+ mci.BaseIva4,
+ mci.PorBaseCorrectora4,
+ mci.PorIva4,
+ mci.CuotaIva4,
+ mci.PorRecargoEquivalencia4,
+ mci.RecargoEquivalencia4,
+ mci.CodigoTransaccion4,
+ mci.Año,
+ mci.Serie,
+ mci.Factura,
+ mci.SuFacturaNo,
+ mci.FechaFactura,
+ mci.ImporteFactura,
+ mci.TipoFactura,
+ mci.CodigoCuentaFactura,
+ mci.CifDni,
+ mci.Nombre,
+ mci.CodigoRetencion,
+ mci.BaseRetencion,
+ mci.PorRetencion,
+ mci.ImporteRetencion,
+ mci.SiglaNacion,
+ mci.EjercicioFactura,
+ mci.FechaOperacion,
+ mci.Exclusion347,
+ TRUE,
+ mci.ClaveOperacionFactura,
+ mci.TipoRectificativa,
+ mci.FechaFacturaOriginal,
+ mci.BaseImponibleOriginal,
+ mci.CuotaIvaOriginal,
+ mci.ClaseAbonoRectificativas,
+ mci.RecargoEquivalenciaOriginal,
+ mci.LibreA1,
+ mci.CodigoIva1,
+ mci.CodigoIva2,
+ mci.CodigoIva3,
+ mci.CodigoIva4,
+ mci.IvaDeducible1,
+ mci.IvaDeducible2,
+ mci.IvaDeducible3,
+ mci.IvaDeducible4,
+ mci.Intracomunitaria
+ FROM vn.XDiario x
+ LEFT JOIN movContaIVA mci ON mci.id = x.id
+ LEFT JOIN (SELECT *
+ FROM (SELECT DISTINCT ASIEN, FECREGCON, FECHA_EX
+ FROM vn.XDiario
+ WHERE enlazadoSage = FALSE
+ ORDER BY ASIEN, FECREGCON DESC, FECHA_EX DESC
+ LIMIT 10000000000000000000
+ ) sub GROUP BY ASIEN
+ )sub2 ON sub2.ASIEN = x.ASIEN
+ LEFT JOIN ( SELECT DISTINCT(account),cu.code
+ FROM vn.bank b
+ JOIN vn.currency cu ON cu.id = b.currencyFk
+ WHERE cu.code <> 'EUR' -- no se informa cuando la divisa en EUR
+ )sub3 ON sub3.account = x.SUBCTA
+ WHERE x.enlazadoSage = FALSE
+ AND x.empresa_id = vCompanyFk
+ AND x.FECHA BETWEEN vDatedFrom AND vDatedTo;
+
+-- Metálicos
+ UPDATE movConta m
+ JOIN (SELECT Asiento,
+ c.socialName name,
+ c.fi,
+ n.SiglaNacion,
+ m.CodigoCuenta,
+ m.Contrapartida
+ FROM movConta m
+ LEFT JOIN vn.client c ON c.id = IF(m.CargoAbono = 'H',
+ CAST(SUBSTRING(m.CodigoCuenta, 3, LENGTH(m.CodigoCuenta)) AS UNSIGNED),
+ CAST(SUBSTRING(m.Contrapartida, 3, LENGTH(m.Contrapartida)) AS UNSIGNED))
+ LEFT JOIN Naciones n ON n.countryFk = c.countryFk
+ WHERE m.Metalico347 = TRUE
+ AND m.enlazadoSage = FALSE
+ )sub ON m.Asiento = sub.Asiento
+ SET m.Metalico347 = TRUE,
+ m.TipoFactura = vInvoiceTypeInformativeCode,
+ m.CifDni = sub.fi,
+ m.Nombre = sub.name,
+ m.SiglaNacion = sub.SiglaNacion
+ WHERE m.enlazadoSage = FALSE;
+
+ UPDATE movConta m
+ SET m.Metalico347 = FALSE,
+ m.TipoFactura = ''
+ WHERE m.CargoAbono = 'D'
+ AND m.enlazadoSage = FALSE;
+
+-- Elimina cuentas de cliente/proveedor que no se utilizarán en la importación
+ DELETE cp
+ FROM clientesProveedores cp
+ LEFT JOIN movConta mc ON mc.codigoCuenta = cp.codigoCuenta
+ AND mc.enlazadoSage = FALSE
+ WHERE mc.codigoCuenta IS NULL;
+
+-- Elimina cuentas contables que no se utilizarán en la importación
+ DELETE pc
+ FROM planCuentasPGC pc
+ LEFT JOIN movConta mc ON mc.codigoCuenta = pc.codigoCuenta
+ AND mc.enlazadoSage = FALSE
+ WHERE mc.codigoCuenta IS NULL;
+
+-- DUAS
+ UPDATE movConta mci
+ JOIN vn.XDiario x ON x.ASIEN = mci.Asiento
+ JOIN TiposIva ti ON ti.CodigoIva = x.IVA
+ JOIN vn.pgcMaster pm ON pm.code = mci.CodigoCuenta COLLATE utf8mb3_unicode_ci
+ SET mci.BaseIva1 = x.BASEEURO,
+ mci.PorIva1 = x.IVA,
+ mci.CuotaIva1 = CAST((x.IVA / 100) * x.BASEEURO AS DECIMAL(10, 2)),
+ mci.CodigoTransaccion1 = vDuaTransactionFk,
+ mci.CodigoIva1 = vTaxImportReducedFk,
+ mci.IvaDeducible1 = TRUE,
+ mci.FechaFacturaOriginal = x.FECHA_EX,
+ mci.SuFacturaNo = x.FACTURAEX,
+ mci.FechaOperacion = x.FECHA_OP,
+ mci.ImporteFactura = mci.ImporteFactura + x.BASEEURO + CAST((x.IVA / 100) * x.BASEEURO AS DECIMAL(10, 2))
+ WHERE pm.description = 'HP Iva pendiente'
+ AND mci.enlazadoSage = FALSE
+ AND x.SERIE = vSerialDua COLLATE utf8mb3_unicode_ci
+ AND ti.Iva = 'I.V.A. 10% Nacional';
+
+ UPDATE movConta mci
+ JOIN vn.XDiario x ON x.ASIEN = mci.Asiento
+ JOIN TiposIva ti ON ti.CodigoIva = x.IVA
+ JOIN vn.pgcMaster pm ON pm.code = mci.CodigoCuenta COLLATE utf8mb3_unicode_ci
+ SET mci.BaseIva2 = x.BASEEURO ,
+ mci.PorIva2 = x.IVA,
+ mci.CuotaIva2 = CAST((x.IVA / 100) * x.BASEEURO AS DECIMAL(10,2)),
+ mci.CodigoTransaccion2 = vDuaTransactionFk ,
+ mci.CodigoIva2 = vTaxImportFk,
+ mci.IvaDeducible2 = TRUE,
+ mci.ImporteFactura = mci.ImporteFactura + x.BASEEURO + CAST((x.IVA / 100) * x.BASEEURO AS DECIMAL(10, 2))
+ WHERE pm.description = 'HP Iva pendiente'
+ AND mci.enlazadoSage = FALSE
+ AND x.SERIE = vSerialDua COLLATE utf8mb3_unicode_ci
+ AND ti.Iva = 'I.V.A. 21%';
+
+ UPDATE movConta mci
+ JOIN vn.XDiario x ON x.ASIEN = mci.Asiento
+ JOIN TiposIva ti ON ti.CodigoIva = x.IVA
+ JOIN vn.pgcMaster pm ON pm.code = mci.CodigoCuenta COLLATE utf8mb3_unicode_ci
+ SET mci.BaseIva3 = x.BASEEURO ,
+ mci.PorIva3 = x.IVA,
+ mci.CuotaIva3 = CAST((x.IVA / 100) * x.BASEEURO AS DECIMAL(10,2)),
+ mci.CodigoTransaccion3 = vDuaTransactionFk ,
+ mci.CodigoIva3 = vTaxImportSuperReducedFk,
+ mci.IvaDeducible3 = TRUE,
+ mci.ImporteFactura = mci.ImporteFactura + x.BASEEURO + CAST((x.IVA / 100) * x.BASEEURO AS DECIMAL(10, 2))
+ WHERE pm.description = 'HP Iva pendiente'
+ AND mci.enlazadoSage = FALSE
+ AND x.SERIE = vSerialDua COLLATE utf8mb3_unicode_ci
+ AND ti.Iva = 'I.V.A. 4%';
+
+-- Rectificativas
+ UPDATE movConta mci
+ JOIN (SELECT x.ASIEN, x.FECHA_RT, x.SERIE_RT, x.FACTU_RT
+ FROM movConta mci
+ JOIN vn.XDiario x ON x.ASIEN = mci.Asiento
+ WHERE mci.TipoRectificativa > 0
+ AND mci.enlazadoSage = FALSE
+ AND x.FACTU_RT IS NOT NULL
+ GROUP BY x.ASIEN
+ ) sub ON sub.ASIEN = mci.Asiento
+ SET mci.EjercicioFacturaOriginal = YEAR(sub.FECHA_RT),
+ mci.SerieFacturaOriginal = sub.SERIE_RT,
+ mci.NumeroFacturaOriginal = sub.FACTU_RT
+ WHERE mci.TipoRectificativa > 0 AND
+ mci.enlazadoSage = FALSE ;
+
+-- Exportaciones Andorras y Canarias cambia TT (la cuenta es compartida)
+ UPDATE movConta mci
+ SET CodigoTransaccion1 = vTransactionExportTaxFreeFk,
+ CodigoTransaccion2 = IF(CodigoTransaccion2 = 0, 0, vTransactionExportTaxFreeFk),
+ CodigoTransaccion3 = IF(CodigoTransaccion3 = 0, 0, vTransactionExportTaxFreeFk),
+ CodigoTransaccion4 = IF(CodigoTransaccion4 = 0, 0, vTransactionExportTaxFreeFk)
+ WHERE enlazadoSage = FALSE
+ AND (CodigoTransaccion1 = vTransactionExportFk
+ OR CodigoTransaccion2 = vTransactionExportFk
+ OR CodigoTransaccion3 = vTransactionExportFk
+ OR CodigoTransaccion4 = vTransactionExportFk)
+ AND SiglaNacion IN (vCountryCanariasCode COLLATE utf8mb3_unicode_ci, vCountryCeutaMelillaCode COLLATE utf8mb3_unicode_ci);
+
+ UPDATE movConta mc
+ SET CodigoDivisa = 'USD',
+ FactorCambio = TRUE,
+ ImporteCambio = ABS( CAST( IF( ImporteDivisa <> 0 AND ImporteCambio = 0, ImporteAsiento / ImporteDivisa, ImporteCambio) AS DECIMAL( 10, 2)))
+ WHERE enlazadoSage = FALSE
+ AND (ImporteCambio <> 0 OR ImporteDivisa <> 0 OR FactorCambio);
+
+ UPDATE movConta mc
+ SET importeDivisa= -importeDivisa
+ WHERE enlazadoSage = FALSE
+ AND importeDivisa > 0
+ AND ImporteAsiento < 0;
+
+ -- Comprobación que los importes e ivas sean correctos, avisa vía CAU
+ SELECT GROUP_CONCAT(Asiento ORDER BY Asiento ASC SEPARATOR ',') INTO vBookEntries
+ FROM(SELECT sub.Asiento
+ FROM (SELECT mc.Asiento, SUM(mc.ImporteAsiento) amount
+ FROM movConta mc
+ WHERE mc.enlazadoSage = FALSE
+ GROUP BY mc.Asiento)sub
+ JOIN (SELECT x.ASIEN, SUM(IFNULL(x.EURODEBE,0) + IFNULL(x.EUROHABER,0)) amount
+ FROM vn.XDiario x
+ WHERE x.enlazadoSage = FALSE
+ GROUP BY ASIEN)sub2 ON sub2.ASIEN = sub.Asiento
+ WHERE sub.amount <> sub2.amount
+ UNION ALL
+ SELECT sub.Asiento
+ FROM (SELECT Asiento, SUM(BaseIva1 + BaseIva2 + BaseIva3 + BaseIva4) amountTaxableBase
+ FROM movConta
+ WHERE TipoFactura <> 'I'
+ AND enlazadoSage = FALSE
+ GROUP BY Asiento) sub
+ JOIN (SELECT ASIEN, SUM(BASEEURO) amountTaxableBase
+ FROM (SELECT ASIEN, SUM(BASEEURO) BASEEURO
+ FROM vn.XDiario
+ WHERE FACTURA
+ AND auxiliar <> '*'
+ AND enlazadoSage = FALSE
+ GROUP BY FACTURA, ASIEN)sub3
+ GROUP BY ASIEN) sub2 ON sub2.ASIEN = sub.Asiento
+ WHERE sub.amountTaxableBase<>sub2.amountTaxableBase
+ AND sub.amountTaxableBase/2 <> sub2.amountTaxableBase) sub;
+
+ IF vBookEntries IS NOT NULL THEN
+ SELECT util.notification_send ("book-entries-imported-incorrectly", CONCAT('{"bookEntries":"', vBookEntries,'"}'), null);
+ END IF;
+END$$
+DELIMITER ;
diff --git a/db/changes/225201/00-aclTicketLog.sql b/db/changes/225201/00-aclTicketLog.sql
new file mode 100644
index 000000000..edba17ab4
--- /dev/null
+++ b/db/changes/225201/00-aclTicketLog.sql
@@ -0,0 +1,3 @@
+INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
+ VALUES
+ ('TicketLog', 'getChanges', 'READ', 'ALLOW', 'ROLE', 'employee');
diff --git a/db/changes/225001/00-entryDeleteRef.sql b/db/changes/225201/00-entryDeleteRef.sql
similarity index 100%
rename from db/changes/225001/00-entryDeleteRef.sql
rename to db/changes/225201/00-entryDeleteRef.sql
diff --git a/db/changes/225001/00-invoiceInConfig.sql b/db/changes/225201/00-invoiceInConfig.sql
similarity index 100%
rename from db/changes/225001/00-invoiceInConfig.sql
rename to db/changes/225201/00-invoiceInConfig.sql
diff --git a/db/changes/225201/00-mdbApp.sql b/db/changes/225201/00-mdbApp.sql
new file mode 100644
index 000000000..3202e3f08
--- /dev/null
+++ b/db/changes/225201/00-mdbApp.sql
@@ -0,0 +1,11 @@
+CREATE TABLE `vn`.`mdbApp` (
+ `app` varchar(100) COLLATE utf8mb3_unicode_ci NOT NULL,
+ `baselineBranchFk` varchar(255) COLLATE utf8mb3_unicode_ci DEFAULT NULL,
+ `userFk` int(10) unsigned DEFAULT NULL,
+ `locked` datetime DEFAULT NULL,
+ PRIMARY KEY (`app`),
+ KEY `mdbApp_FK` (`userFk`),
+ KEY `mdbApp_FK_1` (`baselineBranchFk`),
+ CONSTRAINT `mdbApp_FK` FOREIGN KEY (`userFk`) REFERENCES `account`.`user` (`id`) ON DELETE SET NULL ON UPDATE CASCADE,
+ CONSTRAINT `mdbApp_FK_1` FOREIGN KEY (`baselineBranchFk`) REFERENCES `mdbBranch` (`name`) ON UPDATE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci
diff --git a/db/changes/225201/00-notification_send.sql b/db/changes/225201/00-notification_send.sql
new file mode 100644
index 000000000..a422cebac
--- /dev/null
+++ b/db/changes/225201/00-notification_send.sql
@@ -0,0 +1,24 @@
+DROP FUNCTION IF EXISTS `util`.`notification_send`;
+
+DELIMITER $$
+$$
+CREATE DEFINER=`root`@`localhost` FUNCTION `util`.`notification_send`(vNotificationName VARCHAR(255), vParams TEXT, vAuthorFk INT) RETURNS int(11)
+ MODIFIES SQL DATA
+BEGIN
+/**
+ * Sends a notification.
+ *
+ * @param vNotificationName The notification name
+ * @param vParams The notification parameters formatted as JSON
+ * @param vAuthorFk The notification author or %NULL if there is no author
+ * @return The notification id
+ */
+
+ INSERT INTO notificationQueue
+ SET notificationFk = vNotificationName,
+ params = vParams,
+ authorFk = vAuthorFk;
+
+ RETURN LAST_INSERT_ID();
+END$$
+DELIMITER ;
diff --git a/db/changes/225201/00-supplier_beforeUpdate.sql b/db/changes/225201/00-supplier_beforeUpdate.sql
new file mode 100644
index 000000000..08af8666b
--- /dev/null
+++ b/db/changes/225201/00-supplier_beforeUpdate.sql
@@ -0,0 +1,46 @@
+DROP TRIGGER IF EXISTS `vn`.`supplier_beforeUpdate`;
+USE `vn`;
+
+DELIMITER $$
+$$
+CREATE DEFINER=`root`@`localhost` TRIGGER `vn`.`supplier_beforeUpdate`
+ BEFORE UPDATE ON `supplier`
+ FOR EACH ROW
+BEGIN
+ DECLARE vHasChange BOOL;
+ DECLARE vPayMethodChanged BOOL;
+ DECLARE vPayMethodHasVerified BOOL;
+ DECLARE vParams JSON;
+ DECLARE vOldPayMethodName VARCHAR(20);
+ DECLARE vNewPayMethodName VARCHAR(20);
+
+ SELECT hasVerified INTO vPayMethodHasVerified
+ FROM payMethod
+ WHERE id = NEW.payMethodFk;
+
+ SET vPayMethodChanged = NOT(NEW.payMethodFk <=> OLD.payMethodFk);
+
+ IF vPayMethodChanged THEN
+ SELECT name INTO vOldPayMethodName
+ FROM payMethod
+ WHERE id = OLD.payMethodFk;
+ SELECT name INTO vNewPayMethodName
+ FROM payMethod
+ WHERE id = NEW.payMethodFk;
+
+ SET vParams = JSON_OBJECT(
+ 'name', NEW.name,
+ 'oldPayMethod', vOldPayMethodName,
+ 'newPayMethod', vNewPayMethodName
+ );
+ SELECT util.notification_send('supplier-pay-method-update', vParams, NULL) INTO @id;
+ END IF;
+
+ SET vHasChange = NOT(NEW.payDemFk <=> OLD.payDemFk AND NEW.payDay <=> OLD.payDay) OR vPayMethodChanged;
+
+ IF vHasChange AND vPayMethodHasVerified THEN
+ SET NEW.isPayMethodChecked = FALSE;
+ END IF;
+
+END$$
+DELIMITER ;
diff --git a/db/changes/225201/00-ticketSms.sql b/db/changes/225201/00-ticketSms.sql
new file mode 100644
index 000000000..f454f99b1
--- /dev/null
+++ b/db/changes/225201/00-ticketSms.sql
@@ -0,0 +1,8 @@
+CREATE TABLE `vn`.`ticketSms` (
+ `smsFk` mediumint(8) unsigned NOT NULL,
+ `ticketFk` int(11) DEFAULT NULL,
+ PRIMARY KEY (`smsFk`),
+ KEY `ticketSms_FK_1` (`ticketFk`),
+ CONSTRAINT `ticketSms_FK` FOREIGN KEY (`smsFk`) REFERENCES `sms` (`id`) ON UPDATE CASCADE,
+ CONSTRAINT `ticketSms_FK_1` FOREIGN KEY (`ticketFk`) REFERENCES `ticket` (`id`) ON UPDATE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci
diff --git a/db/changes/225201/00-ticket_canAdvance.sql b/db/changes/225201/00-ticket_canAdvance.sql
new file mode 100644
index 000000000..acc4dcc4a
--- /dev/null
+++ b/db/changes/225201/00-ticket_canAdvance.sql
@@ -0,0 +1,104 @@
+DROP PROCEDURE IF EXISTS `vn`.`ticket_canAdvance`;
+
+DELIMITER $$
+$$
+CREATE DEFINER=`root`@`localhost` PROCEDURE `vn`.`ticket_canAdvance`(vDateFuture DATE, vDateToAdvance DATE, vWarehouseFk INT)
+BEGIN
+/**
+ * Devuelve los tickets y la cantidad de lineas de venta que se pueden adelantar.
+ *
+ * @param vDateFuture Fecha de los tickets que se quieren adelantar.
+ * @param vDateToAdvance Fecha a cuando se quiere adelantar.
+ * @param vWarehouseFk Almacén
+ */
+
+ DECLARE vDateInventory DATE;
+
+ SELECT inventoried INTO vDateInventory FROM vn.config;
+
+ DROP TEMPORARY TABLE IF EXISTS tmp.stock;
+ CREATE TEMPORARY TABLE tmp.stock
+ (itemFk INT PRIMARY KEY,
+ amount INT)
+ ENGINE = MEMORY;
+
+ INSERT INTO tmp.stock(itemFk, amount)
+ SELECT itemFk, SUM(quantity) amount FROM
+ (
+ SELECT itemFk, quantity
+ FROM vn.itemTicketOut
+ WHERE shipped >= vDateInventory
+ AND shipped < vDateFuture
+ AND warehouseFk = vWarehouseFk
+ UNION ALL
+ SELECT itemFk, quantity
+ FROM vn.itemEntryIn
+ WHERE landed >= vDateInventory
+ AND landed < vDateFuture
+ AND isVirtualStock = FALSE
+ AND warehouseInFk = vWarehouseFk
+ UNION ALL
+ SELECT itemFk, quantity
+ FROM vn.itemEntryOut
+ WHERE shipped >= vDateInventory
+ AND shipped < vDateFuture
+ AND warehouseOutFk = vWarehouseFk
+ ) t
+ GROUP BY itemFk HAVING amount != 0;
+
+ DROP TEMPORARY TABLE IF EXISTS tmp.filter;
+ CREATE TEMPORARY TABLE tmp.filter
+ (INDEX (id))
+ SELECT s.ticketFk futureId,
+ t2.ticketFk id,
+ sum((s.quantity <= IFNULL(st.amount,0))) hasStock,
+ count(DISTINCT s.id) saleCount,
+ t2.state,
+ t2.stateCode,
+ st.name futureState,
+ st.code futureStateCode,
+ GROUP_CONCAT(DISTINCT ipt.code ORDER BY ipt.code) futureIpt,
+ t2.ipt,
+ t.workerFk,
+ CAST(sum(litros) AS DECIMAL(10,0)) liters,
+ CAST(count(*) AS DECIMAL(10,0)) `lines`,
+ t2.shipped,
+ t.shipped futureShipped,
+ t2.totalWithVat,
+ t.totalWithVat futureTotalWithVat
+ FROM vn.ticket t
+ JOIN vn.ticketState ts ON ts.ticketFk = t.id
+ JOIN vn.state st ON st.id = ts.stateFk
+ JOIN vn.saleVolume sv ON t.id = sv.ticketFk
+ JOIN (SELECT
+ t2.id ticketFk,
+ t2.addressFk,
+ st.name state,
+ st.code stateCode,
+ GROUP_CONCAT(DISTINCT ipt.code ORDER BY ipt.code) ipt,
+ t2.shipped,
+ t2.totalWithVat
+ FROM vn.ticket t2
+ JOIN vn.sale s ON s.ticketFk = t2.id
+ JOIN vn.item i ON i.id = s.itemFk
+ JOIN vn.ticketState ts ON ts.ticketFk = t2.id
+ JOIN vn.state st ON st.id = ts.stateFk
+ LEFT JOIN vn.itemPackingType ipt ON ipt.code = i.itemPackingTypeFk
+ WHERE t2.shipped BETWEEN vDateToAdvance AND util.dayend(vDateToAdvance)
+ AND t2.warehouseFk = vWarehouseFk
+ GROUP BY t2.id) t2 ON t2.addressFk = t.addressFk
+ JOIN vn.sale s ON s.ticketFk = t.id
+ JOIN vn.item i ON i.id = s.itemFk
+ LEFT JOIN vn.itemPackingType ipt ON ipt.code = i.itemPackingTypeFk
+ LEFT JOIN tmp.stock st ON st.itemFk = s.itemFk
+ WHERE t.shipped BETWEEN vDateFuture AND util.dayend(vDateFuture)
+ AND t.warehouseFk = vWarehouseFk
+ GROUP BY t.id;
+
+ DROP TEMPORARY TABLE tmp.stock;
+END$$
+DELIMITER ;
+
+INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId)
+VALUES
+ ('Ticket', 'getTicketsAdvance', 'READ', 'ALLOW', 'ROLE', 'employee');
diff --git a/db/changes/225201/00-ticket_canbePostponed.sql b/db/changes/225201/00-ticket_canbePostponed.sql
new file mode 100644
index 000000000..572824b4b
--- /dev/null
+++ b/db/changes/225201/00-ticket_canbePostponed.sql
@@ -0,0 +1,73 @@
+DROP PROCEDURE IF EXISTS `vn`.`ticket_canbePostponed`;
+
+DELIMITER $$
+$$
+CREATE DEFINER=`root`@`localhost` PROCEDURE `vn`.`ticket_canbePostponed`(vOriginDated DATE, vFutureDated DATE, vWarehouseFk INT)
+BEGIN
+/**
+ * Devuelve un listado de tickets susceptibles de fusionarse con otros tickets en el futuro
+ *
+ * @param vOriginDated Fecha en cuestión
+ * @param vFutureDated Fecha en el futuro a sondear
+ * @param vWarehouseFk Identificador de vn.warehouse
+ */
+ DROP TEMPORARY TABLE IF EXISTS tmp.filter;
+ CREATE TEMPORARY TABLE tmp.filter
+ (INDEX (id))
+ SELECT sv.ticketFk id,
+ sub2.id futureId,
+ GROUP_CONCAT(DISTINCT i.itemPackingTypeFk ORDER BY i.itemPackingTypeFk) ipt,
+ CAST(sum(litros) AS DECIMAL(10,0)) liters,
+ CAST(count(*) AS DECIMAL(10,0)) `lines`,
+ st.name state,
+ sub2.iptd futureIpt,
+ sub2.state futureState,
+ t.clientFk,
+ t.warehouseFk,
+ ts.alertLevel,
+ t.shipped,
+ sub2.shipped futureShipped,
+ t.workerFk,
+ st.code stateCode,
+ sub2.code futureStateCode
+ FROM vn.saleVolume sv
+ JOIN vn.sale s ON s.id = sv.saleFk
+ JOIN vn.item i ON i.id = s.itemFk
+ JOIN vn.ticket t ON t.id = sv.ticketFk
+ JOIN vn.address a ON a.id = t.addressFk
+ JOIN vn.province p ON p.id = a.provinceFk
+ JOIN vn.country c ON c.id = p.countryFk
+ JOIN vn.ticketState ts ON ts.ticketFk = t.id
+ JOIN vn.state st ON st.id = ts.stateFk
+ JOIN vn.alertLevel al ON al.id = ts.alertLevel
+ LEFT JOIN vn.ticketParking tp ON tp.ticketFk = t.id
+ LEFT JOIN (
+ SELECT *
+ FROM (
+ SELECT
+ t.addressFk,
+ t.id,
+ t.shipped,
+ st.name state,
+ st.code code,
+ GROUP_CONCAT(DISTINCT i.itemPackingTypeFk ORDER BY i.itemPackingTypeFk) iptd
+ FROM vn.ticket t
+ JOIN vn.ticketState ts ON ts.ticketFk = t.id
+ JOIN vn.state st ON st.id = ts.stateFk
+ JOIN vn.sale s ON s.ticketFk = t.id
+ JOIN vn.item i ON i.id = s.itemFk
+ WHERE t.shipped BETWEEN vFutureDated
+ AND util.dayend(vFutureDated)
+ AND t.warehouseFk = vWarehouseFk
+ GROUP BY t.id
+ ) sub
+ GROUP BY sub.addressFk
+ ) sub2 ON sub2.addressFk = t.addressFk AND t.id != sub2.id
+ WHERE t.shipped BETWEEN vOriginDated AND util.dayend(vOriginDated)
+ AND t.warehouseFk = vWarehouseFk
+ AND al.code = 'FREE'
+ AND tp.ticketFk IS NULL
+ GROUP BY sv.ticketFk
+ HAVING futureId;
+END$$
+DELIMITER ;
diff --git a/db/changes/225201/00-ticket_split_merge.sql b/db/changes/225201/00-ticket_split_merge.sql
new file mode 100644
index 000000000..a1a6579e6
--- /dev/null
+++ b/db/changes/225201/00-ticket_split_merge.sql
@@ -0,0 +1,2 @@
+DROP PROCEDURE IF EXISTS `ticket_split`;
+DROP PROCEDURE IF EXISTS `ticket_merge`;
diff --git a/db/changes/225201/00-utilNotification.sql b/db/changes/225201/00-utilNotification.sql
new file mode 100644
index 000000000..74f0de5e2
--- /dev/null
+++ b/db/changes/225201/00-utilNotification.sql
@@ -0,0 +1,4 @@
+INSERT INTO `util`.`notification` (id, name, description) VALUES(3, 'book-entries-imported-incorrectly', 'accounting entries exported incorrectly');
+INSERT INTO `util`.`notificationAcl` (notificationFk, roleFk) VALUES(3, 5);
+INSERT IGNORE INTO `util`.`notificationSubscription` (notificationFk, userFk) VALUES(3, 19663);
+
diff --git a/db/changes/225201/01-create_stateI18n.sql b/db/changes/225201/01-create_stateI18n.sql
new file mode 100644
index 000000000..799360b1e
--- /dev/null
+++ b/db/changes/225201/01-create_stateI18n.sql
@@ -0,0 +1,7 @@
+CREATE TABLE `vn`.`stateI18n` (
+ `stateFk` tinyint(3) unsigned NOT NULL,
+ `lang` char(2) NOT NULL,
+ `name` varchar(255) NOT NULL,
+ PRIMARY KEY (`stateFk`, `lang`),
+ CONSTRAINT `stateI18n_state_id` FOREIGN KEY (`stateFk`) REFERENCES `vn`.`state` (`id`)
+) ENGINE = InnoDB DEFAULT CHARSET = utf8;
diff --git a/db/changes/225001/01-modules.sql b/db/changes/225201/01-modules.sql
similarity index 100%
rename from db/changes/225001/01-modules.sql
rename to db/changes/225201/01-modules.sql
diff --git a/db/changes/225201/02-insert_stateI18n.sql b/db/changes/225201/02-insert_stateI18n.sql
new file mode 100644
index 000000000..7df36d662
--- /dev/null
+++ b/db/changes/225201/02-insert_stateI18n.sql
@@ -0,0 +1,73 @@
+INSERT INTO
+ `vn`.`stateI18n` (`stateFk`, `lang`, `name`)
+VALUES
+ (1, 'en', 'Fix'),
+ (1, 'es', 'Arreglar'),
+ (2, 'en', 'Free'),
+ (2, 'es', 'Libre'),
+ (3, 'en', 'OK'),
+ (3, 'es', 'OK'),
+ (4, 'en', 'Printed'),
+ (4, 'es', 'Impreso'),
+ (5, 'en', 'Preparation'),
+ (5, 'es', 'Preparación'),
+ (6, 'en', 'In Review'),
+ (6, 'es', 'En Revisión'),
+ (7, 'en', 'Unfinished'),
+ (7, 'es', 'Sin Acabar'),
+ (8, 'en', 'Reviewed'),
+ (8, 'es', 'Revisado'),
+ (9, 'en', 'Fitting'),
+ (9, 'es', 'Encajando'),
+ (10, 'en', 'Fitted'),
+ (10, 'es', 'Encajado'),
+ (11, 'en', 'Billed'),
+ (11, 'es', 'Facturado'),
+ (12, 'en', 'Blocked'),
+ (12, 'es', 'Bloqueado'),
+ (13, 'en', 'In Delivery'),
+ (13, 'es', 'En Reparto'),
+ (14, 'en', 'Prepared'),
+ (14, 'es', 'Preparado'),
+ (15, 'en', 'Pending Collection'),
+ (15, 'es', 'Pendiente de Recogida'),
+ (16, 'en', 'Delivered'),
+ (16, 'es', 'Entregado'),
+ (20, 'en', 'Assigned'),
+ (20, 'es', 'Asignado'),
+ (21, 'en', 'Returned'),
+ (21, 'es', 'Retornado'),
+ (22, 'en', 'Pending to extend'),
+ (22, 'es', 'Pendiente ampliar'),
+ (23, 'en', 'URGENT'),
+ (23, 'es', 'URGENTE'),
+ (24, 'en', 'Chained'),
+ (24, 'es', 'Encadenado'),
+ (25, 'en', 'Shipping'),
+ (25, 'es', 'Embarcando'),
+ (26, 'en', 'Preparation'),
+ (26, 'es', 'Preparación previa'),
+ (27, 'en', 'Assisted preparation'),
+ (27, 'es', 'Preparación asistida'),
+ (28, 'en', 'Preparation OK'),
+ (28, 'es', 'Previa OK'),
+ (29, 'en', 'Preparation Printed'),
+ (29, 'es', 'Previa Impreso'),
+ (30, 'en', 'Shipped'),
+ (30, 'es', 'Embarcado'),
+ (31, 'en', 'Stowaway printed'),
+ (31, 'es', 'Polizón Impreso'),
+ (32, 'en', 'Stowaway OK'),
+ (32, 'es', 'Polizón OK'),
+ (33, 'en', 'Auto_Printed'),
+ (33, 'es', 'Auto_Impreso'),
+ (34, 'en', 'Pending payment'),
+ (34, 'es', 'Pendiente de pago'),
+ (35, 'en', 'Half-Embedded'),
+ (35, 'es', 'Semi-Encajado'),
+ (36, 'en', 'Preparation Reviewing'),
+ (36, 'es', 'Previa Revisando'),
+ (37, 'en', 'Preparation Reviewed'),
+ (37, 'es', 'Previa Revisado'),
+ (38, 'en', 'Preparation Chamber'),
+ (38, 'es', 'Preparación Cámara');
\ No newline at end of file
diff --git a/db/changes/225001/02-starredModule.sql b/db/changes/225201/02-starredModule.sql
similarity index 100%
rename from db/changes/225001/02-starredModule.sql
rename to db/changes/225201/02-starredModule.sql
diff --git a/db/changes/230201/00-kkearSaleChecked.sql b/db/changes/230201/00-kkearSaleChecked.sql
new file mode 100644
index 000000000..03e854bbd
--- /dev/null
+++ b/db/changes/230201/00-kkearSaleChecked.sql
@@ -0,0 +1,2 @@
+DELETE FROM `salix`.`ACL` WHERE model="SaleChecked";
+DROP TABLE IF EXISTS `vn`.`saleChecked`;
diff --git a/db/dump/fixtures.sql b/db/dump/fixtures.sql
index 28cd48f13..1ea4fa114 100644
--- a/db/dump/fixtures.sql
+++ b/db/dump/fixtures.sql
@@ -690,7 +690,8 @@ INSERT INTO `vn`.`ticket`(`id`, `priority`, `agencyModeFk`,`warehouseFk`,`routeF
(27 ,NULL, 8, 1, NULL, util.VN_CURDATE(), util.VN_CURDATE(), 1101, 'Wolverine', 1, NULL, 0, 1, 5, 1, util.VN_CURDATE()),
(28, 1, 8, 1, 1, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1103, 'Phone Box', 123, NULL, 0, 1, 5, 1, util.VN_CURDATE()),
(29, 1, 8, 1, 1, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1103, 'Phone Box', 123, NULL, 0, 1, 5, 1, util.VN_CURDATE()),
- (30, 1, 8, 1, 1, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1103, 'Phone Box', 123, NULL, 0, 1, 5, 1, util.VN_CURDATE());
+ (30, 1, 8, 1, 1, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1103, 'Phone Box', 123, NULL, 0, 1, 5, 1, util.VN_CURDATE()),
+ (31, 1, 8, 1, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), DATE_ADD(util.VN_CURDATE(), INTERVAL + 2 DAY), 1103, 'Phone Box', 123, NULL, 0, 1, 5, 1, util.VN_CURDATE());
INSERT INTO `vn`.`ticketObservation`(`id`, `ticketFk`, `observationTypeFk`, `description`)
VALUES
@@ -991,7 +992,8 @@ INSERT INTO `vn`.`sale`(`id`, `itemFk`, `ticketFk`, `concept`, `quantity`, `pric
(33, 5, 14, 'Ranged weapon pistol 9mm', 50, 1.79, 0, 0, 0, util.VN_CURDATE()),
(34, 4, 28, 'Melee weapon heavy shield 1x0.5m', 20, 1.72, 0, 0, 0, util.VN_CURDATE()),
(35, 4, 29, 'Melee weapon heavy shield 1x0.5m', 20, 1.72, 0, 0, 0, util.VN_CURDATE()),
- (36, 4, 30, 'Melee weapon heavy shield 1x0.5m', 20, 1.72, 0, 0, 0, util.VN_CURDATE());
+ (36, 4, 30, 'Melee weapon heavy shield 1x0.5m', 20, 1.72, 0, 0, 0, util.VN_CURDATE()),
+ (37, 4, 31, 'Melee weapon heavy shield 1x0.5m', 20, 1.72, 0, 0, 0, util.VN_CURDATE());
INSERT INTO `vn`.`saleChecked`(`saleFk`, `isChecked`)
VALUES
@@ -1333,9 +1335,9 @@ INSERT INTO `vn`.`itemTypeTag`(`id`, `itemTypeFk`, `tagFk`, `priority`)
CALL `vn`.`itemRefreshTags`(NULL);
-INSERT INTO `vn`.`itemLog` (`id`, `originFk`, `userFk`, `action`, `description`)
+INSERT INTO `vn`.`itemLog` (`id`, `originFk`, `userFk`, `action`, `description`, `changedModel`, `oldInstance`, `newInstance`, `changedModelId`, `changedModelValue`)
VALUES
- ('1', '1', '1', 'insert', 'We made a change!');
+ ('1', '1', '1', 'insert', 'We made a change!', 'Item', '{}', '{}', 1, '1');
INSERT INTO `vn`.`recovery`(`id`, `clientFk`, `started`, `finished`, `amount`, `period`)
VALUES
@@ -2650,7 +2652,7 @@ INSERT INTO `vn`.`mdbVersion` (`app`, `branchFk`, `version`)
INSERT INTO `vn`.`accountingConfig` (`id`, `minDate`, `maxDate`)
VALUES
- (1, '2022-01-01', '2023-01-01');
+ (1, CONCAT(YEAR(DATE_ADD(util.VN_CURDATE(), INTERVAL -1 YEAR)), '-01-01'), CONCAT(YEAR(DATE_ADD(util.VN_CURDATE(), INTERVAL +1 YEAR)), '-01-01'));
INSERT INTO `vn`.`saleGroup` (`userFk`, `parkingFk`, `sectorFk`)
@@ -2689,7 +2691,8 @@ INSERT INTO `util`.`notificationConfig`
INSERT INTO `util`.`notification` (`id`, `name`, `description`)
VALUES
- (1, 'print-email', 'notification fixture one');
+ (1, 'print-email', 'notification fixture one'),
+ (4, 'supplier-pay-method-update', 'A supplier pay method has been updated');
INSERT INTO `util`.`notificationAcl` (`notificationFk`, `roleFk`)
VALUES
@@ -2704,7 +2707,8 @@ INSERT INTO `util`.`notificationQueue` (`id`, `notificationFk`, `params`, `autho
INSERT INTO `util`.`notificationSubscription` (`notificationFk`, `userFk`)
VALUES
(1, 1109),
- (1, 1110);
+ (1, 1110),
+ (3, 1109);
INSERT INTO `vn`.`routeConfig` (`id`, `defaultWorkCenterFk`)
VALUES
@@ -2730,14 +2734,27 @@ UPDATE `account`.`user`
SET `hasGrant` = 1
WHERE `id` = 66;
+INSERT INTO `vn`.`ticketLog` (`originFk`, userFk, `action`, changedModel, oldInstance, newInstance, changedModelId, `description`)
+ VALUES
+ (7, 18, 'update', 'Sale', '{"quantity":1}', '{"quantity":10}', 1, NULL),
+ (7, 18, 'update', 'Ticket', '{"quantity":1,"concept":"Chest ammo box"}', '{"quantity":10,"concept":"Chest ammo box"}', 1, NULL),
+ (7, 18, 'update', 'Sale', '{"price":3}', '{"price":5}', 1, NULL),
+ (7, 18, 'update', NULL, NULL, NULL, NULL, "Cambio cantidad Melee weapon heavy shield 1x0.5m de '5' a '10'");
+
+
INSERT INTO `vn`.`osTicketConfig` (`id`, `host`, `user`, `password`, `oldStatus`, `newStatusId`, `day`, `comment`, `hostDb`, `userDb`, `passwordDb`, `portDb`, `responseType`, `fromEmailId`, `replyTo`)
VALUES
(0, 'http://localhost:56596/scp', 'ostadmin', 'Admin1', 'open', 3, 60, 'Este CAU se ha cerrado automáticamente. Si el problema persiste responda a este mensaje.', 'localhost', 'osticket', 'osticket', 40003, 'reply', 1, 'all');
+INSERT INTO `vn`.`mdbApp` (`app`, `baselineBranchFk`, `userFk`, `locked`)
+ VALUES
+ ('foo', 'master', NULL, NULL),
+ ('bar', 'test', 9, util.VN_NOW());
INSERT INTO `vn`.`ticketLog` (`id`, `originFk`, `userFk`, `action`, `changedModel`, `oldInstance`, `newInstance`, `changedModelId`)
VALUES
(1, 1, 9, 'insert', 'Ticket', '{}', '{"clientFk":1, "nickname": "Bat cave"}', 1);
+
INSERT INTO `salix`.`url` (`appName`, `environment`, `url`)
VALUES
('lilium', 'dev', 'http://localhost:8080/#/'),
@@ -2746,3 +2763,4 @@ INSERT INTO `salix`.`url` (`appName`, `environment`, `url`)
INSERT INTO `vn`.`payDemDetail` (`id`, `detail`)
VALUES
(1, 1);
+
diff --git a/db/dump/structure.sql b/db/dump/structure.sql
index 9a77662ea..47fdd6d74 100644
--- a/db/dump/structure.sql
+++ b/db/dump/structure.sql
@@ -16340,6 +16340,185 @@ CREATE TABLE `invoiceType` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
/*!40101 SET character_set_client = @saved_cs_client */;
+--
+-- Table structure for table `movConta`
+--
+
+DROP TABLE IF EXISTS `movConta`;
+/*!40101 SET @saved_cs_client = @@character_set_client */;
+/*!40101 SET character_set_client = utf8 */;
+CREATE TABLE `movConta` (
+ `OrdenMovimientos` int(11) NOT NULL AUTO_INCREMENT,
+ `MovPosicion` varchar(64) COLLATE utf8mb3_unicode_ci NOT NULL,
+ `Ejercicio` smallint(6) NOT NULL,
+ `CodigoEmpresa` smallint(6) NOT NULL,
+ `Asiento` int(11) NOT NULL,
+ `CargoAbono` varchar(1) COLLATE utf8mb3_unicode_ci NOT NULL,
+ `CodigoCuenta` varchar(15) CHARACTER SET utf8mb3 NOT NULL,
+ `Contrapartida` varchar(15) COLLATE utf8mb3_unicode_ci NOT NULL,
+ `FechaAsiento` datetime NOT NULL,
+ `TipoDocumento` varchar(6) COLLATE utf8mb3_unicode_ci NOT NULL,
+ `DocumentoConta` varchar(9) COLLATE utf8mb3_unicode_ci NOT NULL,
+ `Comentario` varchar(40) COLLATE utf8mb3_unicode_ci NOT NULL,
+ `ImporteAsiento` decimal(28,10) NOT NULL,
+ `CodigoDiario` smallint(6) NOT NULL,
+ `CodigoCanal` varchar(10) COLLATE utf8mb3_unicode_ci NOT NULL,
+ `CodigoActividad` varchar(1) COLLATE utf8mb3_unicode_ci NOT NULL,
+ `FechaVencimiento` datetime DEFAULT NULL,
+ `NumeroPeriodo` smallint(6) NOT NULL,
+ `CodigoUsuario` smallint(6) NOT NULL,
+ `FechaGrabacion` datetime NOT NULL,
+ `TipoEntrada` varchar(2) COLLATE utf8mb3_unicode_ci NOT NULL,
+ `CodigoDepartamento` varchar(10) COLLATE utf8mb3_unicode_ci NOT NULL,
+ `CodigoSeccion` varchar(10) COLLATE utf8mb3_unicode_ci NOT NULL,
+ `CodigoDivisa` varchar(3) COLLATE utf8mb3_unicode_ci NOT NULL,
+ `ImporteCambio` decimal(28,10) NOT NULL,
+ `ImporteDivisa` decimal(28,10) NOT NULL,
+ `FactorCambio` decimal(28,10) NOT NULL,
+ `CodigoProyecto` varchar(10) COLLATE utf8mb3_unicode_ci NOT NULL,
+ `LibreN1` int(11) NOT NULL,
+ `LibreN2` int(11) NOT NULL,
+ `LibreA1` varchar(15) COLLATE utf8mb3_unicode_ci NOT NULL,
+ `LibreA2` varchar(15) COLLATE utf8mb3_unicode_ci NOT NULL,
+ `IdDelegacion` varchar(10) COLLATE utf8mb3_unicode_ci NOT NULL,
+ `MovCartera` varchar(64) COLLATE utf8mb3_unicode_ci DEFAULT NULL,
+ `IdProcesoIME` varchar(64) COLLATE utf8mb3_unicode_ci NOT NULL,
+ `TipoCarteraIME` smallint(6) NOT NULL,
+ `TipoAnaliticaIME` smallint(6) NOT NULL,
+ `StatusTraspasadoIME` tinyint(4) NOT NULL,
+ `TipoImportacionIME` tinyint(4) NOT NULL,
+ `BaseIva1` decimal(28,10) NOT NULL,
+ `PorBaseCorrectora1` decimal(28,10) NOT NULL,
+ `PorIva1` decimal(28,10) NOT NULL,
+ `CuotaIva1` decimal(28,10) NOT NULL,
+ `PorRecargoEquivalencia1` decimal(28,10) NOT NULL,
+ `RecargoEquivalencia1` decimal(28,10) NOT NULL,
+ `CodigoTransaccion1` tinyint(4) NOT NULL,
+ `BaseIva2` decimal(28,10) NOT NULL,
+ `PorBaseCorrectora2` decimal(28,10) NOT NULL,
+ `PorIva2` decimal(28,10) NOT NULL,
+ `CuotaIva2` decimal(28,10) NOT NULL,
+ `PorRecargoEquivalencia2` decimal(28,10) NOT NULL,
+ `RecargoEquivalencia2` decimal(28,10) NOT NULL,
+ `CodigoTransaccion2` tinyint(4) NOT NULL,
+ `BaseIva3` decimal(28,10) NOT NULL,
+ `PorBaseCorrectora3` decimal(28,10) NOT NULL,
+ `PorIva3` decimal(28,10) NOT NULL,
+ `CuotaIva3` decimal(28,10) NOT NULL,
+ `PorRecargoEquivalencia3` decimal(28,10) NOT NULL,
+ `RecargoEquivalencia3` decimal(28,10) NOT NULL,
+ `CodigoTransaccion3` tinyint(4) NOT NULL,
+ `baseIva4` decimal(28,10) NOT NULL,
+ `PorBaseCorrectora4` decimal(28,10) NOT NULL,
+ `PorIva4` decimal(28,10) NOT NULL,
+ `CuotaIva4` decimal(28,10) NOT NULL,
+ `PorRecargoEquivalencia4` decimal(28,10) NOT NULL,
+ `RecargoEquivalencia4` decimal(28,10) NOT NULL,
+ `CodigoTransaccion4` tinyint(4) NOT NULL,
+ `Año` smallint(6) NOT NULL,
+ `Serie` varchar(10) COLLATE utf8mb3_unicode_ci NOT NULL,
+ `Factura` int(11) NOT NULL,
+ `SuFacturaNo` varchar(40) COLLATE utf8mb3_unicode_ci NOT NULL,
+ `FechaFactura` datetime NOT NULL,
+ `ImporteFactura` decimal(28,10) NOT NULL,
+ `TipoFactura` varchar(1) COLLATE utf8mb3_unicode_ci NOT NULL,
+ `CodigoCuentaFactura` varchar(15) COLLATE utf8mb3_unicode_ci NOT NULL,
+ `CifDni` varchar(13) COLLATE utf8mb3_unicode_ci NOT NULL,
+ `Nombre` varchar(35) COLLATE utf8mb3_unicode_ci NOT NULL,
+ `CodigoRetencion` smallint(6) NOT NULL,
+ `BaseRetencion` decimal(28,10) NOT NULL,
+ `PorRetencion` decimal(28,10) NOT NULL,
+ `ImporteRetencion` decimal(28,10) NOT NULL,
+ `AbonoIva` smallint(6) NOT NULL,
+ `CodigoActividadF` varchar(1) COLLATE utf8mb3_unicode_ci NOT NULL,
+ `Intracomunitaria` smallint(6) NOT NULL,
+ `CodigoTerritorio` smallint(6) NOT NULL,
+ `SiglaNacion` varchar(2) COLLATE utf8mb3_unicode_ci NOT NULL,
+ `RetencionInformativa` smallint(6) NOT NULL,
+ `EjercicioFacturaOriginal` smallint(6) NOT NULL,
+ `SerieFacturaOriginal` varchar(10) COLLATE utf8mb3_unicode_ci NOT NULL,
+ `NumeroFacturaOriginal` int(11) NOT NULL,
+ `EjercicioFactura` smallint(6) NOT NULL,
+ `CobroPagoRetencion` varchar(1) COLLATE utf8mb3_unicode_ci NOT NULL,
+ `FechaOperacion` datetime NOT NULL,
+ `Exclusion347` smallint(6) NOT NULL,
+ `MovIdentificadorIME` varchar(64) COLLATE utf8mb3_unicode_ci NOT NULL,
+ `Previsiones` varchar(1) COLLATE utf8mb3_unicode_ci NOT NULL,
+ `MantenerAsiento` tinyint(4) NOT NULL,
+ `OrdenMovIME` smallint(6) NOT NULL,
+ `Metalico347` smallint(6) NOT NULL,
+ `ClaveOperacionFactura_` varchar(1) COLLATE utf8mb3_unicode_ci NOT NULL,
+ `SerieAgrupacion_` varchar(10) COLLATE utf8mb3_unicode_ci NOT NULL,
+ `NumeroFacturaInicial_` int(11) NOT NULL,
+ `NumeroFacturaFinal_` int(11) NOT NULL,
+ `IdAsientoExterno` text COLLATE utf8mb3_unicode_ci NOT NULL,
+ `IdDiarioExterno` varchar(10) COLLATE utf8mb3_unicode_ci NOT NULL,
+ `IdFacturaExterno` text COLLATE utf8mb3_unicode_ci NOT NULL,
+ `IdMovimiento` varchar(40) COLLATE utf8mb3_unicode_ci NOT NULL,
+ `IdCuadre` smallint(6) NOT NULL,
+ `FechaCuadre` datetime NOT NULL,
+ `TipoCuadre` varchar(4) COLLATE utf8mb3_unicode_ci NOT NULL,
+ `AgrupacionCuadre` int(11) NOT NULL,
+ `StatusSaldo` smallint(6) NOT NULL,
+ `StatusConciliacion` smallint(6) NOT NULL,
+ `CodigoConciliacion` int(11) NOT NULL,
+ `FechaConciliacion` datetime NOT NULL,
+ `TipoConciliacion` smallint(6) NOT NULL,
+ `IndicadorContaBanco` varchar(1) COLLATE utf8mb3_unicode_ci NOT NULL,
+ `Descripcion3` varchar(40) COLLATE utf8mb3_unicode_ci NOT NULL,
+ `Descripcion4` varchar(40) COLLATE utf8mb3_unicode_ci NOT NULL,
+ `Descripcion5` varchar(40) COLLATE utf8mb3_unicode_ci NOT NULL,
+ `Descripcion6` varchar(40) COLLATE utf8mb3_unicode_ci NOT NULL,
+ `Descripcion7` varchar(40) COLLATE utf8mb3_unicode_ci NOT NULL,
+ `Descripcion8` text COLLATE utf8mb3_unicode_ci NOT NULL,
+ `Descripcion9` text COLLATE utf8mb3_unicode_ci NOT NULL,
+ `Descripcion2` text COLLATE utf8mb3_unicode_ci NOT NULL,
+ `Descripcion1` text COLLATE utf8mb3_unicode_ci NOT NULL,
+ `Punteo1` smallint(6) NOT NULL,
+ `Punteo9` smallint(6) NOT NULL,
+ `Punteo8` smallint(6) NOT NULL,
+ `Punteo7` smallint(6) NOT NULL,
+ `Punteo6` smallint(6) NOT NULL,
+ `Punteo5` smallint(6) NOT NULL,
+ `Punteo4` smallint(6) NOT NULL,
+ `Punteo3` smallint(6) NOT NULL,
+ `Punteo2` smallint(6) NOT NULL,
+ `CodigoIva1` smallint(6) NOT NULL,
+ `CodigoIva2` smallint(6) NOT NULL,
+ `CodigoIva3` smallint(6) NOT NULL,
+ `CodigoIva4` smallint(6) NOT NULL,
+ `CriterioIva` tinyint(4) NOT NULL,
+ `FechaMaxVencimiento` datetime NOT NULL,
+ `TipoCriterioCaja` tinyint(4) NOT NULL,
+ `MovFacturaOrigenIME` text COLLATE utf8mb3_unicode_ci NOT NULL,
+ `IdFacturaExternoFinal` text COLLATE utf8mb3_unicode_ci NOT NULL,
+ `IdFacturaExternoInicial` text COLLATE utf8mb3_unicode_ci NOT NULL,
+ `IdFacturaExternoOriginal` text COLLATE utf8mb3_unicode_ci NOT NULL,
+ `NumFacturasExternoAgrupacion` int(11) NOT NULL,
+ `CodigoMedioCobro` varchar(1) COLLATE utf8mb3_unicode_ci NOT NULL,
+ `MedioCobro` varchar(31) COLLATE utf8mb3_unicode_ci NOT NULL,
+ `IvaDeducible1` smallint(6) NOT NULL DEFAULT 1,
+ `IvaDeducible2` smallint(6) NOT NULL DEFAULT 1,
+ `IvaDeducible3` smallint(6) NOT NULL DEFAULT 1,
+ `IvaDeducible4` smallint(6) NOT NULL DEFAULT 1,
+ `TipoRectificativa` smallint(6) NOT NULL,
+ `FechaFacturaOriginal` datetime NOT NULL,
+ `BaseImponibleOriginal` decimal(28,10) NOT NULL,
+ `CuotaIvaOriginal` decimal(28,10) NOT NULL,
+ `ClaseAbonoRectificativas` smallint(6) NOT NULL,
+ `RecargoEquivalenciaOriginal` decimal(28,10) NOT NULL,
+ `ObjetoFactura` text COLLATE utf8mb3_unicode_ci NOT NULL,
+ `enlazadoSage` tinyint(1) NOT NULL DEFAULT 0,
+ PRIMARY KEY (`OrdenMovimientos`,`LibreN1`),
+ KEY `ix_movconta2` (`IdProcesoIME`),
+ KEY `CodigoCuenta` (`CodigoCuenta`),
+ KEY `movConta_Asiento` (`Asiento`),
+ KEY `ix_movconta` (`enlazadoSage`,`IdProcesoIME`),
+ KEY `movConta_IdProcesoIME` (`IdProcesoIME`),
+ KEY `movConta_Asiento2` (`Asiento`,`IdProcesoIME`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
+/*!40101 SET character_set_client = @saved_cs_client */;
+
--
-- Table structure for table `movContaIVA`
--
diff --git a/db/export-structure.sh b/db/export-structure.sh
index f52819c54..a4fd4a8c6 100755
--- a/db/export-structure.sh
+++ b/db/export-structure.sh
@@ -84,7 +84,6 @@ IGNORETABLES=(
--ignore-table=vn.warehouseJoined
--ignore-table=vn.workerTeam__
--ignore-table=vn.XDiario__
- --ignore-table=sage.movConta
--ignore-table=sage.movContaCopia
)
mysqldump \
diff --git a/e2e/helpers/selectors.js b/e2e/helpers/selectors.js
index f550e3a9d..e1792ea7b 100644
--- a/e2e/helpers/selectors.js
+++ b/e2e/helpers/selectors.js
@@ -30,7 +30,7 @@ export default {
firstModuleRemovePinIcon: 'vn-home a:nth-child(1) vn-icon[icon="remove_circle"]'
},
recoverPassword: {
- recoverPasswordButton: 'vn-login a[ui-sref="recoverPassword"]',
+ recoverPasswordButton: 'vn-login a[ui-sref="recover-password"]',
email: 'vn-recover-password vn-textfield[ng-model="$ctrl.email"]',
sendEmailButton: 'vn-recover-password vn-submit',
},
@@ -311,10 +311,12 @@ export default {
firstMandateText: 'vn-client-mandate vn-card vn-table vn-tbody > vn-tr'
},
clientLog: {
- lastModificationPreviousValue: 'vn-client-log vn-table vn-td.before',
- lastModificationCurrentValue: 'vn-client-log vn-table vn-td.after',
- penultimateModificationPreviousValue: 'vn-client-log vn-table vn-tr:nth-child(2) vn-td.before',
- penultimateModificationCurrentValue: 'vn-client-log vn-table vn-tr:nth-child(2) vn-td.after'
+ lastModificationPreviousValue: 'vn-client-log vn-tr table tr td.before',
+ lastModificationCurrentValue: 'vn-client-log vn-tr table tr td.after',
+ namePreviousValue: 'vn-client-log vn-tr table tr:nth-child(1) td.before',
+ nameCurrentValue: 'vn-client-log vn-tr table tr:nth-child(1) td.after',
+ activePreviousValue: 'vn-client-log vn-tr:nth-child(2) table tr:nth-child(2) td.before',
+ activeCurrentValue: 'vn-client-log vn-tr:nth-child(2) table tr:nth-child(2) td.after'
},
clientBalance: {
@@ -518,7 +520,7 @@ export default {
},
itemLog: {
anyLineCreated: 'vn-item-log > vn-log vn-tbody > vn-tr',
- fifthLineCreatedProperty: 'vn-item-log > vn-log vn-tbody > vn-tr:nth-child(5) > vn-td > vn-one:nth-child(3) > div span:nth-child(2)',
+ fifthLineCreatedProperty: 'vn-item-log > vn-log vn-tbody > vn-tr:nth-child(5) table tr:nth-child(3) td.after',
},
ticketSummary: {
header: 'vn-ticket-summary > vn-card > h5',
@@ -711,9 +713,10 @@ export default {
ticketLog: {
firstTD: 'vn-ticket-log vn-table vn-td:nth-child(1)',
logButton: 'vn-left-menu a[ui-sref="ticket.card.log"]',
- firstLogEntry: 'vn-ticket-log vn-data-viewer vn-tbody vn-tr',
- changes: 'vn-ticket-log vn-data-viewer vn-tbody > vn-tr > vn-td:nth-child(7)',
- id: 'vn-ticket-log vn-tr:nth-child(1) vn-one:nth-child(1) span'
+ user: 'vn-ticket-log vn-tbody vn-tr vn-td:nth-child(2)',
+ action: 'vn-ticket-log vn-tbody vn-tr vn-td:nth-child(4)',
+ changes: 'vn-ticket-log vn-data-viewer vn-tbody vn-tr table tr:nth-child(2) td.after',
+ id: 'vn-ticket-log vn-tr:nth-child(1) table tr:nth-child(1) td.before'
},
ticketService: {
addServiceButton: 'vn-ticket-service vn-icon-button[vn-tooltip="Add service"] > button',
@@ -735,18 +738,16 @@ export default {
},
ticketFuture: {
openAdvancedSearchButton: 'vn-searchbar .append vn-icon[icon="arrow_drop_down"]',
- originDated: 'vn-date-picker[label="Origin ETD"]',
- futureDated: 'vn-date-picker[label="Destination ETD"]',
- shipped: 'vn-date-picker[label="Origin date"]',
- tfShipped: 'vn-date-picker[label="Destination date"]',
+ originDated: 'vn-date-picker[label="Origin date"]',
+ futureDated: 'vn-date-picker[label="Destination date"]',
linesMax: 'vn-textfield[label="Max Lines"]',
litersMax: 'vn-textfield[label="Max Liters"]',
ipt: 'vn-autocomplete[label="Origin IPT"]',
- tfIpt: 'vn-autocomplete[label="Destination IPT"]',
+ futureIpt: 'vn-autocomplete[label="Destination IPT"]',
tableIpt: 'vn-autocomplete[name="ipt"]',
- tableTfIpt: 'vn-autocomplete[name="tfIpt"]',
+ tableFutureIpt: 'vn-autocomplete[name="futureIpt"]',
state: 'vn-autocomplete[label="Origin Grouped State"]',
- tfState: 'vn-autocomplete[label="Destination Grouped State"]',
+ futureState: 'vn-autocomplete[label="Destination Grouped State"]',
warehouseFk: 'vn-autocomplete[label="Warehouse"]',
problems: 'vn-check[label="With problems"]',
tableButtonSearch: 'vn-button[vn-tooltip="Search"]',
@@ -755,9 +756,34 @@ export default {
firstCheck: 'tbody > tr:nth-child(1) > td > vn-check',
multiCheck: 'vn-multi-check',
tableId: 'vn-textfield[name="id"]',
- tableTfId: 'vn-textfield[name="ticketFuture"]',
- tableLiters: 'vn-textfield[name="litersMax"]',
- tableLines: 'vn-textfield[name="linesMax"]',
+ tableFutureId: 'vn-textfield[name="futureId"]',
+ tableLiters: 'vn-textfield[name="liters"]',
+ tableLines: 'vn-textfield[name="lines"]',
+ submit: 'vn-submit[label="Search"]',
+ table: 'tbody > tr:not(.empty-rows)'
+ },
+ ticketAdvance: {
+ openAdvancedSearchButton: 'vn-searchbar .append vn-icon[icon="arrow_drop_down"]',
+ dateFuture: 'vn-date-picker[label="Origin date"]',
+ dateToAdvance: 'vn-date-picker[label="Destination date"]',
+ linesMax: 'vn-textfield[label="Max Lines"]',
+ litersMax: 'vn-textfield[label="Max Liters"]',
+ futureIpt: 'vn-autocomplete[label="Origin IPT"]',
+ ipt: 'vn-autocomplete[label="Destination IPT"]',
+ tableIpt: 'vn-autocomplete[name="ipt"]',
+ tableFutureIpt: 'vn-autocomplete[name="futureIpt"]',
+ futureState: 'vn-autocomplete[label="Origin Grouped State"]',
+ state: 'vn-autocomplete[label="Destination Grouped State"]',
+ warehouseFk: 'vn-autocomplete[label="Warehouse"]',
+ tableButtonSearch: 'vn-button[vn-tooltip="Search"]',
+ moveButton: 'vn-button[vn-tooltip="Advance tickets"]',
+ acceptButton: '.vn-confirm.shown button[response="accept"]',
+ multiCheck: 'vn-multi-check',
+ tableId: 'vn-textfield[name="id"]',
+ tableFutureId: 'vn-textfield[name="futureId"]',
+ tableLiters: 'vn-textfield[name="liters"]',
+ tableLines: 'vn-textfield[name="lines"]',
+ tableStock: 'vn-textfield[name="hasStock"]',
submit: 'vn-submit[label="Search"]',
table: 'tbody > tr:not(.empty-rows)'
},
@@ -1100,7 +1126,7 @@ export default {
undoChanges: 'vn-travel-basic-data vn-button[label="Undo changes"]'
},
travelLog: {
- firstLogFirstTD: 'vn-travel-log vn-tbody > vn-tr > vn-td:nth-child(1) > div'
+ firstLogFirstTD: 'vn-travel-log vn-tbody > vn-tr > vn-td:nth-child(5)'
},
travelThermograph: {
add: 'vn-travel-thermograph-index vn-float-button[icon="add"]',
diff --git a/e2e/paths/01-salix/04_recoverPassword.spec.js b/e2e/paths/01-salix/04_recoverPassword.spec.js
index 80ef32cb5..e6cb02ab1 100644
--- a/e2e/paths/01-salix/04_recoverPassword.spec.js
+++ b/e2e/paths/01-salix/04_recoverPassword.spec.js
@@ -1,7 +1,7 @@
import selectors from '../../helpers/selectors';
import getBrowser from '../../helpers/puppeteer';
-describe('Login path', async() => {
+describe('RecoverPassword path', async() => {
let browser;
let page;
@@ -10,7 +10,7 @@ describe('Login path', async() => {
page = browser.page;
await page.waitToClick(selectors.recoverPassword.recoverPasswordButton);
- await page.waitForState('recoverPassword');
+ await page.waitForState('recover-password');
});
afterAll(async() => {
diff --git a/e2e/paths/02-client/07_edit_web_access.spec.js b/e2e/paths/02-client/07_edit_web_access.spec.js
index 3d9ccee62..29b39f788 100644
--- a/e2e/paths/02-client/07_edit_web_access.spec.js
+++ b/e2e/paths/02-client/07_edit_web_access.spec.js
@@ -67,22 +67,22 @@ describe('Client Edit web access path', () => {
});
it(`should confirm the last log shows the updated client name and no modifications on active checkbox`, async() => {
- let lastModificationPreviousValue = await page
- .waitToGetProperty(selectors.clientLog.lastModificationPreviousValue, 'innerText');
- let lastModificationCurrentValue = await page
- .waitToGetProperty(selectors.clientLog.lastModificationCurrentValue, 'innerText');
+ let namePreviousValue = await page
+ .waitToGetProperty(selectors.clientLog.namePreviousValue, 'innerText');
+ let nameCurrentValue = await page
+ .waitToGetProperty(selectors.clientLog.nameCurrentValue, 'innerText');
- expect(lastModificationPreviousValue).toEqual('name MaxEisenhardt active false');
- expect(lastModificationCurrentValue).toEqual('name Legion active false');
+ expect(namePreviousValue).toEqual('MaxEisenhardt');
+ expect(nameCurrentValue).toEqual('Legion');
});
it(`should confirm the penultimate log shows the updated active and no modifications on client name`, async() => {
- let penultimateModificationPreviousValue = await page
- .waitToGetProperty(selectors.clientLog.penultimateModificationPreviousValue, 'innerText');
- let penultimateModificationCurrentValue = await page
- .waitToGetProperty(selectors.clientLog.penultimateModificationCurrentValue, 'innerText');
+ let activePreviousValue = await page
+ .waitToGetProperty(selectors.clientLog.activePreviousValue, 'innerText');
+ let activeCurrentValue = await page
+ .waitToGetProperty(selectors.clientLog.activeCurrentValue, 'innerText');
- expect(penultimateModificationPreviousValue).toEqual('name MaxEisenhardt active true');
- expect(penultimateModificationCurrentValue).toEqual('name MaxEisenhardt active false');
+ expect(activePreviousValue).toEqual('✓');
+ expect(activeCurrentValue).toEqual('✗');
});
});
diff --git a/e2e/paths/02-client/13_log.spec.js b/e2e/paths/02-client/13_log.spec.js
index 9b047a47c..8f186d842 100644
--- a/e2e/paths/02-client/13_log.spec.js
+++ b/e2e/paths/02-client/13_log.spec.js
@@ -43,7 +43,7 @@ describe('Client log path', () => {
let lastModificationCurrentValue = await page.
waitToGetProperty(selectors.clientLog.lastModificationCurrentValue, 'innerText');
- expect(lastModificationPreviousValue).toEqual('name DavidCharlesHaller');
- expect(lastModificationCurrentValue).toEqual('name this is a test');
+ expect(lastModificationPreviousValue).toEqual('DavidCharlesHaller');
+ expect(lastModificationCurrentValue).toEqual('this is a test');
});
});
diff --git a/e2e/paths/03-worker/04_time_control.spec.js b/e2e/paths/03-worker/04_time_control.spec.js
index be8df3cf0..4236ae0e4 100644
--- a/e2e/paths/03-worker/04_time_control.spec.js
+++ b/e2e/paths/03-worker/04_time_control.spec.js
@@ -58,6 +58,7 @@ describe('Worker time control path', () => {
});
it(`should return error when insert 'out' of first entry`, async() => {
+ pending('https://redmine.verdnatura.es/issues/4707');
await page.waitToClick(selectors.workerTimeControl.mondayAddTimeButton);
await page.pickTime(selectors.workerTimeControl.dialogTimeInput, eightAm);
await page.autocompleteSearch(selectors.workerTimeControl.dialogTimeDirection, 'out');
@@ -68,6 +69,7 @@ describe('Worker time control path', () => {
});
it(`should insert 'in' monday`, async() => {
+ pending('https://redmine.verdnatura.es/issues/4707');
await page.waitToClick(selectors.workerTimeControl.mondayAddTimeButton);
await page.pickTime(selectors.workerTimeControl.dialogTimeInput, eightAm);
await page.autocompleteSearch(selectors.workerTimeControl.dialogTimeDirection, 'in');
@@ -78,6 +80,7 @@ describe('Worker time control path', () => {
});
it(`should insert 'out' monday`, async() => {
+ pending('https://redmine.verdnatura.es/issues/4707');
await page.waitToClick(selectors.workerTimeControl.mondayAddTimeButton);
await page.pickTime(selectors.workerTimeControl.dialogTimeInput, fourPm);
await page.autocompleteSearch(selectors.workerTimeControl.dialogTimeDirection, 'out');
@@ -88,11 +91,13 @@ describe('Worker time control path', () => {
});
it(`should check Hank Pym worked 8:20 hours`, async() => {
+ pending('https://redmine.verdnatura.es/issues/4707');
await page.waitForTextInElement(selectors.workerTimeControl.mondayWorkedHours, '08:20 h.');
await page.waitForTextInElement(selectors.workerTimeControl.weekWorkedHours, '08:20 h.');
});
it('should remove first entry of monday', async() => {
+ pending('https://redmine.verdnatura.es/issues/4707');
await page.waitForTextInElement(selectors.workerTimeControl.firstEntryOfMonday, eightAm);
await page.waitForTextInElement(selectors.workerTimeControl.secondEntryOfMonday, fourPm);
await page.waitToClick(selectors.workerTimeControl.firstEntryOfMondayDelete);
@@ -103,6 +108,7 @@ describe('Worker time control path', () => {
});
it(`should be the 'out' the first entry of monday`, async() => {
+ pending('https://redmine.verdnatura.es/issues/4707');
const result = await page.waitToGetProperty(selectors.workerTimeControl.firstEntryOfMonday, 'innerText');
expect(result).toEqual(fourPm);
diff --git a/e2e/paths/04-item/08_regularize.spec.js b/e2e/paths/04-item/08_regularize.spec.js
index 2e09a9f63..9b3074776 100644
--- a/e2e/paths/04-item/08_regularize.spec.js
+++ b/e2e/paths/04-item/08_regularize.spec.js
@@ -127,8 +127,8 @@ describe('Item regularize path', () => {
await page.waitForState('ticket.index');
});
- it('should search for the ticket with id 31 once again', async() => {
- await page.accessToSearchResult('31');
+ it('should search for the ticket missing once again', async() => {
+ await page.accessToSearchResult('Missing');
await page.waitForState('ticket.card.summary');
});
diff --git a/e2e/paths/05-ticket/02_expeditions_and_log.spec.js b/e2e/paths/05-ticket/02_expeditions_and_log.spec.js
index f970247e5..ae5e2fb0c 100644
--- a/e2e/paths/05-ticket/02_expeditions_and_log.spec.js
+++ b/e2e/paths/05-ticket/02_expeditions_and_log.spec.js
@@ -32,14 +32,17 @@ describe('Ticket expeditions and log path', () => {
it(`should confirm the expedition deleted is shown now in the ticket log`, async() => {
await page.accessToSection('ticket.card.log');
- const firstLogEntry = await page
- .waitToGetProperty(selectors.ticketLog.firstLogEntry, 'innerText');
+ const user = await page
+ .waitToGetProperty(selectors.ticketLog.user, 'innerText');
+
+ const action = await page
+ .waitToGetProperty(selectors.ticketLog.action, 'innerText');
const id = await page
.waitToGetProperty(selectors.ticketLog.id, 'innerText');
- expect(firstLogEntry).toContain('production');
- expect(firstLogEntry).toContain('Deletes');
+ expect(user).toContain('production');
+ expect(action).toContain('Deletes');
expect(id).toEqual('2');
});
});
diff --git a/e2e/paths/05-ticket/17_log.spec.js b/e2e/paths/05-ticket/17_log.spec.js
index 399eb647b..32829ee74 100644
--- a/e2e/paths/05-ticket/17_log.spec.js
+++ b/e2e/paths/05-ticket/17_log.spec.js
@@ -55,6 +55,6 @@ describe('Ticket log path', () => {
const result = await page.waitToGetProperty(selectors.ticketLog.firstTD, 'innerText');
- expect(result.length).toBeGreaterThan('20');
+ expect(result.length).toBeGreaterThan('15');
});
});
diff --git a/e2e/paths/05-ticket/20_future.spec.js b/e2e/paths/05-ticket/21_future.spec.js
similarity index 71%
rename from e2e/paths/05-ticket/20_future.spec.js
rename to e2e/paths/05-ticket/21_future.spec.js
index 6db2bf4f0..45c39de86 100644
--- a/e2e/paths/05-ticket/20_future.spec.js
+++ b/e2e/paths/05-ticket/21_future.spec.js
@@ -16,9 +16,6 @@ describe('Ticket Future path', () => {
await browser.close();
});
- const now = new Date();
- const tomorrow = new Date(now.getDate() + 1);
-
it('should show errors snackbar because of the required data', async() => {
await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton);
await page.clearInput(selectors.ticketFuture.warehouseFk);
@@ -27,20 +24,6 @@ describe('Ticket Future path', () => {
expect(message.text).toContain('warehouseFk is a required argument');
- await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton);
- await page.clearInput(selectors.ticketFuture.litersMax);
- await page.waitToClick(selectors.ticketFuture.submit);
- message = await page.waitForSnackbar();
-
- expect(message.text).toContain('litersMax is a required argument');
-
- await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton);
- await page.clearInput(selectors.ticketFuture.linesMax);
- await page.waitToClick(selectors.ticketFuture.submit);
- message = await page.waitForSnackbar();
-
- expect(message.text).toContain('linesMax is a required argument');
-
await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton);
await page.clearInput(selectors.ticketFuture.futureDated);
await page.waitToClick(selectors.ticketFuture.submit);
@@ -62,44 +45,13 @@ describe('Ticket Future path', () => {
await page.waitForNumberOfElements(selectors.ticketFuture.table, 4);
});
- it('should search with the origin shipped today', async() => {
- await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton);
- await page.pickDate(selectors.ticketFuture.shipped, now);
- await page.waitToClick(selectors.ticketFuture.submit);
- await page.waitForNumberOfElements(selectors.ticketFuture.table, 4);
- });
-
- it('should search with the origin shipped tomorrow', async() => {
- await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton);
- await page.pickDate(selectors.ticketFuture.shipped, tomorrow);
- await page.waitToClick(selectors.ticketFuture.submit);
- await page.waitForNumberOfElements(selectors.ticketFuture.table, 0);
- });
-
- it('should search with the destination shipped today', async() => {
- await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton);
- await page.clearInput(selectors.ticketFuture.shipped);
- await page.pickDate(selectors.ticketFuture.tfShipped, now);
- await page.waitToClick(selectors.ticketFuture.submit);
- await page.waitForNumberOfElements(selectors.ticketFuture.table, 4);
- });
-
- it('should search with the destination shipped tomorrow', async() => {
- await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton);
- await page.pickDate(selectors.ticketFuture.tfShipped, tomorrow);
- await page.waitToClick(selectors.ticketFuture.submit);
- await page.waitForNumberOfElements(selectors.ticketFuture.table, 0);
- });
-
it('should search with the origin IPT', async() => {
await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton);
- await page.clearInput(selectors.ticketFuture.shipped);
- await page.clearInput(selectors.ticketFuture.tfShipped);
await page.clearInput(selectors.ticketFuture.ipt);
- await page.clearInput(selectors.ticketFuture.tfIpt);
+ await page.clearInput(selectors.ticketFuture.futureIpt);
await page.clearInput(selectors.ticketFuture.state);
- await page.clearInput(selectors.ticketFuture.tfState);
+ await page.clearInput(selectors.ticketFuture.futureState);
await page.autocompleteSearch(selectors.ticketFuture.ipt, 'Horizontal');
await page.waitToClick(selectors.ticketFuture.submit);
@@ -109,14 +61,12 @@ describe('Ticket Future path', () => {
it('should search with the destination IPT', async() => {
await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton);
- await page.clearInput(selectors.ticketFuture.shipped);
- await page.clearInput(selectors.ticketFuture.tfShipped);
await page.clearInput(selectors.ticketFuture.ipt);
- await page.clearInput(selectors.ticketFuture.tfIpt);
+ await page.clearInput(selectors.ticketFuture.futureIpt);
await page.clearInput(selectors.ticketFuture.state);
- await page.clearInput(selectors.ticketFuture.tfState);
+ await page.clearInput(selectors.ticketFuture.futureState);
- await page.autocompleteSearch(selectors.ticketFuture.tfIpt, 'Horizontal');
+ await page.autocompleteSearch(selectors.ticketFuture.futureIpt, 'Horizontal');
await page.waitToClick(selectors.ticketFuture.submit);
await page.waitForNumberOfElements(selectors.ticketFuture.table, 0);
});
@@ -124,12 +74,10 @@ describe('Ticket Future path', () => {
it('should search with the origin grouped state', async() => {
await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton);
- await page.clearInput(selectors.ticketFuture.shipped);
- await page.clearInput(selectors.ticketFuture.tfShipped);
await page.clearInput(selectors.ticketFuture.ipt);
- await page.clearInput(selectors.ticketFuture.tfIpt);
+ await page.clearInput(selectors.ticketFuture.futureIpt);
await page.clearInput(selectors.ticketFuture.state);
- await page.clearInput(selectors.ticketFuture.tfState);
+ await page.clearInput(selectors.ticketFuture.futureState);
await page.autocompleteSearch(selectors.ticketFuture.state, 'Free');
await page.waitToClick(selectors.ticketFuture.submit);
@@ -139,24 +87,20 @@ describe('Ticket Future path', () => {
it('should search with the destination grouped state', async() => {
await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton);
- await page.clearInput(selectors.ticketFuture.shipped);
- await page.clearInput(selectors.ticketFuture.tfShipped);
await page.clearInput(selectors.ticketFuture.ipt);
- await page.clearInput(selectors.ticketFuture.tfIpt);
+ await page.clearInput(selectors.ticketFuture.futureIpt);
await page.clearInput(selectors.ticketFuture.state);
- await page.clearInput(selectors.ticketFuture.tfState);
+ await page.clearInput(selectors.ticketFuture.futureState);
- await page.autocompleteSearch(selectors.ticketFuture.tfState, 'Free');
+ await page.autocompleteSearch(selectors.ticketFuture.futureState, 'Free');
await page.waitToClick(selectors.ticketFuture.submit);
await page.waitForNumberOfElements(selectors.ticketFuture.table, 0);
await page.waitToClick(selectors.ticketFuture.openAdvancedSearchButton);
- await page.clearInput(selectors.ticketFuture.shipped);
- await page.clearInput(selectors.ticketFuture.tfShipped);
await page.clearInput(selectors.ticketFuture.ipt);
- await page.clearInput(selectors.ticketFuture.tfIpt);
+ await page.clearInput(selectors.ticketFuture.futureIpt);
await page.clearInput(selectors.ticketFuture.state);
- await page.clearInput(selectors.ticketFuture.tfState);
+ await page.clearInput(selectors.ticketFuture.futureState);
await page.waitToClick(selectors.ticketFuture.submit);
await page.waitForNumberOfElements(selectors.ticketFuture.table, 4);
@@ -176,7 +120,7 @@ describe('Ticket Future path', () => {
it('should search in smart-table with an ID Destination', async() => {
await page.waitToClick(selectors.ticketFuture.tableButtonSearch);
- await page.write(selectors.ticketFuture.tableTfId, '12');
+ await page.write(selectors.ticketFuture.tableFutureId, '12');
await page.keyboard.press('Enter');
await page.waitForNumberOfElements(selectors.ticketFuture.table, 5);
@@ -199,7 +143,7 @@ describe('Ticket Future path', () => {
it('should search in smart-table with an IPT Destination', async() => {
await page.waitToClick(selectors.ticketFuture.tableButtonSearch);
- await page.autocompleteSearch(selectors.ticketFuture.tableTfIpt, 'Vertical');
+ await page.autocompleteSearch(selectors.ticketFuture.tableFutureIpt, 'Vertical');
await page.waitForNumberOfElements(selectors.ticketFuture.table, 1);
await page.waitToClick(selectors.ticketFuture.tableButtonSearch);
diff --git a/e2e/paths/05-ticket/22_advance.spec.js b/e2e/paths/05-ticket/22_advance.spec.js
new file mode 100644
index 000000000..6aaa81591
--- /dev/null
+++ b/e2e/paths/05-ticket/22_advance.spec.js
@@ -0,0 +1,162 @@
+import selectors from '../../helpers/selectors.js';
+import getBrowser from '../../helpers/puppeteer';
+
+describe('Ticket Advance path', () => {
+ let browser;
+ let page;
+
+ beforeAll(async() => {
+ browser = await getBrowser();
+ page = browser.page;
+ await page.loginAndModule('employee', 'ticket');
+ await page.accessToSection('ticket.advance');
+ });
+
+ afterAll(async() => {
+ await browser.close();
+ });
+
+ it('should show errors snackbar because of the required data', async() => {
+ await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
+ await page.clearInput(selectors.ticketAdvance.warehouseFk);
+
+ await page.waitToClick(selectors.ticketAdvance.submit);
+ let message = await page.waitForSnackbar();
+
+ expect(message.text).toContain('warehouseFk is a required argument');
+
+ await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
+ await page.clearInput(selectors.ticketAdvance.dateToAdvance);
+ await page.waitToClick(selectors.ticketAdvance.submit);
+ message = await page.waitForSnackbar();
+
+ expect(message.text).toContain('dateToAdvance is a required argument');
+
+ await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
+ await page.clearInput(selectors.ticketAdvance.dateFuture);
+ await page.waitToClick(selectors.ticketAdvance.submit);
+ message = await page.waitForSnackbar();
+
+ expect(message.text).toContain('dateFuture is a required argument');
+ });
+
+ it('should search with the required data', async() => {
+ await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
+ await page.waitToClick(selectors.ticketAdvance.submit);
+ await page.waitForNumberOfElements(selectors.ticketAdvance.table, 1);
+ });
+
+ it('should search with the origin IPT', async() => {
+ await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
+ await page.autocompleteSearch(selectors.ticketAdvance.ipt, 'Horizontal');
+ await page.waitToClick(selectors.ticketAdvance.submit);
+ await page.waitForNumberOfElements(selectors.ticketAdvance.table, 0);
+
+ await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
+ await page.clearInput(selectors.ticketAdvance.ipt);
+ await page.waitToClick(selectors.ticketAdvance.submit);
+ await page.waitForNumberOfElements(selectors.ticketAdvance.table, 1);
+ });
+
+ it('should search with the destination IPT', async() => {
+ await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
+ await page.autocompleteSearch(selectors.ticketAdvance.futureIpt, 'Horizontal');
+ await page.waitToClick(selectors.ticketAdvance.submit);
+ await page.waitForNumberOfElements(selectors.ticketAdvance.table, 0);
+
+ await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
+ await page.clearInput(selectors.ticketAdvance.futureIpt);
+ await page.waitToClick(selectors.ticketAdvance.submit);
+ await page.waitForNumberOfElements(selectors.ticketAdvance.table, 1);
+ });
+
+ it('should search with the origin grouped state', async() => {
+ await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
+ await page.autocompleteSearch(selectors.ticketAdvance.futureState, 'Free');
+ await page.waitToClick(selectors.ticketAdvance.submit);
+ await page.waitForNumberOfElements(selectors.ticketAdvance.table, 1);
+
+ await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
+ await page.clearInput(selectors.ticketAdvance.futureState);
+ await page.waitToClick(selectors.ticketAdvance.submit);
+ await page.waitForNumberOfElements(selectors.ticketAdvance.table, 1);
+ });
+
+ it('should search with the destination grouped state', async() => {
+ await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
+ await page.autocompleteSearch(selectors.ticketAdvance.state, 'Free');
+ await page.waitToClick(selectors.ticketAdvance.submit);
+ await page.waitForNumberOfElements(selectors.ticketAdvance.table, 0);
+
+ await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
+ await page.clearInput(selectors.ticketAdvance.state);
+ await page.waitToClick(selectors.ticketAdvance.submit);
+ await page.waitForNumberOfElements(selectors.ticketAdvance.table, 1);
+ });
+
+ it('should search in smart-table with an IPT Origin', async() => {
+ await page.waitToClick(selectors.ticketAdvance.tableButtonSearch);
+ await page.autocompleteSearch(selectors.ticketAdvance.tableFutureIpt, 'Vertical');
+ await page.waitForNumberOfElements(selectors.ticketAdvance.table, 1);
+
+ await page.waitToClick(selectors.ticketAdvance.tableButtonSearch);
+ await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
+ await page.waitToClick(selectors.ticketAdvance.submit);
+ await page.waitForNumberOfElements(selectors.ticketAdvance.table, 1);
+ });
+
+ it('should search in smart-table with an IPT Destination', async() => {
+ await page.waitToClick(selectors.ticketAdvance.tableButtonSearch);
+ await page.autocompleteSearch(selectors.ticketAdvance.tableIpt, 'Vertical');
+ await page.waitForNumberOfElements(selectors.ticketAdvance.table, 1);
+
+ await page.waitToClick(selectors.ticketAdvance.tableButtonSearch);
+ await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
+ await page.waitToClick(selectors.ticketAdvance.submit);
+ await page.waitForNumberOfElements(selectors.ticketAdvance.table, 1);
+ });
+
+ it('should search in smart-table with stock', async() => {
+ await page.waitToClick(selectors.ticketAdvance.tableButtonSearch);
+ await page.write(selectors.ticketAdvance.tableStock, '5');
+ await page.waitForNumberOfElements(selectors.ticketAdvance.table, 2);
+
+ await page.waitToClick(selectors.ticketAdvance.tableButtonSearch);
+ await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
+ await page.waitToClick(selectors.ticketAdvance.submit);
+ await page.waitForNumberOfElements(selectors.ticketAdvance.table, 1);
+ });
+
+ it('should search in smart-table with especified Lines', async() => {
+ await page.waitToClick(selectors.ticketAdvance.tableButtonSearch);
+ await page.write(selectors.ticketAdvance.tableLines, '0');
+ await page.keyboard.press('Enter');
+ await page.waitForNumberOfElements(selectors.ticketAdvance.table, 1);
+
+ await page.waitToClick(selectors.ticketAdvance.tableButtonSearch);
+ await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
+ await page.waitToClick(selectors.ticketAdvance.submit);
+ await page.waitForNumberOfElements(selectors.ticketAdvance.table, 1);
+ });
+
+ it('should search in smart-table with especified Liters', async() => {
+ await page.waitToClick(selectors.ticketAdvance.tableButtonSearch);
+ await page.write(selectors.ticketAdvance.tableLiters, '0');
+ await page.keyboard.press('Enter');
+ await page.waitForNumberOfElements(selectors.ticketAdvance.table, 1);
+
+ await page.waitToClick(selectors.ticketAdvance.tableButtonSearch);
+ await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
+ await page.waitToClick(selectors.ticketAdvance.submit);
+ await page.waitForNumberOfElements(selectors.ticketAdvance.table, 1);
+ });
+
+ it('should check the three last tickets and move to the future', async() => {
+ await page.waitToClick(selectors.ticketAdvance.multiCheck);
+ await page.waitToClick(selectors.ticketAdvance.moveButton);
+ await page.waitToClick(selectors.ticketAdvance.acceptButton);
+ const message = await page.waitForSnackbar();
+
+ expect(message.text).toContain('Tickets moved successfully!');
+ });
+});
diff --git a/e2e/paths/13-supplier/02_basic_data.spec.js b/e2e/paths/13-supplier/02_basic_data.spec.js
index 4f3c49512..9d86e11d4 100644
--- a/e2e/paths/13-supplier/02_basic_data.spec.js
+++ b/e2e/paths/13-supplier/02_basic_data.spec.js
@@ -70,8 +70,8 @@ describe('Supplier basic data path', () => {
});
it('should check the changes have been recorded', async() => {
- const result = await page.waitToGetProperty('#newInstance:nth-child(3)', 'innerText');
+ const result = await page.waitToGetProperty('vn-tr table tr:nth-child(3) td.after', 'innerText');
- expect(result).toEqual('note Some notes');
+ expect(result).toEqual('Some notes');
});
});
diff --git a/front/core/components/crud-model/crud-model.js b/front/core/components/crud-model/crud-model.js
index 1095985dc..16b837d6a 100644
--- a/front/core/components/crud-model/crud-model.js
+++ b/front/core/components/crud-model/crud-model.js
@@ -14,6 +14,7 @@ export default class CrudModel extends ModelProxy {
this.$q = $q;
this.primaryKey = 'id';
this.autoLoad = false;
+ this.page = 1;
}
$onInit() {
@@ -125,13 +126,20 @@ export default class CrudModel extends ModelProxy {
}
}
- loadMore() {
+ loadMore(append) {
if (!this.moreRows)
return this.$q.resolve();
- let filter = Object.assign({}, this.currentFilter);
- filter.skip = this.orgData ? this.orgData.length : 0;
- return this.sendRequest(filter, true);
+ const filter = Object.assign({}, this.currentFilter);
+ if (append)
+ filter.skip = this.orgData ? this.orgData.length : 0;
+
+ if (!append) {
+ this.page += 1;
+ filter.limit = this.page * this.limit;
+ }
+
+ return this.sendRequest(filter, append);
}
clear() {
diff --git a/front/core/components/crud-model/index.spec.js b/front/core/components/crud-model/index.spec.js
index 8673e947f..7eab80405 100644
--- a/front/core/components/crud-model/index.spec.js
+++ b/front/core/components/crud-model/index.spec.js
@@ -148,7 +148,7 @@ describe('Component vnCrudModel', () => {
controller.moreRows = true;
- controller.loadMore();
+ controller.loadMore(true);
expect(controller.sendRequest).toHaveBeenCalledWith({'skip': 2}, true);
});
diff --git a/front/core/components/drop-down/index.js b/front/core/components/drop-down/index.js
index 08d0da6d0..302c1c6b5 100644
--- a/front/core/components/drop-down/index.js
+++ b/front/core/components/drop-down/index.js
@@ -212,12 +212,12 @@ export default class DropDown extends Popover {
&& !this.model.isLoading;
if (shouldLoad)
- this.model.loadMore();
+ this.model.loadMore(true);
}
onLoadMoreClick(event) {
if (event.defaultPrevented) return;
- this.model.loadMore();
+ this.model.loadMore(true);
}
onContainerClick(event) {
diff --git a/front/core/components/model-proxy/model-proxy.js b/front/core/components/model-proxy/model-proxy.js
index 26c28c803..0b8d7ebf9 100644
--- a/front/core/components/model-proxy/model-proxy.js
+++ b/front/core/components/model-proxy/model-proxy.js
@@ -374,9 +374,10 @@ export class Paginable {
/**
* When limit is enabled, loads the next set of rows.
*
+ * @param {Boolean} append - Whether should append new data
* @return {Promise} The request promise
*/
- loadMore() {
- return Promise.resolve();
+ loadMore(append) {
+ return Promise.resolve(append);
}
}
diff --git a/front/core/components/pagination/pagination.js b/front/core/components/pagination/pagination.js
index 9979be368..e7127734c 100644
--- a/front/core/components/pagination/pagination.js
+++ b/front/core/components/pagination/pagination.js
@@ -73,7 +73,7 @@ class Pagination extends Component {
if (shouldLoad) {
this.nLoads++;
- this.model.loadMore();
+ this.model.loadMore(false);
this.$.$apply();
}
}
@@ -82,7 +82,7 @@ class Pagination extends Component {
if (this.maxLoads > 0 && this.nLoads == this.maxLoads)
this.nLoads = 0;
- this.model.loadMore();
+ this.model.loadMore(false);
}
$onDestroy() {
diff --git a/front/core/components/smart-table/index.js b/front/core/components/smart-table/index.js
index 8d2c3c153..770dcdf32 100644
--- a/front/core/components/smart-table/index.js
+++ b/front/core/components/smart-table/index.js
@@ -147,7 +147,7 @@ export default class SmartTable extends Component {
for (const column of this.columns) {
if (viewConfig.configuration[column.field] == false) {
const baseSelector = `smart-table[view-config-id="${this.viewConfigId}"] table`;
- selectors.push(`${baseSelector} thead > tr > th:nth-child(${column.index + 1})`);
+ selectors.push(`${baseSelector} thead > tr:not([second-header]) > th:nth-child(${column.index + 1})`);
selectors.push(`${baseSelector} tbody > tr > td:nth-child(${column.index + 1})`);
}
}
@@ -235,7 +235,7 @@ export default class SmartTable extends Component {
}
registerColumns() {
- const header = this.element.querySelector('thead > tr');
+ const header = this.element.querySelector('thead > tr:not([second-header])');
if (!header) return;
const columns = header.querySelectorAll('th');
@@ -254,7 +254,7 @@ export default class SmartTable extends Component {
}
emptyDataRows() {
- const header = this.element.querySelector('thead > tr');
+ const header = this.element.querySelector('thead > tr:not([second-header])');
const columns = header.querySelectorAll('th');
const tbody = this.element.querySelector('tbody');
if (tbody) {
@@ -333,7 +333,7 @@ export default class SmartTable extends Component {
}
displaySearch() {
- const header = this.element.querySelector('thead > tr');
+ const header = this.element.querySelector('thead > tr:not([second-header])');
if (!header) return;
const tbody = this.element.querySelector('tbody');
diff --git a/front/core/components/smart-table/table.scss b/front/core/components/smart-table/table.scss
index c38c149ca..996c41a74 100644
--- a/front/core/components/smart-table/table.scss
+++ b/front/core/components/smart-table/table.scss
@@ -8,6 +8,16 @@ smart-table table {
& > thead {
border-bottom: $border;
+ & > tr[second-header] {
+ & > th
+ {
+ text-align: center;
+ border-bottom-style: groove;
+ font-weight: bold;
+ text-transform: uppercase;
+ }
+ }
+
& > * > th {
font-weight: normal;
}
@@ -60,6 +70,9 @@ smart-table table {
vertical-align: middle;
}
}
+ &[separator]{
+ border-left-style: groove;
+ }
vn-icon.bright, i.bright {
color: #f7931e;
}
@@ -108,4 +121,4 @@ smart-table table {
font-size: 1.375rem;
text-align: center;
}
-}
\ No newline at end of file
+}
diff --git a/front/core/services/auth.js b/front/core/services/auth.js
index 04520cd0b..c15a34d94 100644
--- a/front/core/services/auth.js
+++ b/front/core/services/auth.js
@@ -24,7 +24,7 @@ export default class Auth {
initialize() {
let criteria = {
to: state => {
- const outLayout = ['login', 'recoverPassword', 'resetPassword'];
+ const outLayout = ['login', 'recover-password', 'reset-password'];
return !outLayout.some(ol => ol == state.name);
}
};
diff --git a/front/package-lock.json b/front/package-lock.json
index 6922cae53..256797df0 100644
--- a/front/package-lock.json
+++ b/front/package-lock.json
@@ -3,6 +3,13 @@
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
+<<<<<<< HEAD
+ "dependencies": {
+ "@uirouter/angularjs": {
+ "version": "1.0.29",
+ "resolved": "https://registry.npmjs.org/@uirouter/angularjs/-/angularjs-1.0.29.tgz",
+ "integrity": "sha512-RImWnBarNixkMto0o8stEaGwZmvhv5cnuOLXyMU2pY8MP2rgEF74ZNJTLeJCW14LR7XDUxVH8Mk8bPI6lxedmQ==",
+=======
"packages": {
"": {
"name": "salix-front",
@@ -174,11 +181,22 @@
"version": "1.0.30",
"resolved": "https://registry.npmjs.org/@uirouter/angularjs/-/angularjs-1.0.30.tgz",
"integrity": "sha512-qkc3RFZc91S5K0gc/QVAXc9LGDPXjR04vDgG/11j8+yyZEuQojXxKxdLhKIepiPzqLmGRVqzBmBc27gtqaEeZg==",
+>>>>>>> dev
"requires": {
"@uirouter/core": "6.0.8"
}
},
"@uirouter/core": {
+<<<<<<< HEAD
+ "version": "6.0.7",
+ "resolved": "https://registry.npmjs.org/@uirouter/core/-/core-6.0.7.tgz",
+ "integrity": "sha512-KUTJxL+6q0PiBnFx4/Z+Hsyg0pSGiaW5yZQeJmUxknecjpTbnXkLU8H2EqRn9N2B+qDRa7Jg8RcgeNDPY72O1w=="
+ },
+ "angular": {
+ "version": "1.8.2",
+ "resolved": "https://registry.npmjs.org/angular/-/angular-1.8.2.tgz",
+ "integrity": "sha512-IauMOej2xEe7/7Ennahkbb5qd/HFADiNuLSESz9Q27inmi32zB0lnAsFeLEWcox3Gd1F6YhNd1CP7/9IukJ0Gw=="
+=======
"version": "6.0.8",
"resolved": "https://registry.npmjs.org/@uirouter/core/-/core-6.0.8.tgz",
"integrity": "sha512-Gc/BAW47i4L54p8dqYCJJZuv2s3tqlXQ0fvl6Zp2xrblELPVfxmjnc0eurx3XwfQdaqm3T6uls6tQKkof/4QMw=="
@@ -187,6 +205,7 @@
"version": "1.8.3",
"resolved": "https://registry.npmjs.org/angular/-/angular-1.8.3.tgz",
"integrity": "sha512-5qjkWIQQVsHj4Sb5TcEs4WZWpFeVFHXwxEBHUhrny41D8UrBAd6T/6nPPAsLngJCReIOqi95W3mxdveveutpZw=="
+>>>>>>> dev
},
"angular-animate": {
"version": "1.8.2",
@@ -202,17 +221,29 @@
}
},
"angular-translate": {
+<<<<<<< HEAD
+ "version": "2.18.4",
+ "resolved": "https://registry.npmjs.org/angular-translate/-/angular-translate-2.18.4.tgz",
+ "integrity": "sha512-KohNrkH6J9PK+VW0L/nsRTcg5Fw70Ajwwe3Jbfm54Pf9u9Fd+wuingoKv+h45mKf38eT+Ouu51FPua8VmZNoCw==",
+=======
"version": "2.19.0",
"resolved": "https://registry.npmjs.org/angular-translate/-/angular-translate-2.19.0.tgz",
"integrity": "sha512-Z/Fip5uUT2N85dPQ0sMEe1JdF5AehcDe4tg/9mWXNDVU531emHCg53ZND9Oe0dyNiGX5rWcJKmsL1Fujus1vGQ==",
+>>>>>>> dev
"requires": {
"angular": "^1.8.0"
}
},
"angular-translate-loader-partial": {
+<<<<<<< HEAD
+ "version": "2.18.4",
+ "resolved": "https://registry.npmjs.org/angular-translate-loader-partial/-/angular-translate-loader-partial-2.18.4.tgz",
+ "integrity": "sha512-bsjR+FbB0sdA2528E/ugwKdlPPQhA1looxLxI3otayBTFXBpED33besfSZhYAISLgNMSL038vSssfRUen9qD8w==",
+=======
"version": "2.19.0",
"resolved": "https://registry.npmjs.org/angular-translate-loader-partial/-/angular-translate-loader-partial-2.19.0.tgz",
"integrity": "sha512-NnMw13LMV4bPQmJK7/pZOZAnPxe0M5OtUHchADs5Gye7V7feonuEnrZ8e1CKhBlv9a7IQyWoqcBa4Lnhg8gk5w==",
+>>>>>>> dev
"requires": {
"angular-translate": "~2.19.0"
}
@@ -253,9 +284,15 @@
}
},
"moment": {
+<<<<<<< HEAD
+ "version": "2.29.1",
+ "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
+ "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ=="
+=======
"version": "2.29.4",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
"integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w=="
+>>>>>>> dev
},
"oclazyload": {
"version": "0.6.3",
diff --git a/front/salix/components/app/app.html b/front/salix/components/app/app.html
index f14fab2dd..d6169308a 100644
--- a/front/salix/components/app/app.html
+++ b/front/salix/components/app/app.html
@@ -1,8 +1,3 @@
-
-
-
-
+
diff --git a/front/salix/components/app/app.js b/front/salix/components/app/app.js
index 20f0ad969..97384d1e1 100644
--- a/front/salix/components/app/app.js
+++ b/front/salix/components/app/app.js
@@ -19,12 +19,6 @@ export default class App extends Component {
this.vnApp.logger = this;
}
- get showLayout() {
- const state = this.$state.current.name || this.$location.$$path.substring(1).replace('/', '.');
- const outLayout = ['login', 'recoverPassword', 'resetPassword'];
- return state && !outLayout.some(ol => ol == state);
- }
-
$onDestroy() {
this.deregisterCallback();
this.vnApp.logger = null;
diff --git a/front/salix/components/index.js b/front/salix/components/index.js
index dbe9fe81a..f6727fadf 100644
--- a/front/salix/components/index.js
+++ b/front/salix/components/index.js
@@ -5,10 +5,10 @@ import './descriptor-popover';
import './home/home';
import './layout';
import './left-menu/left-menu';
-import './login/index';
-import './login/login';
-import './login/recover-password';
-import './login/reset-password';
+import './login';
+import './outLayout';
+import './recover-password';
+import './reset-password';
import './module-card';
import './module-main';
import './side-menu/side-menu';
@@ -19,3 +19,4 @@ import './user-popover';
import './upload-photo';
import './bank-entity';
import './log';
+import './sendSms';
diff --git a/front/salix/components/log/index.html b/front/salix/components/log/index.html
index 0a0449038..79dfcef8c 100644
--- a/front/salix/components/log/index.html
+++ b/front/salix/components/log/index.html
@@ -1,10 +1,12 @@
-
@@ -13,81 +15,53 @@
Date
- Author
- Model
- Action
- Name
- Before
- After
+ User
+ Model
+ Action
+ Name
+ Changes
{{::log.creationDate | date:'dd/MM/yyyy HH:mm'}}
-
-
- Changed by :
- {{::log.user.name || 'System' | translate}}
-
-
-
- Model :
- {{::log.changedModel | dashIfEmpty}}
-
-
- Action :
- {{::$ctrl.actionsText[log.action] | dashIfEmpty}}
-
-
- Name :
- {{::log.changedModelValue | dashIfEmpty}}
-
-
-
+
{{::log.user.name || 'System' | translate}}
-
+
{{::log.changedModel}}
-
+
{{::$ctrl.actionsText[log.action]}}
-
+
{{::log.changedModelValue}}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{::log.description}}
-
-
+
+
+
+
+ Field
+ Before
+ After
+
+
+
+
+ {{prop.name}}
+ {{prop.old}}
+ {{prop.new}}
+
+
+
+
+ {{::log.description}}
+
@@ -96,4 +70,4 @@
-
\ No newline at end of file
+
diff --git a/front/salix/components/log/index.js b/front/salix/components/log/index.js
index f30878b9f..1c54aa9b8 100644
--- a/front/salix/components/log/index.js
+++ b/front/salix/components/log/index.js
@@ -2,15 +2,17 @@ import ngModule from '../../module';
import Section from '../section';
import './style.scss';
+const validDate = /^(-?(?:[1-9][0-9]*)?[0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(.[0-9]+)?(Z)?$/;
+
export default class Controller extends Section {
constructor($element, $) {
super($element, $);
this.actionsText = {
- 'insert': 'Creates',
- 'update': 'Updates',
- 'delete': 'Deletes',
- 'select': 'Views'
- }; ``;
+ insert: 'Creates',
+ update: 'Updates',
+ delete: 'Deletes',
+ select: 'Views'
+ };
this.filter = {
include: [{
relation: 'user',
@@ -33,32 +35,57 @@ export default class Controller extends Section {
set logs(value) {
this._logs = value;
- if (!value) return;
-
+ if (!this.logs) return;
+ const empty = {};
const validations = window.validations;
- value.forEach(log => {
- const locale = validations[log.changedModel] && validations[log.changedModel].locale ? validations[log.changedModel].locale : {};
+ for (const log of value) {
+ const oldValues = log.oldInstance || empty;
+ const newValues = log.newInstance || empty;
+ const locale = validations[log.changedModel]?.locale || empty;
- log.oldProperties = this.getInstance(log.oldInstance, locale);
- log.newProperties = this.getInstance(log.newInstance, locale);
- });
+ let props = Object.keys(oldValues).concat(Object.keys(newValues));
+ props = [...new Set(props)];
+
+ log.props = [];
+ for (const prop of props) {
+ log.props.push({
+ name: locale[prop] || prop,
+ old: this.formatValue(oldValues[prop]),
+ new: this.formatValue(newValues[prop])
+ });
+ }
+ }
}
- getInstance(instance, locale) {
- const properties = [];
- let validDate = /^(-?(?:[1-9][0-9]*)?[0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(.[0-9]+)?(Z)?$/;
+ get showModelName() {
+ return !(this.changedModel && this.changedModelId);
+ }
- if (typeof instance == 'object' && instance != null) {
- Object.keys(instance).forEach(property => {
- if (validDate.test(instance[property]))
- instance[property] = new Date(instance[property]).toLocaleString('es-ES');
+ formatValue(value) {
+ let type = typeof value;
- const key = locale[property] || property;
- properties.push({key, value: instance[property]});
- });
- return properties;
+ if (type === 'string' && validDate.test(value)) {
+ value = new Date(value);
+ type = typeof value;
+ }
+
+ switch (type) {
+ case 'boolean':
+ return value ? '✓' : '✗';
+ case 'object':
+ if (value instanceof Date) {
+ const hasZeroTime =
+ value.getHours() === 0 &&
+ value.getMinutes() === 0 &&
+ value.getSeconds() === 0;
+ const format = hasZeroTime ? 'dd/MM/yyyy' : 'dd/MM/yyyy HH:mm:ss';
+ return this.$filter('date')(value, format);
+ }
+ else
+ return value;
+ default:
+ return value;
}
- return null;
}
showWorkerDescriptor(event, workerId) {
@@ -73,6 +100,8 @@ ngModule.vnComponent('vnLog', {
bindings: {
model: '<',
originId: '<',
+ changedModel: '',
+ changedModelId: '',
url: '@'
}
});
diff --git a/front/salix/components/log/locale/es.yml b/front/salix/components/log/locale/es.yml
index f483bea5e..d341095d8 100644
--- a/front/salix/components/log/locale/es.yml
+++ b/front/salix/components/log/locale/es.yml
@@ -11,4 +11,5 @@ Updates: Actualiza
Deletes: Elimina
Views: Visualiza
System: Sistema
-note: nota
\ No newline at end of file
+note: nota
+Changes: Cambios
diff --git a/front/salix/components/log/style.scss b/front/salix/components/log/style.scss
index ca1de113a..bc943996d 100644
--- a/front/salix/components/log/style.scss
+++ b/front/salix/components/log/style.scss
@@ -23,6 +23,28 @@ vn-log {
display: block;
}
}
+ .attributes {
+ width: 100%;
+
+ tr {
+ height: 10px;
+
+ & > td {
+ padding: 2px;
+ }
+ & > td.field,
+ & > th.field {
+ width: 20%;
+ color: gray;
+ }
+ & > td.before,
+ & > th.before,
+ & > td.after,
+ & > th.after {
+ width: 40%;
+ }
+ }
+ }
}
.ellipsis {
white-space: nowrap;
@@ -40,4 +62,4 @@ vn-log {
.alignSpan {
overflow: hidden;
display: inline-block;
-}
\ No newline at end of file
+}
diff --git a/front/salix/components/login/index.html b/front/salix/components/login/index.html
index 186979f8c..963c23061 100644
--- a/front/salix/components/login/index.html
+++ b/front/salix/components/login/index.html
@@ -1,6 +1,27 @@
-
-
-
+
+
+
+
+
+
+
diff --git a/front/salix/components/login/index.js b/front/salix/components/login/index.js
index f0e21fa29..150e896a1 100644
--- a/front/salix/components/login/index.js
+++ b/front/salix/components/login/index.js
@@ -1,16 +1,43 @@
import ngModule from '../../module';
-import Component from 'core/lib/component';
import './style.scss';
-export default class OutLayout extends Component {
- constructor($element, $scope) {
- super($element, $scope);
+/**
+ * A simple login form.
+ */
+export default class Controller {
+ constructor($, $element, vnAuth) {
+ Object.assign(this, {
+ $,
+ $element,
+ vnAuth,
+ user: localStorage.getItem('lastUser'),
+ remember: true
+ });
+ }
+
+ submit() {
+ this.loading = true;
+ this.vnAuth.login(this.user, this.password, this.remember)
+ .then(() => {
+ localStorage.setItem('lastUser', this.user);
+ this.loading = false;
+ })
+ .catch(err => {
+ this.loading = false;
+ this.password = '';
+ this.focusUser();
+ throw err;
+ });
+ }
+
+ focusUser() {
+ this.$.userField.select();
+ this.$.userField.focus();
}
}
+Controller.$inject = ['$scope', '$element', 'vnAuth'];
-OutLayout.$inject = ['$element', '$scope'];
-
-ngModule.vnComponent('vnOutLayout', {
+ngModule.vnComponent('vnLogin', {
template: require('./index.html'),
- controller: OutLayout
+ controller: Controller
});
diff --git a/front/salix/components/login/locale/es.yml b/front/salix/components/login/locale/es.yml
index e3a5815c1..c34861bfb 100644
--- a/front/salix/components/login/locale/es.yml
+++ b/front/salix/components/login/locale/es.yml
@@ -1,16 +1,5 @@
User: Usuario
Password: Contraseña
-Email: Correo electrónico
Do not close session: No cerrar sesión
Enter: Entrar
I do not remember my password: No recuerdo mi contraseña
-Recover password: Recuperar contraseña
-We will sent you an email to recover your password: Te enviaremos un correo para restablecer tu contraseña
-Notification sent!: ¡Notificación enviada!
-Reset password: Restrablecer contraseña
-New password: Nueva contraseña
-Repeat password: Repetir contraseña
-Password requirements: >
- La contraseña debe tener al menos {{ length }} caracteres de longitud,
- {{nAlpha}} caracteres alfabéticos, {{nUpper}} letras mayúsculas, {{nDigits}}
- dígitos y {{nPunct}} símbolos (Ej: $%&.)
diff --git a/front/salix/components/login/login.html b/front/salix/components/login/login.html
deleted file mode 100644
index a078fa0af..000000000
--- a/front/salix/components/login/login.html
+++ /dev/null
@@ -1,27 +0,0 @@
-
-
-
-
-
-
-
diff --git a/front/salix/components/login/login.js b/front/salix/components/login/login.js
deleted file mode 100644
index b5f8c1e7d..000000000
--- a/front/salix/components/login/login.js
+++ /dev/null
@@ -1,43 +0,0 @@
-import ngModule from '../../module';
-import './style.scss';
-
-/**
- * A simple login form.
- */
-export default class Controller {
- constructor($, $element, vnAuth) {
- Object.assign(this, {
- $,
- $element,
- vnAuth,
- user: localStorage.getItem('lastUser'),
- remember: true
- });
- }
-
- submit() {
- this.loading = true;
- this.vnAuth.login(this.user, this.password, this.remember)
- .then(() => {
- localStorage.setItem('lastUser', this.user);
- this.loading = false;
- })
- .catch(err => {
- this.loading = false;
- this.password = '';
- this.focusUser();
- throw err;
- });
- }
-
- focusUser() {
- this.$.userField.select();
- this.$.userField.focus();
- }
-}
-Controller.$inject = ['$scope', '$element', 'vnAuth'];
-
-ngModule.vnComponent('vnLogin', {
- template: require('./login.html'),
- controller: Controller
-});
diff --git a/front/salix/components/login/style.scss b/front/salix/components/login/style.scss
index 8985893f2..f13c9cf86 100644
--- a/front/salix/components/login/style.scss
+++ b/front/salix/components/login/style.scss
@@ -1,8 +1,6 @@
@import "variables";
-vn-login,
-vn-reset-password,
-vn-recover-password{
+vn-login{
.footer {
margin-top: 32px;
text-align: center;
@@ -24,69 +22,3 @@ vn-recover-password{
}
}
}
-
-vn-out-layout{
- position: absolute;
- height: 100%;
- width: 100%;
- margin: 0;
- padding: 0;
- color: $color-font;
- font-size: 1.1rem;
- font-weight: normal;
- background-color: $color-bg-dark;
- display: flex;
- justify-content: center;
- align-items: center;
- overflow: auto;
-
- & > .box {
- box-sizing: border-box;
- position: absolute;
- max-width: 304px;
- min-width: 240px;
- padding: 48px;
- background-color: $color-bg-panel;
- box-shadow: 0 0 16px 0 rgba(0, 0, 0, .6);
- border-radius: 8px;
-
- & > img {
- width: 100%;
- padding-bottom: 16px;
- }
- & > form {
- & > .vn-textfield {
- width: 100%;
- }
- & > .vn-check {
- display: block;
- .md-label {
- white-space: inherit;
- }
- }
- }
-
- h5{
- color: $color-primary;
- }
-
- .text-secondary{
- text-align: center;
- padding-bottom: 16px;
- }
-
- }
-
- @media screen and (max-width: 600px) {
- background-color: $color-bg-panel;
-
- & > .box {
- padding: 16px;
- box-shadow: none;
- }
- }
-
- a{
- color: $color-primary;
- }
-}
diff --git a/front/salix/components/outLayout/index.html b/front/salix/components/outLayout/index.html
new file mode 100644
index 000000000..186979f8c
--- /dev/null
+++ b/front/salix/components/outLayout/index.html
@@ -0,0 +1,6 @@
+
+
+
+
diff --git a/front/salix/components/outLayout/index.js b/front/salix/components/outLayout/index.js
new file mode 100644
index 000000000..f0e21fa29
--- /dev/null
+++ b/front/salix/components/outLayout/index.js
@@ -0,0 +1,16 @@
+import ngModule from '../../module';
+import Component from 'core/lib/component';
+import './style.scss';
+
+export default class OutLayout extends Component {
+ constructor($element, $scope) {
+ super($element, $scope);
+ }
+}
+
+OutLayout.$inject = ['$element', '$scope'];
+
+ngModule.vnComponent('vnOutLayout', {
+ template: require('./index.html'),
+ controller: OutLayout
+});
diff --git a/front/salix/components/login/logo.svg b/front/salix/components/outLayout/logo.svg
similarity index 100%
rename from front/salix/components/login/logo.svg
rename to front/salix/components/outLayout/logo.svg
diff --git a/front/salix/components/outLayout/style.scss b/front/salix/components/outLayout/style.scss
new file mode 100644
index 000000000..aa94fefb3
--- /dev/null
+++ b/front/salix/components/outLayout/style.scss
@@ -0,0 +1,67 @@
+@import "variables";
+
+vn-out-layout{
+ position: absolute;
+ height: 100%;
+ width: 100%;
+ margin: 0;
+ padding: 0;
+ color: $color-font;
+ font-size: 1.1rem;
+ font-weight: normal;
+ background-color: $color-bg-dark;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ overflow: auto;
+
+ & > .box {
+ box-sizing: border-box;
+ position: absolute;
+ max-width: 304px;
+ min-width: 240px;
+ padding: 48px;
+ background-color: $color-bg-panel;
+ box-shadow: 0 0 16px 0 rgba(0, 0, 0, .6);
+ border-radius: 8px;
+
+ & > img {
+ width: 100%;
+ padding-bottom: 16px;
+ }
+ & > form {
+ & > .vn-textfield {
+ width: 100%;
+ }
+ & > .vn-check {
+ display: block;
+ .md-label {
+ white-space: inherit;
+ }
+ }
+ }
+
+ h5{
+ color: $color-primary;
+ }
+
+ .text-secondary{
+ text-align: center;
+ padding-bottom: 16px;
+ }
+
+ }
+
+ @media screen and (max-width: 600px) {
+ background-color: $color-bg-panel;
+
+ & > .box {
+ padding: 16px;
+ box-shadow: none;
+ }
+ }
+
+ a{
+ color: $color-primary;
+ }
+}
diff --git a/front/salix/components/login/recover-password.html b/front/salix/components/recover-password/index.html
similarity index 100%
rename from front/salix/components/login/recover-password.html
rename to front/salix/components/recover-password/index.html
diff --git a/front/salix/components/login/recover-password.js b/front/salix/components/recover-password/index.js
similarity index 94%
rename from front/salix/components/login/recover-password.js
rename to front/salix/components/recover-password/index.js
index fa9bfc459..3de7f3266 100644
--- a/front/salix/components/login/recover-password.js
+++ b/front/salix/components/recover-password/index.js
@@ -32,6 +32,6 @@ export default class Controller {
Controller.$inject = ['$scope', '$element', '$http', 'vnApp', '$translate', '$state'];
ngModule.vnComponent('vnRecoverPassword', {
- template: require('./recover-password.html'),
+ template: require('./index.html'),
controller: Controller
});
diff --git a/front/salix/components/recover-password/locale/es.yml b/front/salix/components/recover-password/locale/es.yml
new file mode 100644
index 000000000..b71c71415
--- /dev/null
+++ b/front/salix/components/recover-password/locale/es.yml
@@ -0,0 +1,3 @@
+Recover password: Recuperar contraseña
+We will sent you an email to recover your password: Te enviaremos un correo para restablecer tu contraseña
+Notification sent!: ¡Notificación enviada!
diff --git a/front/salix/components/recover-password/style.scss b/front/salix/components/recover-password/style.scss
new file mode 100644
index 000000000..d3c6f594e
--- /dev/null
+++ b/front/salix/components/recover-password/style.scss
@@ -0,0 +1,24 @@
+@import "variables";
+
+vn-recover-password{
+ .footer {
+ margin-top: 32px;
+ text-align: center;
+ position: relative;
+ & > .vn-submit {
+ display: block;
+
+ & > input {
+ display: block;
+ width: 100%;
+ }
+ }
+ & > .spinner-wrapper {
+ position: absolute;
+ width: 0;
+ top: 3px;
+ right: -8px;
+ overflow: visible;
+ }
+ }
+}
diff --git a/front/salix/components/login/reset-password.html b/front/salix/components/reset-password/index.html
similarity index 100%
rename from front/salix/components/login/reset-password.html
rename to front/salix/components/reset-password/index.html
diff --git a/front/salix/components/login/reset-password.js b/front/salix/components/reset-password/index.js
similarity index 96%
rename from front/salix/components/login/reset-password.js
rename to front/salix/components/reset-password/index.js
index 9ee1fdb62..20c6c34fe 100644
--- a/front/salix/components/login/reset-password.js
+++ b/front/salix/components/reset-password/index.js
@@ -43,6 +43,6 @@ export default class Controller {
Controller.$inject = ['$scope', '$element', '$http', 'vnApp', '$translate', '$state', '$location'];
ngModule.vnComponent('vnResetPassword', {
- template: require('./reset-password.html'),
+ template: require('./index.html'),
controller: Controller
});
diff --git a/front/salix/components/login/locale/en.yml b/front/salix/components/reset-password/locale/en.yml
similarity index 71%
rename from front/salix/components/login/locale/en.yml
rename to front/salix/components/reset-password/locale/en.yml
index 1ddd454b7..e5419e1c8 100644
--- a/front/salix/components/login/locale/en.yml
+++ b/front/salix/components/reset-password/locale/en.yml
@@ -1,7 +1,3 @@
-User: User
-Password: Password
-Do not close session: Do not close session
-Enter: Enter
Password requirements: >
The password must have at least {{ length }} length characters,
{{nAlpha}} alphabetic characters, {{nUpper}} capital letters, {{nDigits}}
diff --git a/front/salix/components/reset-password/locale/es.yml b/front/salix/components/reset-password/locale/es.yml
new file mode 100644
index 000000000..0771d5dc3
--- /dev/null
+++ b/front/salix/components/reset-password/locale/es.yml
@@ -0,0 +1,8 @@
+Reset password: Restrablecer contraseña
+New password: Nueva contraseña
+Repeat password: Repetir contraseñaç
+Password changed!: ¡Contraseña cambiada!
+Password requirements: >
+ La contraseña debe tener al menos {{ length }} caracteres de longitud,
+ {{nAlpha}} caracteres alfabéticos, {{nUpper}} letras mayúsculas, {{nDigits}}
+ dígitos y {{nPunct}} símbolos (Ej: $%&.)
diff --git a/front/salix/components/reset-password/style.scss b/front/salix/components/reset-password/style.scss
new file mode 100644
index 000000000..87e4adc8c
--- /dev/null
+++ b/front/salix/components/reset-password/style.scss
@@ -0,0 +1,24 @@
+@import "variables";
+
+vn-reset-password{
+ .footer {
+ margin-top: 32px;
+ text-align: center;
+ position: relative;
+ & > .vn-submit {
+ display: block;
+
+ & > input {
+ display: block;
+ width: 100%;
+ }
+ }
+ & > .spinner-wrapper {
+ position: absolute;
+ width: 0;
+ top: 3px;
+ right: -8px;
+ overflow: visible;
+ }
+ }
+}
diff --git a/modules/client/front/sms/index.html b/front/salix/components/sendSms/index.html
similarity index 100%
rename from modules/client/front/sms/index.html
rename to front/salix/components/sendSms/index.html
diff --git a/modules/ticket/front/sms/index.js b/front/salix/components/sendSms/index.js
similarity index 52%
rename from modules/ticket/front/sms/index.js
rename to front/salix/components/sendSms/index.js
index 6bc252dc1..0947550b0 100644
--- a/modules/ticket/front/sms/index.js
+++ b/front/salix/components/sendSms/index.js
@@ -1,19 +1,26 @@
-import ngModule from '../module';
-import Component from 'core/lib/component';
+import ngModule from '../../module';
import './style.scss';
+import Dialog from '../../../core/components/dialog';
+
+export default class sendSmsDialog extends Dialog {
+ constructor($element, $scope, $http, $translate, vnApp) {
+ super($element, $scope, $http, $translate, vnApp);
+
+ new CustomEvent('openSmsDialog', {
+ detail: {
+ this: this
+ }
+ });
+ }
-class Controller extends Component {
open() {
this.$.SMSDialog.show();
}
charactersRemaining() {
- const element = this.$.message;
- const value = element.input.value;
-
+ const element = this.sms.message;
const maxLength = 160;
- const textAreaLength = new Blob([value]).size;
- return maxLength - textAreaLength;
+ return maxLength - element.length;
}
onResponse() {
@@ -25,23 +32,19 @@ class Controller extends Component {
if (this.charactersRemaining() < 0)
throw new Error(`The message it's too long`);
- this.$http.post(`Tickets/${this.sms.ticketId}/sendSms`, this.sms).then(res => {
- this.vnApp.showMessage(this.$t('SMS sent!'));
-
- if (res.data) this.emit('send', {response: res.data});
- });
+ return this.onSend({$sms: this.sms});
} catch (e) {
this.vnApp.showError(this.$t(e.message));
return false;
}
- return true;
}
}
-ngModule.vnComponent('vnTicketSms', {
+ngModule.vnComponent('vnSmsDialog', {
template: require('./index.html'),
- controller: Controller,
+ controller: sendSmsDialog,
bindings: {
sms: '<',
+ onSend: '&',
}
});
diff --git a/modules/client/front/sms/locale/es.yml b/front/salix/components/sendSms/locale/es.yml
similarity index 100%
rename from modules/client/front/sms/locale/es.yml
rename to front/salix/components/sendSms/locale/es.yml
diff --git a/modules/client/front/sms/style.scss b/front/salix/components/sendSms/style.scss
similarity index 100%
rename from modules/client/front/sms/style.scss
rename to front/salix/components/sendSms/style.scss
diff --git a/front/salix/routes.js b/front/salix/routes.js
index be893800f..f32c143ef 100644
--- a/front/salix/routes.js
+++ b/front/salix/routes.js
@@ -3,25 +3,38 @@ import getMainRoute from 'core/lib/get-main-route';
config.$inject = ['$stateProvider', '$urlRouterProvider'];
function config($stateProvider, $urlRouterProvider) {
- $urlRouterProvider.otherwise('/');
+ $urlRouterProvider
+ .otherwise('/');
$stateProvider
+ .state('layout', {
+ abstract: true,
+ template: '
',
+ })
+ .state('outLayout', {
+ abstract: true,
+ template: '
',
+ })
.state('login', {
+ parent: 'outLayout',
url: '/login?continue',
description: 'Login',
template: '
'
})
- .state('recoverPassword', {
+ .state('recover-password', {
+ parent: 'outLayout',
url: '/recover-password',
- description: 'Recover-password',
- template: '
asd '
+ description: 'Recover password',
+ template: '
'
})
- .state('resetPassword', {
+ .state('reset-password', {
+ parent: 'outLayout',
url: '/reset-password',
- description: 'Reset-password',
+ description: 'Reset password',
template: '
'
})
.state('home', {
+ parent: 'layout',
url: '/',
description: 'Home',
template: '
'
@@ -52,6 +65,10 @@ function config($stateProvider, $urlRouterProvider) {
};
if (route.abstract)
configRoute.abstract = true;
+
+ if (!route.state.includes('.'))
+ configRoute.parent = 'layout';
+
if (route.routeParams)
configRoute.params = route.routeParams;
diff --git a/loopback/locale/en.json b/loopback/locale/en.json
index d4695f72c..a406b55a5 100644
--- a/loopback/locale/en.json
+++ b/loopback/locale/en.json
@@ -66,9 +66,10 @@
"MESSAGE_INSURANCE_CHANGE": "I have changed the insurence credit of client [{{clientName}} ({{clientId}})]({{{url}}}) to *{{credit}} €*",
"Changed client paymethod": "I have changed the pay method for client [{{clientName}} ({{clientId}})]({{{url}}})",
"Sent units from ticket": "I sent *{{quantity}}* units of [{{concept}} ({{itemId}})]({{{itemUrl}}}) to *\"{{nickname}}\"* coming from ticket id [{{ticketId}}]({{{ticketUrl}}})",
- "Claim will be picked": "The product from the claim [{{claimId}}]({{{claimUrl}}}) from the client *{{clientName}}* will be picked",
- "Claim state has changed to incomplete": "The state of the claim [{{claimId}}]({{{claimUrl}}}) from client *{{clientName}}* has changed to *incomplete*",
- "Claim state has changed to canceled": "The state of the claim [{{claimId}}]({{{claimUrl}}}) from client *{{clientName}}* has changed to *canceled*",
+ "Change quantity": "{{concept}} change of {{oldQuantity}} to {{newQuantity}}",
+ "Claim will be picked": "The product from the claim [({{claimId}})]({{{claimUrl}}}) from the client *{{clientName}}* will be picked",
+ "Claim state has changed to incomplete": "The state of the claim [({{claimId}})]({{{claimUrl}}}) from client *{{clientName}}* has changed to *incomplete*",
+ "Claim state has changed to canceled": "The state of the claim [({{claimId}})]({{{claimUrl}}}) from client *{{clientName}}* has changed to *canceled*",
"Customs agent is required for a non UEE member": "Customs agent is required for a non UEE member",
"Incoterms is required for a non UEE member": "Incoterms is required for a non UEE member",
"Client checked as validated despite of duplication": "Client checked as validated despite of duplication from client id {{clientId}}",
@@ -140,8 +141,10 @@
"You don't have grant privilege": "You don't have grant privilege",
"You don't own the role and you can't assign it to another user": "You don't own the role and you can't assign it to another user",
"Email verify": "Email verify",
- "Ticket merged": "Ticket [{{id}}]({{{fullPath}}}) ({{{originDated}}}) merged with [{{tfId}}]({{{fullPathFuture}}}) ({{{futureDated}}})",
+ "Ticket merged": "Ticket [{{originId}}]({{{originFullPath}}}) ({{{originDated}}}) merged with [{{destinationId}}]({{{destinationFullPath}}}) ({{{destinationDated}}})",
"Sale(s) blocked, please contact production": "Sale(s) blocked, please contact production",
+ "App locked": "App locked by user {{userId}}",
+ "The sales of the receiver ticket can't be modified": "The sales of the receiver ticket can't be modified",
"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"
diff --git a/loopback/locale/es.json b/loopback/locale/es.json
index 1b0a50433..ea83b36c4 100644
--- a/loopback/locale/es.json
+++ b/loopback/locale/es.json
@@ -134,9 +134,10 @@
"MESSAGE_INSURANCE_CHANGE": "He cambiado el crédito asegurado del cliente [{{clientName}} ({{clientId}})]({{{url}}}) a *{{credit}} €*",
"Changed client paymethod": "He cambiado la forma de pago del cliente [{{clientName}} ({{clientId}})]({{{url}}})",
"Sent units from ticket": "Envio *{{quantity}}* unidades de [{{concept}} ({{itemId}})]({{{itemUrl}}}) a *\"{{nickname}}\"* provenientes del ticket id [{{ticketId}}]({{{ticketUrl}}})",
- "Claim will be picked": "Se recogerá el género de la reclamación [{{claimId}}]({{{claimUrl}}}) del cliente *{{clientName}}*",
- "Claim state has changed to incomplete": "Se ha cambiado el estado de la reclamación [{{claimId}}]({{{claimUrl}}}) del cliente *{{clientName}}* a *incompleta*",
- "Claim state has changed to canceled": "Se ha cambiado el estado de la reclamación [{{claimId}}]({{{claimUrl}}}) del cliente *{{clientName}}* a *anulado*",
+ "Change quantity": "{{concept}} cambia de {{oldQuantity}} a {{newQuantity}}",
+ "Claim will be picked": "Se recogerá el género de la reclamación [({{claimId}})]({{{claimUrl}}}) del cliente *{{clientName}}*",
+ "Claim state has changed to incomplete": "Se ha cambiado el estado de la reclamación [({{claimId}})]({{{claimUrl}}}) del cliente *{{clientName}}* a *incompleta*",
+ "Claim state has changed to canceled": "Se ha cambiado el estado de la reclamación [({{claimId}})]({{{claimUrl}}}) del cliente *{{clientName}}* a *anulado*",
"Client checked as validated despite of duplication": "Cliente comprobado a pesar de que existe el cliente id {{clientId}}",
"ORDER_ROW_UNAVAILABLE": "No hay disponibilidad de este producto",
"Distance must be lesser than 1000": "La distancia debe ser inferior a 1000",
@@ -241,13 +242,15 @@
"Claim pickup order sent": "Reclamación Orden de recogida enviada [{{claimId}}]({{{claimUrl}}}) al cliente *{{clientName}}*",
"You don't have grant privilege": "No tienes privilegios para dar privilegios",
"You don't own the role and you can't assign it to another user": "No eres el propietario del rol y no puedes asignarlo a otro usuario",
- "Ticket merged": "Ticket [{{id}}]({{{fullPath}}}) ({{{originDated}}}) fusionado con [{{tfId}}]({{{fullPathFuture}}}) ({{{futureDated}}})",
+ "Ticket merged": "Ticket [{{originId}}]({{{originFullPath}}}) ({{{originDated}}}) fusionado con [{{destinationId}}]({{{destinationFullPath}}}) ({{{destinationDated}}})",
"Already has this status": "Ya tiene este estado",
"There aren't records for this week": "No existen registros para esta semana",
"Empty data source": "Origen de datos vacio",
+ "App locked": "Aplicación bloqueada por el usuario {{userId}}",
"Email verify": "Correo de verificación",
"Landing cannot be lesser than shipment": "Landing cannot be lesser than shipment",
- "Receipt's bank was not found": "No se encontró el banco del recibo",
- "This receipt was not compensated": "Este recibo no ha sido compensado",
- "Client's email was not found": "No se encontró el email del cliente"
-}
+ "Receipt's bank was not found": "No se encontró el banco del recibo",
+ "This receipt was not compensated": "Este recibo no ha sido compensado",
+ "Client's email was not found": "No se encontró el email del cliente",
+ "Aplicación bloqueada por el usuario 9": "Aplicación bloqueada por el usuario 9"
+}
\ No newline at end of file
diff --git a/modules/client/back/model-config.json b/modules/client/back/model-config.json
index 4ef34ca3a..b466aa5a1 100644
--- a/modules/client/back/model-config.json
+++ b/modules/client/back/model-config.json
@@ -104,6 +104,9 @@
"SageTransactionType": {
"dataSource": "vn"
},
+ "TicketSms": {
+ "dataSource": "vn"
+ },
"TpvError": {
"dataSource": "vn"
},
diff --git a/modules/client/back/models/ticket-sms.json b/modules/client/back/models/ticket-sms.json
new file mode 100644
index 000000000..03f592f51
--- /dev/null
+++ b/modules/client/back/models/ticket-sms.json
@@ -0,0 +1,28 @@
+{
+ "name": "TicketSms",
+ "base": "VnModel",
+ "options": {
+ "mysql": {
+ "table": "ticketSms"
+ }
+ },
+ "properties": {
+ "smsFk": {
+ "type": "number",
+ "id": true,
+ "description": "Identifier"
+ }
+ },
+ "relations": {
+ "ticket": {
+ "type": "belongsTo",
+ "model": "Ticket",
+ "foreignKey": "ticketFk"
+ },
+ "sms": {
+ "type": "belongsTo",
+ "model": "Sms",
+ "foreignKey": "smsFk"
+ }
+ }
+}
diff --git a/modules/client/front/descriptor/index.html b/modules/client/front/descriptor/index.html
index cad226416..ef5c2997f 100644
--- a/modules/client/front/descriptor/index.html
+++ b/modules/client/front/descriptor/index.html
@@ -113,10 +113,11 @@
-
-
+
diff --git a/modules/client/front/descriptor/index.js b/modules/client/front/descriptor/index.js
index 4a0d1cd2a..4d8d70edf 100644
--- a/modules/client/front/descriptor/index.js
+++ b/modules/client/front/descriptor/index.js
@@ -39,6 +39,11 @@ class Controller extends Descriptor {
};
this.$.sms.open();
}
+
+ onSmsSend(sms) {
+ return this.$http.post(`Clients/${this.id}/sendSms`, sms)
+ .then(() => this.vnApp.showSuccess(this.$t('SMS sent')));
+ }
}
ngModule.vnComponent('vnClientDescriptor', {
diff --git a/modules/client/front/index.js b/modules/client/front/index.js
index a5782c789..ff767bc9e 100644
--- a/modules/client/front/index.js
+++ b/modules/client/front/index.js
@@ -35,7 +35,6 @@ import './sample/index';
import './sample/create';
import './web-payment';
import './log';
-import './sms';
import './postcode';
import './postcode/province';
import './postcode/city';
diff --git a/modules/client/front/sms/index.js b/modules/client/front/sms/index.js
deleted file mode 100644
index 701ee39af..000000000
--- a/modules/client/front/sms/index.js
+++ /dev/null
@@ -1,49 +0,0 @@
-import ngModule from '../module';
-import Section from 'salix/components/section';
-import './style.scss';
-
-class Controller extends Section {
- open() {
- this.$.SMSDialog.show();
- }
-
- charactersRemaining() {
- const element = this.$.message;
- const value = element.input.value;
-
- const maxLength = 160;
- const textAreaLength = new Blob([value]).size;
- return maxLength - textAreaLength;
- }
-
- onResponse() {
- try {
- if (!this.sms.destination)
- throw new Error(`The destination can't be empty`);
- if (!this.sms.message)
- throw new Error(`The message can't be empty`);
- if (this.charactersRemaining() < 0)
- throw new Error(`The message it's too long`);
-
- this.$http.post(`Clients/${this.$params.id}/sendSms`, this.sms).then(res => {
- this.vnApp.showMessage(this.$t('SMS sent!'));
-
- if (res.data) this.emit('send', {response: res.data});
- });
- } catch (e) {
- this.vnApp.showError(this.$t(e.message));
- return false;
- }
- return true;
- }
-}
-
-Controller.$inject = ['$element', '$scope', '$http', '$translate', 'vnApp'];
-
-ngModule.vnComponent('vnClientSms', {
- template: require('./index.html'),
- controller: Controller,
- bindings: {
- sms: '<',
- }
-});
diff --git a/modules/client/front/sms/index.spec.js b/modules/client/front/sms/index.spec.js
deleted file mode 100644
index 793c80d6e..000000000
--- a/modules/client/front/sms/index.spec.js
+++ /dev/null
@@ -1,74 +0,0 @@
-import './index';
-
-describe('Client', () => {
- describe('Component vnClientSms', () => {
- let controller;
- let $httpBackend;
- let $element;
-
- beforeEach(ngModule('client'));
-
- beforeEach(inject(($componentController, $rootScope, _$httpBackend_) => {
- $httpBackend = _$httpBackend_;
- let $scope = $rootScope.$new();
- $element = angular.element(' ');
- controller = $componentController('vnClientSms', {$element, $scope});
- controller.client = {id: 1101};
- controller.$params = {id: 1101};
- controller.$.message = {
- input: {
- value: 'My SMS'
- }
- };
- }));
-
- describe('onResponse()', () => {
- it('should perform a POST query and show a success snackbar', () => {
- let params = {destinationFk: 1101, destination: 111111111, message: 'My SMS'};
- controller.sms = {destinationFk: 1101, destination: 111111111, message: 'My SMS'};
-
- jest.spyOn(controller.vnApp, 'showMessage');
- $httpBackend.expect('POST', `Clients/1101/sendSms`, params).respond(200, params);
-
- controller.onResponse();
- $httpBackend.flush();
-
- expect(controller.vnApp.showMessage).toHaveBeenCalledWith('SMS sent!');
- });
-
- it('should call onResponse without the destination and show an error snackbar', () => {
- controller.sms = {destinationFk: 1101, message: 'My SMS'};
-
- jest.spyOn(controller.vnApp, 'showError');
-
- controller.onResponse('accept');
-
- expect(controller.vnApp.showError).toHaveBeenCalledWith(`The destination can't be empty`);
- });
-
- it('should call onResponse without the message and show an error snackbar', () => {
- controller.sms = {destinationFk: 1101, destination: 222222222};
-
- jest.spyOn(controller.vnApp, 'showError');
-
- controller.onResponse('accept');
-
- expect(controller.vnApp.showError).toHaveBeenCalledWith(`The message can't be empty`);
- });
- });
-
- describe('charactersRemaining()', () => {
- it('should return the characters remaining in a element', () => {
- controller.$.message = {
- input: {
- value: 'My message 0€'
- }
- };
-
- let result = controller.charactersRemaining();
-
- expect(result).toEqual(145);
- });
- });
- });
-});
diff --git a/modules/entry/front/buy/index/index.js b/modules/entry/front/buy/index/index.js
index 6d9ee5760..322b81d4e 100644
--- a/modules/entry/front/buy/index/index.js
+++ b/modules/entry/front/buy/index/index.js
@@ -73,6 +73,12 @@ export default class Controller extends Section {
this.vnApp.showSuccess(this.$t('Data saved!'));
});
}
+
+ itemSearchFunc($search) {
+ return /^\d+$/.test($search)
+ ? {id: $search}
+ : {name: {like: '%' + $search + '%'}};
+ }
}
ngModule.vnComponent('vnEntryBuyIndex', {
diff --git a/modules/invoiceOut/back/methods/invoiceOut/downloadZip.js b/modules/invoiceOut/back/methods/invoiceOut/downloadZip.js
index 72a00b764..fe005f1ab 100644
--- a/modules/invoiceOut/back/methods/invoiceOut/downloadZip.js
+++ b/modules/invoiceOut/back/methods/invoiceOut/downloadZip.js
@@ -9,31 +9,43 @@ module.exports = Self => {
accepts: [
{
arg: 'ids',
- type: ['number'],
- description: 'The invoice ids'
+ type: 'string',
+ description: 'The invoices ids',
+ }
+ ],
+ returns: [
+ {
+ arg: 'body',
+ type: 'file',
+ root: true
+ }, {
+ arg: 'Content-Type',
+ type: 'string',
+ http: {target: 'header'}
+ }, {
+ arg: 'Content-Disposition',
+ type: 'string',
+ http: {target: 'header'}
}
],
- returns: {
- arg: 'base64',
- type: 'string',
- root: true
- },
http: {
path: '/downloadZip',
- verb: 'POST'
+ verb: 'GET'
}
});
Self.downloadZip = async function(ctx, ids, options) {
const models = Self.app.models;
const myOptions = {};
+ const zip = new JSZip();
if (typeof options == 'object')
Object.assign(myOptions, options);
- const zip = new JSZip();
- let totalSize = 0;
const zipConfig = await models.ZipConfig.findOne(null, myOptions);
+ let totalSize = 0;
+ ids = ids.split(',');
+
for (let id of ids) {
if (zipConfig && totalSize > zipConfig.maxSize) throw new UserError('Files are too large');
const invoiceOutPdf = await models.InvoiceOut.download(ctx, id, myOptions);
@@ -44,8 +56,10 @@ module.exports = Self => {
totalSize += sizeInMegabytes;
zip.file(fileName, body);
}
- const base64 = await zip.generateAsync({type: 'base64'});
- return base64;
+
+ const stream = zip.generateNodeStream({streamFiles: true});
+
+ return [stream, 'application/zip', `filename="download.zip"`];
};
function extractFileName(str) {
diff --git a/modules/invoiceOut/back/methods/invoiceOut/specs/downloadZip.spec.js b/modules/invoiceOut/back/methods/invoiceOut/specs/downloadZip.spec.js
index e458ad9ff..4d1833635 100644
--- a/modules/invoiceOut/back/methods/invoiceOut/specs/downloadZip.spec.js
+++ b/modules/invoiceOut/back/methods/invoiceOut/specs/downloadZip.spec.js
@@ -3,7 +3,7 @@ const UserError = require('vn-loopback/util/user-error');
describe('InvoiceOut downloadZip()', () => {
const userId = 9;
- const invoiceIds = [1, 2];
+ const invoiceIds = '1,2';
const ctx = {
req: {
diff --git a/modules/invoiceOut/front/index/index.js b/modules/invoiceOut/front/index/index.js
index a46060073..2cde3c940 100644
--- a/modules/invoiceOut/front/index/index.js
+++ b/modules/invoiceOut/front/index/index.js
@@ -29,13 +29,13 @@ export default class Controller extends Section {
window.open(url, '_blank');
} else {
const invoiceOutIds = this.checked;
- const params = {
- ids: invoiceOutIds
- };
- this.$http.post(`InvoiceOuts/downloadZip`, params)
- .then(res => {
- location.href = 'data:application/zip;base64,' + res.data;
- });
+ const invoicesIds = invoiceOutIds.join(',');
+ const serializedParams = this.$httpParamSerializer({
+ access_token: this.vnToken.token,
+ ids: invoicesIds
+ });
+ const url = `api/InvoiceOuts/downloadZip?${serializedParams}`;
+ window.open(url, '_blank');
}
}
}
diff --git a/modules/mdb/back/methods/mdbApp/lock.js b/modules/mdb/back/methods/mdbApp/lock.js
new file mode 100644
index 000000000..98e61fb53
--- /dev/null
+++ b/modules/mdb/back/methods/mdbApp/lock.js
@@ -0,0 +1,66 @@
+const UserError = require('vn-loopback/util/user-error');
+
+module.exports = Self => {
+ Self.remoteMethodCtx('lock', {
+ description: 'Lock an app for the user',
+ accessType: 'WRITE',
+ accepts: [
+ {
+ arg: 'appName',
+ type: 'string',
+ required: true,
+ description: 'The app name',
+ http: {source: 'path'}
+
+ }
+ ],
+ returns: {
+ type: ['object'],
+ root: true
+ },
+ http: {
+ path: `/:appName/lock`,
+ verb: 'POST'
+ }
+ });
+
+ Self.lock = async(ctx, appName, options) => {
+ const models = Self.app.models;
+ const userId = ctx.req.accessToken.userId;
+ const myOptions = {};
+ const $t = ctx.req.__; // $translate
+
+ let tx;
+
+ if (typeof options == 'object')
+ Object.assign(myOptions, options);
+
+ if (!myOptions.transaction) {
+ tx = await Self.beginTransaction({});
+ myOptions.transaction = tx;
+ }
+
+ try {
+ const mdbApp = await models.MdbApp.findById(appName, {fields: ['app', 'locked', 'userFk']}, myOptions);
+
+ if (mdbApp.locked) {
+ throw new UserError($t('App locked', {
+ userId: mdbApp.userFk
+ }));
+ }
+
+ const updatedMdbApp = await mdbApp.updateAttributes({
+ userFk: userId,
+ locked: new Date()
+ }, myOptions);
+
+ if (tx) await tx.commit();
+
+ return updatedMdbApp;
+ } catch (e) {
+ if (tx) await tx.rollback();
+
+ throw e;
+ }
+ };
+};
diff --git a/modules/mdb/back/methods/mdbApp/specs/lock.spec.js b/modules/mdb/back/methods/mdbApp/specs/lock.spec.js
new file mode 100644
index 000000000..162d0490a
--- /dev/null
+++ b/modules/mdb/back/methods/mdbApp/specs/lock.spec.js
@@ -0,0 +1,51 @@
+const models = require('vn-loopback/server/server').models;
+
+describe('MdbApp lock()', () => {
+ it('should throw an error if the app is already locked', async() => {
+ const tx = await models.MdbApp.beginTransaction({});
+ let error;
+
+ try {
+ const options = {transaction: tx};
+ const appName = 'bar';
+ const developerId = 9;
+ const ctx = {
+ req: {
+ accessToken: {userId: developerId},
+ __: () => {}
+ }
+ };
+
+ const result = await models.MdbApp.lock(ctx, appName, options);
+
+ expect(result.locked).not.toBeNull();
+
+ await tx.rollback();
+ } catch (e) {
+ error = e;
+
+ await tx.rollback();
+ }
+
+ expect(error).toBeDefined();
+ });
+
+ it(`should lock a mdb `, async() => {
+ const tx = await models.MdbApp.beginTransaction({});
+
+ try {
+ const options = {transaction: tx};
+ const appName = 'foo';
+ const developerId = 9;
+ const ctx = {req: {accessToken: {userId: developerId}}};
+
+ const result = await models.MdbApp.lock(ctx, appName, options);
+
+ expect(result.locked).not.toBeNull();
+
+ await tx.rollback();
+ } catch (e) {
+ await tx.rollback();
+ }
+ });
+});
diff --git a/modules/mdb/back/methods/mdbApp/specs/unlock.spec.js b/modules/mdb/back/methods/mdbApp/specs/unlock.spec.js
new file mode 100644
index 000000000..9f1678372
--- /dev/null
+++ b/modules/mdb/back/methods/mdbApp/specs/unlock.spec.js
@@ -0,0 +1,22 @@
+const models = require('vn-loopback/server/server').models;
+
+describe('MdbApp unlock()', () => {
+ it(`should unlock a mdb `, async() => {
+ const tx = await models.MdbApp.beginTransaction({});
+
+ try {
+ const options = {transaction: tx};
+ const appName = 'bar';
+ const developerId = 9;
+ const ctx = {req: {accessToken: {userId: developerId}}};
+
+ const result = await models.MdbApp.unlock(ctx, appName, options);
+
+ expect(result.locked).toBeNull();
+
+ await tx.rollback();
+ } catch (e) {
+ await tx.rollback();
+ }
+ });
+});
diff --git a/modules/mdb/back/methods/mdbApp/unlock.js b/modules/mdb/back/methods/mdbApp/unlock.js
new file mode 100644
index 000000000..6bf67ddf4
--- /dev/null
+++ b/modules/mdb/back/methods/mdbApp/unlock.js
@@ -0,0 +1,40 @@
+module.exports = Self => {
+ Self.remoteMethodCtx('unlock', {
+ description: 'Unlock an app for the user',
+ accessType: 'WRITE',
+ accepts: [
+ {
+ arg: 'appName',
+ type: 'string',
+ required: true,
+ description: 'The app name',
+ http: {source: 'path'}
+
+ }
+ ],
+ returns: {
+ type: ['object'],
+ root: true
+ },
+ http: {
+ path: `/:appName/unlock`,
+ verb: 'POST'
+ }
+ });
+
+ Self.unlock = async(ctx, appName, options) => {
+ const models = Self.app.models;
+ const myOptions = {};
+
+ if (typeof options == 'object')
+ Object.assign(myOptions, options);
+
+ const mdbApp = await models.MdbApp.findById(appName, null, myOptions);
+ const updatedMdbApp = await mdbApp.updateAttributes({
+ userFk: null,
+ locked: null
+ }, myOptions);
+
+ return updatedMdbApp;
+ };
+};
diff --git a/modules/mdb/back/methods/mdbVersion/upload.js b/modules/mdb/back/methods/mdbVersion/upload.js
index 57df35ce7..5dfe5d3ef 100644
--- a/modules/mdb/back/methods/mdbVersion/upload.js
+++ b/modules/mdb/back/methods/mdbVersion/upload.js
@@ -23,6 +23,12 @@ module.exports = Self => {
type: 'string',
required: true,
description: `The branch name`
+ },
+ {
+ arg: 'unlock',
+ type: 'boolean',
+ required: false,
+ description: `It allows unlock the app`
}
],
returns: {
@@ -35,9 +41,11 @@ module.exports = Self => {
}
});
- Self.upload = async(ctx, appName, newVersion, branch, options) => {
+ Self.upload = async(ctx, appName, newVersion, branch, unlock, options) => {
const models = Self.app.models;
+ const userId = ctx.req.accessToken.userId;
const myOptions = {};
+ const $t = ctx.req.__; // $translate
const TempContainer = models.TempContainer;
const AccessContainer = models.AccessContainer;
@@ -55,6 +63,14 @@ module.exports = Self => {
let srcFile;
try {
+ const mdbApp = await models.MdbApp.findById(appName, null, myOptions);
+
+ if (mdbApp.locked && mdbApp.userFk != userId) {
+ throw new UserError($t('App locked', {
+ userId: mdbApp.userFk
+ }));
+ }
+
const tempContainer = await TempContainer.container('access');
const uploaded = await TempContainer.upload(tempContainer.name, ctx.req, ctx.result, fileOptions);
const files = Object.values(uploaded.files).map(file => {
@@ -79,7 +95,7 @@ module.exports = Self => {
const existBranch = await models.MdbBranch.findOne({
where: {name: branch}
- });
+ }, myOptions);
if (!existBranch)
throw new UserError('Not exist this branch');
@@ -108,7 +124,9 @@ module.exports = Self => {
app: appName,
branchFk: branch,
version: newVersion
- });
+ }, myOptions);
+
+ if (unlock) await models.MdbApp.unlock(ctx, appName, myOptions);
if (tx) await tx.commit();
} catch (e) {
diff --git a/modules/mdb/back/model-config.json b/modules/mdb/back/model-config.json
index d5be8de87..6107f8790 100644
--- a/modules/mdb/back/model-config.json
+++ b/modules/mdb/back/model-config.json
@@ -1,4 +1,7 @@
{
+ "MdbApp": {
+ "dataSource": "vn"
+ },
"MdbBranch": {
"dataSource": "vn"
},
diff --git a/modules/mdb/back/models/mdbApp.js b/modules/mdb/back/models/mdbApp.js
new file mode 100644
index 000000000..dce715573
--- /dev/null
+++ b/modules/mdb/back/models/mdbApp.js
@@ -0,0 +1,4 @@
+module.exports = Self => {
+ require('../methods/mdbApp/lock')(Self);
+ require('../methods/mdbApp/unlock')(Self);
+};
diff --git a/modules/mdb/back/models/mdbApp.json b/modules/mdb/back/models/mdbApp.json
new file mode 100644
index 000000000..868f8c1d0
--- /dev/null
+++ b/modules/mdb/back/models/mdbApp.json
@@ -0,0 +1,31 @@
+{
+ "name": "MdbApp",
+ "base": "VnModel",
+ "options": {
+ "mysql": {
+ "table": "mdbApp"
+ }
+ },
+ "properties": {
+ "app": {
+ "type": "string",
+ "description": "The app name",
+ "id": true
+ },
+ "locked": {
+ "type": "date"
+ }
+ },
+ "relations": {
+ "branch": {
+ "type": "belongsTo",
+ "model": "MdbBranch",
+ "foreignKey": "baselineBranchFk"
+ },
+ "user": {
+ "type": "belongsTo",
+ "model": "MdbBranch",
+ "foreignKey": "userFk"
+ }
+ }
+}
diff --git a/modules/monitor/back/methods/sales-monitor/clientsFilter.js b/modules/monitor/back/methods/sales-monitor/clientsFilter.js
index 3756a706b..09ea24eb1 100644
--- a/modules/monitor/back/methods/sales-monitor/clientsFilter.js
+++ b/modules/monitor/back/methods/sales-monitor/clientsFilter.js
@@ -38,6 +38,7 @@ module.exports = Self => {
date.setHours(0, 0, 0, 0);
const stmt = new ParameterizedSQL(`
SELECT
+ v.id,
u.name AS salesPerson,
IFNULL(sc.workerSubstitute, c.salesPersonFk) AS salesPersonFk,
c.id AS clientFk,
diff --git a/modules/monitor/front/index/clients/index.html b/modules/monitor/front/index/clients/index.html
index 381c0e1ae..c0e3d1b14 100644
--- a/modules/monitor/front/index/clients/index.html
+++ b/modules/monitor/front/index/clients/index.html
@@ -61,7 +61,7 @@
-
+
{{::visit.dated | date:'dd/MM/yy'}}
diff --git a/modules/monitor/front/index/orders/index.html b/modules/monitor/front/index/orders/index.html
index 6126e23ef..74e80e40e 100644
--- a/modules/monitor/front/index/orders/index.html
+++ b/modules/monitor/front/index/orders/index.html
@@ -41,7 +41,7 @@
SalesPerson
-
diff --git a/modules/monitor/front/index/tickets/index.html b/modules/monitor/front/index/tickets/index.html
index 138788ed6..2f7c34e2d 100644
--- a/modules/monitor/front/index/tickets/index.html
+++ b/modules/monitor/front/index/tickets/index.html
@@ -78,7 +78,7 @@
- {
}
});
- it('should return the tickets matching the OK State in destination date', async () => {
+ it('should return the tickets matching the OK State in destination date', async() => {
const tx = await models.Ticket.beginTransaction({});
try {
- const options = { transaction: tx };
+ const options = {transaction: tx};
const args = {
originDated: today,
futureDated: today,
- litersMax: 9999,
- linesMax: 9999,
warehouseFk: 1,
- tfState: "OK"
+ futureState: 'OK'
};
- const ctx = { req: { accessToken: { userId: 9 } }, args };
+ const ctx = {req: {accessToken: {userId: 9}}, args};
const result = await models.Ticket.getTicketsFuture(ctx, options);
expect(result.length).toEqual(4);
@@ -273,22 +152,20 @@ describe('TicketFuture getTicketsFuture()', () => {
}
});
- it('should return the tickets matching the correct IPT in origin date', async () => {
+ it('should return the tickets matching the correct IPT in origin date', async() => {
const tx = await models.Ticket.beginTransaction({});
try {
- const options = { transaction: tx };
+ const options = {transaction: tx};
const args = {
originDated: today,
futureDated: today,
- litersMax: 9999,
- linesMax: 9999,
warehouseFk: 1,
ipt: null
};
- const ctx = { req: { accessToken: { userId: 9 } }, args };
+ const ctx = {req: {accessToken: {userId: 9}}, args};
const result = await models.Ticket.getTicketsFuture(ctx, options);
expect(result.length).toEqual(4);
@@ -300,22 +177,20 @@ describe('TicketFuture getTicketsFuture()', () => {
}
});
- it('should return the tickets matching the incorrect IPT in origin date', async () => {
+ it('should return the tickets matching the incorrect IPT in origin date', async() => {
const tx = await models.Ticket.beginTransaction({});
try {
- const options = { transaction: tx };
+ const options = {transaction: tx};
const args = {
originDated: today,
futureDated: today,
- litersMax: 9999,
- linesMax: 9999,
warehouseFk: 1,
ipt: 0
};
- const ctx = { req: { accessToken: { userId: 9 } }, args };
+ const ctx = {req: {accessToken: {userId: 9}}, args};
const result = await models.Ticket.getTicketsFuture(ctx, options);
expect(result.length).toEqual(0);
@@ -327,22 +202,20 @@ describe('TicketFuture getTicketsFuture()', () => {
}
});
- it('should return the tickets matching the correct IPT in destination date', async () => {
+ it('should return the tickets matching the correct IPT in destination date', async() => {
const tx = await models.Ticket.beginTransaction({});
try {
- const options = { transaction: tx };
+ const options = {transaction: tx};
const args = {
originDated: today,
futureDated: today,
- litersMax: 9999,
- linesMax: 9999,
warehouseFk: 1,
- tfIpt: null
+ futureIpt: null
};
- const ctx = { req: { accessToken: { userId: 9 } }, args };
+ const ctx = {req: {accessToken: {userId: 9}}, args};
const result = await models.Ticket.getTicketsFuture(ctx, options);
expect(result.length).toEqual(4);
@@ -354,22 +227,20 @@ describe('TicketFuture getTicketsFuture()', () => {
}
});
- it('should return the tickets matching the incorrect IPT in destination date', async () => {
+ it('should return the tickets matching the incorrect IPT in destination date', async() => {
const tx = await models.Ticket.beginTransaction({});
try {
- const options = { transaction: tx };
+ const options = {transaction: tx};
const args = {
originDated: today,
futureDated: today,
- litersMax: 9999,
- linesMax: 9999,
warehouseFk: 1,
- tfIpt: 0
+ futureIpt: 0
};
- const ctx = { req: { accessToken: { userId: 9 } }, args };
+ const ctx = {req: {accessToken: {userId: 9}}, args};
const result = await models.Ticket.getTicketsFuture(ctx, options);
expect(result.length).toEqual(0);
@@ -381,22 +252,20 @@ describe('TicketFuture getTicketsFuture()', () => {
}
});
- it('should return the tickets matching the ID in origin date', async () => {
+ it('should return the tickets matching the ID in origin date', async() => {
const tx = await models.Ticket.beginTransaction({});
try {
- const options = { transaction: tx };
+ const options = {transaction: tx};
const args = {
originDated: today,
futureDated: today,
- litersMax: 9999,
- linesMax: 9999,
warehouseFk: 1,
id: 13
};
- const ctx = { req: { accessToken: { userId: 9 } }, args };
+ const ctx = {req: {accessToken: {userId: 9}}, args};
const result = await models.Ticket.getTicketsFuture(ctx, options);
expect(result.length).toEqual(1);
@@ -408,22 +277,20 @@ describe('TicketFuture getTicketsFuture()', () => {
}
});
- it('should return the tickets matching the ID in destination date', async () => {
+ it('should return the tickets matching the ID in destination date', async() => {
const tx = await models.Ticket.beginTransaction({});
try {
- const options = { transaction: tx };
+ const options = {transaction: tx};
const args = {
originDated: today,
futureDated: today,
- litersMax: 9999,
- linesMax: 9999,
warehouseFk: 1,
- tfId: 12
+ futureId: 12
};
- const ctx = { req: { accessToken: { userId: 9 } }, args };
+ const ctx = {req: {accessToken: {userId: 9}}, args};
const result = await models.Ticket.getTicketsFuture(ctx, options);
expect(result.length).toEqual(4);
@@ -434,5 +301,4 @@ describe('TicketFuture getTicketsFuture()', () => {
throw e;
}
});
-
});
diff --git a/modules/ticket/back/methods/ticket/specs/merge.spec.js b/modules/ticket/back/methods/ticket/specs/merge.spec.js
index 713f86ad6..275484f67 100644
--- a/modules/ticket/back/methods/ticket/specs/merge.spec.js
+++ b/modules/ticket/back/methods/ticket/specs/merge.spec.js
@@ -3,15 +3,15 @@ const LoopBackContext = require('loopback-context');
describe('ticket merge()', () => {
const tickets = [{
- id: 13,
- ticketFuture: 12,
- workerFk: 1,
- originETD: new Date(),
- destETD: new Date()
+ originId: 13,
+ destinationId: 12,
+ originShipped: new Date(),
+ destinationShipped: new Date(),
+ workerFk: 1
}];
const activeCtx = {
- accessToken: { userId: 9 },
+ accessToken: {userId: 9},
};
beforeEach(() => {
@@ -22,26 +22,26 @@ describe('ticket merge()', () => {
const ctx = {
req: {
- accessToken: { userId: 9 },
- headers: { origin: 'http://localhost:5000' },
+ accessToken: {userId: 9},
+ headers: {origin: 'http://localhost:5000'},
}
};
ctx.req.__ = value => {
return value;
};
- it('should merge two tickets', async () => {
+ it('should merge two tickets', async() => {
const tx = await models.Ticket.beginTransaction({});
try {
- const options = { transaction: tx };
+ const options = {transaction: tx};
const chatNotificationBeforeMerge = await models.Chat.find();
await models.Ticket.merge(ctx, tickets, options);
- const createdTicketLog = await models.TicketLog.find({ where: { originFk: tickets[0].id } }, options);
- const deletedTicket = await models.Ticket.findOne({ where: { id: tickets[0].id } }, options);
- const salesTicketFuture = await models.Sale.find({ where: { ticketFk: tickets[0].ticketFuture } }, options);
+ const createdTicketLog = await models.TicketLog.find({where: {originFk: tickets[0].originId}}, options);
+ const deletedTicket = await models.Ticket.findOne({where: {id: tickets[0].originId}}, options);
+ const salesTicketFuture = await models.Sale.find({where: {ticketFk: tickets[0].destinationId}}, options);
const chatNotificationAfterMerge = await models.Chat.find();
expect(createdTicketLog.length).toEqual(1);
diff --git a/modules/ticket/back/methods/ticket/specs/priceDifference.spec.js b/modules/ticket/back/methods/ticket/specs/priceDifference.spec.js
index 96d29c46f..5470382f9 100644
--- a/modules/ticket/back/methods/ticket/specs/priceDifference.spec.js
+++ b/modules/ticket/back/methods/ticket/specs/priceDifference.spec.js
@@ -87,7 +87,7 @@ describe('sale priceDifference()', () => {
const secondtItem = result.items[1];
expect(firstItem.movable).toEqual(410);
- expect(secondtItem.movable).toEqual(1810);
+ expect(secondtItem.movable).toEqual(1790);
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 f50253b10..f94b8be2a 100644
--- a/modules/ticket/back/methods/ticket/specs/sendSms.spec.js
+++ b/modules/ticket/back/methods/ticket/specs/sendSms.spec.js
@@ -15,9 +15,16 @@ describe('ticket sendSms()', () => {
const sms = await models.Ticket.sendSms(ctx, id, destination, message, options);
const createdLog = await models.TicketLog.findById(sms.logId, null, options);
+
+ const filter = {
+ ticketFk: createdLog.originFk
+ };
+ const ticketSms = await models.TicketSms.findOne(filter, options);
+
const json = JSON.parse(JSON.stringify(createdLog.newInstance));
expect(json.message).toEqual(message);
+ expect(ticketSms.ticketFk).toEqual(createdLog.originFk);
await tx.rollback();
} catch (e) {
diff --git a/modules/ticket/back/model-config.json b/modules/ticket/back/model-config.json
index baaca595e..50cfbd08a 100644
--- a/modules/ticket/back/model-config.json
+++ b/modules/ticket/back/model-config.json
@@ -32,9 +32,6 @@
"Sale": {
"dataSource": "vn"
},
- "SaleChecked": {
- "dataSource": "vn"
- },
"SaleCloned": {
"dataSource": "vn"
},
@@ -44,7 +41,7 @@
"SaleTracking": {
"dataSource": "vn"
},
- "State":{
+ "State": {
"dataSource": "vn"
},
"Ticket": {
@@ -71,16 +68,16 @@
"TicketRequest": {
"dataSource": "vn"
},
- "TicketState":{
+ "TicketState": {
"dataSource": "vn"
},
- "TicketLastState":{
+ "TicketLastState": {
"dataSource": "vn"
},
- "TicketService":{
+ "TicketService": {
"dataSource": "vn"
},
- "TicketServiceType":{
+ "TicketServiceType": {
"dataSource": "vn"
},
"TicketTracking": {
@@ -94,8 +91,5 @@
},
"TicketConfig": {
"dataSource": "vn"
- },
- "TicketFuture": {
- "dataSource": "vn"
}
}
diff --git a/modules/ticket/back/models/sale-checked.json b/modules/ticket/back/models/sale-checked.json
deleted file mode 100644
index 96d790505..000000000
--- a/modules/ticket/back/models/sale-checked.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "name": "SaleChecked",
- "base": "VnModel",
- "options": {
- "mysql": {
- "table": "saleChecked"
- }
- },
- "properties": {
- "isChecked": {
- "type": "number"
- },
- "saleFk": {
- "id": true
- }
- },
- "relations": {
- "sale": {
- "type": "belongsTo",
- "model": "Sale",
- "foreignKey": "saleFk"
- }
- }
-}
\ No newline at end of file
diff --git a/modules/ticket/back/models/sale.json b/modules/ticket/back/models/sale.json
index e18f0291f..b30954ad1 100644
--- a/modules/ticket/back/models/sale.json
+++ b/modules/ticket/back/models/sale.json
@@ -56,11 +56,6 @@
"foreignKey": "ticketFk",
"required": true
},
- "isChecked": {
- "type": "hasOne",
- "model": "SaleChecked",
- "foreignKey": "saleFk"
- },
"components": {
"type": "hasMany",
"model": "SaleComponent",
@@ -80,6 +75,6 @@
"type": "hasOne",
"model": "ItemShelvingSale",
"foreignKey": "saleFk"
- }
+ }
}
}
diff --git a/modules/ticket/back/models/ticket-future.json b/modules/ticket/back/models/ticket-future.json
deleted file mode 100644
index 00277ab8a..000000000
--- a/modules/ticket/back/models/ticket-future.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "name": "TicketFuture",
- "base": "PersistedModel",
- "acls": [
- {
- "accessType": "READ",
- "principalType": "ROLE",
- "principalId": "employee",
- "permission": "ALLOW"
- }
- ]
- }
diff --git a/modules/ticket/back/models/ticket-log.js b/modules/ticket/back/models/ticket-log.js
new file mode 100644
index 000000000..81855ada7
--- /dev/null
+++ b/modules/ticket/back/models/ticket-log.js
@@ -0,0 +1,3 @@
+module.exports = function(Self) {
+ require('../methods/ticket-log/getChanges')(Self);
+};
diff --git a/modules/ticket/back/models/ticket-methods.js b/modules/ticket/back/models/ticket-methods.js
index 8fd74d35c..73df0579c 100644
--- a/modules/ticket/back/models/ticket-methods.js
+++ b/modules/ticket/back/models/ticket-methods.js
@@ -33,8 +33,9 @@ module.exports = function(Self) {
require('../methods/ticket/closeByTicket')(Self);
require('../methods/ticket/closeByAgency')(Self);
require('../methods/ticket/closeByRoute')(Self);
- require('../methods/ticket-future/getTicketsFuture')(Self);
+ require('../methods/ticket/getTicketsFuture')(Self);
require('../methods/ticket/merge')(Self);
+ require('../methods/ticket/getTicketsAdvance')(Self);
require('../methods/ticket/isRoleAdvanced')(Self);
require('../methods/ticket/collectionLabel')(Self);
require('../methods/ticket/expeditionPalletLabel')(Self);
diff --git a/modules/ticket/front/advance-search-panel/index.html b/modules/ticket/front/advance-search-panel/index.html
new file mode 100644
index 000000000..e8d5dc60d
--- /dev/null
+++ b/modules/ticket/front/advance-search-panel/index.html
@@ -0,0 +1,76 @@
+
+
+
diff --git a/modules/ticket/front/advance-search-panel/index.js b/modules/ticket/front/advance-search-panel/index.js
new file mode 100644
index 000000000..259a40931
--- /dev/null
+++ b/modules/ticket/front/advance-search-panel/index.js
@@ -0,0 +1,43 @@
+import ngModule from '../module';
+import SearchPanel from 'core/components/searchbar/search-panel';
+
+class Controller extends SearchPanel {
+ constructor($, $element) {
+ super($, $element);
+ this.filter = this.$.filter;
+ this.getGroupedStates();
+ this.getItemPackingTypes();
+ }
+
+ getGroupedStates() {
+ let groupedStates = [];
+ this.$http.get('AlertLevels').then(res => {
+ for (let state of res.data) {
+ groupedStates.push({
+ id: state.id,
+ code: state.code,
+ name: this.$t(state.code)
+ });
+ }
+ this.groupedStates = groupedStates;
+ });
+ }
+
+ getItemPackingTypes() {
+ let itemPackingTypes = [];
+ this.$http.get('ItemPackingTypes').then(res => {
+ for (let ipt of res.data) {
+ itemPackingTypes.push({
+ code: ipt.code,
+ description: this.$t(ipt.description)
+ });
+ }
+ this.itemPackingTypes = itemPackingTypes;
+ });
+ }
+}
+
+ngModule.vnComponent('vnAdvanceTicketSearchPanel', {
+ template: require('./index.html'),
+ controller: Controller
+});
diff --git a/modules/ticket/front/advance-search-panel/locale/en.yml b/modules/ticket/front/advance-search-panel/locale/en.yml
new file mode 100644
index 000000000..f01932c7a
--- /dev/null
+++ b/modules/ticket/front/advance-search-panel/locale/en.yml
@@ -0,0 +1 @@
+Advance tickets: Advance tickets
diff --git a/modules/ticket/front/advance-search-panel/locale/es.yml b/modules/ticket/front/advance-search-panel/locale/es.yml
new file mode 100644
index 000000000..3dce7dae5
--- /dev/null
+++ b/modules/ticket/front/advance-search-panel/locale/es.yml
@@ -0,0 +1 @@
+Advance tickets: Adelantar tickets
diff --git a/modules/ticket/front/advance/index.html b/modules/ticket/front/advance/index.html
new file mode 100644
index 000000000..f63c0fbf7
--- /dev/null
+++ b/modules/ticket/front/advance/index.html
@@ -0,0 +1,160 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Origin
+ Destination
+
+
+
+
+
+
+
+ ID
+
+
+ Date
+
+
+ IPT
+
+
+ State
+
+
+ Import
+
+
+ ID
+
+
+ Date
+
+
+ IPT
+
+
+ State
+
+
+ Liters
+
+
+ Stock
+
+
+ Lines
+
+
+ Import
+
+
+
+
+
+
+
+
+
+
+
+ {{::ticket.futureId | dashIfEmpty}}
+
+
+
+
+ {{::ticket.futureShipped | date: 'dd/MM/yyyy'}}
+
+
+ {{::ticket.futureIpt | dashIfEmpty}}
+
+
+ {{::ticket.futureState | dashIfEmpty}}
+
+
+
+
+ {{::(ticket.futureTotalWithVat ? ticket.futureTotalWithVat : 0) | currency: 'EUR': 2}}
+
+
+
+
+ {{::ticket.id | dashIfEmpty}}
+
+
+
+
+ {{::ticket.shipped | date: 'dd/MM/yyyy'}}
+
+
+ {{::ticket.ipt | dashIfEmpty}}
+
+
+ {{::ticket.state | dashIfEmpty}}
+
+
+ {{::ticket.liters | dashIfEmpty}}
+ {{::ticket.hasStock | dashIfEmpty}}
+ {{::ticket.lines | dashIfEmpty}}
+
+
+ {{::(ticket.totalWithVat ? ticket.totalWithVat : 0) | currency: 'EUR': 2}}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/modules/ticket/front/advance/index.js b/modules/ticket/front/advance/index.js
new file mode 100644
index 000000000..1404f9472
--- /dev/null
+++ b/modules/ticket/front/advance/index.js
@@ -0,0 +1,177 @@
+import ngModule from '../module';
+import Section from 'salix/components/section';
+
+export default class Controller extends Section {
+ constructor($element, $) {
+ super($element, $);
+ this.$checkAll = false;
+
+ this.smartTableOptions = {
+ activeButtons: {
+ search: true,
+ },
+ columns: [
+ {
+ field: 'state',
+ searchable: false
+ },
+ {
+ field: 'futureState',
+ searchable: false
+ },
+ {
+ field: 'totalWithVat',
+ searchable: false
+ },
+ {
+ field: 'futureTotalWithVat',
+ searchable: false
+ },
+ {
+ field: 'shipped',
+ searchable: false
+ },
+ {
+ field: 'futureShipped',
+ searchable: false
+ },
+ {
+ field: 'ipt',
+ autocomplete: {
+ url: 'ItemPackingTypes',
+ showField: 'description',
+ valueField: 'code'
+ }
+ },
+ {
+ field: 'futureIpt',
+ autocomplete: {
+ url: 'ItemPackingTypes',
+ showField: 'description',
+ valueField: 'code'
+ }
+ },
+ ]
+ };
+ }
+
+ $postLink() {
+ this.setDefaultFilter();
+ }
+
+ setDefaultFilter() {
+ let today = new Date();
+ const tomorrow = new Date(today);
+ tomorrow.setDate(tomorrow.getDate() + 1);
+ this.filterParams = {
+ dateFuture: tomorrow,
+ dateToAdvance: today,
+ warehouseFk: this.vnConfig.warehouseFk
+ };
+ this.$.model.applyFilter(null, this.filterParams);
+ }
+
+ compareDate(date) {
+ let today = new Date();
+ today.setHours(0, 0, 0, 0);
+ let timeTicket = new Date(date);
+ timeTicket.setHours(0, 0, 0, 0);
+
+ let comparation = today - timeTicket;
+
+ if (comparation == 0)
+ return 'warning';
+ if (comparation < 0)
+ return 'success';
+ }
+
+ get checked() {
+ const tickets = this.$.model.data || [];
+ const checkedLines = [];
+ for (let ticket of tickets) {
+ if (ticket.checked)
+ checkedLines.push(ticket);
+ }
+
+ return checkedLines;
+ }
+
+ stateColor(state) {
+ if (state === 'OK')
+ return 'success';
+ else if (state === 'Libre')
+ return 'notice';
+ }
+
+ dateRange(value) {
+ const minHour = new Date(value);
+ minHour.setHours(0, 0, 0, 0);
+ const maxHour = new Date(value);
+ maxHour.setHours(23, 59, 59, 59);
+
+ return [minHour, maxHour];
+ }
+
+ totalPriceColor(totalWithVat) {
+ const total = parseInt(totalWithVat);
+ if (total > 0 && total < 50)
+ return 'warning';
+ }
+
+ get confirmationMessage() {
+ if (!this.$.model) return 0;
+
+ return this.$t(`Advance confirmation`, {
+ checked: this.checked.length
+ });
+ }
+
+ moveTicketsAdvance() {
+ let ticketsToMove = [];
+ this.checked.forEach(ticket => {
+ ticketsToMove.push({
+ originId: ticket.futureId,
+ destinationId: ticket.id,
+ originShipped: ticket.futureShipped,
+ destinationShipped: ticket.shipped,
+ workerFk: ticket.workerFk
+ });
+ });
+ const params = {tickets: ticketsToMove};
+ return this.$http.post('Tickets/merge', params)
+ .then(() => {
+ this.$.model.refresh();
+ this.vnApp.showSuccess(this.$t('Success'));
+ });
+ }
+
+ exprBuilder(param, value) {
+ switch (param) {
+ case 'id':
+ return {'id': value};
+ case 'futureId':
+ return {'futureId': value};
+ case 'liters':
+ return {'liters': value};
+ case 'lines':
+ return {'lines': value};
+ case 'ipt':
+ return {'ipt': value};
+ case 'futureIpt':
+ return {'futureIpt': value};
+ case 'totalWithVat':
+ return {'totalWithVat': value};
+ case 'futureTotalWithVat':
+ return {'futureTotalWithVat': value};
+ case 'hasStock':
+ return {'hasStock': value};
+ }
+ }
+}
+
+Controller.$inject = ['$element', '$scope'];
+
+ngModule.vnComponent('vnTicketAdvance', {
+ template: require('./index.html'),
+ controller: Controller
+});
diff --git a/modules/ticket/front/advance/index.spec.js b/modules/ticket/front/advance/index.spec.js
new file mode 100644
index 000000000..c5a04daee
--- /dev/null
+++ b/modules/ticket/front/advance/index.spec.js
@@ -0,0 +1,113 @@
+import './index.js';
+import crudModel from 'core/mocks/crud-model';
+
+describe('Component vnTicketAdvance', () => {
+ let controller;
+ let $httpBackend;
+
+ beforeEach(ngModule('ticket')
+ );
+
+ beforeEach(inject(($componentController, _$httpBackend_) => {
+ $httpBackend = _$httpBackend_;
+ const $element = angular.element(' ');
+ controller = $componentController('vnTicketAdvance', {$element});
+ controller.$.model = crudModel;
+ controller.$.model.data = [{
+ id: 1,
+ checked: true,
+ state: 'OK'
+ }, {
+ id: 2,
+ checked: true,
+ state: 'Libre'
+ }];
+ }));
+
+ describe('compareDate()', () => {
+ it('should return warning when the date is the present', () => {
+ let today = new Date();
+ let result = controller.compareDate(today);
+
+ expect(result).toEqual('warning');
+ });
+
+ it('should return sucess when the date is in the future', () => {
+ let futureDate = new Date();
+ futureDate = futureDate.setDate(futureDate.getDate() + 10);
+ let result = controller.compareDate(futureDate);
+
+ expect(result).toEqual('success');
+ });
+
+ it('should return undefined when the date is in the past', () => {
+ let pastDate = new Date();
+ pastDate = pastDate.setDate(pastDate.getDate() - 10);
+ let result = controller.compareDate(pastDate);
+
+ expect(result).toEqual(undefined);
+ });
+ });
+
+ describe('checked()', () => {
+ it('should return an array of checked tickets', () => {
+ const result = controller.checked;
+ const firstRow = result[0];
+ const secondRow = result[1];
+
+ expect(result.length).toEqual(2);
+ expect(firstRow.id).toEqual(1);
+ expect(secondRow.id).toEqual(2);
+ });
+ });
+
+ describe('stateColor()', () => {
+ it('should return success to the OK tickets', () => {
+ const ok = controller.stateColor(controller.$.model.data[0].state);
+ const notOk = controller.stateColor(controller.$.model.data[1].state);
+
+ expect(ok).toEqual('success');
+ expect(notOk).not.toEqual('success');
+ });
+
+ it('should return success to the FREE tickets', () => {
+ const notFree = controller.stateColor(controller.$.model.data[0].state);
+ const free = controller.stateColor(controller.$.model.data[1].state);
+
+ expect(free).toEqual('notice');
+ expect(notFree).not.toEqual('notice');
+ });
+ });
+
+ describe('dateRange()', () => {
+ it('should return two dates with the hours at the start and end of the given date', () => {
+ const now = new Date();
+
+ const today = now.getDate();
+
+ const dateRange = controller.dateRange(now);
+ const start = dateRange[0].toString();
+ const end = dateRange[1].toString();
+
+ expect(start).toContain(today);
+ expect(start).toContain('00:00:00');
+
+ expect(end).toContain(today);
+ expect(end).toContain('23:59:59');
+ });
+ });
+
+ describe('moveTicketsAdvance()', () => {
+ it('should make an HTTP Post query', () => {
+ jest.spyOn(controller.$.model, 'refresh');
+ jest.spyOn(controller.vnApp, 'showSuccess');
+
+ $httpBackend.expectPOST(`Tickets/merge`).respond();
+ controller.moveTicketsAdvance();
+ $httpBackend.flush();
+
+ expect(controller.vnApp.showSuccess).toHaveBeenCalled();
+ expect(controller.$.model.refresh).toHaveBeenCalledWith();
+ });
+ });
+});
diff --git a/modules/ticket/front/advance/locale/en.yml b/modules/ticket/front/advance/locale/en.yml
new file mode 100644
index 000000000..a47d951d0
--- /dev/null
+++ b/modules/ticket/front/advance/locale/en.yml
@@ -0,0 +1,2 @@
+Advance tickets: Advance tickets
+Success: Tickets moved successfully!
diff --git a/modules/ticket/front/advance/locale/es.yml b/modules/ticket/front/advance/locale/es.yml
new file mode 100644
index 000000000..b444fbdd3
--- /dev/null
+++ b/modules/ticket/front/advance/locale/es.yml
@@ -0,0 +1,6 @@
+Advance tickets: Adelantar tickets
+Search advance tickets by date: Busca tickets para adelantar por fecha
+Advance confirmation: ¿Desea adelantar {{checked}} tickets?
+Success: Tickets movidos correctamente
+Lines: Líneas
+Liters: Litros
diff --git a/modules/ticket/front/descriptor-menu/index.html b/modules/ticket/front/descriptor-menu/index.html
index 0c04b42fb..805e0b391 100644
--- a/modules/ticket/front/descriptor-menu/index.html
+++ b/modules/ticket/front/descriptor-menu/index.html
@@ -43,7 +43,7 @@
ng-if="!$ctrl.hasDocuwareFile"
ng-click="$ctrl.showPdfDeliveryNote('withoutPrices')"
translate>
- as PDF without prices
+ as PDF without prices
SMS Minimum import
+
+ SMS Notify changes
+
@@ -251,13 +257,13 @@
-
-
-
-
+
-
\ No newline at end of file
+
diff --git a/modules/ticket/front/descriptor-menu/index.js b/modules/ticket/front/descriptor-menu/index.js
index 100d27cd0..168002d07 100644
--- a/modules/ticket/front/descriptor-menu/index.js
+++ b/modules/ticket/front/descriptor-menu/index.js
@@ -225,6 +225,18 @@ class Controller extends Section {
});
}
+ sendChangesSms() {
+ return this.$http.get(`TicketLogs/${this.id}/getChanges`)
+ .then(res => {
+ const params = {
+ ticketId: this.id,
+ created: this.ticket.updated,
+ changes: res.data
+ };
+ this.showSMSDialog({message: this.$t('Send changes', params)});
+ });
+ }
+
showSMSDialog(params) {
const address = this.ticket.address;
const client = this.ticket.client;
@@ -239,6 +251,7 @@ class Controller extends Section {
destinationFk: this.ticket.clientFk,
destination: phone
}, params);
+
this.$.sms.open();
}
@@ -294,6 +307,11 @@ class Controller extends Section {
this.$state.go('ticket.card.sale', {id: refundTicket.id});
});
}
+
+ onSmsSend(sms) {
+ return this.$http.post(`Tickets/${this.id}/sendSms`, sms)
+ .then(() => this.vnApp.showSuccess(this.$t('SMS sent')));
+ }
}
Controller.$inject = ['$element', '$scope', 'vnReport', 'vnEmail'];
diff --git a/modules/ticket/front/descriptor-menu/index.spec.js b/modules/ticket/front/descriptor-menu/index.spec.js
index 1716e36f6..48b64f4a0 100644
--- a/modules/ticket/front/descriptor-menu/index.spec.js
+++ b/modules/ticket/front/descriptor-menu/index.spec.js
@@ -258,14 +258,24 @@ describe('Ticket Component vnTicketDescriptorMenu', () => {
});
});
- describe('showSMSDialog()', () => {
- it('should set the destionationFk and destination properties and then call the sms open() method', () => {
+ describe('sendChangesSms()', () => {
+ it('should make a query and open the sms dialog', () => {
controller.$.sms = {open: () => {}};
jest.spyOn(controller.$.sms, 'open');
- controller.showSMSDialog();
+ $httpBackend.expectGET(`TicketLogs/${ticket.id}/getChanges`).respond();
+ controller.sendChangesSms();
+ $httpBackend.flush();
expect(controller.$.sms.open).toHaveBeenCalledWith();
+ });
+ });
+
+ describe('showSMSDialog()', () => {
+ it('should set the destionationFk and destination properties and then call the sms open() method', () => {
+ controller.$.sms = {open: () => {}};
+ controller.showSMSDialog();
+
expect(controller.newSMS).toEqual({
destinationFk: ticket.clientFk,
destination: ticket.address.mobile,
diff --git a/modules/ticket/front/descriptor-menu/locale/es.yml b/modules/ticket/front/descriptor-menu/locale/es.yml
index a09a32131..a2725f485 100644
--- a/modules/ticket/front/descriptor-menu/locale/es.yml
+++ b/modules/ticket/front/descriptor-menu/locale/es.yml
@@ -11,4 +11,5 @@ Show Proforma: Ver proforma
Refund all: Abonar todo
Invoice sent: Factura enviada
The following refund ticket have been created: "Se ha creado siguiente ticket de abono: {{ticketId}}"
-Transfer client: Transferir cliente
\ No newline at end of file
+Transfer client: Transferir cliente
+SMS Notify changes: SMS Notificar cambios
diff --git a/modules/ticket/front/descriptor/locale/en.yml b/modules/ticket/front/descriptor/locale/en.yml
index 64075c7ef..8eed2265d 100644
--- a/modules/ticket/front/descriptor/locale/en.yml
+++ b/modules/ticket/front/descriptor/locale/en.yml
@@ -1,2 +1,3 @@
Make a payment: "Verdnatura communicates:\rYour order is pending of payment.\rPlease, enter the web page and make the payment with card.\rThank you."
Minimum is needed: "Verdnatura communicates:\rA minimum import of 50€ (Without BAT) is needed for your order {{ticketId}} from date {{created | date: 'dd/MM/yyyy'}} to receive it with no extra fees."
+Send changes: "Verdnatura communicates:\rOrder {{ticketId}} date {{created | date: 'dd/MM/yyyy'}}\r{{changes}}"
diff --git a/modules/ticket/front/descriptor/locale/es.yml b/modules/ticket/front/descriptor/locale/es.yml
index bce9e62d7..d921b5dc2 100644
--- a/modules/ticket/front/descriptor/locale/es.yml
+++ b/modules/ticket/front/descriptor/locale/es.yml
@@ -23,3 +23,4 @@ Restore ticket: Restaurar ticket
You are going to restore this ticket: Vas a restaurar este ticket
Are you sure you want to restore this ticket?: ¿Seguro que quieres restaurar el ticket?
Are you sure you want to refund all?: ¿Seguro que quieres abonar todo?
+Send changes: "Verdnatura le recuerda:\rPedido {{ticketId}} día {{created | date: 'dd/MM/yyyy'}}\r{{changes}}"
diff --git a/modules/ticket/front/future-search-panel/index.html b/modules/ticket/front/future-search-panel/index.html
index 1b3ae453e..18b574f2a 100644
--- a/modules/ticket/front/future-search-panel/index.html
+++ b/modules/ticket/front/future-search-panel/index.html
@@ -4,43 +4,26 @@
+ ng-model="filter.originDated"
+ required="true">
-
-
-
-
-
-
+ required="true">
-
-
+ ng-model="filter.litersMax">
+
+
@@ -48,22 +31,22 @@
data="$ctrl.itemPackingTypes"
label="Origin IPT"
value-field="code"
- show-field="name"
+ show-field="description"
ng-model="filter.ipt"
info="IPT">
- {{name}}
+ {{description}}
- {{name}}
+ {{description}}
@@ -83,7 +66,7 @@
label="Destination Grouped State"
value-field="code"
show-field="name"
- ng-model="filter.tfState">
+ ng-model="filter.futureState">
{{name}}
diff --git a/modules/ticket/front/future-search-panel/index.js b/modules/ticket/front/future-search-panel/index.js
index 1a1f0e4c5..d7e7b3a5e 100644
--- a/modules/ticket/front/future-search-panel/index.js
+++ b/modules/ticket/front/future-search-panel/index.js
@@ -28,9 +28,8 @@ class Controller extends SearchPanel {
this.$http.get('ItemPackingTypes').then(res => {
for (let ipt of res.data) {
itemPackingTypes.push({
- id: ipt.id,
+ description: this.$t(ipt.description),
code: ipt.code,
- name: this.$t(ipt.code)
});
}
this.itemPackingTypes = itemPackingTypes;
diff --git a/modules/ticket/front/future-search-panel/locale/en.yml b/modules/ticket/front/future-search-panel/locale/en.yml
index fe71865cb..767c20152 100644
--- a/modules/ticket/front/future-search-panel/locale/en.yml
+++ b/modules/ticket/front/future-search-panel/locale/en.yml
@@ -1,9 +1 @@
Future tickets: Tickets a futuro
-FREE: Free
-DELIVERED: Delivered
-ON_PREPARATION: On preparation
-PACKED: Packed
-F: Fruits and vegetables
-V: Vertical
-H: Horizontal
-P: Feed
diff --git a/modules/ticket/front/future-search-panel/locale/es.yml b/modules/ticket/front/future-search-panel/locale/es.yml
index 82deba538..9d72c5b06 100644
--- a/modules/ticket/front/future-search-panel/locale/es.yml
+++ b/modules/ticket/front/future-search-panel/locale/es.yml
@@ -11,13 +11,4 @@ With problems: Con problemas
Warehouse: Almacén
Origin Grouped State: Estado agrupado origen
Destination Grouped State: Estado agrupado destino
-FREE: Libre
-DELIVERED: Servido
-ON_PREPARATION: En preparacion
-PACKED: Encajado
-F: Frutas y verduras
-V: Vertical
-H: Horizontal
-P: Pienso
-ETD: Tiempo estimado de entrega
IPT: Encajado
diff --git a/modules/ticket/front/future/index.html b/modules/ticket/front/future/index.html
index d30cbaf19..1af1fb9ba 100644
--- a/modules/ticket/front/future/index.html
+++ b/modules/ticket/front/future/index.html
@@ -1,7 +1,7 @@
+ auto-load="false">
+
+
+ Origin
+ Destination
+
-
+
Problems
- Origin ID
+ ID
-
- Origin ETD
+
+ Date
+
+
+ IPT
- Origin State
+ State
-
- IPT
-
-
+
Liters
-
+
Available Lines
-
- Destination ID
+
+ ID
-
- Destination ETD
+
+ Date
-
- Destination State
-
-
+
IPT
+
+ State
+
@@ -125,38 +130,38 @@
{{::ticket.id}}
-
- {{::ticket.originETD | date: 'dd/MM/yyyy'}}
+
+ {{::ticket.shipped | date: 'dd/MM/yyyy'}}
+ {{::ticket.ipt}}
{{::ticket.state}}
- {{::ticket.ipt}}
{{::ticket.liters}}
{{::ticket.lines}}
- {{::ticket.ticketFuture}}
+ {{::ticket.futureId}}
-
- {{::ticket.destETD | date: 'dd/MM/yyyy'}}
+
+ {{::ticket.futureShipped | date: 'dd/MM/yyyy'}}
+ {{::ticket.futureIpt}}
- {{::ticket.tfState}}
+ class="chip {{$ctrl.stateColor(ticket.futureState)}}">
+ {{::ticket.futureState}}
- {{::ticket.tfIpt}}
diff --git a/modules/ticket/front/future/index.js b/modules/ticket/front/future/index.js
index 311b9c307..56ba1608e 100644
--- a/modules/ticket/front/future/index.js
+++ b/modules/ticket/front/future/index.js
@@ -11,15 +11,15 @@ export default class Controller extends Section {
search: true,
},
columns: [{
- field: 'problems',
+ field: 'totalProblems',
+ searchable: false,
+ },
+ {
+ field: 'shipped',
searchable: false
},
{
- field: 'originETD',
- searchable: false
- },
- {
- field: 'destETD',
+ field: 'futureShipped',
searchable: false
},
{
@@ -27,7 +27,7 @@ export default class Controller extends Section {
searchable: false
},
{
- field: 'tfState',
+ field: 'futureState',
searchable: false
},
{
@@ -39,7 +39,7 @@ export default class Controller extends Section {
}
},
{
- field: 'tfIpt',
+ field: 'futureIpt',
autocomplete: {
url: 'ItemPackingTypes',
showField: 'description',
@@ -48,6 +48,9 @@ export default class Controller extends Section {
},
]
};
+ }
+
+ $postLink() {
this.setDefaultFilter();
}
@@ -57,10 +60,9 @@ export default class Controller extends Section {
this.filterParams = {
originDated: today,
futureDated: today,
- linesMax: '9999',
- litersMax: '9999',
- warehouseFk: 1
+ warehouseFk: this.vnConfig.warehouseFk
};
+ this.$.model.applyFilter(null, this.filterParams);
}
compareDate(date) {
@@ -113,7 +115,17 @@ export default class Controller extends Section {
}
moveTicketsFuture() {
- let params = { tickets: this.checked };
+ let ticketsToMove = [];
+ this.checked.forEach(ticket => {
+ ticketsToMove.push({
+ originId: ticket.id,
+ destinationId: ticket.futureId,
+ originShipped: ticket.shipped,
+ destinationShipped: ticket.futureShipped,
+ workerFk: ticket.workerFk
+ });
+ });
+ let params = {tickets: ticketsToMove};
return this.$http.post('Tickets/merge', params)
.then(() => {
this.$.model.refresh();
@@ -123,18 +135,18 @@ export default class Controller extends Section {
exprBuilder(param, value) {
switch (param) {
- case 'id':
- return { 'id': value };
- case 'ticketFuture':
- return { 'ticketFuture': value };
- case 'litersMax':
- return { 'liters': value };
- case 'linesMax':
- return { 'lines': value };
- case 'ipt':
- return { 'ipt': value };
- case 'tfIpt':
- return { 'tfIpt': value };
+ case 'id':
+ return {'id': value};
+ case 'futureId':
+ return {'futureId': value};
+ case 'liters':
+ return {'liters': value};
+ case 'lines':
+ return {'lines': value};
+ case 'ipt':
+ return {'ipt': value};
+ case 'futureIpt':
+ return {'futureIpt': value};
}
}
}
diff --git a/modules/ticket/front/future/index.spec.js b/modules/ticket/front/future/index.spec.js
index 63deebc4f..c609a4891 100644
--- a/modules/ticket/front/future/index.spec.js
+++ b/modules/ticket/front/future/index.spec.js
@@ -2,33 +2,30 @@ import './index.js';
import crudModel from 'core/mocks/crud-model';
describe('Component vnTicketFuture', () => {
+ const today = new Date();
let controller;
let $httpBackend;
- let $window;
- beforeEach(ngModule('ticket')
- );
+ beforeEach(ngModule('ticket'));
- beforeEach(inject(($componentController, _$window_, _$httpBackend_) => {
+ beforeEach(inject(($componentController, _$httpBackend_) => {
$httpBackend = _$httpBackend_;
- $window = _$window_;
const $element = angular.element(' ');
- controller = $componentController('vnTicketFuture', { $element });
+ controller = $componentController('vnTicketFuture', {$element});
controller.$.model = crudModel;
controller.$.model.data = [{
id: 1,
checked: true,
- state: "OK"
+ state: 'OK'
}, {
id: 2,
checked: true,
- state: "Libre"
+ state: 'Libre'
}];
}));
describe('compareDate()', () => {
it('should return warning when the date is the present', () => {
- let today = new Date();
let result = controller.compareDate(today);
expect(result).toEqual('warning');
@@ -67,6 +64,7 @@ describe('Component vnTicketFuture', () => {
it('should return success to the OK tickets', () => {
const ok = controller.stateColor(controller.$.model.data[0].state);
const notOk = controller.stateColor(controller.$.model.data[1].state);
+
expect(ok).toEqual('success');
expect(notOk).not.toEqual('success');
});
@@ -74,6 +72,7 @@ describe('Component vnTicketFuture', () => {
it('should return success to the FREE tickets', () => {
const notFree = controller.stateColor(controller.$.model.data[0].state);
const free = controller.stateColor(controller.$.model.data[1].state);
+
expect(free).toEqual('notice');
expect(notFree).not.toEqual('notice');
});
@@ -81,18 +80,14 @@ describe('Component vnTicketFuture', () => {
describe('dateRange()', () => {
it('should return two dates with the hours at the start and end of the given date', () => {
- const now = new Date();
-
- const today = now.getDate();
-
- const dateRange = controller.dateRange(now);
+ const dateRange = controller.dateRange(today);
const start = dateRange[0].toString();
const end = dateRange[1].toString();
- expect(start).toContain(today);
+ expect(start).toContain(today.getDate());
expect(start).toContain('00:00:00');
- expect(end).toContain(today);
+ expect(end).toContain(today.getDate());
expect(end).toContain('23:59:59');
});
});
diff --git a/modules/ticket/front/future/locale/en.yml b/modules/ticket/front/future/locale/en.yml
index 66d3ce269..4400e6992 100644
--- a/modules/ticket/front/future/locale/en.yml
+++ b/modules/ticket/front/future/locale/en.yml
@@ -1,6 +1,2 @@
Move confirmation: Do you want to move {{checked}} tickets to the future?
-FREE: Free
-DELIVERED: Delivered
-ON_PREPARATION: On preparation
-PACKED: Packed
Success: Tickets moved successfully!
diff --git a/modules/ticket/front/future/locale/es.yml b/modules/ticket/front/future/locale/es.yml
index 9be0be6a4..9fceea111 100644
--- a/modules/ticket/front/future/locale/es.yml
+++ b/modules/ticket/front/future/locale/es.yml
@@ -3,20 +3,14 @@ Search tickets: Buscar tickets
Search future tickets by date: Buscar tickets por fecha
Problems: Problemas
Origin ID: ID origen
-Closing: Cierre
Origin State: Estado origen
Destination State: Estado destino
Liters: Litros
Available Lines: Líneas disponibles
Destination ID: ID destino
-Destination ETD: ETD Destino
-Origin ETD: ETD Origen
Move tickets: Mover tickets
Move confirmation: ¿Desea mover {{checked}} tickets hacia el futuro?
Success: Tickets movidos correctamente
-ETD: Tiempo estimado de entrega
IPT: Encajado
-FREE: Libre
-DELIVERED: Servido
-ON_PREPARATION: En preparacion
-PACKED: Encajado
+Origin Date: Fecha origen
+Destination Date: Fecha destino
diff --git a/modules/ticket/front/index.js b/modules/ticket/front/index.js
index 6106a22eb..029dc16a4 100644
--- a/modules/ticket/front/index.js
+++ b/modules/ticket/front/index.js
@@ -20,7 +20,6 @@ import './package/index';
import './sale';
import './tracking/index';
import './tracking/edit';
-import './sale-checked';
import './services';
import './component';
import './sale-tracking';
@@ -32,7 +31,8 @@ import './weekly';
import './dms/index';
import './dms/create';
import './dms/edit';
-import './sms';
import './boxing';
import './future';
import './future-search-panel';
+import './advance';
+import './advance-search-panel';
diff --git a/modules/ticket/front/routes.json b/modules/ticket/front/routes.json
index 2963d54c4..c86b3a1ef 100644
--- a/modules/ticket/front/routes.json
+++ b/modules/ticket/front/routes.json
@@ -8,7 +8,8 @@
"main": [
{"state": "ticket.index", "icon": "icon-ticket"},
{"state": "ticket.weekly.index", "icon": "schedule"},
- {"state": "ticket.future", "icon": "keyboard_double_arrow_right"}
+ {"state": "ticket.future", "icon": "keyboard_double_arrow_right"},
+ {"state": "ticket.advance", "icon": "keyboard_double_arrow_left"}
],
"card": [
{"state": "ticket.card.basicData.stepOne", "icon": "settings"},
@@ -22,7 +23,6 @@
{"state": "ticket.card.expedition", "icon": "icon-package"},
{"state": "ticket.card.service", "icon": "icon-services"},
{"state": "ticket.card.package", "icon": "icon-bucket"},
- {"state": "ticket.card.saleChecked", "icon": "assignment"},
{"state": "ticket.card.components", "icon": "icon-components"},
{"state": "ticket.card.saleTracking", "icon": "assignment"},
{"state": "ticket.card.dms.index", "icon": "cloud_download"},
@@ -158,15 +158,6 @@
},
"acl": ["production", "administrative", "salesPerson"]
},
- {
- "url" : "/sale-checked",
- "state": "ticket.card.saleChecked",
- "component": "vn-ticket-sale-checked",
- "description": "Sale checked",
- "params": {
- "ticket": "$ctrl.ticket"
- }
- },
{
"url" : "/components",
"state": "ticket.card.components",
@@ -290,6 +281,12 @@
"state": "ticket.future",
"component": "vn-ticket-future",
"description": "Future tickets"
+ },
+ {
+ "url": "/advance",
+ "state": "ticket.advance",
+ "component": "vn-ticket-advance",
+ "description": "Advance tickets"
}
]
}
diff --git a/modules/ticket/front/sale-checked/index.html b/modules/ticket/front/sale-checked/index.html
deleted file mode 100644
index 1bc6f1f68..000000000
--- a/modules/ticket/front/sale-checked/index.html
+++ /dev/null
@@ -1,60 +0,0 @@
-
-
-
-
-
-
-
- Is checked
- Item
- Description
- Quantity
-
-
-
-
-
-
-
-
-
-
- {{::sale.itemFk | zeroFill:6}}
-
-
-
-
- {{::sale.item.name}}
-
- {{::sale.item.subName}}
-
-
-
-
-
- {{::sale.quantity}}
-
-
-
-
-
-
-
diff --git a/modules/ticket/front/sale-checked/index.js b/modules/ticket/front/sale-checked/index.js
deleted file mode 100644
index 857ac49e3..000000000
--- a/modules/ticket/front/sale-checked/index.js
+++ /dev/null
@@ -1,42 +0,0 @@
-import ngModule from '../module';
-import Section from 'salix/components/section';
-
-class Controller extends Section {
- constructor($element, $) {
- super($element, $);
- this.filter = {
- include: [
- {
- relation: 'item'
- }, {
- relation: 'isChecked',
- scope: {
- fields: ['isChecked']
- }
- }
- ]
- };
- }
- showItemDescriptor(event, sale) {
- this.quicklinks = {
- btnThree: {
- icon: 'icon-transaction',
- state: `item.card.diary({
- id: ${sale.itemFk},
- warehouseFk: ${this.ticket.warehouseFk},
- lineFk: ${sale.id}
- })`,
- tooltip: 'Item diary'
- }
- };
- this.$.itemDescriptor.show(event.target, sale.itemFk);
- }
-}
-
-ngModule.vnComponent('vnTicketSaleChecked', {
- template: require('./index.html'),
- controller: Controller,
- bindings: {
- ticket: '<'
- }
-});
diff --git a/modules/ticket/front/sms/index.html b/modules/ticket/front/sms/index.html
deleted file mode 100644
index 97bdfef14..000000000
--- a/modules/ticket/front/sms/index.html
+++ /dev/null
@@ -1,45 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{'Characters remaining' | translate}}:
-
- {{$ctrl.charactersRemaining()}}
-
-
-
-
-
-
-
- Send
-
-
\ No newline at end of file
diff --git a/modules/ticket/front/sms/index.spec.js b/modules/ticket/front/sms/index.spec.js
deleted file mode 100644
index b133db04d..000000000
--- a/modules/ticket/front/sms/index.spec.js
+++ /dev/null
@@ -1,71 +0,0 @@
-import './index';
-
-describe('Ticket', () => {
- describe('Component vnTicketSms', () => {
- let controller;
- let $httpBackend;
-
- beforeEach(ngModule('ticket'));
-
- beforeEach(inject(($componentController, $rootScope, _$httpBackend_) => {
- $httpBackend = _$httpBackend_;
- let $scope = $rootScope.$new();
- const $element = angular.element(' ');
- controller = $componentController('vnTicketSms', {$element, $scope});
- controller.$.message = {
- input: {
- value: 'My SMS'
- }
- };
- }));
-
- describe('onResponse()', () => {
- it('should perform a POST query and show a success snackbar', () => {
- let params = {ticketId: 11, destinationFk: 1101, destination: 111111111, message: 'My SMS'};
- controller.sms = {ticketId: 11, destinationFk: 1101, destination: 111111111, message: 'My SMS'};
-
- jest.spyOn(controller.vnApp, 'showMessage');
- $httpBackend.expect('POST', `Tickets/11/sendSms`, params).respond(200, params);
-
- controller.onResponse();
- $httpBackend.flush();
-
- expect(controller.vnApp.showMessage).toHaveBeenCalledWith('SMS sent!');
- });
-
- it('should call onResponse without the destination and show an error snackbar', () => {
- controller.sms = {destinationFk: 1101, message: 'My SMS'};
-
- jest.spyOn(controller.vnApp, 'showError');
-
- controller.onResponse();
-
- expect(controller.vnApp.showError).toHaveBeenCalledWith(`The destination can't be empty`);
- });
-
- it('should call onResponse without the message and show an error snackbar', () => {
- controller.sms = {destinationFk: 1101, destination: 222222222};
-
- jest.spyOn(controller.vnApp, 'showError');
-
- controller.onResponse();
-
- expect(controller.vnApp.showError).toHaveBeenCalledWith(`The message can't be empty`);
- });
- });
-
- describe('charactersRemaining()', () => {
- it('should return the characters remaining in a element', () => {
- controller.$.message = {
- input: {
- value: 'My message 0€'
- }
- };
-
- let result = controller.charactersRemaining();
-
- expect(result).toEqual(145);
- });
- });
- });
-});
diff --git a/modules/ticket/front/sms/locale/es.yml b/modules/ticket/front/sms/locale/es.yml
deleted file mode 100644
index 64c3fcca6..000000000
--- a/modules/ticket/front/sms/locale/es.yml
+++ /dev/null
@@ -1,9 +0,0 @@
-Send SMS: Enviar SMS
-Destination: Destinatario
-Message: Mensaje
-SMS sent!: ¡SMS enviado!
-Characters remaining: Carácteres restantes
-The destination can't be empty: El destinatario no puede estar vacio
-The message can't be empty: El mensaje no puede estar vacio
-The message it's too long: El mensaje es demasiado largo
-Special characters like accents counts as a multiple: Carácteres especiales como los acentos cuentan como varios
\ No newline at end of file
diff --git a/modules/ticket/front/sms/style.scss b/modules/ticket/front/sms/style.scss
deleted file mode 100644
index 84571a5f4..000000000
--- a/modules/ticket/front/sms/style.scss
+++ /dev/null
@@ -1,5 +0,0 @@
-@import "variables";
-
-.SMSDialog {
- min-width: 400px
-}
\ No newline at end of file
diff --git a/modules/worker/back/methods/worker-time-control/specs/sendMail.spec.js b/modules/worker/back/methods/worker-time-control/specs/sendMail.spec.js
index 24bfd6904..5b2436be9 100644
--- a/modules/worker/back/methods/worker-time-control/specs/sendMail.spec.js
+++ b/modules/worker/back/methods/worker-time-control/specs/sendMail.spec.js
@@ -10,6 +10,7 @@ describe('workerTimeControl sendMail()', () => {
const ctx = {req: activeCtx, args: {}};
it('should fill time control of a worker without records in Journey and with rest', async() => {
+ pending('https://redmine.verdnatura.es/issues/4903');
const tx = await models.WorkerTimeControl.beginTransaction({});
try {
@@ -34,6 +35,7 @@ describe('workerTimeControl sendMail()', () => {
});
it('should fill time control of a worker without records in Journey and without rest', async() => {
+ pending('https://redmine.verdnatura.es/issues/4903');
const workdayOf20Hours = 3;
const tx = await models.WorkerTimeControl.beginTransaction({});
@@ -61,6 +63,7 @@ describe('workerTimeControl sendMail()', () => {
});
it('should fill time control of a worker with records in Journey and with rest', async() => {
+ pending('https://redmine.verdnatura.es/issues/4903');
const tx = await models.WorkerTimeControl.beginTransaction({});
try {
@@ -92,6 +95,7 @@ describe('workerTimeControl sendMail()', () => {
});
it('should fill time control of a worker with records in Journey and without rest', async() => {
+ pending('https://redmine.verdnatura.es/issues/4903');
const tx = await models.WorkerTimeControl.beginTransaction({});
try {
diff --git a/modules/worker/back/methods/worker-time-control/specs/timeEntry.spec.js b/modules/worker/back/methods/worker-time-control/specs/timeEntry.spec.js
index 7f652519b..e9924c67b 100644
--- a/modules/worker/back/methods/worker-time-control/specs/timeEntry.spec.js
+++ b/modules/worker/back/methods/worker-time-control/specs/timeEntry.spec.js
@@ -201,6 +201,7 @@ describe('workerTimeControl add/delete timeEntry()', () => {
describe('WorkerTimeControl_clockIn calls', () => {
it('should fail to add a time entry if the target user has an absence that day', async() => {
+ pending('https://redmine.verdnatura.es/issues/4707');
activeCtx.accessToken.userId = salesBossId;
const workerId = hankPymId;
const date = new Date();
@@ -247,6 +248,7 @@ describe('workerTimeControl add/delete timeEntry()', () => {
describe('direction errors', () => {
it('should throw an error when trying "in" direction twice', async() => {
+ pending('https://redmine.verdnatura.es/issues/4707');
activeCtx.accessToken.userId = salesBossId;
const workerId = hankPymId;
@@ -276,6 +278,7 @@ describe('workerTimeControl add/delete timeEntry()', () => {
});
it('should throw an error when trying "in" direction after insert "in" and "middle"', async() => {
+ pending('https://redmine.verdnatura.es/issues/4707');
activeCtx.accessToken.userId = salesBossId;
const workerId = hankPymId;
@@ -309,6 +312,7 @@ describe('workerTimeControl add/delete timeEntry()', () => {
});
it('Should throw an error when trying "out" before closing a "middle" couple', async() => {
+ pending('https://redmine.verdnatura.es/issues/4707');
activeCtx.accessToken.userId = salesBossId;
const workerId = hankPymId;
@@ -342,6 +346,7 @@ describe('workerTimeControl add/delete timeEntry()', () => {
});
it('should throw an error when trying "middle" after "out"', async() => {
+ pending('https://redmine.verdnatura.es/issues/4707');
activeCtx.accessToken.userId = salesBossId;
const workerId = hankPymId;
@@ -375,6 +380,7 @@ describe('workerTimeControl add/delete timeEntry()', () => {
});
it('should throw an error when trying "out" direction twice', async() => {
+ pending('https://redmine.verdnatura.es/issues/4707');
activeCtx.accessToken.userId = salesBossId;
const workerId = hankPymId;
@@ -446,6 +452,7 @@ describe('workerTimeControl add/delete timeEntry()', () => {
});
it('should not fail as the 12h rest is fulfilled', async() => {
+ pending('https://redmine.verdnatura.es/issues/4707');
activeCtx.accessToken.userId = salesBossId;
const workerId = hankPymId;
@@ -482,6 +489,7 @@ describe('workerTimeControl add/delete timeEntry()', () => {
describe('for 3500kg drivers with enforced 9h rest', () => {
it('should throw an error when the 9h enforced rest is not fulfilled', async() => {
+ pending('https://redmine.verdnatura.es/issues/4707');
activeCtx.accessToken.userId = salesBossId;
const workerId = jessicaJonesId;
@@ -516,6 +524,7 @@ describe('workerTimeControl add/delete timeEntry()', () => {
});
it('should not fail when the 9h enforced rest is fulfilled', async() => {
+ pending('https://redmine.verdnatura.es/issues/4707');
activeCtx.accessToken.userId = salesBossId;
const workerId = jessicaJonesId;
@@ -552,6 +561,7 @@ describe('workerTimeControl add/delete timeEntry()', () => {
describe('for 36h weekly rest', () => {
it('should throw an error when the 36h weekly rest is not fulfilled', async() => {
+ pending('https://redmine.verdnatura.es/issues/4707');
activeCtx.accessToken.userId = salesBossId;
const workerId = hankPymId;
@@ -586,6 +596,7 @@ describe('workerTimeControl add/delete timeEntry()', () => {
});
it('should throw an error when the 36h weekly rest is not fulfilled again', async() => {
+ pending('https://redmine.verdnatura.es/issues/4707');
activeCtx.accessToken.userId = salesBossId;
const workerId = hankPymId;
@@ -619,6 +630,7 @@ describe('workerTimeControl add/delete timeEntry()', () => {
describe('for 72h weekly rest', () => {
it('should throw when the 72h weekly rest is not fulfilled yet', async() => {
+ pending('https://redmine.verdnatura.es/issues/4707');
activeCtx.accessToken.userId = salesBossId;
const workerId = hankPymId;
diff --git a/print/templates/email/book-entries-imported-incorrectly/assets/css/import.js b/print/templates/email/book-entries-imported-incorrectly/assets/css/import.js
new file mode 100644
index 000000000..1582b82c5
--- /dev/null
+++ b/print/templates/email/book-entries-imported-incorrectly/assets/css/import.js
@@ -0,0 +1,12 @@
+const Stylesheet = require(`vn-print/core/stylesheet`);
+
+const path = require('path');
+const vnPrintPath = path.resolve('print');
+
+module.exports = new Stylesheet([
+ `${vnPrintPath}/common/css/spacing.css`,
+ `${vnPrintPath}/common/css/misc.css`,
+ `${vnPrintPath}/common/css/layout.css`,
+ `${vnPrintPath}/common/css/email.css`])
+ .mergeStyles();
+
diff --git a/print/templates/email/book-entries-imported-incorrectly/book-entries-imported-incorrectly.html b/print/templates/email/book-entries-imported-incorrectly/book-entries-imported-incorrectly.html
new file mode 100644
index 000000000..044ae0312
--- /dev/null
+++ b/print/templates/email/book-entries-imported-incorrectly/book-entries-imported-incorrectly.html
@@ -0,0 +1,8 @@
+
+
+
diff --git a/print/templates/email/book-entries-imported-incorrectly/book-entries-imported-incorrectly.js b/print/templates/email/book-entries-imported-incorrectly/book-entries-imported-incorrectly.js
new file mode 100755
index 000000000..c8a427d30
--- /dev/null
+++ b/print/templates/email/book-entries-imported-incorrectly/book-entries-imported-incorrectly.js
@@ -0,0 +1,15 @@
+const Component = require(`vn-print/core/component`);
+const emailBody = new Component('email-body');
+
+module.exports = {
+ name: 'book-entries-imported-incorrectly',
+ components: {
+ 'email-body': emailBody.build(),
+ },
+ props: {
+ bookEntries: {
+ type: String,
+ required: true
+ }
+ }
+};
diff --git a/print/templates/email/book-entries-imported-incorrectly/locale/en.yml b/print/templates/email/book-entries-imported-incorrectly/locale/en.yml
new file mode 100644
index 000000000..30c5dd292
--- /dev/null
+++ b/print/templates/email/book-entries-imported-incorrectly/locale/en.yml
@@ -0,0 +1,5 @@
+subject: Book entries imported incorrectly
+title: Book entries imported incorrectly
+description: There are book entries that differ between the info from XDiario and the one that has been imported into Sage.
+ Book entries nº {0}
+ If you consider that it is due to a computer error, forward this email to cau@verdnatura.es
diff --git a/print/templates/email/book-entries-imported-incorrectly/locale/es.yml b/print/templates/email/book-entries-imported-incorrectly/locale/es.yml
new file mode 100644
index 000000000..f48ad0a3b
--- /dev/null
+++ b/print/templates/email/book-entries-imported-incorrectly/locale/es.yml
@@ -0,0 +1,5 @@
+subject: Asientos contables importados incorrectamente
+title: Asientos contables importados incorrectamente
+description: Existen asientos que difieren entre la info. de XDiario y la que se ha importado a Sage.
+ Asientos nº {0}
+ Si considera que es debido a un error informático, reenvíe este correo a cau@verdnatura.es
diff --git a/print/templates/email/supplier-pay-method-update/assets/css/import.js b/print/templates/email/supplier-pay-method-update/assets/css/import.js
new file mode 100644
index 000000000..4b4bb7086
--- /dev/null
+++ b/print/templates/email/supplier-pay-method-update/assets/css/import.js
@@ -0,0 +1,11 @@
+const Stylesheet = require(`vn-print/core/stylesheet`);
+
+const path = require('path');
+const vnPrintPath = path.resolve('print');
+
+module.exports = new Stylesheet([
+ `${vnPrintPath}/common/css/spacing.css`,
+ `${vnPrintPath}/common/css/misc.css`,
+ `${vnPrintPath}/common/css/layout.css`,
+ `${vnPrintPath}/common/css/email.css`])
+ .mergeStyles();
diff --git a/print/templates/email/supplier-pay-method-update/locale/en.yml b/print/templates/email/supplier-pay-method-update/locale/en.yml
new file mode 100644
index 000000000..f04ccc5ce
--- /dev/null
+++ b/print/templates/email/supplier-pay-method-update/locale/en.yml
@@ -0,0 +1,3 @@
+subject: Pay method updated
+title: Pay method updated
+description: The pay method of the supplier {0} has been updated from {1} to {2}
diff --git a/print/templates/email/supplier-pay-method-update/locale/es.yml b/print/templates/email/supplier-pay-method-update/locale/es.yml
new file mode 100644
index 000000000..59ee0e02f
--- /dev/null
+++ b/print/templates/email/supplier-pay-method-update/locale/es.yml
@@ -0,0 +1,3 @@
+subject: Método de pago actualizado
+title: Método de pago actualizado
+description: Se ha actualizado el método de pago del proveedor {0} de {1} a {2}
diff --git a/print/templates/email/supplier-pay-method-update/supplier-pay-method-update.html b/print/templates/email/supplier-pay-method-update/supplier-pay-method-update.html
new file mode 100644
index 000000000..df8543cd9
--- /dev/null
+++ b/print/templates/email/supplier-pay-method-update/supplier-pay-method-update.html
@@ -0,0 +1,8 @@
+
+
+
diff --git a/print/templates/email/supplier-pay-method-update/supplier-pay-method-update.js b/print/templates/email/supplier-pay-method-update/supplier-pay-method-update.js
new file mode 100755
index 000000000..283b2689c
--- /dev/null
+++ b/print/templates/email/supplier-pay-method-update/supplier-pay-method-update.js
@@ -0,0 +1,23 @@
+const Component = require(`vn-print/core/component`);
+const emailBody = new Component('email-body');
+
+module.exports = {
+ name: 'supplier-pay-method-update',
+ components: {
+ 'email-body': emailBody.build(),
+ },
+ props: {
+ name: {
+ type: String,
+ required: true
+ },
+ oldPayMethod: {
+ type: String,
+ required: true
+ },
+ newPayMethod: {
+ type: String,
+ required: true
+ }
+ }
+};
diff --git a/print/templates/reports/expedition-pallet-label/assets/css/style.css b/print/templates/reports/expedition-pallet-label/assets/css/style.css
index 68e91fb47..bd7366486 100644
--- a/print/templates/reports/expedition-pallet-label/assets/css/style.css
+++ b/print/templates/reports/expedition-pallet-label/assets/css/style.css
@@ -17,7 +17,6 @@ html {
}
.mainTable {
width: 100%;
- height: 100%;
border: 10px solid;
border-radius: 20px;
-moz-border-radius: 20px;
@@ -54,8 +53,17 @@ html {
}
#QR {
padding: 25px;
- padding-left: 40px;
+ margin-left: 35px;
+ float:left;
+}
+#barcode{
+ text-align: center;
+}
+#right {
+ float: right;
margin-top: 20px;
+ width: 250;
+ max-width: 250px;
}
#additionalInfo {
padding-top: 20px;
diff --git a/print/templates/reports/expedition-pallet-label/expedition-pallet-label.html b/print/templates/reports/expedition-pallet-label/expedition-pallet-label.html
index 45c6ab463..e4360c79d 100644
--- a/print/templates/reports/expedition-pallet-label/expedition-pallet-label.html
+++ b/print/templates/reports/expedition-pallet-label/expedition-pallet-label.html
@@ -4,10 +4,11 @@
- {{labelData.truck || '---'}}
+ {{labelData.truck || '---'}}
-
+
+
@@ -25,11 +26,13 @@
-
-
- Pallet: {{id}}
- User: {{username.name || '---'}}
- Day: {{labelData.dayName.toUpperCase() || '---'}}
+
+
+
+
Pallet: {{id}}
+
User: {{username.name || '---'}}
+
Day: {{labelData.dayName.toUpperCase() || '---'}}
+
diff --git a/print/templates/reports/expedition-pallet-label/expedition-pallet-label.js b/print/templates/reports/expedition-pallet-label/expedition-pallet-label.js
index 3613da08f..0e8c297e8 100644
--- a/print/templates/reports/expedition-pallet-label/expedition-pallet-label.js
+++ b/print/templates/reports/expedition-pallet-label/expedition-pallet-label.js
@@ -1,5 +1,7 @@
const Component = require(`vn-print/core/component`);
const reportBody = new Component('report-body');
+const jsBarcode = require('jsbarcode');
+const {DOMImplementation, XMLSerializer} = require('xmldom');
const UserError = require('vn-loopback/util/user-error');
const qrcode = require('qrcode');
@@ -39,6 +41,20 @@ module.exports = {
const data = String(id);
return qrcode.toDataURL(data, {margin: 0});
},
+ getBarcode(id) {
+ const xmlSerializer = new XMLSerializer();
+ const document = new DOMImplementation().createDocument('http://www.w3.org/1999/xhtml', 'html', null);
+ const svgNode = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
+
+ jsBarcode(svgNode, id, {
+ xmlDocument: document,
+ format: 'code128',
+ displayValue: false,
+ width: 6,
+ height: 90,
+ });
+ return xmlSerializer.serializeToString(svgNode);
+ },
},
components: {
'report-body': reportBody.build()
diff --git a/print/templates/reports/expedition-pallet-label/options.json b/print/templates/reports/expedition-pallet-label/options.json
index 269e058f0..5814b2c0f 100644
--- a/print/templates/reports/expedition-pallet-label/options.json
+++ b/print/templates/reports/expedition-pallet-label/options.json
@@ -2,8 +2,8 @@
"width": "10cm",
"height": "15cm",
"margin": {
- "top": "0.5cm",
- "right": "0.2cm",
+ "top": "0.3cm",
+ "right": "0.07cm",
"bottom": "0cm",
"left": "0cm"
},