5488-use_checkAccessAcl #1482
|
@ -8,7 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
## [2316.01] - 2023-05-04
|
## [2316.01] - 2023-05-04
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
-
|
- (Usuarios -> Histórico) Nueva sección
|
||||||
|
- (Roles -> Histórico) Nueva sección
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- (Artículo -> Precio fijado) Modificado el buscador superior por uno lateral
|
- (Artículo -> Precio fijado) Modificado el buscador superior por uno lateral
|
||||||
|
|
|
@ -52,6 +52,7 @@ pipeline {
|
||||||
}}}
|
}}}
|
||||||
environment {
|
environment {
|
||||||
NODE_ENV = ""
|
NODE_ENV = ""
|
||||||
|
TZ = 'Europe/Madrid'
|
||||||
}
|
}
|
||||||
parallel {
|
parallel {
|
||||||
stage('Frontend') {
|
stage('Frontend') {
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
name: account
|
||||||
|
columns:
|
||||||
|
id: id
|
||||||
|
name: name
|
||||||
|
roleFk: role
|
||||||
|
nickname: nickname
|
||||||
|
lang: lang
|
||||||
|
password: password
|
||||||
|
bcryptPassword: bcrypt password
|
||||||
|
active: active
|
||||||
|
email: email
|
||||||
|
emailVerified: email verified
|
||||||
|
created: created
|
||||||
|
updated: updated
|
||||||
|
image: image
|
||||||
|
hasGrant: has grant
|
||||||
|
userFk: user
|
|
@ -0,0 +1,17 @@
|
||||||
|
name: cuenta
|
||||||
|
columns:
|
||||||
|
id: id
|
||||||
|
name: nombre
|
||||||
|
roleFk: rol
|
||||||
|
nickname: apodo
|
||||||
|
lang: idioma
|
||||||
|
password: contraseña
|
||||||
|
bcryptPassword: contraseña bcrypt
|
||||||
|
active: activo
|
||||||
|
email: email
|
||||||
|
emailVerified: email verificado
|
||||||
|
created: creado
|
||||||
|
updated: actualizado
|
||||||
|
image: imagen
|
||||||
|
hasGrant: tiene permiso
|
||||||
|
userFk: usuario
|
|
@ -40,8 +40,7 @@ module.exports = Self => {
|
||||||
try {
|
try {
|
||||||
const sale = await models.Sale.findById(saleId, null, myOptions);
|
const sale = await models.Sale.findById(saleId, null, myOptions);
|
||||||
const saleUpdated = await sale.updateAttributes({
|
const saleUpdated = await sale.updateAttributes({
|
||||||
originalQuantity: sale.quantity,
|
quantity
|
||||||
quantity: quantity
|
|
||||||
}, myOptions);
|
}, myOptions);
|
||||||
|
|
||||||
if (tx) await tx.commit();
|
if (tx) await tx.commit();
|
||||||
|
|
|
@ -30,7 +30,7 @@ describe('setSaleQuantity()', () => {
|
||||||
await models.Collection.setSaleQuantity(saleId, newQuantity, options);
|
await models.Collection.setSaleQuantity(saleId, newQuantity, options);
|
||||||
const updateSale = await models.Sale.findById(saleId, null, options);
|
const updateSale = await models.Sale.findById(saleId, null, options);
|
||||||
|
|
||||||
expect(updateSale.originalQuantity).toEqual(originalSale.quantity);
|
expect(updateSale.quantity).not.toEqual(originalSale.quantity);
|
||||||
expect(updateSale.quantity).toEqual(newQuantity);
|
expect(updateSale.quantity).toEqual(newQuantity);
|
||||||
|
|
||||||
await tx.rollback();
|
await tx.rollback();
|
||||||
|
|
|
@ -8,7 +8,7 @@ CREATE DEFINER=`root`@`localhost` PROCEDURE `vn`.`invoiceOut_new`(
|
||||||
BEGIN
|
BEGIN
|
||||||
/**
|
/**
|
||||||
* Creación de facturas emitidas.
|
* Creación de facturas emitidas.
|
||||||
* requiere previamente tabla ticketToInvoice(id).
|
* requiere previamente tabla tmp.ticketToInvoice(id).
|
||||||
*
|
*
|
||||||
* @param vSerial serie a la cual se hace la factura
|
* @param vSerial serie a la cual se hace la factura
|
||||||
* @param vInvoiceDate fecha de la factura
|
* @param vInvoiceDate fecha de la factura
|
||||||
|
@ -36,13 +36,13 @@ BEGIN
|
||||||
|
|
||||||
SELECT t.clientFk, t.companyFk
|
SELECT t.clientFk, t.companyFk
|
||||||
INTO vClient, vCompany
|
INTO vClient, vCompany
|
||||||
FROM ticketToInvoice tt
|
FROM tmp.ticketToInvoice tt
|
||||||
JOIN ticket t ON t.id = tt.id
|
JOIN ticket t ON t.id = tt.id
|
||||||
LIMIT 1;
|
LIMIT 1;
|
||||||
|
|
||||||
-- Eliminem de ticketToInvoice els tickets que no han de ser facturats
|
-- Eliminem de tmp.ticketToInvoice els tickets que no han de ser facturats
|
||||||
DELETE ti.*
|
DELETE ti.*
|
||||||
FROM ticketToInvoice ti
|
FROM tmp.ticketToInvoice ti
|
||||||
JOIN ticket t ON t.id = ti.id
|
JOIN ticket t ON t.id = ti.id
|
||||||
JOIN sale s ON s.ticketFk = t.id
|
JOIN sale s ON s.ticketFk = t.id
|
||||||
JOIN item i ON i.id = s.itemFk
|
JOIN item i ON i.id = s.itemFk
|
||||||
|
@ -57,7 +57,7 @@ BEGIN
|
||||||
|
|
||||||
SELECT SUM(s.quantity * s.price * (100 - s.discount)/100), ts.id
|
SELECT SUM(s.quantity * s.price * (100 - s.discount)/100), ts.id
|
||||||
INTO vIsAnySaleToInvoice, vIsAnyServiceToInvoice
|
INTO vIsAnySaleToInvoice, vIsAnyServiceToInvoice
|
||||||
FROM ticketToInvoice t
|
FROM tmp.ticketToInvoice t
|
||||||
LEFT JOIN sale s ON s.ticketFk = t.id
|
LEFT JOIN sale s ON s.ticketFk = t.id
|
||||||
LEFT JOIN ticketService ts ON ts.ticketFk = t.id;
|
LEFT JOIN ticketService ts ON ts.ticketFk = t.id;
|
||||||
|
|
||||||
|
@ -100,13 +100,13 @@ BEGIN
|
||||||
WHERE id = vNewInvoiceId;
|
WHERE id = vNewInvoiceId;
|
||||||
|
|
||||||
UPDATE ticket t
|
UPDATE ticket t
|
||||||
JOIN ticketToInvoice ti ON ti.id = t.id
|
JOIN tmp.ticketToInvoice ti ON ti.id = t.id
|
||||||
SET t.refFk = vNewRef;
|
SET t.refFk = vNewRef;
|
||||||
|
|
||||||
DROP TEMPORARY TABLE IF EXISTS tmp.updateInter;
|
DROP TEMPORARY TABLE IF EXISTS tmp.updateInter;
|
||||||
CREATE TEMPORARY TABLE tmp.updateInter ENGINE = MEMORY
|
CREATE TEMPORARY TABLE tmp.updateInter ENGINE = MEMORY
|
||||||
SELECT s.id,ti.id ticket_id,vWorker Id_Trabajador
|
SELECT s.id,ti.id ticket_id,vWorker Id_Trabajador
|
||||||
FROM ticketToInvoice ti
|
FROM tmp.ticketToInvoice ti
|
||||||
LEFT JOIN ticketState ts ON ti.id = ts.ticket
|
LEFT JOIN ticketState ts ON ti.id = ts.ticket
|
||||||
JOIN state s
|
JOIN state s
|
||||||
WHERE IFNULL(ts.alertLevel,0) < 3 and s.`code` = getAlert3State(ti.id);
|
WHERE IFNULL(ts.alertLevel,0) < 3 and s.`code` = getAlert3State(ti.id);
|
||||||
|
@ -116,7 +116,7 @@ BEGIN
|
||||||
|
|
||||||
INSERT INTO ticketLog (action, userFk, originFk, description)
|
INSERT INTO ticketLog (action, userFk, originFk, description)
|
||||||
SELECT 'UPDATE', account.myUser_getId(), ti.id, CONCAT('Crea factura ', vNewRef)
|
SELECT 'UPDATE', account.myUser_getId(), ti.id, CONCAT('Crea factura ', vNewRef)
|
||||||
FROM ticketToInvoice ti;
|
FROM tmp.ticketToInvoice ti;
|
||||||
|
|
||||||
CALL invoiceExpenceMake(vNewInvoiceId);
|
CALL invoiceExpenceMake(vNewInvoiceId);
|
||||||
CALL invoiceTaxMake(vNewInvoiceId,vTaxArea);
|
CALL invoiceTaxMake(vNewInvoiceId,vTaxArea);
|
||||||
|
@ -159,7 +159,7 @@ BEGIN
|
||||||
(KEY (ticketFk))
|
(KEY (ticketFk))
|
||||||
ENGINE = MEMORY
|
ENGINE = MEMORY
|
||||||
SELECT id ticketFk
|
SELECT id ticketFk
|
||||||
FROM ticketToInvoice;
|
FROM tmp.ticketToInvoice;
|
||||||
|
|
||||||
CALL `ticket_getTax`('NATIONAL');
|
CALL `ticket_getTax`('NATIONAL');
|
||||||
|
|
||||||
|
@ -220,6 +220,6 @@ BEGIN
|
||||||
|
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
DROP TEMPORARY TABLE `ticketToInvoice`;
|
DROP TEMPORARY TABLE `tmp`.`ticketToInvoice`;
|
||||||
END$$
|
END$$
|
||||||
DELIMITER ;
|
DELIMITER ;
|
||||||
|
|
|
@ -10,14 +10,14 @@ CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`invoiceOut_new`(
|
||||||
BEGIN
|
BEGIN
|
||||||
/**
|
/**
|
||||||
* Creación de facturas emitidas.
|
* Creación de facturas emitidas.
|
||||||
* requiere previamente tabla ticketToInvoice(id).
|
* requiere previamente tabla tmp.ticketToInvoice(id).
|
||||||
*
|
*
|
||||||
* @param vSerial serie a la cual se hace la factura
|
* @param vSerial serie a la cual se hace la factura
|
||||||
* @param vInvoiceDate fecha de la factura
|
* @param vInvoiceDate fecha de la factura
|
||||||
* @param vTaxArea tipo de iva en relacion a la empresa y al cliente
|
* @param vTaxArea tipo de iva en relacion a la empresa y al cliente
|
||||||
* @param vNewInvoiceId id de la factura que se acaba de generar
|
* @param vNewInvoiceId id de la factura que se acaba de generar
|
||||||
* @return vNewInvoiceId
|
* @return vNewInvoiceId
|
||||||
*/
|
*/
|
||||||
DECLARE vIsAnySaleToInvoice BOOL;
|
DECLARE vIsAnySaleToInvoice BOOL;
|
||||||
DECLARE vIsAnyServiceToInvoice BOOL;
|
DECLARE vIsAnyServiceToInvoice BOOL;
|
||||||
DECLARE vNewRef VARCHAR(255);
|
DECLARE vNewRef VARCHAR(255);
|
||||||
|
@ -37,32 +37,32 @@ BEGIN
|
||||||
DECLARE vMaxShipped DATE;
|
DECLARE vMaxShipped DATE;
|
||||||
|
|
||||||
SET vInvoiceDate = IFNULL(vInvoiceDate, util.CURDATE());
|
SET vInvoiceDate = IFNULL(vInvoiceDate, util.CURDATE());
|
||||||
|
|
||||||
SELECT t.clientFk,
|
SELECT t.clientFk,
|
||||||
t.companyFk,
|
t.companyFk,
|
||||||
MAX(DATE(t.shipped)),
|
MAX(DATE(t.shipped)),
|
||||||
DATE(vInvoiceDate) >= invoiceOut_getMaxIssued(
|
DATE(vInvoiceDate) >= invoiceOut_getMaxIssued(
|
||||||
vSerial,
|
vSerial,
|
||||||
t.companyFk,
|
t.companyFk,
|
||||||
YEAR(vInvoiceDate))
|
YEAR(vInvoiceDate))
|
||||||
INTO vClientFk,
|
INTO vClientFk,
|
||||||
vCompanyFk,
|
vCompanyFk,
|
||||||
vMaxShipped,
|
vMaxShipped,
|
||||||
vIsCorrectInvoiceDate
|
vIsCorrectInvoiceDate
|
||||||
FROM ticketToInvoice tt
|
FROM tmp.ticketToInvoice tt
|
||||||
JOIN ticket t ON t.id = tt.id;
|
JOIN ticket t ON t.id = tt.id;
|
||||||
|
|
||||||
IF(vMaxShipped > vInvoiceDate) THEN
|
IF(vMaxShipped > vInvoiceDate) THEN
|
||||||
CALL util.throw("Invoice date can't be less than max date");
|
CALL util.throw("Invoice date can't be less than max date");
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
IF NOT vIsCorrectInvoiceDate THEN
|
IF NOT vIsCorrectInvoiceDate THEN
|
||||||
CALL util.throw('Exists an invoice with a previous date');
|
CALL util.throw('Exists an invoice with a previous date');
|
||||||
END IF;
|
END IF;
|
||||||
|
|
||||||
-- Eliminem de ticketToInvoice els tickets que no han de ser facturats
|
-- Eliminem de tmp.ticketToInvoice els tickets que no han de ser facturats
|
||||||
DELETE ti.*
|
DELETE ti.*
|
||||||
FROM ticketToInvoice ti
|
FROM tmp.ticketToInvoice ti
|
||||||
JOIN ticket t ON t.id = ti.id
|
JOIN ticket t ON t.id = ti.id
|
||||||
JOIN sale s ON s.ticketFk = t.id
|
JOIN sale s ON s.ticketFk = t.id
|
||||||
JOIN item i ON i.id = s.itemFk
|
JOIN item i ON i.id = s.itemFk
|
||||||
|
@ -77,11 +77,11 @@ BEGIN
|
||||||
|
|
||||||
SELECT SUM(s.quantity * s.price * (100 - s.discount)/100) <> 0
|
SELECT SUM(s.quantity * s.price * (100 - s.discount)/100) <> 0
|
||||||
INTO vIsAnySaleToInvoice
|
INTO vIsAnySaleToInvoice
|
||||||
FROM ticketToInvoice t
|
FROM tmp.ticketToInvoice t
|
||||||
JOIN sale s ON s.ticketFk = t.id;
|
JOIN sale s ON s.ticketFk = t.id;
|
||||||
|
|
||||||
SELECT COUNT(*) > 0 INTO vIsAnyServiceToInvoice
|
SELECT COUNT(*) > 0 INTO vIsAnyServiceToInvoice
|
||||||
FROM ticketToInvoice t
|
FROM tmp.ticketToInvoice t
|
||||||
JOIN ticketService ts ON ts.ticketFk = t.id;
|
JOIN ticketService ts ON ts.ticketFk = t.id;
|
||||||
|
|
||||||
IF (vIsAnySaleToInvoice OR vIsAnyServiceToInvoice)
|
IF (vIsAnySaleToInvoice OR vIsAnyServiceToInvoice)
|
||||||
|
@ -121,13 +121,13 @@ BEGIN
|
||||||
WHERE id = vNewInvoiceId;
|
WHERE id = vNewInvoiceId;
|
||||||
|
|
||||||
UPDATE ticket t
|
UPDATE ticket t
|
||||||
JOIN ticketToInvoice ti ON ti.id = t.id
|
JOIN tmp.ticketToInvoice ti ON ti.id = t.id
|
||||||
SET t.refFk = vNewRef;
|
SET t.refFk = vNewRef;
|
||||||
|
|
||||||
DROP TEMPORARY TABLE IF EXISTS tmp.updateInter;
|
DROP TEMPORARY TABLE IF EXISTS tmp.updateInter;
|
||||||
CREATE TEMPORARY TABLE tmp.updateInter ENGINE = MEMORY
|
CREATE TEMPORARY TABLE tmp.updateInter ENGINE = MEMORY
|
||||||
SELECT s.id,ti.id ticket_id,vWorker Id_Trabajador
|
SELECT s.id,ti.id ticket_id,vWorker Id_Trabajador
|
||||||
FROM ticketToInvoice ti
|
FROM tmp.ticketToInvoice ti
|
||||||
LEFT JOIN ticketState ts ON ti.id = ts.ticket
|
LEFT JOIN ticketState ts ON ti.id = ts.ticket
|
||||||
JOIN state s
|
JOIN state s
|
||||||
WHERE IFNULL(ts.alertLevel,0) < 3 and s.`code` = getAlert3State(ti.id);
|
WHERE IFNULL(ts.alertLevel,0) < 3 and s.`code` = getAlert3State(ti.id);
|
||||||
|
@ -137,7 +137,7 @@ BEGIN
|
||||||
|
|
||||||
INSERT INTO ticketLog (action, userFk, originFk, description)
|
INSERT INTO ticketLog (action, userFk, originFk, description)
|
||||||
SELECT 'UPDATE', account.myUser_getId(), ti.id, CONCAT('Crea factura ', vNewRef)
|
SELECT 'UPDATE', account.myUser_getId(), ti.id, CONCAT('Crea factura ', vNewRef)
|
||||||
FROM ticketToInvoice ti;
|
FROM tmp.ticketToInvoice ti;
|
||||||
|
|
||||||
CALL invoiceExpenceMake(vNewInvoiceId);
|
CALL invoiceExpenceMake(vNewInvoiceId);
|
||||||
CALL invoiceTaxMake(vNewInvoiceId,vTaxArea);
|
CALL invoiceTaxMake(vNewInvoiceId,vTaxArea);
|
||||||
|
@ -157,12 +157,12 @@ BEGIN
|
||||||
WHERE io.id = vNewInvoiceId;
|
WHERE io.id = vNewInvoiceId;
|
||||||
|
|
||||||
DROP TEMPORARY TABLE tmp.updateInter;
|
DROP TEMPORARY TABLE tmp.updateInter;
|
||||||
|
|
||||||
SELECT COUNT(*), id
|
SELECT COUNT(*), id
|
||||||
INTO vIsInterCompany, vInterCompanyFk
|
INTO vIsInterCompany, vInterCompanyFk
|
||||||
FROM company
|
FROM company
|
||||||
WHERE clientFk = vClientFk;
|
WHERE clientFk = vClientFk;
|
||||||
|
|
||||||
IF (vIsInterCompany) THEN
|
IF (vIsInterCompany) THEN
|
||||||
|
|
||||||
INSERT INTO invoiceIn(supplierFk, supplierRef, issued, companyFk)
|
INSERT INTO invoiceIn(supplierFk, supplierRef, issued, companyFk)
|
||||||
|
@ -175,7 +175,7 @@ BEGIN
|
||||||
(KEY (ticketFk))
|
(KEY (ticketFk))
|
||||||
ENGINE = MEMORY
|
ENGINE = MEMORY
|
||||||
SELECT id ticketFk
|
SELECT id ticketFk
|
||||||
FROM ticketToInvoice;
|
FROM tmp.ticketToInvoice;
|
||||||
|
|
||||||
CALL `ticket_getTax`('NATIONAL');
|
CALL `ticket_getTax`('NATIONAL');
|
||||||
|
|
||||||
|
@ -201,7 +201,7 @@ BEGIN
|
||||||
) sub;
|
) sub;
|
||||||
|
|
||||||
INSERT INTO invoiceInTax(invoiceInFk, taxableBase, expenceFk, taxTypeSageFk, transactionTypeSageFk)
|
INSERT INTO invoiceInTax(invoiceInFk, taxableBase, expenceFk, taxTypeSageFk, transactionTypeSageFk)
|
||||||
SELECT vNewInvoiceInFk,
|
SELECT vNewInvoiceInFk,
|
||||||
SUM(tt.taxableBase) - IF(tt.code = @vTaxCodeGeneral,
|
SUM(tt.taxableBase) - IF(tt.code = @vTaxCodeGeneral,
|
||||||
@vTaxableBaseServices, 0) taxableBase,
|
@vTaxableBaseServices, 0) taxableBase,
|
||||||
i.expenceFk,
|
i.expenceFk,
|
||||||
|
@ -215,13 +215,13 @@ BEGIN
|
||||||
ORDER BY tt.priority;
|
ORDER BY tt.priority;
|
||||||
|
|
||||||
CALL invoiceInDueDay_calculate(vNewInvoiceInFk);
|
CALL invoiceInDueDay_calculate(vNewInvoiceInFk);
|
||||||
|
|
||||||
SELECT COUNT(*) INTO vIsCEESerial
|
SELECT COUNT(*) INTO vIsCEESerial
|
||||||
FROM invoiceOutSerial
|
FROM invoiceOutSerial
|
||||||
WHERE code = vSerial;
|
WHERE code = vSerial;
|
||||||
|
|
||||||
IF vIsCEESerial THEN
|
IF vIsCEESerial THEN
|
||||||
|
|
||||||
INSERT INTO invoiceInIntrastat (
|
INSERT INTO invoiceInIntrastat (
|
||||||
invoiceInFk,
|
invoiceInFk,
|
||||||
intrastatFk,
|
intrastatFk,
|
||||||
|
@ -253,6 +253,6 @@ BEGIN
|
||||||
DROP TEMPORARY TABLE tmp.ticketServiceTax;
|
DROP TEMPORARY TABLE tmp.ticketServiceTax;
|
||||||
END IF;
|
END IF;
|
||||||
END IF;
|
END IF;
|
||||||
DROP TEMPORARY TABLE `ticketToInvoice`;
|
DROP TEMPORARY TABLE tmp.`ticketToInvoice`;
|
||||||
END$$
|
END$$
|
||||||
DELIMITER ;
|
DELIMITER ;
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
DROP PROCEDURE `vn`.`refund`;
|
||||||
|
DROP PROCEDURE `vn`.`ticket_doRefund`;
|
|
@ -0,0 +1 @@
|
||||||
|
ALTER TABLE `vn`.`entry` DROP COLUMN `notes`;
|
|
@ -0,0 +1,9 @@
|
||||||
|
-- vn.companyI18n definition
|
||||||
|
CREATE TABLE `vn`.`companyI18n` (
|
||||||
|
`companyFk` smallint(5) unsigned NOT NULL,
|
||||||
|
`lang` char(2) CHARACTER SET utf8mb3 NOT NULL,
|
||||||
|
`footnotes` longtext COLLATE utf8mb3_unicode_ci DEFAULT NULL,
|
||||||
|
PRIMARY KEY (`companyFk`,`lang`),
|
||||||
|
CONSTRAINT `companyI18n_FK` FOREIGN KEY (`companyFk`) REFERENCES `company` (`id`) ON UPDATE CASCADE
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
ALTER TABLE `vn`.`company` ADD `web` varchar(100) NULL;
|
|
@ -0,0 +1,5 @@
|
||||||
|
DROP PROCEDURE IF EXISTS `vn`.`sale_setQuantity`;
|
||||||
|
DROP PROCEDURE IF EXISTS `vn`.`collection_updateSale`;
|
||||||
|
DROP PROCEDURE IF EXISTS `vn`.`replaceMovimientosMark`;
|
||||||
|
DROP PROCEDURE IF EXISTS `vn`.`saleTracking_Replace`;
|
||||||
|
DROP PROCEDURE IF EXISTS `vn`.`sale_updateOriginalQuantity`;
|
|
@ -0,0 +1,5 @@
|
||||||
|
UPDATE vn.supplier s
|
||||||
|
JOIN vn.country c ON c.id = s.countryFk
|
||||||
|
SET s.nif = MID(REPLACE(s.nif, ' ', ''), 3, LENGTH(REPLACE(s.nif, ' ', '')) - 1)
|
||||||
|
WHERE s.isVies = TRUE
|
||||||
|
AND c.code = LEFT(REPLACE(s.nif, ' ', ''), 2);
|
|
@ -0,0 +1,5 @@
|
||||||
|
UPDATE IGNORE vn.client c
|
||||||
|
JOIN vn.country co ON co.id = c.countryFk
|
||||||
|
SET c.fi = MID(REPLACE(c.fi, ' ', ''), 3, LENGTH(REPLACE(c.fi, ' ', '')) - 1)
|
||||||
|
WHERE c.isVies = TRUE
|
||||||
|
AND co.code = LEFT(REPLACE(c.fi, ' ', ''), 2);
|
|
@ -546,7 +546,8 @@ INSERT INTO `vn`.`supplier`(`id`, `name`, `nickname`,`account`,`countryFk`,`nif`
|
||||||
VALUES
|
VALUES
|
||||||
(1, 'Plants SL', 'Plants nick', 4100000001, 1, '06089160W', 0, util.VN_CURDATE(), 1, 'supplier address 1', 'PONTEVEDRA', 1, 15214, 1, 1, 15, 4, 1, 1, 18, 'flowerPlants', 1, '400664487V'),
|
(1, 'Plants SL', 'Plants nick', 4100000001, 1, '06089160W', 0, util.VN_CURDATE(), 1, 'supplier address 1', 'PONTEVEDRA', 1, 15214, 1, 1, 15, 4, 1, 1, 18, 'flowerPlants', 1, '400664487V'),
|
||||||
(2, 'Farmer King', 'The farmer', 4000020002, 1, '87945234L', 0, util.VN_CURDATE(), 1, 'supplier address 2', 'GOTHAM', 2, 43022, 1, 2, 10, 93, 2, 8, 18, 'animals', 1, '400664487V'),
|
(2, 'Farmer King', 'The farmer', 4000020002, 1, '87945234L', 0, util.VN_CURDATE(), 1, 'supplier address 2', 'GOTHAM', 2, 43022, 1, 2, 10, 93, 2, 8, 18, 'animals', 1, '400664487V'),
|
||||||
(442, 'Verdnatura Levante SL', 'Verdnatura', 5115000442, 1, '06815934E', 0, util.VN_CURDATE(), 1, 'supplier address 3', 'GOTHAM', 1, 43022, 1, 2, 15, 6, 9, 3, 18, 'complements', 1, '400664487V');
|
(442, 'Verdnatura Levante SL', 'Verdnatura', 5115000442, 1, '06815934E', 0, util.VN_CURDATE(), 1, 'supplier address 3', 'GOTHAM', 1, 43022, 1, 2, 15, 6, 9, 3, 18, 'complements', 1, '400664487V'),
|
||||||
|
(1381, 'Ornamentales', 'Ornamentales', 7185000440, 1, '03815934E', 0, util.VN_CURDATE(), 1, 'supplier address 4', 'GOTHAM', 1, 43022, 1, 2, 15, 6, 9, 3, 18, 'complements', 1, '400664487V');
|
||||||
|
|
||||||
INSERT INTO `vn`.`supplierContact`(`id`, `supplierFk`, `phone`, `mobile`, `email`, `observation`, `name`)
|
INSERT INTO `vn`.`supplierContact`(`id`, `supplierFk`, `phone`, `mobile`, `email`, `observation`, `name`)
|
||||||
VALUES
|
VALUES
|
||||||
|
@ -1408,16 +1409,16 @@ INSERT INTO `vn`.`travel`(`id`,`shipped`, `landed`, `warehouseInFk`, `warehouseO
|
||||||
(7, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 5, 4, 1, 50.00, 500, 'seventh travel', 2, 1),
|
(7, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 5, 4, 1, 50.00, 500, 'seventh travel', 2, 1),
|
||||||
(8, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 5, 1, 1, 50.00, 500, 'eight travel', 1, 2);
|
(8, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 5, 1, 1, 50.00, 500, 'eight travel', 1, 2);
|
||||||
|
|
||||||
INSERT INTO `vn`.`entry`(`id`, `supplierFk`, `created`, `travelFk`, `isConfirmed`, `companyFk`, `invoiceNumber`, `reference`, `isExcludedFromAvailable`, `isRaid`, `notes`, `evaNotes`)
|
INSERT INTO `vn`.`entry`(`id`, `supplierFk`, `created`, `travelFk`, `isConfirmed`, `companyFk`, `invoiceNumber`, `reference`, `isExcludedFromAvailable`, `isRaid`, `evaNotes`)
|
||||||
VALUES
|
VALUES
|
||||||
(1, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 1, 1, 442, 'IN2001', 'Movement 1', 0, 0, '', ''),
|
(1, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 1, 1, 442, 'IN2001', 'Movement 1', 0, 0, ''),
|
||||||
(2, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 2, 0, 442, 'IN2002', 'Movement 2', 0, 0, 'this is the note two', 'observation two'),
|
(2, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 2, 0, 442, 'IN2002', 'Movement 2', 0, 0, 'observation two'),
|
||||||
(3, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 3, 0, 442, 'IN2003', 'Movement 3', 0, 0, 'this is the note three', 'observation three'),
|
(3, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 3, 0, 442, 'IN2003', 'Movement 3', 0, 0, 'observation three'),
|
||||||
(4, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 2, 0, 69, 'IN2004', 'Movement 4', 0, 0, 'this is the note four', 'observation four'),
|
(4, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 2, 0, 69, 'IN2004', 'Movement 4', 0, 0, 'observation four'),
|
||||||
(5, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 5, 0, 442, 'IN2005', 'Movement 5', 0, 0, 'this is the note five', 'observation five'),
|
(5, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 5, 0, 442, 'IN2005', 'Movement 5', 0, 0, 'observation five'),
|
||||||
(6, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 6, 0, 442, 'IN2006', 'Movement 6', 0, 0, 'this is the note six', 'observation six'),
|
(6, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 6, 0, 442, 'IN2006', 'Movement 6', 0, 0, 'observation six'),
|
||||||
(7, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 7, 0, 442, 'IN2007', 'Movement 7', 0, 0, 'this is the note seven', 'observation seven'),
|
(7, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 7, 0, 442, 'IN2007', 'Movement 7', 0, 0, 'observation seven'),
|
||||||
(8, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 7, 0, 442, 'IN2008', 'Movement 8', 1, 1, '', '');
|
(8, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 7, 0, 442, 'IN2008', 'Movement 8', 1, 1, '');
|
||||||
|
|
||||||
INSERT INTO `bs`.`waste`(`buyer`, `year`, `week`, `family`, `itemFk`, `itemTypeFk`, `saleTotal`, `saleWaste`, `rate`)
|
INSERT INTO `bs`.`waste`(`buyer`, `year`, `week`, `family`, `itemFk`, `itemTypeFk`, `saleTotal`, `saleWaste`, `rate`)
|
||||||
VALUES
|
VALUES
|
||||||
|
@ -2789,7 +2790,7 @@ INSERT INTO `vn`.`profileType` (`id`, `name`)
|
||||||
|
|
||||||
INSERT INTO `salix`.`url` (`appName`, `environment`, `url`)
|
INSERT INTO `salix`.`url` (`appName`, `environment`, `url`)
|
||||||
VALUES
|
VALUES
|
||||||
('lilium', 'dev', 'http://localhost:8080/#/'),
|
('lilium', 'dev', 'http://localhost:9000/#/'),
|
||||||
('salix', 'dev', 'http://localhost:5000/#!/');
|
('salix', 'dev', 'http://localhost:5000/#!/');
|
||||||
|
|
||||||
INSERT INTO `vn`.`report` (`id`, `name`, `paperSizeFk`, `method`)
|
INSERT INTO `vn`.`report` (`id`, `name`, `paperSizeFk`, `method`)
|
||||||
|
|
|
@ -42776,7 +42776,7 @@ CREATE DEFINER=`root`@`localhost` FUNCTION `hasAnyNegativeBase`() RETURNS tinyin
|
||||||
BEGIN
|
BEGIN
|
||||||
|
|
||||||
/* Calcula si existe alguna base imponible negativa
|
/* Calcula si existe alguna base imponible negativa
|
||||||
* Requiere la tabla temporal vn.ticketToInvoice(id)
|
* Requiere la tabla temporal tmp.ticketToInvoice(id)
|
||||||
*
|
*
|
||||||
* returns BOOLEAN
|
* returns BOOLEAN
|
||||||
*/
|
*/
|
||||||
|
@ -42787,7 +42787,7 @@ BEGIN
|
||||||
(KEY (ticketFk))
|
(KEY (ticketFk))
|
||||||
ENGINE = MEMORY
|
ENGINE = MEMORY
|
||||||
SELECT id ticketFk
|
SELECT id ticketFk
|
||||||
FROM ticketToInvoice;
|
FROM tmp.ticketToInvoice;
|
||||||
|
|
||||||
CALL ticket_getTax(NULL);
|
CALL ticket_getTax(NULL);
|
||||||
|
|
||||||
|
@ -55223,7 +55223,7 @@ DELIMITER ;;
|
||||||
CREATE DEFINER=`root`@`localhost` PROCEDURE `invoiceExpenceMake`(IN vInvoice INT)
|
CREATE DEFINER=`root`@`localhost` PROCEDURE `invoiceExpenceMake`(IN vInvoice INT)
|
||||||
BEGIN
|
BEGIN
|
||||||
/* Inserta las partidas de gasto correspondientes a la factura
|
/* Inserta las partidas de gasto correspondientes a la factura
|
||||||
* REQUIERE tabla ticketToInvoice
|
* REQUIERE tabla tmp.ticketToInvoice
|
||||||
* @param vInvoice Numero de factura
|
* @param vInvoice Numero de factura
|
||||||
*/
|
*/
|
||||||
DELETE FROM invoiceOutExpence
|
DELETE FROM invoiceOutExpence
|
||||||
|
@ -55233,7 +55233,7 @@ BEGIN
|
||||||
SELECT vInvoice,
|
SELECT vInvoice,
|
||||||
expenceFk,
|
expenceFk,
|
||||||
SUM(ROUND(quantity * price * (100 - discount)/100,2)) amount
|
SUM(ROUND(quantity * price * (100 - discount)/100,2)) amount
|
||||||
FROM ticketToInvoice t
|
FROM tmp.ticketToInvoice t
|
||||||
JOIN sale s ON s.ticketFk = t.id
|
JOIN sale s ON s.ticketFk = t.id
|
||||||
JOIN item i ON i.id = s.itemFk
|
JOIN item i ON i.id = s.itemFk
|
||||||
GROUP BY i.expenceFk
|
GROUP BY i.expenceFk
|
||||||
|
@ -55243,7 +55243,7 @@ BEGIN
|
||||||
SELECT vInvoice,
|
SELECT vInvoice,
|
||||||
tst.expenceFk,
|
tst.expenceFk,
|
||||||
SUM(ROUND(ts.quantity * ts.price ,2)) amount
|
SUM(ROUND(ts.quantity * ts.price ,2)) amount
|
||||||
FROM ticketToInvoice t
|
FROM tmp.ticketToInvoice t
|
||||||
JOIN ticketService ts ON ts.ticketFk = t.id
|
JOIN ticketService ts ON ts.ticketFk = t.id
|
||||||
JOIN ticketServiceType tst ON tst.id = ts.ticketServiceTypeFk
|
JOIN ticketServiceType tst ON tst.id = ts.ticketServiceTypeFk
|
||||||
HAVING amount != 0;
|
HAVING amount != 0;
|
||||||
|
@ -55270,9 +55270,9 @@ BEGIN
|
||||||
|
|
||||||
SET vMaxTicketDate = vn2008.DAYEND(vMaxTicketDate);
|
SET vMaxTicketDate = vn2008.DAYEND(vMaxTicketDate);
|
||||||
|
|
||||||
DROP TEMPORARY TABLE IF EXISTS `ticketToInvoice`;
|
DROP TEMPORARY TABLE IF EXISTS `tmp`.`ticketToInvoice`;
|
||||||
|
|
||||||
CREATE TEMPORARY TABLE `ticketToInvoice`
|
CREATE TEMPORARY TABLE `tmp`.`ticketToInvoice`
|
||||||
(PRIMARY KEY (`id`))
|
(PRIMARY KEY (`id`))
|
||||||
ENGINE = MEMORY
|
ENGINE = MEMORY
|
||||||
SELECT Id_Ticket id FROM vn2008.Tickets WHERE (Fecha BETWEEN vMinDateTicket
|
SELECT Id_Ticket id FROM vn2008.Tickets WHERE (Fecha BETWEEN vMinDateTicket
|
||||||
|
@ -55305,8 +55305,8 @@ BEGIN
|
||||||
SET vMinTicketDate = util.firstDayOfYear(vMaxTicketDate - INTERVAL 1 YEAR);
|
SET vMinTicketDate = util.firstDayOfYear(vMaxTicketDate - INTERVAL 1 YEAR);
|
||||||
SET vMaxTicketDate = util.dayend(vMaxTicketDate);
|
SET vMaxTicketDate = util.dayend(vMaxTicketDate);
|
||||||
|
|
||||||
DROP TEMPORARY TABLE IF EXISTS `ticketToInvoice`;
|
DROP TEMPORARY TABLE IF EXISTS `tmp`.`ticketToInvoice`;
|
||||||
CREATE TEMPORARY TABLE `ticketToInvoice`
|
CREATE TEMPORARY TABLE `tmp`.`ticketToInvoice`
|
||||||
(PRIMARY KEY (`id`))
|
(PRIMARY KEY (`id`))
|
||||||
ENGINE = MEMORY
|
ENGINE = MEMORY
|
||||||
SELECT id FROM ticket t
|
SELECT id FROM ticket t
|
||||||
|
@ -55333,9 +55333,9 @@ DELIMITER ;;
|
||||||
CREATE DEFINER=`root`@`localhost` PROCEDURE `invoiceFromTicket`(IN vTicket INT)
|
CREATE DEFINER=`root`@`localhost` PROCEDURE `invoiceFromTicket`(IN vTicket INT)
|
||||||
BEGIN
|
BEGIN
|
||||||
|
|
||||||
DROP TEMPORARY TABLE IF EXISTS `ticketToInvoice`;
|
DROP TEMPORARY TABLE IF EXISTS `tmp`.`ticketToInvoice`;
|
||||||
|
|
||||||
CREATE TEMPORARY TABLE `ticketToInvoice`
|
CREATE TEMPORARY TABLE `tmp`.`ticketToInvoice`
|
||||||
(PRIMARY KEY (`id`))
|
(PRIMARY KEY (`id`))
|
||||||
ENGINE = MEMORY
|
ENGINE = MEMORY
|
||||||
SELECT id FROM vn.ticket
|
SELECT id FROM vn.ticket
|
||||||
|
@ -55931,9 +55931,9 @@ BEGIN
|
||||||
JOIN invoiceOut io ON io.companyFk = s.id
|
JOIN invoiceOut io ON io.companyFk = s.id
|
||||||
WHERE io.id = vInvoiceFk;
|
WHERE io.id = vInvoiceFk;
|
||||||
|
|
||||||
DROP TEMPORARY TABLE IF EXISTS ticketToInvoice;
|
DROP TEMPORARY TABLE IF EXISTS tmp.ticketToInvoice;
|
||||||
|
|
||||||
CREATE TEMPORARY TABLE ticketToInvoice
|
CREATE TEMPORARY TABLE tmp.ticketToInvoice
|
||||||
SELECT id
|
SELECT id
|
||||||
FROM ticket
|
FROM ticket
|
||||||
WHERE refFk = vInvoiceRef;
|
WHERE refFk = vInvoiceRef;
|
||||||
|
@ -56408,9 +56408,9 @@ BEGIN
|
||||||
JOIN client c ON c.id = io.clientFk
|
JOIN client c ON c.id = io.clientFk
|
||||||
WHERE io.id = vInvoice;
|
WHERE io.id = vInvoice;
|
||||||
|
|
||||||
DROP TEMPORARY TABLE IF EXISTS ticketToInvoice;
|
DROP TEMPORARY TABLE IF EXISTS tmp.ticketToInvoice;
|
||||||
|
|
||||||
CREATE TEMPORARY TABLE ticketToInvoice
|
CREATE TEMPORARY TABLE tmp.ticketToInvoice
|
||||||
SELECT id
|
SELECT id
|
||||||
FROM ticket
|
FROM ticket
|
||||||
WHERE refFk = vInvoiceRef;
|
WHERE refFk = vInvoiceRef;
|
||||||
|
@ -56456,7 +56456,7 @@ CREATE DEFINER=`root`@`localhost` PROCEDURE `invoiceOut_exportationFromClient`(
|
||||||
vCompanyFk INT)
|
vCompanyFk INT)
|
||||||
BEGIN
|
BEGIN
|
||||||
/**
|
/**
|
||||||
* Genera tabla temporal ticketToInvoice necesaría para el proceso de facturación
|
* Genera tabla temporal tmp.ticketToInvoice necesaría para el proceso de facturación
|
||||||
* Los abonos quedan excluidos en las exportaciones
|
* Los abonos quedan excluidos en las exportaciones
|
||||||
*
|
*
|
||||||
* @param vMaxTicketDate Fecha hasta la cual cogerá tickets para facturar
|
* @param vMaxTicketDate Fecha hasta la cual cogerá tickets para facturar
|
||||||
|
@ -56467,8 +56467,8 @@ BEGIN
|
||||||
SET vMinTicketDate = util.firstDayOfYear(vMaxTicketDate - INTERVAL 1 YEAR);
|
SET vMinTicketDate = util.firstDayOfYear(vMaxTicketDate - INTERVAL 1 YEAR);
|
||||||
SET vMaxTicketDate = util.dayend(vMaxTicketDate);
|
SET vMaxTicketDate = util.dayend(vMaxTicketDate);
|
||||||
|
|
||||||
DROP TEMPORARY TABLE IF EXISTS `ticketToInvoice`;
|
DROP TEMPORARY TABLE IF EXISTS `tmp`.`ticketToInvoice`;
|
||||||
CREATE TEMPORARY TABLE `ticketToInvoice`
|
CREATE TEMPORARY TABLE `tmp`.`ticketToInvoice`
|
||||||
(PRIMARY KEY (`id`))
|
(PRIMARY KEY (`id`))
|
||||||
ENGINE = MEMORY
|
ENGINE = MEMORY
|
||||||
SELECT t.id
|
SELECT t.id
|
||||||
|
@ -56503,7 +56503,7 @@ CREATE DEFINER=`root`@`localhost` PROCEDURE `invoiceOut_new`(
|
||||||
BEGIN
|
BEGIN
|
||||||
/**
|
/**
|
||||||
* Creación de facturas emitidas.
|
* Creación de facturas emitidas.
|
||||||
* requiere previamente tabla ticketToInvoice(id).
|
* requiere previamente tabla tmp.ticketToInvoice(id).
|
||||||
*
|
*
|
||||||
* @param vSerial serie a la cual se hace la factura
|
* @param vSerial serie a la cual se hace la factura
|
||||||
* @param vInvoiceDate fecha de la factura
|
* @param vInvoiceDate fecha de la factura
|
||||||
|
@ -56531,13 +56531,13 @@ BEGIN
|
||||||
|
|
||||||
SELECT t.clientFk, t.companyFk
|
SELECT t.clientFk, t.companyFk
|
||||||
INTO vClientFk, vCompanyFk
|
INTO vClientFk, vCompanyFk
|
||||||
FROM ticketToInvoice tt
|
FROM tmp.ticketToInvoice tt
|
||||||
JOIN ticket t ON t.id = tt.id
|
JOIN ticket t ON t.id = tt.id
|
||||||
LIMIT 1;
|
LIMIT 1;
|
||||||
|
|
||||||
-- Eliminem de ticketToInvoice els tickets que no han de ser facturats
|
-- Eliminem de tmp.ticketToInvoice els tickets que no han de ser facturats
|
||||||
DELETE ti.*
|
DELETE ti.*
|
||||||
FROM ticketToInvoice ti
|
FROM tmp.ticketToInvoice ti
|
||||||
JOIN ticket t ON t.id = ti.id
|
JOIN ticket t ON t.id = ti.id
|
||||||
JOIN sale s ON s.ticketFk = t.id
|
JOIN sale s ON s.ticketFk = t.id
|
||||||
JOIN item i ON i.id = s.itemFk
|
JOIN item i ON i.id = s.itemFk
|
||||||
|
@ -56552,7 +56552,7 @@ BEGIN
|
||||||
|
|
||||||
SELECT SUM(s.quantity * s.price * (100 - s.discount)/100), ts.id
|
SELECT SUM(s.quantity * s.price * (100 - s.discount)/100), ts.id
|
||||||
INTO vIsAnySaleToInvoice, vIsAnyServiceToInvoice
|
INTO vIsAnySaleToInvoice, vIsAnyServiceToInvoice
|
||||||
FROM ticketToInvoice t
|
FROM tmp.ticketToInvoice t
|
||||||
LEFT JOIN sale s ON s.ticketFk = t.id
|
LEFT JOIN sale s ON s.ticketFk = t.id
|
||||||
LEFT JOIN ticketService ts ON ts.ticketFk = t.id;
|
LEFT JOIN ticketService ts ON ts.ticketFk = t.id;
|
||||||
|
|
||||||
|
@ -56593,13 +56593,13 @@ BEGIN
|
||||||
WHERE id = vNewInvoiceId;
|
WHERE id = vNewInvoiceId;
|
||||||
|
|
||||||
UPDATE ticket t
|
UPDATE ticket t
|
||||||
JOIN ticketToInvoice ti ON ti.id = t.id
|
JOIN tmp.ticketToInvoice ti ON ti.id = t.id
|
||||||
SET t.refFk = vNewRef;
|
SET t.refFk = vNewRef;
|
||||||
|
|
||||||
DROP TEMPORARY TABLE IF EXISTS tmp.updateInter;
|
DROP TEMPORARY TABLE IF EXISTS tmp.updateInter;
|
||||||
CREATE TEMPORARY TABLE tmp.updateInter ENGINE = MEMORY
|
CREATE TEMPORARY TABLE tmp.updateInter ENGINE = MEMORY
|
||||||
SELECT s.id,ti.id ticket_id,vWorker Id_Trabajador
|
SELECT s.id,ti.id ticket_id,vWorker Id_Trabajador
|
||||||
FROM ticketToInvoice ti
|
FROM tmp.ticketToInvoice ti
|
||||||
LEFT JOIN ticketState ts ON ti.id = ts.ticket
|
LEFT JOIN ticketState ts ON ti.id = ts.ticket
|
||||||
JOIN state s
|
JOIN state s
|
||||||
WHERE IFNULL(ts.alertLevel,0) < 3 and s.`code` = getAlert3State(ti.id);
|
WHERE IFNULL(ts.alertLevel,0) < 3 and s.`code` = getAlert3State(ti.id);
|
||||||
|
@ -56609,7 +56609,7 @@ BEGIN
|
||||||
|
|
||||||
INSERT INTO ticketLog (action, userFk, originFk, description)
|
INSERT INTO ticketLog (action, userFk, originFk, description)
|
||||||
SELECT 'UPDATE', account.myUser_getId(), ti.id, CONCAT('Crea factura ', vNewRef)
|
SELECT 'UPDATE', account.myUser_getId(), ti.id, CONCAT('Crea factura ', vNewRef)
|
||||||
FROM ticketToInvoice ti;
|
FROM tmp.ticketToInvoice ti;
|
||||||
|
|
||||||
CALL invoiceExpenceMake(vNewInvoiceId);
|
CALL invoiceExpenceMake(vNewInvoiceId);
|
||||||
CALL invoiceTaxMake(vNewInvoiceId,vTaxArea);
|
CALL invoiceTaxMake(vNewInvoiceId,vTaxArea);
|
||||||
|
@ -56647,7 +56647,7 @@ BEGIN
|
||||||
(KEY (ticketFk))
|
(KEY (ticketFk))
|
||||||
ENGINE = MEMORY
|
ENGINE = MEMORY
|
||||||
SELECT id ticketFk
|
SELECT id ticketFk
|
||||||
FROM ticketToInvoice;
|
FROM tmp.ticketToInvoice;
|
||||||
|
|
||||||
CALL `ticket_getTax`('NATIONAL');
|
CALL `ticket_getTax`('NATIONAL');
|
||||||
|
|
||||||
|
@ -56725,7 +56725,7 @@ BEGIN
|
||||||
DROP TEMPORARY TABLE tmp.ticketServiceTax;
|
DROP TEMPORARY TABLE tmp.ticketServiceTax;
|
||||||
END IF;
|
END IF;
|
||||||
END IF;
|
END IF;
|
||||||
DROP TEMPORARY TABLE `ticketToInvoice`;
|
DROP TEMPORARY TABLE `tmp`.`ticketToInvoice`;
|
||||||
END ;;
|
END ;;
|
||||||
DELIMITER ;
|
DELIMITER ;
|
||||||
/*!50003 SET sql_mode = @saved_sql_mode */ ;
|
/*!50003 SET sql_mode = @saved_sql_mode */ ;
|
||||||
|
@ -56876,7 +56876,7 @@ BEGIN
|
||||||
(KEY (ticketFk))
|
(KEY (ticketFk))
|
||||||
ENGINE = MEMORY
|
ENGINE = MEMORY
|
||||||
SELECT id ticketFk
|
SELECT id ticketFk
|
||||||
FROM ticketToInvoice;
|
FROM tmp.ticketToInvoice;
|
||||||
|
|
||||||
CALL ticket_getTax(vTaxArea);
|
CALL ticket_getTax(vTaxArea);
|
||||||
|
|
||||||
|
@ -68689,7 +68689,7 @@ DELIMITER ;
|
||||||
/*!50003 SET character_set_client = @saved_cs_client */ ;
|
/*!50003 SET character_set_client = @saved_cs_client */ ;
|
||||||
/*!50003 SET character_set_results = @saved_cs_results */ ;
|
/*!50003 SET character_set_results = @saved_cs_results */ ;
|
||||||
/*!50003 SET collation_connection = @saved_col_connection */ ;
|
/*!50003 SET collation_connection = @saved_col_connection */ ;
|
||||||
/*!50003 DROP PROCEDURE IF EXISTS `ticketToInvoiceByAddress` */;
|
/*!50003 DROP PROCEDURE IF EXISTS `tmp`.`ticketToInvoiceByAddress` */;
|
||||||
/*!50003 SET @saved_cs_client = @@character_set_client */ ;
|
/*!50003 SET @saved_cs_client = @@character_set_client */ ;
|
||||||
/*!50003 SET @saved_cs_results = @@character_set_results */ ;
|
/*!50003 SET @saved_cs_results = @@character_set_results */ ;
|
||||||
/*!50003 SET @saved_col_connection = @@collation_connection */ ;
|
/*!50003 SET @saved_col_connection = @@collation_connection */ ;
|
||||||
|
@ -68709,9 +68709,9 @@ BEGIN
|
||||||
|
|
||||||
SET vEnded = util.dayEnd(vEnded);
|
SET vEnded = util.dayEnd(vEnded);
|
||||||
|
|
||||||
DROP TEMPORARY TABLE IF EXISTS vn.ticketToInvoice;
|
DROP TEMPORARY TABLE IF EXISTS tmp.ticketToInvoice;
|
||||||
|
|
||||||
CREATE TEMPORARY TABLE vn.ticketToInvoice
|
CREATE TEMPORARY TABLE tmp.ticketToInvoice
|
||||||
SELECT id
|
SELECT id
|
||||||
FROM vn.ticket
|
FROM vn.ticket
|
||||||
WHERE addressFk = vAddress
|
WHERE addressFk = vAddress
|
||||||
|
@ -68745,9 +68745,9 @@ BEGIN
|
||||||
|
|
||||||
SET vEnded = util.dayEnd(vEnded);
|
SET vEnded = util.dayEnd(vEnded);
|
||||||
|
|
||||||
DROP TEMPORARY TABLE IF EXISTS vn.ticketToInvoice;
|
DROP TEMPORARY TABLE IF EXISTS tmp.ticketToInvoice;
|
||||||
|
|
||||||
CREATE TEMPORARY TABLE vn.ticketToInvoice
|
CREATE TEMPORARY TABLE tmp.ticketToInvoice
|
||||||
SELECT id
|
SELECT id
|
||||||
FROM vn.ticket
|
FROM vn.ticket
|
||||||
WHERE clientFk = vClient
|
WHERE clientFk = vClient
|
||||||
|
@ -68808,9 +68808,9 @@ BEGIN
|
||||||
JOIN vn.client c ON c.id = io.clientFk
|
JOIN vn.client c ON c.id = io.clientFk
|
||||||
WHERE io.id = vInvoice;
|
WHERE io.id = vInvoice;
|
||||||
|
|
||||||
DROP TEMPORARY TABLE IF EXISTS vn.ticketToInvoice;
|
DROP TEMPORARY TABLE IF EXISTS tmp.ticketToInvoice;
|
||||||
|
|
||||||
CREATE TEMPORARY TABLE vn.ticketToInvoice
|
CREATE TEMPORARY TABLE tmp.ticketToInvoice
|
||||||
SELECT id
|
SELECT id
|
||||||
FROM vn.ticket
|
FROM vn.ticket
|
||||||
WHERE refFk = vInvoiceRef;
|
WHERE refFk = vInvoiceRef;
|
||||||
|
|
|
@ -68,6 +68,7 @@ TABLES=(
|
||||||
time
|
time
|
||||||
volumeConfig
|
volumeConfig
|
||||||
workCenter
|
workCenter
|
||||||
|
companyI18n
|
||||||
)
|
)
|
||||||
dump_tables ${TABLES[@]}
|
dump_tables ${TABLES[@]}
|
||||||
|
|
||||||
|
|
|
@ -218,6 +218,23 @@ let actions = {
|
||||||
return handle.jsonValue();
|
return handle.jsonValue();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getValue: async function(selector) {
|
||||||
|
return await this.waitToGetProperty(selector, 'value');
|
||||||
|
},
|
||||||
|
|
||||||
|
getValues: async function(selectorMap) {
|
||||||
|
const values = {};
|
||||||
|
for (const key in selectorMap)
|
||||||
|
values[key] = await this.waitToGetProperty(selectorMap[key], 'value');
|
||||||
|
return values;
|
||||||
|
},
|
||||||
|
|
||||||
|
innerText: async function(selector) {
|
||||||
|
const element = await this.$(selector);
|
||||||
|
const handle = await element.getProperty('innerText');
|
||||||
|
return handle.jsonValue();
|
||||||
|
},
|
||||||
|
|
||||||
waitPropertyLength: async function(selector, property, minLength) {
|
waitPropertyLength: async function(selector, property, minLength) {
|
||||||
await this.waitForFunction((selector, property, minLength) => {
|
await this.waitForFunction((selector, property, minLength) => {
|
||||||
const element = document.querySelector(selector);
|
const element = document.querySelector(selector);
|
||||||
|
|
|
@ -283,12 +283,6 @@ export default {
|
||||||
cancelEditAddressButton: 'vn-client-address-edit > form > vn-button-bar > vn-button > button',
|
cancelEditAddressButton: 'vn-client-address-edit > form > vn-button-bar > vn-button > button',
|
||||||
watcher: 'vn-client-address-edit vn-watcher'
|
watcher: 'vn-client-address-edit vn-watcher'
|
||||||
},
|
},
|
||||||
clientWebAccess: {
|
|
||||||
enableWebAccessCheckbox: 'vn-check[label="Enable web access"]',
|
|
||||||
userName: 'vn-client-web-access vn-textfield[ng-model="$ctrl.account.name"]',
|
|
||||||
email: 'vn-client-web-access vn-textfield[ng-model="$ctrl.account.email"]',
|
|
||||||
saveButton: 'button[type=submit]'
|
|
||||||
},
|
|
||||||
clientNotes: {
|
clientNotes: {
|
||||||
addNoteFloatButton: 'vn-float-button',
|
addNoteFloatButton: 'vn-float-button',
|
||||||
note: 'vn-textarea[ng-model="$ctrl.note.text"]',
|
note: 'vn-textarea[ng-model="$ctrl.note.text"]',
|
||||||
|
@ -312,15 +306,6 @@ export default {
|
||||||
clientMandate: {
|
clientMandate: {
|
||||||
firstMandateText: 'vn-client-mandate vn-card vn-table vn-tbody > vn-tr'
|
firstMandateText: 'vn-client-mandate vn-card vn-table vn-tbody > vn-tr'
|
||||||
},
|
},
|
||||||
clientLog: {
|
|
||||||
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: {
|
clientBalance: {
|
||||||
company: 'vn-client-balance-index vn-autocomplete[ng-model="$ctrl.companyId"]',
|
company: 'vn-client-balance-index vn-autocomplete[ng-model="$ctrl.companyId"]',
|
||||||
newPaymentButton: `vn-float-button`,
|
newPaymentButton: `vn-float-button`,
|
||||||
|
@ -755,6 +740,7 @@ export default {
|
||||||
anyDocument: 'vn-ticket-dms-index > vn-data-viewer vn-tbody vn-tr'
|
anyDocument: 'vn-ticket-dms-index > vn-data-viewer vn-tbody vn-tr'
|
||||||
},
|
},
|
||||||
ticketFuture: {
|
ticketFuture: {
|
||||||
|
searchResult: 'vn-ticket-future tbody tr',
|
||||||
openAdvancedSearchButton: 'vn-searchbar .append vn-icon[icon="arrow_drop_down"]',
|
openAdvancedSearchButton: 'vn-searchbar .append vn-icon[icon="arrow_drop_down"]',
|
||||||
originDated: 'vn-date-picker[label="Origin date"]',
|
originDated: 'vn-date-picker[label="Origin date"]',
|
||||||
futureDated: 'vn-date-picker[label="Destination date"]',
|
futureDated: 'vn-date-picker[label="Destination date"]',
|
||||||
|
@ -770,7 +756,6 @@ export default {
|
||||||
problems: 'vn-check[label="With problems"]',
|
problems: 'vn-check[label="With problems"]',
|
||||||
tableButtonSearch: 'vn-button[vn-tooltip="Search"]',
|
tableButtonSearch: 'vn-button[vn-tooltip="Search"]',
|
||||||
moveButton: 'vn-button[vn-tooltip="Future tickets"]',
|
moveButton: 'vn-button[vn-tooltip="Future tickets"]',
|
||||||
acceptButton: '.vn-confirm.shown button[response="accept"]',
|
|
||||||
firstCheck: 'tbody > tr:nth-child(1) > td > vn-check',
|
firstCheck: 'tbody > tr:nth-child(1) > td > vn-check',
|
||||||
multiCheck: 'vn-multi-check',
|
multiCheck: 'vn-multi-check',
|
||||||
tableId: 'vn-textfield[name="id"]',
|
tableId: 'vn-textfield[name="id"]',
|
||||||
|
@ -1361,18 +1346,6 @@ export default {
|
||||||
notes: 'vn-supplier-basic-data vn-textarea[ng-model="$ctrl.supplier.note"]',
|
notes: 'vn-supplier-basic-data vn-textarea[ng-model="$ctrl.supplier.note"]',
|
||||||
saveButton: 'vn-supplier-basic-data button[type="submit"]',
|
saveButton: 'vn-supplier-basic-data button[type="submit"]',
|
||||||
},
|
},
|
||||||
supplierFiscalData: {
|
|
||||||
socialName: 'vn-supplier-fiscal-data vn-textfield[ng-model="$ctrl.supplier.name"]',
|
|
||||||
taxNumber: 'vn-supplier-fiscal-data vn-textfield[ng-model="$ctrl.supplier.nif"]',
|
|
||||||
account: 'vn-supplier-fiscal-data vn-textfield[ng-model="$ctrl.supplier.account"]',
|
|
||||||
sageTaxType: 'vn-supplier-fiscal-data vn-autocomplete[ng-model="$ctrl.supplier.sageTaxTypeFk"]',
|
|
||||||
sageWihholding: 'vn-supplier-fiscal-data vn-autocomplete[ng-model="$ctrl.supplier.sageWithholdingFk"]',
|
|
||||||
postCode: 'vn-supplier-fiscal-data vn-datalist[ng-model="$ctrl.supplier.postCode"]',
|
|
||||||
city: 'vn-supplier-fiscal-data vn-datalist[ng-model="$ctrl.supplier.city"]',
|
|
||||||
province: 'vn-supplier-fiscal-data vn-autocomplete[ng-model="$ctrl.supplier.provinceFk"]',
|
|
||||||
country: 'vn-supplier-fiscal-data vn-autocomplete[ng-model="$ctrl.supplier.countryFk"]',
|
|
||||||
saveButton: 'vn-supplier-fiscal-data button[type="submit"]',
|
|
||||||
},
|
|
||||||
supplierBillingData: {
|
supplierBillingData: {
|
||||||
payMethod: 'vn-supplier-billing-data vn-autocomplete[ng-model="$ctrl.supplier.payMethodFk"]',
|
payMethod: 'vn-supplier-billing-data vn-autocomplete[ng-model="$ctrl.supplier.payMethodFk"]',
|
||||||
payDem: 'vn-supplier-billing-data vn-autocomplete[ng-model="$ctrl.supplier.payDemFk"]',
|
payDem: 'vn-supplier-billing-data vn-autocomplete[ng-model="$ctrl.supplier.payDemFk"]',
|
||||||
|
|
|
@ -81,9 +81,7 @@ describe('SmartTable SearchBar integration', () => {
|
||||||
await page.accessToSection('item.fixedPrice');
|
await page.accessToSection('item.fixedPrice');
|
||||||
await page.keyboard.press('Enter');
|
await page.keyboard.press('Enter');
|
||||||
|
|
||||||
const result = await page.waitToGetProperty(selectors.itemFixedPrice.firstItemID, 'value');
|
await page.waitForTextInField(selectors.itemFixedPrice.firstItemID, '1');
|
||||||
|
|
||||||
expect(result).toEqual('1');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should order by last id, reload page and have same order', async() => {
|
it('should order by last id, reload page and have same order', async() => {
|
||||||
|
@ -91,9 +89,7 @@ describe('SmartTable SearchBar integration', () => {
|
||||||
await page.reload({
|
await page.reload({
|
||||||
waitUntil: 'networkidle2'
|
waitUntil: 'networkidle2'
|
||||||
});
|
});
|
||||||
const result = await page.waitToGetProperty(selectors.itemFixedPrice.firstItemID, 'value');
|
await page.waitForTextInField(selectors.itemFixedPrice.firstItemID, '13');
|
||||||
|
|
||||||
expect(result).toEqual('13');
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,88 +1,56 @@
|
||||||
/* eslint max-len: ["error", { "code": 150 }]*/
|
|
||||||
import selectors from '../../helpers/selectors';
|
|
||||||
import getBrowser from '../../helpers/puppeteer';
|
import getBrowser from '../../helpers/puppeteer';
|
||||||
|
|
||||||
describe('Client Edit web access path', () => {
|
const $ = {
|
||||||
|
enableWebAccess: 'vn-client-web-access vn-check[label="Enable web access"]',
|
||||||
|
userName: 'vn-client-web-access vn-textfield[ng-model="$ctrl.account.name"]',
|
||||||
|
email: 'vn-client-web-access vn-textfield[ng-model="$ctrl.account.email"]',
|
||||||
|
saveButton: 'vn-client-web-access button[type=submit]',
|
||||||
|
nameValue: 'vn-client-log .change:nth-child(1) .basic-json:nth-child(1) vn-json-value',
|
||||||
|
activeValue: 'vn-client-log .change:nth-child(2) .basic-json:nth-child(2) vn-json-value'
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('Client web access path', () => {
|
||||||
let browser;
|
let browser;
|
||||||
let page;
|
let page;
|
||||||
|
|
||||||
beforeAll(async() => {
|
beforeAll(async() => {
|
||||||
browser = await getBrowser();
|
browser = await getBrowser();
|
||||||
page = browser.page;
|
page = browser.page;
|
||||||
await page.loginAndModule('salesPerson', 'client');
|
await page.loginAndModule('salesPerson', 'client');
|
||||||
await page.accessToSearchResult('max');
|
await page.accessToSearchResult('max');
|
||||||
await page.accessToSection('client.card.webAccess');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async() => {
|
afterAll(async() => {
|
||||||
await browser.close();
|
await browser.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should uncheck the Enable web access checkbox', async() => {
|
it('should modify and save web access attributes', async() => {
|
||||||
await page.waitToClick(selectors.clientWebAccess.enableWebAccessCheckbox);
|
await page.accessToSection('client.card.webAccess');
|
||||||
await page.waitToClick(selectors.clientWebAccess.saveButton);
|
await page.click($.enableWebAccess);
|
||||||
const message = await page.waitForSnackbar();
|
await page.click($.saveButton);
|
||||||
|
const enableMessage = await page.waitForSnackbar();
|
||||||
|
await page.overwrite($.userName, 'Legion');
|
||||||
|
await page.overwrite($.email, 'legion@marvel.com');
|
||||||
|
await page.click($.saveButton);
|
||||||
|
const modifyMessage = await page.waitForSnackbar();
|
||||||
|
|
||||||
expect(message.text).toContain('Data saved!');
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should update the name`, async() => {
|
|
||||||
await page.clearInput(selectors.clientWebAccess.userName);
|
|
||||||
await page.write(selectors.clientWebAccess.userName, 'Legion');
|
|
||||||
await page.waitToClick(selectors.clientWebAccess.saveButton);
|
|
||||||
const message = await page.waitForSnackbar();
|
|
||||||
|
|
||||||
expect(message.text).toContain('Data saved!');
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should update the email`, async() => {
|
|
||||||
await page.clearInput(selectors.clientWebAccess.email);
|
|
||||||
await page.write(selectors.clientWebAccess.email, 'legion@marvel.com');
|
|
||||||
await page.waitToClick(selectors.clientWebAccess.saveButton);
|
|
||||||
const message = await page.waitForSnackbar();
|
|
||||||
|
|
||||||
expect(message.text).toContain('Data saved!');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should reload the section and confirm web access is now unchecked', async() => {
|
|
||||||
await page.reloadSection('client.card.webAccess');
|
await page.reloadSection('client.card.webAccess');
|
||||||
const result = await page.checkboxState(selectors.clientWebAccess.enableWebAccessCheckbox);
|
const hasAccess = await page.checkboxState($.enableWebAccess);
|
||||||
|
const userName = await page.getValue($.userName);
|
||||||
|
const email = await page.getValue($.email);
|
||||||
|
|
||||||
expect(result).toBe('unchecked');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should confirm web access name have been updated', async() => {
|
|
||||||
const result = await page.waitToGetProperty(selectors.clientWebAccess.userName, 'value');
|
|
||||||
|
|
||||||
expect(result).toEqual('Legion');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should confirm web access email have been updated', async() => {
|
|
||||||
const result = await page.waitToGetProperty(selectors.clientWebAccess.email, 'value');
|
|
||||||
|
|
||||||
expect(result).toEqual('legion@marvel.com');
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should navigate to the log section`, async() => {
|
|
||||||
await page.accessToSection('client.card.log');
|
await page.accessToSection('client.card.log');
|
||||||
});
|
const logName = await page.innerText($.nameValue);
|
||||||
|
const logActive = await page.innerText($.activeValue);
|
||||||
|
|
||||||
it(`should confirm the last log shows the updated client name and no modifications on active checkbox`, async() => {
|
expect(enableMessage.type).toBe('success');
|
||||||
let namePreviousValue = await page
|
expect(modifyMessage.type).toBe('success');
|
||||||
.waitToGetProperty(selectors.clientLog.namePreviousValue, 'innerText');
|
|
||||||
let nameCurrentValue = await page
|
|
||||||
.waitToGetProperty(selectors.clientLog.nameCurrentValue, 'innerText');
|
|
||||||
|
|
||||||
expect(namePreviousValue).toEqual('MaxEisenhardt');
|
expect(hasAccess).toBe('unchecked');
|
||||||
expect(nameCurrentValue).toEqual('Legion');
|
expect(userName).toEqual('Legion');
|
||||||
});
|
expect(email).toEqual('legion@marvel.com');
|
||||||
|
|
||||||
it(`should confirm the penultimate log shows the updated active and no modifications on client name`, async() => {
|
expect(logName).toEqual('Legion');
|
||||||
let activePreviousValue = await page
|
expect(logActive).toEqual('✗');
|
||||||
.waitToGetProperty(selectors.clientLog.activePreviousValue, 'innerText');
|
|
||||||
let activeCurrentValue = await page
|
|
||||||
.waitToGetProperty(selectors.clientLog.activeCurrentValue, 'innerText');
|
|
||||||
|
|
||||||
expect(activePreviousValue).toEqual('✓');
|
|
||||||
expect(activeCurrentValue).toEqual('✗');
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -246,6 +246,7 @@ describe('Ticket Edit sale path', () => {
|
||||||
it('should select the third sale and create a claim of it', async() => {
|
it('should select the third sale and create a claim of it', async() => {
|
||||||
await page.accessToSearchResult('16');
|
await page.accessToSearchResult('16');
|
||||||
await page.accessToSection('ticket.card.sale');
|
await page.accessToSection('ticket.card.sale');
|
||||||
|
await page.waitToClick(selectors.ticketSales.firstSaleCheckbox);
|
||||||
await page.waitToClick(selectors.ticketSales.thirdSaleCheckbox);
|
await page.waitToClick(selectors.ticketSales.thirdSaleCheckbox);
|
||||||
await page.waitToClick(selectors.ticketSales.moreMenu);
|
await page.waitToClick(selectors.ticketSales.moreMenu);
|
||||||
await page.waitToClick(selectors.ticketSales.moreMenuCreateClaim);
|
await page.waitToClick(selectors.ticketSales.moreMenuCreateClaim);
|
||||||
|
|
|
@ -126,10 +126,11 @@ describe('Ticket Future path', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should check the three last tickets and move to the future', async() => {
|
it('should check the three last tickets and move to the future', async() => {
|
||||||
|
await page.waitForNumberOfElements(selectors.ticketFuture.searchResult, 4);
|
||||||
await page.waitToClick(selectors.ticketFuture.multiCheck);
|
await page.waitToClick(selectors.ticketFuture.multiCheck);
|
||||||
await page.waitToClick(selectors.ticketFuture.firstCheck);
|
await page.waitToClick(selectors.ticketFuture.firstCheck);
|
||||||
await page.waitToClick(selectors.ticketFuture.moveButton);
|
await page.waitToClick(selectors.ticketFuture.moveButton);
|
||||||
await page.waitToClick(selectors.ticketFuture.acceptButton);
|
await page.waitToClick(selectors.globalItems.acceptButton);
|
||||||
const message = await page.waitForSnackbar();
|
const message = await page.waitForSnackbar();
|
||||||
|
|
||||||
expect(message.text).toContain('Tickets moved successfully!');
|
expect(message.text).toContain('Tickets moved successfully!');
|
||||||
|
|
|
@ -35,7 +35,7 @@ describe('InvoiceIn serial path', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should go to index and check if the search-panel has the correct params', async() => {
|
it('should go to index and check if the search-panel has the correct params', async() => {
|
||||||
await page.click(selectors.invoiceInSerial.goToIndex);
|
await page.waitToClick(selectors.invoiceInSerial.goToIndex);
|
||||||
const params = await page.$$(selectors.invoiceInIndex.topbarSearchParams);
|
const params = await page.$$(selectors.invoiceInIndex.topbarSearchParams);
|
||||||
const serial = await params[0].getProperty('title');
|
const serial = await params[0].getProperty('title');
|
||||||
const isBooked = await params[1].getProperty('title');
|
const isBooked = await params[1].getProperty('title');
|
||||||
|
|
|
@ -20,7 +20,6 @@ describe('Entry basic data path', () => {
|
||||||
it('should edit the basic data', async() => {
|
it('should edit the basic data', async() => {
|
||||||
await page.write(selectors.entryBasicData.reference, 'new movement 8');
|
await page.write(selectors.entryBasicData.reference, 'new movement 8');
|
||||||
await page.write(selectors.entryBasicData.invoiceNumber, 'new movement 8');
|
await page.write(selectors.entryBasicData.invoiceNumber, 'new movement 8');
|
||||||
await page.write(selectors.entryBasicData.notes, 'new notes');
|
|
||||||
await page.write(selectors.entryBasicData.observations, ' edited');
|
await page.write(selectors.entryBasicData.observations, ' edited');
|
||||||
await page.autocompleteSearch(selectors.entryBasicData.supplier, 'Plants nick');
|
await page.autocompleteSearch(selectors.entryBasicData.supplier, 'Plants nick');
|
||||||
await page.autocompleteSearch(selectors.entryBasicData.currency, 'eur');
|
await page.autocompleteSearch(selectors.entryBasicData.currency, 'eur');
|
||||||
|
@ -53,12 +52,6 @@ describe('Entry basic data path', () => {
|
||||||
expect(result).toEqual('new movement 8');
|
expect(result).toEqual('new movement 8');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should confirm the note was edited', async() => {
|
|
||||||
const result = await page.waitToGetProperty(selectors.entryBasicData.notes, 'value');
|
|
||||||
|
|
||||||
expect(result).toEqual('new notes');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should confirm the observation was edited', async() => {
|
it('should confirm the observation was edited', async() => {
|
||||||
const result = await page.waitToGetProperty(selectors.entryBasicData.observations, 'value');
|
const result = await page.waitToGetProperty(selectors.entryBasicData.observations, 'value');
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,20 @@
|
||||||
import selectors from '../../helpers/selectors.js';
|
|
||||||
import getBrowser from '../../helpers/puppeteer';
|
import getBrowser from '../../helpers/puppeteer';
|
||||||
|
|
||||||
|
const $ = {
|
||||||
|
saveButton: 'vn-supplier-fiscal-data button[type="submit"]',
|
||||||
|
};
|
||||||
|
const $inputs = {
|
||||||
|
province: 'vn-supplier-fiscal-data [name="province"]',
|
||||||
|
country: 'vn-supplier-fiscal-data [name="country"]',
|
||||||
|
postcode: 'vn-supplier-fiscal-data [name="postcode"]',
|
||||||
|
city: 'vn-supplier-fiscal-data [name="city"]',
|
||||||
|
socialName: 'vn-supplier-fiscal-data [name="socialName"]',
|
||||||
|
taxNumber: 'vn-supplier-fiscal-data [name="taxNumber"]',
|
||||||
|
account: 'vn-supplier-fiscal-data [name="account"]',
|
||||||
|
sageWithholding: 'vn-supplier-fiscal-data [ng-model="$ctrl.supplier.sageWithholdingFk"]',
|
||||||
|
sageTaxType: 'vn-supplier-fiscal-data [ng-model="$ctrl.supplier.sageTaxTypeFk"]'
|
||||||
|
};
|
||||||
|
|
||||||
describe('Supplier fiscal data path', () => {
|
describe('Supplier fiscal data path', () => {
|
||||||
let browser;
|
let browser;
|
||||||
let page;
|
let page;
|
||||||
|
@ -10,102 +24,44 @@ describe('Supplier fiscal data path', () => {
|
||||||
page = browser.page;
|
page = browser.page;
|
||||||
await page.loginAndModule('administrative', 'supplier');
|
await page.loginAndModule('administrative', 'supplier');
|
||||||
await page.accessToSearchResult('2');
|
await page.accessToSearchResult('2');
|
||||||
await page.accessToSection('supplier.card.fiscalData');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async() => {
|
afterAll(async() => {
|
||||||
await browser.close();
|
await browser.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should attempt to edit the fiscal data but fail as the tax number is invalid', async() => {
|
it('should attempt to edit the fiscal data and check data is saved', async() => {
|
||||||
await page.clearInput(selectors.supplierFiscalData.city);
|
await page.accessToSection('supplier.card.fiscalData');
|
||||||
await page.clearInput(selectors.supplierFiscalData.province);
|
await page.clearInput($inputs.province);
|
||||||
await page.clearInput(selectors.supplierFiscalData.country);
|
await page.clearInput($inputs.country);
|
||||||
await page.clearInput(selectors.supplierFiscalData.postCode);
|
await page.clearInput($inputs.postcode);
|
||||||
await page.write(selectors.supplierFiscalData.city, 'Valencia');
|
await page.overwrite($inputs.city, 'Valencia');
|
||||||
await page.waitForTimeout(1000); // must repeat this action twice or fails. also #2699 may be a cool solution to this.
|
await page.overwrite($inputs.socialName, 'Farmer King SL');
|
||||||
await page.clearInput(selectors.supplierFiscalData.city);
|
await page.overwrite($inputs.taxNumber, 'Wrong tax number');
|
||||||
await page.write(selectors.supplierFiscalData.city, 'Valencia');
|
await page.overwrite($inputs.account, '0123456789');
|
||||||
await page.clearInput(selectors.supplierFiscalData.socialName);
|
await page.autocompleteSearch($inputs.sageWithholding, 'retencion estimacion objetiva');
|
||||||
await page.write(selectors.supplierFiscalData.socialName, 'Farmer King SL');
|
await page.autocompleteSearch($inputs.sageTaxType, 'operaciones no sujetas');
|
||||||
await page.clearInput(selectors.supplierFiscalData.taxNumber);
|
await page.click($.saveButton);
|
||||||
await page.write(selectors.supplierFiscalData.taxNumber, 'Wrong tax number');
|
const errorMessage = await page.waitForSnackbar();
|
||||||
await page.clearInput(selectors.supplierFiscalData.account);
|
await page.overwrite($inputs.taxNumber, '12345678Z');
|
||||||
await page.write(selectors.supplierFiscalData.account, '0123456789');
|
await page.click($.saveButton);
|
||||||
await page.autocompleteSearch(selectors.supplierFiscalData.sageWihholding, 'retencion estimacion objetiva');
|
const successMessage = await page.waitForSnackbar();
|
||||||
await page.autocompleteSearch(selectors.supplierFiscalData.sageTaxType, 'operaciones no sujetas');
|
|
||||||
|
|
||||||
await page.waitToClick(selectors.supplierFiscalData.saveButton);
|
|
||||||
const message = await page.waitForSnackbar();
|
|
||||||
|
|
||||||
expect(message.text).toContain('Invalid Tax number');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should save the changes as the tax number is valid this time', async() => {
|
|
||||||
await page.clearInput(selectors.supplierFiscalData.taxNumber);
|
|
||||||
await page.write(selectors.supplierFiscalData.taxNumber, '12345678Z');
|
|
||||||
|
|
||||||
await page.waitToClick(selectors.supplierFiscalData.saveButton);
|
|
||||||
const message = await page.waitForSnackbar();
|
|
||||||
|
|
||||||
expect(message.text).toContain('Data saved!');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should reload the section', async() => {
|
|
||||||
await page.reloadSection('supplier.card.fiscalData');
|
await page.reloadSection('supplier.card.fiscalData');
|
||||||
});
|
const values = await page.getValues($inputs);
|
||||||
|
|
||||||
it('should check the socialName was edited', async() => {
|
expect(errorMessage.text).toContain('Invalid Tax number');
|
||||||
const result = await page.waitToGetProperty(selectors.supplierFiscalData.socialName, 'value');
|
expect(successMessage.type).toBe('success');
|
||||||
|
expect(values).toEqual({
|
||||||
expect(result).toEqual('Farmer King SL');
|
province: 'Province one (España)',
|
||||||
});
|
country: 'España',
|
||||||
|
postcode: '46000',
|
||||||
it('should check the taxNumber was edited', async() => {
|
city: 'Valencia',
|
||||||
const result = await page.waitToGetProperty(selectors.supplierFiscalData.taxNumber, 'value');
|
socialName: 'Farmer King SL',
|
||||||
|
taxNumber: '12345678Z',
|
||||||
expect(result).toEqual('12345678Z');
|
account: '0123456789',
|
||||||
});
|
sageWithholding: 'RETENCION ESTIMACION OBJETIVA',
|
||||||
|
sageTaxType: 'Operaciones no sujetas'
|
||||||
it('should check the account was edited', async() => {
|
});
|
||||||
const result = await page.waitToGetProperty(selectors.supplierFiscalData.account, 'value');
|
|
||||||
|
|
||||||
expect(result).toEqual('0123456789');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should check the sageWihholding was edited', async() => {
|
|
||||||
const result = await page.waitToGetProperty(selectors.supplierFiscalData.sageWihholding, 'value');
|
|
||||||
|
|
||||||
expect(result).toEqual('RETENCION ESTIMACION OBJETIVA');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should check the sageTaxType was edited', async() => {
|
|
||||||
const result = await page.waitToGetProperty(selectors.supplierFiscalData.sageTaxType, 'value');
|
|
||||||
|
|
||||||
expect(result).toEqual('Operaciones no sujetas');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should check the postCode was edited', async() => {
|
|
||||||
const result = await page.waitToGetProperty(selectors.supplierFiscalData.postCode, 'value');
|
|
||||||
|
|
||||||
expect(result).toEqual('46000');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should check the city was edited', async() => {
|
|
||||||
const result = await page.waitToGetProperty(selectors.supplierFiscalData.city, 'value');
|
|
||||||
|
|
||||||
expect(result).toEqual('Valencia');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should check the province was edited', async() => {
|
|
||||||
const result = await page.waitToGetProperty(selectors.supplierFiscalData.province, 'value');
|
|
||||||
|
|
||||||
expect(result).toEqual('Province one (España)');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should check the country was edited', async() => {
|
|
||||||
const result = await page.waitToGetProperty(selectors.supplierFiscalData.country, 'value');
|
|
||||||
|
|
||||||
expect(result).toEqual('España');
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -174,7 +174,6 @@ export default class Autocomplete extends Field {
|
||||||
|
|
||||||
refreshDisplayed() {
|
refreshDisplayed() {
|
||||||
let display = '';
|
let display = '';
|
||||||
let hasTemplate = this.$transclude && this.$transclude.isSlotFilled('tplItem');
|
|
||||||
|
|
||||||
if (this._selection && this.showField) {
|
if (this._selection && this.showField) {
|
||||||
if (this.multiple && Array.isArray(this._selection)) {
|
if (this.multiple && Array.isArray(this._selection)) {
|
||||||
|
@ -182,19 +181,8 @@ export default class Autocomplete extends Field {
|
||||||
if (display.length > 0) display += ', ';
|
if (display.length > 0) display += ', ';
|
||||||
display += item[this.showField];
|
display += item[this.showField];
|
||||||
}
|
}
|
||||||
} else {
|
} else
|
||||||
display = this._selection[this.showField];
|
display = this._selection[this.showField];
|
||||||
if (hasTemplate) {
|
|
||||||
let template = this.$transclude(() => {}, null, 'tplItem');
|
|
||||||
const element = template[0];
|
|
||||||
const description = element.querySelector('.text-secondary');
|
|
||||||
if (description) description.remove();
|
|
||||||
|
|
||||||
const displayElement = angular.element(element);
|
|
||||||
const displayText = displayElement.text();
|
|
||||||
display = this.$interpolate(displayText)(this._selection);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.input.value = display;
|
this.input.value = display;
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
<div class="letter">
|
||||||
|
{{::$ctrl.val && $ctrl.val.charAt(0).toUpperCase()}}
|
||||||
|
</div>
|
||||||
|
<div class="image" ng-transclude>
|
||||||
|
</div>
|
|
@ -0,0 +1,63 @@
|
||||||
|
import ngModule from '../../module';
|
||||||
|
import Component from 'core/lib/component';
|
||||||
|
import './style.scss';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays colored avatar based on value.
|
||||||
|
*
|
||||||
|
* @property {*} val The value
|
||||||
|
*/
|
||||||
|
export default class Avatar extends Component {
|
||||||
|
get val() {
|
||||||
|
return this._val;
|
||||||
|
}
|
||||||
|
|
||||||
|
set val(value) {
|
||||||
|
this._val = value;
|
||||||
|
|
||||||
|
const val = value || '';
|
||||||
|
let hash = 0;
|
||||||
|
for (let i = 0; i < val.length; i++)
|
||||||
|
hash += val.charCodeAt(i);
|
||||||
|
const color = '#' + colors[hash % colors.length];
|
||||||
|
|
||||||
|
const el = this.element;
|
||||||
|
el.style.backgroundColor = color;
|
||||||
|
el.title = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ngModule.vnComponent('vnAvatar', {
|
||||||
|
template: require('./index.html'),
|
||||||
|
controller: Avatar,
|
||||||
|
bindings: {
|
||||||
|
val: '@?'
|
||||||
|
},
|
||||||
|
transclude: true
|
||||||
|
});
|
||||||
|
|
||||||
|
const colors = [
|
||||||
|
'e2553d', // Coral
|
||||||
|
'FFA07A', // Salmon
|
||||||
|
'FFDAB9', // Peach
|
||||||
|
'a17077', // Pink
|
||||||
|
'bf0e99', // Pink light
|
||||||
|
'52a500', // Green chartreuse
|
||||||
|
'00aeae', // Cian
|
||||||
|
'b754cf', // Purple middle
|
||||||
|
'8a69cd', // Blue lavender
|
||||||
|
'1fa8a1', // Green ocean
|
||||||
|
'DC143C', // Red crimson
|
||||||
|
'5681cf', // Blue steel
|
||||||
|
'FF1493', // Ping intense
|
||||||
|
'02ba02', // Green lime
|
||||||
|
'1E90FF', // Blue sky
|
||||||
|
'8B008B', // Purple dark
|
||||||
|
'cc7000', // Orange bright
|
||||||
|
'00b5b8', // Turquoise
|
||||||
|
'8B0000', // Red dark
|
||||||
|
'008080', // Green bluish
|
||||||
|
'2F4F4F', // Gray board
|
||||||
|
'7e7e7e', // Gray
|
||||||
|
'5d5d5d', // Gray dark
|
||||||
|
];
|
|
@ -0,0 +1,32 @@
|
||||||
|
@import "variables";
|
||||||
|
|
||||||
|
vn-avatar {
|
||||||
|
display: block;
|
||||||
|
border-radius: 50%;
|
||||||
|
overflow: hidden;
|
||||||
|
height: 36px;
|
||||||
|
width: 36px;
|
||||||
|
font-size: 22px;
|
||||||
|
background-color: $color-main;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
& > * {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
& > .letter {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
& > .image {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
|
||||||
|
& > img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -166,7 +166,7 @@ export default class Field extends FormInput {
|
||||||
if (event.defaultPrevented) return;
|
if (event.defaultPrevented) return;
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
this.field = null;
|
this.field = null;
|
||||||
this.input.dispatchEvent(new Event('change'));
|
this.element.dispatchEvent(new Event('change'));
|
||||||
}
|
}
|
||||||
|
|
||||||
buildInput(type) {
|
buildInput(type) {
|
||||||
|
|
|
@ -17,6 +17,7 @@ import './pagination/pagination';
|
||||||
import './searchbar/searchbar';
|
import './searchbar/searchbar';
|
||||||
import './scroll-up/scroll-up';
|
import './scroll-up/scroll-up';
|
||||||
import './autocomplete';
|
import './autocomplete';
|
||||||
|
import './avatar';
|
||||||
import './button';
|
import './button';
|
||||||
import './button-menu';
|
import './button-menu';
|
||||||
import './calendar';
|
import './calendar';
|
||||||
|
@ -32,6 +33,7 @@ import './float-button';
|
||||||
import './icon-menu';
|
import './icon-menu';
|
||||||
import './icon-button';
|
import './icon-button';
|
||||||
import './input-number';
|
import './input-number';
|
||||||
|
import './json-value';
|
||||||
import './label-value';
|
import './label-value';
|
||||||
import './range';
|
import './range';
|
||||||
import './input-time';
|
import './input-time';
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
import ngModule from '../../module';
|
||||||
|
import Component from 'core/lib/component';
|
||||||
|
import './style.scss';
|
||||||
|
|
||||||
|
const maxStrLen = 50;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays pretty JSON value.
|
||||||
|
*
|
||||||
|
* @property {*} value The value
|
||||||
|
*/
|
||||||
|
export default class Controller extends Component {
|
||||||
|
get value() {
|
||||||
|
return this._value;
|
||||||
|
}
|
||||||
|
|
||||||
|
set value(value) {
|
||||||
|
const wasEmpty = this._value === undefined;
|
||||||
|
this._value = value;
|
||||||
|
|
||||||
|
let text;
|
||||||
|
let cssClass;
|
||||||
|
const type = typeof value;
|
||||||
|
|
||||||
|
if (value == null) {
|
||||||
|
text = '∅';
|
||||||
|
cssClass = 'null';
|
||||||
|
} else {
|
||||||
|
cssClass = type;
|
||||||
|
switch (type) {
|
||||||
|
case 'boolean':
|
||||||
|
text = value ? '✓' : '✗';
|
||||||
|
cssClass = value ? 'true' : 'false';
|
||||||
|
break;
|
||||||
|
case 'string':
|
||||||
|
text = value.length <= maxStrLen
|
||||||
|
? value
|
||||||
|
: value.substring(0, maxStrLen) + '...';
|
||||||
|
break;
|
||||||
|
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';
|
||||||
|
text = this.$filter('date')(value, format);
|
||||||
|
} else
|
||||||
|
text = value;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
text = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const el = this.element;
|
||||||
|
el.textContent = text;
|
||||||
|
el.title = type == 'string' && value.length > maxStrLen ? value : '';
|
||||||
|
|
||||||
|
cssClass = `json-${cssClass}`;
|
||||||
|
if (wasEmpty)
|
||||||
|
el.classList.add(cssClass);
|
||||||
|
else
|
||||||
|
el.classList.replace(this.className, cssClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ngModule.vnComponent('vnJsonValue', {
|
||||||
|
controller: Controller,
|
||||||
|
bindings: {
|
||||||
|
value: '<?'
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,79 @@
|
||||||
|
import './index';
|
||||||
|
|
||||||
|
describe('Component vnJsonValue', () => {
|
||||||
|
let controller;
|
||||||
|
let $scope;
|
||||||
|
let $element;
|
||||||
|
let el;
|
||||||
|
|
||||||
|
beforeEach(ngModule('vnCore'));
|
||||||
|
|
||||||
|
beforeEach(inject(($componentController, $rootScope) => {
|
||||||
|
$scope = $rootScope.$new();
|
||||||
|
$element = angular.element('<vn-json-value></vn-json-value>');
|
||||||
|
controller = $componentController('vnJsonValue', {$element, $scope});
|
||||||
|
el = controller.element;
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('set value()', () => {
|
||||||
|
it('should display null symbol when value is null equivalent', () => {
|
||||||
|
controller.value = null;
|
||||||
|
|
||||||
|
expect(el.textContent).toEqual('∅');
|
||||||
|
expect(el.className).toContain('json-null');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display ballot when value is false', () => {
|
||||||
|
controller.value = false;
|
||||||
|
|
||||||
|
expect(el.textContent).toEqual('✗');
|
||||||
|
expect(el.className).toContain('json-false');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display check when value is true', () => {
|
||||||
|
controller.value = true;
|
||||||
|
|
||||||
|
expect(el.textContent).toEqual('✓');
|
||||||
|
expect(el.className).toContain('json-true');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display string when value is an string', () => {
|
||||||
|
controller.value = 'Foo';
|
||||||
|
|
||||||
|
expect(el.textContent).toEqual('Foo');
|
||||||
|
expect(el.className).toContain('json-string');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display only date when value is date with time set to zero', () => {
|
||||||
|
const date = Date.vnNew();
|
||||||
|
date.setHours(0, 0, 0, 0);
|
||||||
|
controller.value = date;
|
||||||
|
|
||||||
|
expect(el.textContent).toEqual('01/01/2001');
|
||||||
|
expect(el.className).toContain('json-object');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display full date without time when value is date with time', () => {
|
||||||
|
const date = Date.vnNew();
|
||||||
|
date.setHours(15, 45);
|
||||||
|
controller.value = date;
|
||||||
|
|
||||||
|
expect(el.textContent).toEqual('01/01/2001 15:45:00');
|
||||||
|
expect(el.className).toContain('json-object');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display object when value is an object', () => {
|
||||||
|
controller.value = {foo: 'bar'};
|
||||||
|
|
||||||
|
expect(el.textContent).toEqual('[object Object]');
|
||||||
|
expect(el.className).toContain('json-object');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display number when value is a number', () => {
|
||||||
|
controller.value = 2050;
|
||||||
|
|
||||||
|
expect(el.textContent).toEqual('2050');
|
||||||
|
expect(el.className).toContain('json-number');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,23 @@
|
||||||
|
vn-json-value {
|
||||||
|
display: inline;
|
||||||
|
|
||||||
|
&.json-string {
|
||||||
|
color: #d172cc;
|
||||||
|
}
|
||||||
|
&.json-object {
|
||||||
|
color: #d1a572;
|
||||||
|
}
|
||||||
|
&.json-number {
|
||||||
|
color: #85d0ff;
|
||||||
|
}
|
||||||
|
&.json-true {
|
||||||
|
color: #7dc489;
|
||||||
|
}
|
||||||
|
&.json-false {
|
||||||
|
color: #c74949;
|
||||||
|
}
|
||||||
|
&.json-null {
|
||||||
|
color: #cd7c7c;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
}
|
|
@ -41,10 +41,15 @@ vn-table {
|
||||||
display: table-row;
|
display: table-row;
|
||||||
height: 48px;
|
height: 48px;
|
||||||
}
|
}
|
||||||
vn-thead, .vn-thead,
|
& > thead,
|
||||||
vn-tbody, .vn-tbody,
|
& > tbody,
|
||||||
vn-tfoot, .vn-tfoot,
|
& > tfoot,
|
||||||
thead, tbody, tfoot {
|
& > vn-thead,
|
||||||
|
& > vn-tbody,
|
||||||
|
& > vn-tfoot,
|
||||||
|
& > .vn-thead,
|
||||||
|
& > .vn-tbody,
|
||||||
|
& > .vn-tfoot {
|
||||||
& > * {
|
& > * {
|
||||||
display: table-row;
|
display: table-row;
|
||||||
|
|
||||||
|
@ -111,14 +116,14 @@ vn-table {
|
||||||
color: inherit;
|
color: inherit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
a.vn-tbody {
|
& > a.vn-tbody {
|
||||||
&.clickable {
|
&.clickable {
|
||||||
@extend %clickable;
|
@extend %clickable;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
vn-tbody > *,
|
& > vn-tbody > *,
|
||||||
.vn-tbody > *,
|
& > .vn-tbody > *,
|
||||||
tbody > * {
|
& > tbody > * {
|
||||||
border-bottom: $border-thin;
|
border-bottom: $border-thin;
|
||||||
|
|
||||||
&:last-child {
|
&:last-child {
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
$font-size: 11pt;
|
$font-size: 11pt;
|
||||||
$menu-width: 256px;
|
$menu-width: 256px;
|
||||||
$right-menu-width: 318px;
|
|
||||||
$topbar-height: 56px;
|
$topbar-height: 56px;
|
||||||
$mobile-width: 800px;
|
$mobile-width: 800px;
|
||||||
$float-spacing: 20px;
|
$float-spacing: 20px;
|
||||||
|
|
|
@ -88,13 +88,13 @@ vn-layout {
|
||||||
}
|
}
|
||||||
&.right-menu {
|
&.right-menu {
|
||||||
& > vn-topbar > .end {
|
& > vn-topbar > .end {
|
||||||
width: 80px + $right-menu-width;
|
width: 80px + $menu-width;
|
||||||
}
|
}
|
||||||
& > .main-view {
|
& > .main-view {
|
||||||
padding-right: $right-menu-width;
|
padding-right: $menu-width;
|
||||||
}
|
}
|
||||||
[fixed-bottom-right] {
|
[fixed-bottom-right] {
|
||||||
right: $right-menu-width;
|
right: $menu-width;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
& > .main-view {
|
& > .main-view {
|
||||||
|
|
|
@ -3,70 +3,212 @@
|
||||||
url="{{$ctrl.url}}"
|
url="{{$ctrl.url}}"
|
||||||
filter="$ctrl.filter"
|
filter="$ctrl.filter"
|
||||||
link="{originFk: $ctrl.originId}"
|
link="{originFk: $ctrl.originId}"
|
||||||
where="{changedModel: $ctrl.changedModel,
|
where="{changedModel: $ctrl.changedModel, changedModelId: $ctrl.changedModelId}"
|
||||||
changedModelId: $ctrl.changedModelId}"
|
|
||||||
data="$ctrl.logs"
|
data="$ctrl.logs"
|
||||||
limit="20"
|
order="creationDate DESC, id DESC"
|
||||||
|
limit="20">
|
||||||
|
</vn-crud-model>
|
||||||
|
<vn-crud-model
|
||||||
|
url="{{$ctrl.url}}/{{$ctrl.originId}}/models"
|
||||||
|
data="models"
|
||||||
|
order="changedModel"
|
||||||
auto-load="true">
|
auto-load="true">
|
||||||
</vn-crud-model>
|
</vn-crud-model>
|
||||||
<vn-data-viewer model="model" class="vn-w-xl">
|
<vn-data-viewer model="model" class="vn-w-md vn-px-sm">
|
||||||
<vn-card>
|
<div class="change vn-mb-sm" ng-repeat="log in $ctrl.logs">
|
||||||
<vn-table model="model">
|
<div class="user-wrapper">
|
||||||
<vn-thead>
|
<vn-avatar class="vn-mt-xs"
|
||||||
<vn-tr>
|
ng-class="::{system: !log.user}"
|
||||||
<vn-th field="creationDate">Date</vn-th>
|
val="{{::log.user ? log.user.nickname : 'System'}}"
|
||||||
<vn-th field="userFk" shrink>User</vn-th>
|
ng-click="$ctrl.showWorkerDescriptor($event, log)">
|
||||||
<vn-th field="changedModel" ng-if="$ctrl.showModelName" shrink>Model</vn-th>
|
<img
|
||||||
<vn-th field="action" shrink>Action</vn-th>
|
ng-if="::log.user.image"
|
||||||
<vn-th field="changedModelValue" ng-if="$ctrl.showModelName">Name</vn-th>
|
ng-src="/api/Images/user/160x160/{{::log.userFk}}/download?access_token={{::$ctrl.vnToken.token}}">
|
||||||
<vn-th expand>Changes</vn-th>
|
</img>
|
||||||
</vn-tr>
|
</vn-avatar>
|
||||||
</vn-thead>
|
<div class="arrow bg-panel"></div>
|
||||||
<vn-tbody>
|
<div class="line"></div>
|
||||||
<vn-tr ng-repeat="log in $ctrl.logs">
|
</div>
|
||||||
<vn-td shrink-datetime>
|
<vn-card class="detail vn-pa-sm">
|
||||||
{{::log.creationDate | date:'dd/MM/yyyy HH:mm'}}
|
<div class="header vn-mb-sm">
|
||||||
</vn-td>
|
<div
|
||||||
<vn-td>
|
class="date text-secondary text-caption"
|
||||||
<span ng-class="{'link': log.user.worker.id, 'value': !log.user.worker.id}"
|
title="{{::log.creationDate | date:'dd/MM/yyyy HH:mm'}}">
|
||||||
ng-click="$ctrl.showWorkerDescriptor($event, log.user.worker.id)"
|
{{::$ctrl.relativeDate(log.creationDate)}}
|
||||||
translate>{{::log.user.name || 'System' | translate}}
|
</div>
|
||||||
|
<span class="chip" ng-class="::$ctrl.actionsClass[log.action]" translate>
|
||||||
|
{{::$ctrl.actionsText[log.action]}}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="model vn-mb-sm"
|
||||||
|
title="{{::log.changedModelValue}}"
|
||||||
|
ng-if="::log.changedModel || log.changedModelValue">
|
||||||
|
<span class="model-name"
|
||||||
|
ng-if="::$ctrl.showModelName"
|
||||||
|
title="{{::log.changedModel}}">
|
||||||
|
{{::log.changedModelI18n}}
|
||||||
|
</span>
|
||||||
|
<span class="model-id"
|
||||||
|
ng-if="::log.changedModelId">
|
||||||
|
#{{::log.changedModelId}}
|
||||||
|
</span>
|
||||||
|
<span class="model-value">
|
||||||
|
{{::log.changedModelValue}}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="changes"
|
||||||
|
ng-class="::log.props.length ? 'props' : 'no-props'"
|
||||||
|
vn-id="changes">
|
||||||
|
<vn-icon icon="visibility"
|
||||||
|
class="expand-button"
|
||||||
|
ng-click="$ctrl.toggleAttributes(log, changes, true)">
|
||||||
|
</vn-icon>
|
||||||
|
<vn-icon icon="visibility_off"
|
||||||
|
class="shrink-button"
|
||||||
|
ng-click="$ctrl.toggleAttributes(log, changes, false)">
|
||||||
|
</vn-icon>
|
||||||
|
<div class="changes-wrapper">
|
||||||
|
<span ng-if="::log.props.length"
|
||||||
|
class="attributes">
|
||||||
|
<span ng-if="!log.expand" ng-repeat="prop in ::log.props"
|
||||||
|
class="basic-json">
|
||||||
|
<span class="json-field"
|
||||||
|
title="{{::prop.name}}">
|
||||||
|
{{::prop.nameI18n}}:
|
||||||
|
</span>
|
||||||
|
<vn-json-value value="::$ctrl.mainVal(prop, log.action)"></vn-json-value><span ng-if="::!$last">,</span>
|
||||||
</span>
|
</span>
|
||||||
</vn-td>
|
<div ng-if="log.expand"
|
||||||
<vn-td ng-if="$ctrl.showModelName">
|
class="expanded-json">
|
||||||
{{::log.changedModel}}
|
<div ng-repeat="prop in ::log.props">
|
||||||
</vn-td>
|
<span class="json-field"
|
||||||
<vn-td shrink translate>
|
title="{{::prop.name}}">
|
||||||
{{::$ctrl.actionsText[log.action]}}
|
{{::prop.nameI18n}}:
|
||||||
</vn-td>
|
</span>
|
||||||
<vn-td ng-if="$ctrl.showModelName">
|
<vn-json-value value="::$ctrl.mainVal(prop, log.action)"></vn-json-value>
|
||||||
{{::log.changedModelValue}}
|
<span ng-if="::log.action == 'update'">
|
||||||
</vn-td>
|
← <vn-json-value value="::prop.old"></vn-json-value>
|
||||||
<vn-td expand>
|
</span>
|
||||||
<table class="attributes">
|
</div>
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th translate class="field">Field</th>
|
|
||||||
<th translate>Before</th>
|
|
||||||
<th translate>After</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr ng-repeat="prop in ::log.props">
|
|
||||||
<td class="field">{{prop.name}}</td>
|
|
||||||
<td class="before">{{prop.old}}</td>
|
|
||||||
<td class="after">{{prop.new}}</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<div ng-if="log.description != null">
|
|
||||||
{{::log.description}}
|
|
||||||
</div>
|
</div>
|
||||||
</vn-td>
|
</span>
|
||||||
</vn-tr>
|
<span ng-if="::!log.props.length"
|
||||||
</vn-tbody>
|
class="description">
|
||||||
</vn-table>
|
{{::log.description}}
|
||||||
</vn-card>
|
</span>
|
||||||
|
<span ng-if="::!log.description && !log.props.length"
|
||||||
|
class="no-changes"
|
||||||
|
translate>
|
||||||
|
No changes
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</vn-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</vn-data-viewer>
|
</vn-data-viewer>
|
||||||
|
<vn-side-menu side="right">
|
||||||
|
<form vn-vertical
|
||||||
|
ng-model-options="{updateOn: 'change blur'}"
|
||||||
|
class="vn-pa-md filter">
|
||||||
|
<vn-textfield
|
||||||
|
label="Name"
|
||||||
|
ng-model="filter.changedModelValue">
|
||||||
|
</vn-textfield>
|
||||||
|
<vn-vertical>
|
||||||
|
<vn-radio
|
||||||
|
label="All"
|
||||||
|
val="all"
|
||||||
|
ng-model="filter.who">
|
||||||
|
</vn-radio>
|
||||||
|
<vn-radio
|
||||||
|
label="User"
|
||||||
|
val="user"
|
||||||
|
ng-model="filter.who">
|
||||||
|
</vn-radio>
|
||||||
|
<vn-radio
|
||||||
|
label="System"
|
||||||
|
val="system"
|
||||||
|
ng-model="filter.who">
|
||||||
|
</vn-radio>
|
||||||
|
</div>
|
||||||
|
<vn-autocomplete
|
||||||
|
ng-show="filter.who != 'system'"
|
||||||
|
label="User"
|
||||||
|
ng-model="filter.userFk"
|
||||||
|
value-field="id"
|
||||||
|
show-field="nickname"
|
||||||
|
fields="['id', 'name', 'nickname', 'image']"
|
||||||
|
search-function="$ctrl.searchUser($search)"
|
||||||
|
url="{{$ctrl.url}}/{{$ctrl.originId}}/editors"
|
||||||
|
order="nickname">
|
||||||
|
<tpl-item>
|
||||||
|
<div style="display: flex;">
|
||||||
|
<vn-avatar
|
||||||
|
class="vn-mr-sm"
|
||||||
|
val="{{::nickname}}">
|
||||||
|
<img
|
||||||
|
ng-if="::image"
|
||||||
|
ng-src="/api/Images/user/160x160/{{::id}}/download?access_token={{::$ctrl.vnToken.token}}">
|
||||||
|
</img>
|
||||||
|
</vn-avatar>
|
||||||
|
<div>
|
||||||
|
<div>{{::nickname}}</div>
|
||||||
|
<div class="text-secondary text-caption">{{::name}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</tpl-item>
|
||||||
|
</vn-autocomplete>
|
||||||
|
<vn-autocomplete
|
||||||
|
label="Model"
|
||||||
|
ng-model="filter.changedModel"
|
||||||
|
value-field="changedModel"
|
||||||
|
show-field="changedModel"
|
||||||
|
data="models">
|
||||||
|
</vn-autocomplete>
|
||||||
|
<vn-textfield
|
||||||
|
label="Id"
|
||||||
|
ng-model="filter.changedModelId">
|
||||||
|
</vn-textfield>
|
||||||
|
<vn-vertical>
|
||||||
|
<vn-check
|
||||||
|
label="Creates"
|
||||||
|
ng-model="filter.actions.insert">
|
||||||
|
</vn-check>
|
||||||
|
<vn-check
|
||||||
|
label="Updates"
|
||||||
|
ng-model="filter.actions.update">
|
||||||
|
</vn-check>
|
||||||
|
<vn-check
|
||||||
|
label="Deletes"
|
||||||
|
ng-model="filter.actions.delete">
|
||||||
|
</vn-check>
|
||||||
|
<vn-check
|
||||||
|
label="Views"
|
||||||
|
ng-model="filter.actions.select">
|
||||||
|
</vn-check>
|
||||||
|
</div>
|
||||||
|
<vn-date-picker
|
||||||
|
label="Date"
|
||||||
|
ng-model="filter.from">
|
||||||
|
</vn-date-picker>
|
||||||
|
<vn-date-picker
|
||||||
|
label="To"
|
||||||
|
ng-model="filter.to">
|
||||||
|
</vn-date-picker>
|
||||||
|
<vn-button-bar vn-vertical class="vn-mt-sm">
|
||||||
|
<vn-button
|
||||||
|
label="Filter"
|
||||||
|
ng-click="$ctrl.applyFilter(filter)">
|
||||||
|
</vn-button>
|
||||||
|
<vn-button
|
||||||
|
label="Reset"
|
||||||
|
class="flat"
|
||||||
|
ng-click="$ctrl.resetFilter()"
|
||||||
|
ng-if="model.userFilter">
|
||||||
|
</vn-button>
|
||||||
|
</vn-button-bar>
|
||||||
|
</form>
|
||||||
|
</vn-side-menu>
|
||||||
<vn-worker-descriptor-popover vn-id="workerDescriptor">
|
<vn-worker-descriptor-popover vn-id="workerDescriptor">
|
||||||
</vn-worker-descriptor-popover>
|
</vn-worker-descriptor-popover>
|
||||||
|
|
|
@ -13,11 +13,17 @@ export default class Controller extends Section {
|
||||||
delete: 'Deletes',
|
delete: 'Deletes',
|
||||||
select: 'Views'
|
select: 'Views'
|
||||||
};
|
};
|
||||||
|
this.actionsClass = {
|
||||||
|
insert: 'success',
|
||||||
|
update: 'warning',
|
||||||
|
delete: 'alert',
|
||||||
|
select: 'notice'
|
||||||
|
};
|
||||||
this.filter = {
|
this.filter = {
|
||||||
include: [{
|
include: [{
|
||||||
relation: 'user',
|
relation: 'user',
|
||||||
scope: {
|
scope: {
|
||||||
fields: ['name'],
|
fields: ['nickname', 'name', 'image'],
|
||||||
include: {
|
include: {
|
||||||
relation: 'worker',
|
relation: 'worker',
|
||||||
scope: {
|
scope: {
|
||||||
|
@ -27,6 +33,20 @@ export default class Controller extends Section {
|
||||||
},
|
},
|
||||||
}],
|
}],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.dateFilter = this.$filter('date');
|
||||||
|
this.lang = this.$translate.use();
|
||||||
|
this.today = Date.vnNew();
|
||||||
|
this.today.setHours(0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
$postLink() {
|
||||||
|
this.resetFilter();
|
||||||
|
this.$.$watch(
|
||||||
|
() => this.$.filter,
|
||||||
|
() => this.applyFilter(),
|
||||||
|
true
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
get logs() {
|
get logs() {
|
||||||
|
@ -42,6 +62,7 @@ export default class Controller extends Section {
|
||||||
const oldValues = log.oldInstance || empty;
|
const oldValues = log.oldInstance || empty;
|
||||||
const newValues = log.newInstance || empty;
|
const newValues = log.newInstance || empty;
|
||||||
const locale = validations[log.changedModel]?.locale || empty;
|
const locale = validations[log.changedModel]?.locale || empty;
|
||||||
|
log.changedModelI18n = locale.name || log.changedModel;
|
||||||
|
|
||||||
let props = Object.keys(oldValues).concat(Object.keys(newValues));
|
let props = Object.keys(oldValues).concat(Object.keys(newValues));
|
||||||
props = [...new Set(props)];
|
props = [...new Set(props)];
|
||||||
|
@ -49,9 +70,10 @@ export default class Controller extends Section {
|
||||||
log.props = [];
|
log.props = [];
|
||||||
for (const prop of props) {
|
for (const prop of props) {
|
||||||
log.props.push({
|
log.props.push({
|
||||||
name: locale[prop] || prop,
|
name: prop,
|
||||||
old: this.formatValue(oldValues[prop]),
|
nameI18n: locale.columns?.[prop] || prop,
|
||||||
new: this.formatValue(newValues[prop])
|
old: this.castJsonValue(oldValues[prop]),
|
||||||
|
new: this.castJsonValue(newValues[prop])
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,36 +83,112 @@ export default class Controller extends Section {
|
||||||
return !(this.changedModel && this.changedModelId);
|
return !(this.changedModel && this.changedModelId);
|
||||||
}
|
}
|
||||||
|
|
||||||
formatValue(value) {
|
castJsonValue(value) {
|
||||||
let type = typeof value;
|
return typeof value === 'string' && validDate.test(value)
|
||||||
|
? new Date(value)
|
||||||
|
: value;
|
||||||
|
}
|
||||||
|
|
||||||
if (type === 'string' && validDate.test(value)) {
|
mainVal(prop, action) {
|
||||||
value = new Date(value);
|
return action == 'delete' ? prop.old : prop.new;
|
||||||
type = typeof value;
|
}
|
||||||
|
|
||||||
|
toggleAttributes(log, changesEl, force) {
|
||||||
|
log.expand = force;
|
||||||
|
changesEl.classList.toggle('expanded', force);
|
||||||
|
}
|
||||||
|
|
||||||
|
relativeDate(dateVal) {
|
||||||
|
if (dateVal == null) return '';
|
||||||
|
const date = new Date(dateVal);
|
||||||
|
const dateZeroTime = new Date(dateVal);
|
||||||
|
dateZeroTime.setHours(0, 0, 0, 0);
|
||||||
|
const diff = Math.trunc((this.today.getTime() - dateZeroTime.getTime()) / (1000 * 3600 * 24));
|
||||||
|
|
||||||
|
let format;
|
||||||
|
if (diff == 0)
|
||||||
|
format = `'${this.$t('today')}'`;
|
||||||
|
else if (diff == 1)
|
||||||
|
format = `'${this.$t('yesterday')}'`;
|
||||||
|
else if (diff > 1 && diff < 7)
|
||||||
|
format = `'${date.toLocaleDateString(this.lang, {weekday: 'short'})}'`;
|
||||||
|
else if (this.today.getFullYear() == date.getFullYear())
|
||||||
|
format = `d '${date.toLocaleDateString(this.lang, {month: 'short'})}'`;
|
||||||
|
else
|
||||||
|
format = `dd/MM/yyyy`;
|
||||||
|
|
||||||
|
return this.dateFilter(date, `${format} HH:mm`);
|
||||||
|
}
|
||||||
|
|
||||||
|
resetFilter() {
|
||||||
|
this.$.filter = {who: 'all'};
|
||||||
|
}
|
||||||
|
|
||||||
|
applyFilter() {
|
||||||
|
const filter = this.$.filter;
|
||||||
|
|
||||||
|
function getParam(prop, value) {
|
||||||
|
if (value == null || value == '') return null;
|
||||||
|
switch (prop) {
|
||||||
|
case 'changedModelValue':
|
||||||
|
return {[prop]: {like: `%${value}%`}};
|
||||||
|
case 'who':
|
||||||
|
switch (value) {
|
||||||
|
case 'all':
|
||||||
|
return null;
|
||||||
|
case 'user':
|
||||||
|
return {userFk: {neq: null}};
|
||||||
|
case 'system':
|
||||||
|
return {userFk: null};
|
||||||
|
}
|
||||||
|
case 'actions':
|
||||||
|
const inq = [];
|
||||||
|
for (const action in value) {
|
||||||
|
if (value[action])
|
||||||
|
inq.push(action);
|
||||||
|
}
|
||||||
|
return inq.length ? {action: {inq}} : null;
|
||||||
|
case 'from':
|
||||||
|
if (filter.to) {
|
||||||
|
return {creationDate: {gte: value}};
|
||||||
|
} else {
|
||||||
|
const to = new Date(value);
|
||||||
|
to.setHours(23, 59, 59, 999);
|
||||||
|
return {creationDate: {between: [value, to]}};
|
||||||
|
}
|
||||||
|
case 'to':
|
||||||
|
const to = new Date(value);
|
||||||
|
to.setHours(23, 59, 59, 999);
|
||||||
|
return {creationDate: {lte: to}};
|
||||||
|
default:
|
||||||
|
return {[prop]: value};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (type) {
|
const and = [];
|
||||||
case 'boolean':
|
for (const prop in filter) {
|
||||||
return value ? '✓' : '✗';
|
const param = getParam(prop, filter[prop]);
|
||||||
case 'object':
|
if (param) and.push(param);
|
||||||
if (value instanceof Date) {
|
}
|
||||||
const hasZeroTime =
|
|
||||||
value.getHours() === 0 &&
|
const lbFilter = and.length ? {where: {and}} : null;
|
||||||
value.getMinutes() === 0 &&
|
return this.$.model.applyFilter(lbFilter);
|
||||||
value.getSeconds() === 0;
|
}
|
||||||
const format = hasZeroTime ? 'dd/MM/yyyy' : 'dd/MM/yyyy HH:mm:ss';
|
|
||||||
return this.$filter('date')(value, format);
|
searchUser(search) {
|
||||||
}
|
if (/^[0-9]+$/.test(search)) {
|
||||||
else
|
return {id: search};
|
||||||
return value;
|
} else {
|
||||||
default:
|
return {or: [
|
||||||
return value;
|
{name: search},
|
||||||
|
{nickname: {like: `%${search}%`}}
|
||||||
|
]}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
showWorkerDescriptor(event, workerId) {
|
showWorkerDescriptor(event, log) {
|
||||||
if (!workerId) return;
|
if (log.user?.worker)
|
||||||
this.$.workerDescriptor.show(event.target, workerId);
|
this.$.workerDescriptor.show(event.target, log.userFk);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
import './index';
|
||||||
|
|
||||||
|
describe('Salix Component vnLog', () => {
|
||||||
|
let controller;
|
||||||
|
let $scope;
|
||||||
|
let $element;
|
||||||
|
|
||||||
|
beforeEach(ngModule('salix'));
|
||||||
|
|
||||||
|
beforeEach(inject(($componentController, $rootScope) => {
|
||||||
|
$scope = $rootScope.$new();
|
||||||
|
$element = angular.element('<vn-log></vn-log>');
|
||||||
|
controller = $componentController('vnLog', {$element, $scope});
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('relativeDate()', () => {
|
||||||
|
let date;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
date = Date.vnNew();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return empty string when date is null', () => {
|
||||||
|
const ret = controller.relativeDate(null);
|
||||||
|
|
||||||
|
expect(ret).toEqual('');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return empty string when date is undefined', () => {
|
||||||
|
const ret = controller.relativeDate(undefined);
|
||||||
|
|
||||||
|
expect(ret).toEqual('');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return today and time when date is today', () => {
|
||||||
|
const ret = controller.relativeDate(date);
|
||||||
|
|
||||||
|
expect(ret).toEqual('today 12:00');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return yesterday and time when date is yesterday', () => {
|
||||||
|
date.setDate(date.getDate() - 1);
|
||||||
|
const ret = controller.relativeDate(date);
|
||||||
|
|
||||||
|
expect(ret).toEqual('yesterday 12:00');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return abreviated weekday name and time when date is on past week', () => {
|
||||||
|
date.setDate(date.getDate() - 3);
|
||||||
|
const ret = controller.relativeDate(date);
|
||||||
|
|
||||||
|
expect(ret).toEqual('Fri 12:00');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return abreviated month name, day number and time when date is on this year', () => {
|
||||||
|
date.setDate(date.getDate() + 20);
|
||||||
|
const ret = controller.relativeDate(date);
|
||||||
|
|
||||||
|
expect(ret).toEqual('21 Jan 12:00');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return abreviated month name, day number, year and time when date is on different year', () => {
|
||||||
|
date.setDate(date.getDate() - 20);
|
||||||
|
const ret = controller.relativeDate(date);
|
||||||
|
|
||||||
|
expect(ret).toEqual('12/12/2000 12:00');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should convert to date and return string when date is not a Date class instance', () => {
|
||||||
|
const ret = controller.relativeDate(date.toJSON());
|
||||||
|
|
||||||
|
expect(ret).toEqual('today 12:00');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('castJsonValue()', () => {
|
||||||
|
it('should return date when string has valid JSON date format', () => {
|
||||||
|
const now = Date.vnNew();
|
||||||
|
|
||||||
|
const ret = controller.castJsonValue(now.toJSON());
|
||||||
|
|
||||||
|
expect(ret).toBeInstanceOf(Date);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return same value when is string with invalid JSON date format', () => {
|
||||||
|
const ret = controller.castJsonValue('Foo');
|
||||||
|
|
||||||
|
expect(ret).toEqual('Foo');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return same value when is not an string', () => {
|
||||||
|
const ret = controller.castJsonValue(1001);
|
||||||
|
|
||||||
|
expect(ret).toEqual(1001);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -13,3 +13,6 @@ Views: Visualiza
|
||||||
System: Sistema
|
System: Sistema
|
||||||
note: nota
|
note: nota
|
||||||
Changes: Cambios
|
Changes: Cambios
|
||||||
|
No changes: No hay cambios
|
||||||
|
today: hoy
|
||||||
|
yesterday: ayer
|
||||||
|
|
|
@ -1,66 +1,152 @@
|
||||||
@import "variables";
|
@import "variables";
|
||||||
|
|
||||||
vn-log {
|
vn-log {
|
||||||
vn-td {
|
.change {
|
||||||
vertical-align: initial !important;
|
display: flex;
|
||||||
}
|
|
||||||
.changes {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.label {
|
|
||||||
color: $color-font-secondary;
|
|
||||||
}
|
|
||||||
.value {
|
|
||||||
color: $color-font;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 1570px) {
|
& > .user-wrapper {
|
||||||
vn-table .expendable {
|
position: relative;
|
||||||
|
padding-right: 10px;
|
||||||
|
|
||||||
|
& > vn-avatar {
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&.system {
|
||||||
|
background-color: $color-main !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
& > .arrow {
|
||||||
|
height: 8px;
|
||||||
|
width: 8px;
|
||||||
|
position: absolute;
|
||||||
|
transform: rotateY(0deg) rotate(45deg);
|
||||||
|
top: 18px;
|
||||||
|
right: -4px;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
& > .line {
|
||||||
|
position: absolute;
|
||||||
|
background-color: $color-main;
|
||||||
|
width: 2px;
|
||||||
|
left: 17px;
|
||||||
|
z-index: -1;
|
||||||
|
top: 44px;
|
||||||
|
bottom: -8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:last-child > .user-wrapper > .line {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
.changes {
|
.detail {
|
||||||
padding-top: 10px;
|
position: relative;
|
||||||
display: block;
|
flex-grow: 1;
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 2px;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
& > .header {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
& > .chip {
|
||||||
|
padding: 2px 4px;
|
||||||
|
border-radius: 4px;
|
||||||
|
display: inline-block;
|
||||||
|
color: $color-font-bg;
|
||||||
|
|
||||||
|
&.notice {
|
||||||
|
background-color: $color-notice-medium;
|
||||||
|
}
|
||||||
|
&.success {
|
||||||
|
background-color: $color-success-medium;
|
||||||
|
}
|
||||||
|
&.warning {
|
||||||
|
background-color: $color-main-medium;
|
||||||
|
}
|
||||||
|
&.alert {
|
||||||
|
background-color: lighten($color-alert, 5%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.date {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
& > .model {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
& > .model-name {
|
||||||
|
text-transform: capitalize;
|
||||||
|
}
|
||||||
|
& > .model-value {
|
||||||
|
font-style: italic;
|
||||||
|
color: #c7bd2b;
|
||||||
|
}
|
||||||
|
& > .model-id {
|
||||||
|
color: $color-font-secondary;
|
||||||
|
font-size: .9em;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.attributes {
|
.changes {
|
||||||
width: 100%;
|
overflow: hidden;
|
||||||
|
background-color: rgba(255, 255, 255, .05);
|
||||||
|
border-radius: 4px;
|
||||||
|
color: $color-font-secondary;
|
||||||
|
transition: max-height 150ms ease-in-out;
|
||||||
|
max-height: 28px;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
tr {
|
& > .expand-button,
|
||||||
height: 10px;
|
& > .shrink-button {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
&.props {
|
||||||
|
padding-right: 24px;
|
||||||
|
|
||||||
& > td {
|
& > .expand-button,
|
||||||
padding: 2px;
|
& > .shrink-button {
|
||||||
|
position: absolute;
|
||||||
|
top: 6px;
|
||||||
|
right: 8px;
|
||||||
|
font-size: inherit;
|
||||||
|
float: right;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
& > td.field,
|
& > .expand-button {
|
||||||
& > th.field {
|
display: block;
|
||||||
width: 20%;
|
|
||||||
color: gray;
|
|
||||||
}
|
}
|
||||||
& > td.before,
|
&.expanded {
|
||||||
& > th.before,
|
max-height: 500px;
|
||||||
& > td.after,
|
padding-right: 0;
|
||||||
& > th.after {
|
|
||||||
width: 40%;
|
& > .changes-wrapper {
|
||||||
white-space: pre-line;
|
text-overflow: initial;
|
||||||
|
white-space: initial;
|
||||||
|
}
|
||||||
|
& > .shrink-button {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
& > .expand-button {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
& > .changes-wrapper {
|
||||||
|
padding: 4px 6px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
& > .no-changes {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
.json-field {
|
||||||
|
text-transform: capitalize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.ellipsis {
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
max-width: 400px;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
.no-ellipsize,
|
|
||||||
[no-ellipsize] {
|
|
||||||
text-overflow: '';
|
|
||||||
white-space: normal;
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
.alignSpan {
|
|
||||||
overflow: hidden;
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
const mergeFilters = require('vn-loopback/util/filter').mergeFilters;
|
||||||
|
|
||||||
|
module.exports = Self => {
|
||||||
|
Self.remoteMethod('editors', {
|
||||||
|
description: 'Get the list of entity editors',
|
||||||
|
accepts: [
|
||||||
|
{
|
||||||
|
arg: 'id',
|
||||||
|
type: 'integer',
|
||||||
|
description: 'The model id',
|
||||||
|
required: true
|
||||||
|
}, {
|
||||||
|
arg: 'filter',
|
||||||
|
type: 'Object',
|
||||||
|
description: 'The user filter object'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
returns: {
|
||||||
|
type: [Self],
|
||||||
|
root: true
|
||||||
|
},
|
||||||
|
http: {
|
||||||
|
path: `/:id/editors`,
|
||||||
|
verb: 'GET'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Self.editors = async(id, filter) => {
|
||||||
|
const res = await Self.find({
|
||||||
|
fields: ['userFk'],
|
||||||
|
where: {originFk: id}
|
||||||
|
});
|
||||||
|
const userIds = new Set(res.map(x => x.userFk));
|
||||||
|
|
||||||
|
filter = mergeFilters(filter, {
|
||||||
|
where: {id: {inq: [...userIds]}}
|
||||||
|
});
|
||||||
|
return await Self.app.models.VnUser.find(filter);
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,44 @@
|
||||||
|
const mergeFilters = require('vn-loopback/util/filter').mergeFilters;
|
||||||
|
|
||||||
|
module.exports = Self => {
|
||||||
|
Self.remoteMethod('models', {
|
||||||
|
description: 'Get the list of entity models',
|
||||||
|
accepts: [
|
||||||
|
{
|
||||||
|
arg: 'id',
|
||||||
|
type: 'integer',
|
||||||
|
description: 'The model id',
|
||||||
|
required: true
|
||||||
|
}, {
|
||||||
|
arg: 'filter',
|
||||||
|
type: 'Object',
|
||||||
|
description: 'The filter object'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
returns: {
|
||||||
|
type: [Self],
|
||||||
|
root: true
|
||||||
|
},
|
||||||
|
http: {
|
||||||
|
path: `/:id/models`,
|
||||||
|
verb: 'GET'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Self.models = async(id, filter) => {
|
||||||
|
filter = mergeFilters(filter, {
|
||||||
|
fields: ['changedModel'],
|
||||||
|
where: {
|
||||||
|
originFk: id,
|
||||||
|
changedModel: {neq: null}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const res = await Self.find(filter);
|
||||||
|
|
||||||
|
const set = new Set();
|
||||||
|
return res.filter(x => set.has(x.changedModel)
|
||||||
|
? false
|
||||||
|
: set.add(x.changedModel)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
};
|
|
@ -0,0 +1,10 @@
|
||||||
|
|
||||||
|
module.exports = function(Self) {
|
||||||
|
Object.assign(Self, {
|
||||||
|
setup() {
|
||||||
|
Self.super_.setup.call(this);
|
||||||
|
require('../methods/log/editors')(this);
|
||||||
|
require('../methods/log/models')(this);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"name": "Log",
|
||||||
|
"base": "VnModel"
|
||||||
|
}
|
|
@ -28,12 +28,14 @@ module.exports = function(Self) {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Register field ACL validation
|
// Register field ACL validation
|
||||||
/* this.beforeRemote('prototype.patchAttributes', ctx => this.checkUpdateAcls(ctx));
|
/*
|
||||||
|
this.beforeRemote('prototype.patchAttributes', ctx => this.checkUpdateAcls(ctx));
|
||||||
this.beforeRemote('updateAll', ctx => this.checkUpdateAcls(ctx));
|
this.beforeRemote('updateAll', ctx => this.checkUpdateAcls(ctx));
|
||||||
this.beforeRemote('patchOrCreate', ctx => this.checkInsertAcls(ctx));
|
this.beforeRemote('patchOrCreate', ctx => this.checkInsertAcls(ctx));
|
||||||
this.beforeRemote('create', ctx => this.checkInsertAcls(ctx));
|
this.beforeRemote('create', ctx => this.checkInsertAcls(ctx));
|
||||||
this.beforeRemote('replaceById', ctx => this.checkInsertAcls(ctx));
|
this.beforeRemote('replaceById', ctx => this.checkInsertAcls(ctx));
|
||||||
this.beforeRemote('replaceOrCreate', ctx => this.checkInsertAcls(ctx)); */
|
this.beforeRemote('replaceOrCreate', ctx => this.checkInsertAcls(ctx));
|
||||||
|
*/
|
||||||
|
|
||||||
this.remoteMethod('crud', {
|
this.remoteMethod('crud', {
|
||||||
description: `Create, update or/and delete instances from model with a single request`,
|
description: `Create, update or/and delete instances from model with a single request`,
|
||||||
|
|
|
@ -156,18 +156,19 @@
|
||||||
"Component cost not set": "Componente coste no está estabecido",
|
"Component cost not set": "Componente coste no está estabecido",
|
||||||
"Tickets with associated refunds can't be deleted. This ticket is associated with refund Nº 2": "Tickets with associated refunds can't be deleted. This ticket is associated with refund Nº 2",
|
"Tickets with associated refunds can't be deleted. This ticket is associated with refund Nº 2": "Tickets with associated refunds can't be deleted. This ticket is associated with refund Nº 2",
|
||||||
"Description cannot be blank": "Description cannot be blank",
|
"Description cannot be blank": "Description cannot be blank",
|
||||||
"company": "Company",
|
"company": "Company",
|
||||||
"country": "Country",
|
"country": "Country",
|
||||||
"clientId": "Id client",
|
"clientId": "Id client",
|
||||||
"clientSocialName": "Client",
|
"clientSocialName": "Client",
|
||||||
"amount": "Amount",
|
"amount": "Amount",
|
||||||
"taxableBase": "Taxable base",
|
"taxableBase": "Taxable base",
|
||||||
"ticketFk": "Id ticket",
|
"ticketFk": "Id ticket",
|
||||||
"isActive": "Active",
|
"isActive": "Active",
|
||||||
"hasToInvoice": "Invoice",
|
"hasToInvoice": "Invoice",
|
||||||
"isTaxDataChecked": "Data checked",
|
"isTaxDataChecked": "Data checked",
|
||||||
"comercialId": "Id Comercial",
|
"comercialId": "Id Comercial",
|
||||||
"comercialName": "Comercial",
|
"comercialName": "Comercial",
|
||||||
"Added observation": "Added observation",
|
"Added observation": "Added observation",
|
||||||
"Comment added to client": "Comment added to client"
|
"Comment added to client": "Comment added to client",
|
||||||
}
|
"This ticket is already a refund": "This ticket is already a refund"
|
||||||
|
}
|
|
@ -279,15 +279,16 @@
|
||||||
"Comment added to client": "Observación añadida al cliente {{clientFk}}",
|
"Comment added to client": "Observación añadida al cliente {{clientFk}}",
|
||||||
"Cannot create a new claimBeginning from a different ticket": "No se puede crear una línea de reclamación de un ticket diferente al origen",
|
"Cannot create a new claimBeginning from a different ticket": "No se puede crear una línea de reclamación de un ticket diferente al origen",
|
||||||
"company": "Compañía",
|
"company": "Compañía",
|
||||||
"country": "País",
|
"country": "País",
|
||||||
"clientId": "Id cliente",
|
"clientId": "Id cliente",
|
||||||
"clientSocialName": "Cliente",
|
"clientSocialName": "Cliente",
|
||||||
"amount": "Importe",
|
"amount": "Importe",
|
||||||
"taxableBase": "Base",
|
"taxableBase": "Base",
|
||||||
"ticketFk": "Id ticket",
|
"ticketFk": "Id ticket",
|
||||||
"isActive": "Activo",
|
"isActive": "Activo",
|
||||||
"hasToInvoice": "Facturar",
|
"hasToInvoice": "Facturar",
|
||||||
"isTaxDataChecked": "Datos comprobados",
|
"isTaxDataChecked": "Datos comprobados",
|
||||||
"comercialId": "Id comercial",
|
"comercialId": "Id comercial",
|
||||||
"comercialName": "Comercial"
|
"comercialName": "Comercial",
|
||||||
}
|
"Invalid NIF for VIES": "Invalid NIF for VIES"
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
name: mail
|
||||||
|
columns:
|
||||||
|
id: id
|
||||||
|
receiver: receiver
|
||||||
|
replyTo: reply to
|
||||||
|
subject: subject
|
||||||
|
body: body
|
|
@ -0,0 +1,7 @@
|
||||||
|
name: mail
|
||||||
|
columns:
|
||||||
|
id: id
|
||||||
|
receiver: receptor
|
||||||
|
replyTo: responder a
|
||||||
|
subject: asunto
|
||||||
|
body: cuerpo
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "RoleLog",
|
"name": "RoleLog",
|
||||||
"base": "VnModel",
|
"base": "Log",
|
||||||
"options": {
|
"options": {
|
||||||
"mysql": {
|
"mysql": {
|
||||||
"table": "account.roleLog"
|
"table": "account.roleLog"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "UserLog",
|
"name": "UserLog",
|
||||||
"base": "VnModel",
|
"base": "Log",
|
||||||
"options": {
|
"options": {
|
||||||
"mysql": {
|
"mysql": {
|
||||||
"table": "account.userLog"
|
"table": "account.userLog"
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
</vn-crud-model>
|
</vn-crud-model>
|
||||||
<vn-portal slot="topbar">
|
<vn-portal slot="topbar">
|
||||||
<vn-searchbar
|
<vn-searchbar
|
||||||
|
vn-focus
|
||||||
panel="vn-user-search-panel"
|
panel="vn-user-search-panel"
|
||||||
info="Search user by id, name or nickname"
|
info="Search user by id, name or nickname"
|
||||||
model="model"
|
model="model"
|
||||||
|
@ -15,4 +16,4 @@
|
||||||
<vn-portal slot="menu">
|
<vn-portal slot="menu">
|
||||||
<vn-left-menu></vn-left-menu>
|
<vn-left-menu></vn-left-menu>
|
||||||
</vn-portal>
|
</vn-portal>
|
||||||
<ui-view></ui-view>
|
<ui-view></ui-view>
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
name: claim beginning
|
||||||
|
columns:
|
||||||
|
id: id
|
||||||
|
quantity: quantity
|
||||||
|
claimFk: claim
|
||||||
|
saleFk: sale
|
|
@ -0,0 +1,6 @@
|
||||||
|
name: comienzo reclamación
|
||||||
|
columns:
|
||||||
|
id: id
|
||||||
|
quantity: cantidad
|
||||||
|
claimFk: reclamación
|
||||||
|
saleFk: línea
|
|
@ -0,0 +1,9 @@
|
||||||
|
name: claim development
|
||||||
|
columns:
|
||||||
|
id: id
|
||||||
|
claimFk: claim
|
||||||
|
claimResponsibleFk: responsible
|
||||||
|
claimReasonFk: reason
|
||||||
|
claimResultFk: result
|
||||||
|
claimRedeliveryFk: redelivery
|
||||||
|
workerFk: worker
|
|
@ -0,0 +1,9 @@
|
||||||
|
name: desarrollo reclamación
|
||||||
|
columns:
|
||||||
|
id: id
|
||||||
|
claimFk: reclamación
|
||||||
|
claimResponsibleFk: responsable
|
||||||
|
claimReasonFk: motivo
|
||||||
|
claimResultFk: resultado
|
||||||
|
claimRedeliveryFk: reenvío
|
||||||
|
workerFk: trabajador
|
|
@ -0,0 +1,4 @@
|
||||||
|
name: claim dms
|
||||||
|
columns:
|
||||||
|
dmsFk: dms
|
||||||
|
claimFk: claim
|
|
@ -0,0 +1,4 @@
|
||||||
|
name: documento reclamación
|
||||||
|
columns:
|
||||||
|
dmsFk: dms
|
||||||
|
claimFk: reclamación
|
|
@ -0,0 +1,7 @@
|
||||||
|
name: claim end
|
||||||
|
columns:
|
||||||
|
id: id
|
||||||
|
claimFk: claim
|
||||||
|
saleFk: sale
|
||||||
|
workerFk: worker
|
||||||
|
claimDestinationFk: destination
|
|
@ -0,0 +1,7 @@
|
||||||
|
name: final reclamación
|
||||||
|
columns:
|
||||||
|
id: id
|
||||||
|
claimFk: reclamación
|
||||||
|
saleFk: línea
|
||||||
|
workerFk: trabajador
|
||||||
|
claimDestinationFk: destino
|
|
@ -0,0 +1,7 @@
|
||||||
|
name: claim observation
|
||||||
|
columns:
|
||||||
|
id: id
|
||||||
|
claimFk: claim
|
||||||
|
text: text
|
||||||
|
created: created
|
||||||
|
workerFk: worker
|
|
@ -0,0 +1,7 @@
|
||||||
|
name: observación reclamación
|
||||||
|
columns:
|
||||||
|
id: id
|
||||||
|
claimFk: reclamación
|
||||||
|
text: texto
|
||||||
|
created: creado
|
||||||
|
workerFk: tabajador
|
|
@ -0,0 +1,16 @@
|
||||||
|
name: claim
|
||||||
|
columns:
|
||||||
|
id: id
|
||||||
|
observation: observation
|
||||||
|
ticketCreated: ticket created
|
||||||
|
isChargedToMana: charged to mana
|
||||||
|
created: created
|
||||||
|
responsibility: responsibility
|
||||||
|
hasToPickUp: has to pickUp
|
||||||
|
ticketFk: ticket
|
||||||
|
claimStateFk: claim state
|
||||||
|
workerFk: worker
|
||||||
|
packages: packages
|
||||||
|
rma: rma
|
||||||
|
clientFk: client
|
||||||
|
claimFk: claim
|
|
@ -0,0 +1,16 @@
|
||||||
|
name: reclamación
|
||||||
|
columns:
|
||||||
|
id: id
|
||||||
|
observation: observación
|
||||||
|
ticketCreated: ticket creado
|
||||||
|
isChargedToMana: cargado al maná
|
||||||
|
created: creado
|
||||||
|
responsibility: responsabilidad
|
||||||
|
hasToPickUp: es recogida
|
||||||
|
ticketFk: ticket
|
||||||
|
claimStateFk: estado reclamación
|
||||||
|
workerFk: trabajador
|
||||||
|
packages: paquetes
|
||||||
|
rma: rma
|
||||||
|
clientFk: cliente
|
||||||
|
claimFk: reclamación
|
|
@ -109,6 +109,11 @@ module.exports = Self => {
|
||||||
zoneFk: zone.id
|
zoneFk: zone.id
|
||||||
}, myOptions);
|
}, myOptions);
|
||||||
|
|
||||||
|
await models.TicketRefund.create({
|
||||||
|
refundTicketFk: newRefundTicket.id,
|
||||||
|
originalTicketFk: claim.ticket().id
|
||||||
|
}, myOptions);
|
||||||
|
|
||||||
await saveObservation({
|
await saveObservation({
|
||||||
description: `Reclama ticket: ${claim.ticketFk}`,
|
description: `Reclama ticket: ${claim.ticketFk}`,
|
||||||
ticketFk: newRefundTicket.id,
|
ticketFk: newRefundTicket.id,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "ClaimLog",
|
"name": "ClaimLog",
|
||||||
"base": "VnModel",
|
"base": "Log",
|
||||||
"options": {
|
"options": {
|
||||||
"mysql": {
|
"mysql": {
|
||||||
"table": "claimLog"
|
"table": "claimLog"
|
||||||
|
@ -50,7 +50,7 @@
|
||||||
"type": "belongsTo",
|
"type": "belongsTo",
|
||||||
"model": "VnUser",
|
"model": "VnUser",
|
||||||
"foreignKey": "userFk"
|
"foreignKey": "userFk"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"scope": {
|
"scope": {
|
||||||
"order": ["creationDate DESC", "id DESC"]
|
"order": ["creationDate DESC", "id DESC"]
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
value="{{$ctrl.claimedTotal | currency: 'EUR':2}}">
|
value="{{$ctrl.claimedTotal | currency: 'EUR':2}}">
|
||||||
</vn-label-value>
|
</vn-label-value>
|
||||||
</vn-card>
|
</vn-card>
|
||||||
<vn-card class="vn-pa-lg vn-w-lg">
|
<vn-card class="vn-pa-md vn-w-lg">
|
||||||
<smart-table
|
<smart-table
|
||||||
model="model"
|
model="model"
|
||||||
options="$ctrl.smartTableOptions"
|
options="$ctrl.smartTableOptions"
|
||||||
|
@ -31,10 +31,10 @@
|
||||||
translate-attr="{title: 'Imports claim details'}">
|
translate-attr="{title: 'Imports claim details'}">
|
||||||
</vn-button>
|
</vn-button>
|
||||||
<vn-button
|
<vn-button
|
||||||
label="Change destination"
|
label="Change destination"
|
||||||
disabled="$ctrl.checked.length == 0"
|
disabled="$ctrl.checked.length == 0"
|
||||||
ng-click="changeDestination.show()">
|
ng-click="changeDestination.show()">
|
||||||
</vn-button>
|
</vn-button>
|
||||||
<vn-range
|
<vn-range
|
||||||
label="Responsability"
|
label="Responsability"
|
||||||
min-label="Company"
|
min-label="Company"
|
||||||
|
@ -45,15 +45,15 @@
|
||||||
step="1"
|
step="1"
|
||||||
on-change="$ctrl.save({responsibility: value})">
|
on-change="$ctrl.save({responsibility: value})">
|
||||||
</vn-range>
|
</vn-range>
|
||||||
|
<vn-check class="right"
|
||||||
|
vn-one
|
||||||
|
label="Is paid with mana"
|
||||||
|
ng-model="$ctrl.claim.isChargedToMana"
|
||||||
|
on-change="$ctrl.save({isChargedToMana: value})">
|
||||||
|
</vn-check>
|
||||||
</vn-tool-bar>
|
</vn-tool-bar>
|
||||||
<vn-check class="right"
|
|
||||||
vn-one
|
|
||||||
label="Is paid with mana"
|
|
||||||
ng-model="$ctrl.claim.isChargedToMana"
|
|
||||||
on-change="$ctrl.save({isChargedToMana: value})">
|
|
||||||
</vn-check>
|
|
||||||
</section>
|
</section>
|
||||||
</slot-actions>
|
</slot-actions>
|
||||||
<slot-table>
|
<slot-table>
|
||||||
<table model="model">
|
<table model="model">
|
||||||
<thead>
|
<thead>
|
||||||
|
|
|
@ -1,48 +1 @@
|
||||||
<vn-crud-model
|
|
||||||
vn-id="model"
|
|
||||||
auto-load="true"
|
|
||||||
filter="::$ctrl.filter"
|
|
||||||
url="ClaimDms"
|
|
||||||
link="{claimFk: $ctrl.$params.id}"
|
|
||||||
limit="20"
|
|
||||||
data="$ctrl.photos">
|
|
||||||
</vn-crud-model>
|
|
||||||
<vn-horizontal class="photo-list drop-zone" vn-droppable="$ctrl.onDrop($event)">
|
|
||||||
<section class="empty-rows" ng-if="!$ctrl.photos.length">
|
|
||||||
<section><vn-icon icon="image"></vn-icon></section>
|
|
||||||
<section translate>Drag & Drop photos here...</section>
|
|
||||||
</section>
|
|
||||||
<section class="photo" ng-repeat="photo in $ctrl.photos">
|
|
||||||
<section class="image vn-shadow" on-error-src
|
|
||||||
ng-style="{'background': 'url(' + $ctrl.getImagePath(photo.dmsFk) + ')'}"
|
|
||||||
zoom-image="{{$ctrl.getImagePath(photo.dmsFk)}}"
|
|
||||||
ng-if="photo.dms.contentType != 'video/mp4'">
|
|
||||||
</section>
|
|
||||||
<video id="videobcg" muted="muted" controls ng-if="photo.dms.contentType == 'video/mp4'"
|
|
||||||
class="video">
|
|
||||||
<source src="{{$ctrl.getImagePath(photo.dmsFk)}}" type="video/mp4">
|
|
||||||
</video>
|
|
||||||
<section class="actions">
|
|
||||||
<vn-button
|
|
||||||
class="round"
|
|
||||||
ng-click="confirm.show($index)"
|
|
||||||
title="{{'Remove file' | translate}}"
|
|
||||||
tabindex="-1"
|
|
||||||
icon="delete">
|
|
||||||
</vn-button>
|
|
||||||
</section>
|
|
||||||
</section>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-confirm
|
|
||||||
vn-id="confirm"
|
|
||||||
message="This file will be deleted"
|
|
||||||
question="Are you sure you want to continue?"
|
|
||||||
on-accept="$ctrl.deleteDms($data)">
|
|
||||||
</vn-confirm>
|
|
||||||
<vn-float-button
|
|
||||||
icon="add"
|
|
||||||
vn-tooltip="Select file"
|
|
||||||
vn-bind="+"
|
|
||||||
ng-click="$ctrl.openUploadDialog()"
|
|
||||||
fixed-bottom-right>
|
|
||||||
</vn-float-button>
|
|
||||||
|
|
|
@ -1,105 +1,17 @@
|
||||||
import ngModule from '../module';
|
import ngModule from '../module';
|
||||||
import Section from 'salix/components/section';
|
import Section from 'salix/components/section';
|
||||||
import './style.scss';
|
|
||||||
|
|
||||||
class Controller extends Section {
|
class Controller extends Section {
|
||||||
constructor($element, $, vnFile) {
|
constructor($element, $) {
|
||||||
super($element, $);
|
super($element, $);
|
||||||
this.vnFile = vnFile;
|
|
||||||
this.filter = {
|
|
||||||
include: [
|
|
||||||
{
|
|
||||||
relation: 'dms'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteDms(index) {
|
async $onInit() {
|
||||||
const dmsFk = this.photos[index].dmsFk;
|
const url = await this.vnApp.getUrl(`claim/${this.$params.id}/photos`);
|
||||||
return this.$http.post(`ClaimDms/${dmsFk}/removeFile`)
|
window.location.href = url;
|
||||||
.then(() => {
|
|
||||||
this.$.model.remove(index);
|
|
||||||
this.vnApp.showSuccess(this.$t('File deleted'));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onDrop($event) {
|
|
||||||
const files = $event.dataTransfer.files;
|
|
||||||
this.setDefaultParams().then(() => {
|
|
||||||
this.dms.files = files;
|
|
||||||
this.create();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
setDefaultParams() {
|
|
||||||
const filter = {
|
|
||||||
where: {code: 'claim'}
|
|
||||||
};
|
|
||||||
return this.$http.get('DmsTypes/findOne', {filter}).then(res => {
|
|
||||||
const dmsTypeId = res.data && res.data.id;
|
|
||||||
const companyId = this.vnConfig.companyFk;
|
|
||||||
const warehouseId = this.vnConfig.warehouseFk;
|
|
||||||
this.dms = {
|
|
||||||
hasFile: false,
|
|
||||||
hasFileAttached: false,
|
|
||||||
reference: this.claim.id,
|
|
||||||
warehouseId: warehouseId,
|
|
||||||
companyId: companyId,
|
|
||||||
dmsTypeId: dmsTypeId,
|
|
||||||
description: this.$t('FileDescription', {
|
|
||||||
claimId: this.claim.id,
|
|
||||||
clientId: this.claim.client.id,
|
|
||||||
clientName: this.claim.client.name
|
|
||||||
}).toUpperCase()
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
openUploadDialog() {
|
|
||||||
const element = document.createElement('input');
|
|
||||||
element.setAttribute('type', 'file');
|
|
||||||
element.setAttribute('multiple', true);
|
|
||||||
element.click();
|
|
||||||
|
|
||||||
element.addEventListener('change', () =>
|
|
||||||
this.setDefaultParams().then(() => {
|
|
||||||
this.dms.files = element.files;
|
|
||||||
this.create();
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
create() {
|
|
||||||
const query = `claims/${this.claim.id}/uploadFile`;
|
|
||||||
const options = {
|
|
||||||
method: 'POST',
|
|
||||||
url: query,
|
|
||||||
params: this.dms,
|
|
||||||
headers: {'Content-Type': undefined},
|
|
||||||
transformRequest: files => {
|
|
||||||
const formData = new FormData();
|
|
||||||
|
|
||||||
for (let i = 0; i < files.length; i++)
|
|
||||||
formData.append(files[i].name, files[i]);
|
|
||||||
|
|
||||||
return formData;
|
|
||||||
},
|
|
||||||
data: this.dms.files
|
|
||||||
};
|
|
||||||
this.$http(options).then(() => {
|
|
||||||
this.vnApp.showSuccess(this.$t('File uploaded!'));
|
|
||||||
this.$.model.refresh();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getImagePath(dmsId) {
|
|
||||||
return this.vnFile.getPath(`/api/Claims/${dmsId}/downloadFile`);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Controller.$inject = ['$element', '$scope', 'vnFile'];
|
|
||||||
|
|
||||||
ngModule.vnComponent('vnClaimPhotos', {
|
ngModule.vnComponent('vnClaimPhotos', {
|
||||||
template: require('./index.html'),
|
template: require('./index.html'),
|
||||||
controller: Controller,
|
controller: Controller,
|
||||||
|
|
|
@ -1,70 +0,0 @@
|
||||||
import './index';
|
|
||||||
import crudModel from 'core/mocks/crud-model';
|
|
||||||
|
|
||||||
describe('Claim', () => {
|
|
||||||
describe('Component vnClaimPhotos', () => {
|
|
||||||
let $scope;
|
|
||||||
let $httpBackend;
|
|
||||||
let controller;
|
|
||||||
|
|
||||||
beforeEach(ngModule('claim'));
|
|
||||||
|
|
||||||
beforeEach(inject(($componentController, $rootScope, _$httpBackend_) => {
|
|
||||||
$httpBackend = _$httpBackend_;
|
|
||||||
$scope = $rootScope.$new();
|
|
||||||
controller = $componentController('vnClaimPhotos', {$element: null, $scope});
|
|
||||||
controller.$.model = crudModel;
|
|
||||||
controller.claim = {
|
|
||||||
id: 1,
|
|
||||||
client: {id: 1101, name: 'Bruce Wayne'}
|
|
||||||
};
|
|
||||||
}));
|
|
||||||
|
|
||||||
describe('deleteDms()', () => {
|
|
||||||
it('should make an HTTP Post query', () => {
|
|
||||||
jest.spyOn(controller.vnApp, 'showSuccess');
|
|
||||||
jest.spyOn(controller.$.model, 'remove');
|
|
||||||
|
|
||||||
const dmsId = 1;
|
|
||||||
const dmsIndex = 0;
|
|
||||||
controller.photos = [{dmsFk: 1}];
|
|
||||||
|
|
||||||
$httpBackend.expectPOST(`ClaimDms/${dmsId}/removeFile`).respond();
|
|
||||||
controller.deleteDms(dmsIndex);
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(controller.$.model.remove).toHaveBeenCalledWith(dmsIndex);
|
|
||||||
expect(controller.vnApp.showSuccess).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('setDefaultParams()', () => {
|
|
||||||
it('should make an HTTP GET query, then set all dms properties', () => {
|
|
||||||
$httpBackend.expectRoute('GET', `DmsTypes/findOne`).respond({});
|
|
||||||
controller.setDefaultParams();
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(controller.dms).toBeDefined();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('create()', () => {
|
|
||||||
it('should make an HTTP Post query, then refresh the model data', () => {
|
|
||||||
const claimId = 1;
|
|
||||||
const dmsIndex = 0;
|
|
||||||
jest.spyOn(controller.vnApp, 'showSuccess');
|
|
||||||
jest.spyOn(controller.$.model, 'refresh');
|
|
||||||
controller.photos = [{dmsFk: 1}];
|
|
||||||
controller.dmsIndex = dmsIndex;
|
|
||||||
controller.dms = {files: []};
|
|
||||||
|
|
||||||
$httpBackend.expectPOST(`claims/${claimId}/uploadFile`).respond({});
|
|
||||||
controller.create();
|
|
||||||
$httpBackend.flush();
|
|
||||||
|
|
||||||
expect(controller.$.model.refresh).toHaveBeenCalled();
|
|
||||||
expect(controller.vnApp.showSuccess).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,5 +0,0 @@
|
||||||
Are you sure you want to continue?: ¿Seguro que quieres continuar?
|
|
||||||
Drag & Drop photos here...: Arrastra y suelta fotos aquí...
|
|
||||||
File deleted: Archivo eliminado
|
|
||||||
File uploaded!: Archivo subido!
|
|
||||||
Select file: Seleccionar fichero
|
|
|
@ -1,47 +0,0 @@
|
||||||
@import "./variables";
|
|
||||||
|
|
||||||
vn-claim-photos {
|
|
||||||
height: 100%;
|
|
||||||
|
|
||||||
.drop-zone {
|
|
||||||
color: $color-font-secondary;
|
|
||||||
box-sizing: border-box;
|
|
||||||
border-radius: 8px;
|
|
||||||
text-align: center;
|
|
||||||
min-height: 100%;
|
|
||||||
|
|
||||||
.empty-rows {
|
|
||||||
padding: 80px $spacing-md;
|
|
||||||
font-size: 1.375rem
|
|
||||||
}
|
|
||||||
|
|
||||||
vn-icon {
|
|
||||||
font-size: 3rem
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.photo-list {
|
|
||||||
padding: $spacing-md;
|
|
||||||
min-height: 100%;
|
|
||||||
|
|
||||||
.photo {
|
|
||||||
width: 512px;
|
|
||||||
height: 288px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.video {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
object-fit: cover;
|
|
||||||
cursor: pointer;
|
|
||||||
box-shadow: 0 2px 2px 0 rgba(0,0,0,.14),
|
|
||||||
0 3px 1px -2px rgba(0,0,0,.2),
|
|
||||||
0 1px 5px 0 rgba(0,0,0,.12);
|
|
||||||
border: 2px solid transparent;
|
|
||||||
|
|
||||||
}
|
|
||||||
.video:hover {
|
|
||||||
border: 2px solid $color-primary
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
name: address
|
||||||
|
columns:
|
||||||
|
id: id
|
||||||
|
nickname: nickname
|
||||||
|
street: street
|
||||||
|
city: city
|
||||||
|
postalCode: postal code
|
||||||
|
phone: phone
|
||||||
|
mobile: mobile
|
||||||
|
isActive: active
|
||||||
|
longitude: longitude
|
||||||
|
latitude: latitude
|
||||||
|
isEqualizated: equalizated
|
||||||
|
isLogifloraAllowed: logiflora allowed
|
||||||
|
provinceFk: province
|
||||||
|
clientFk: client
|
||||||
|
agencyModeFk: agency
|
||||||
|
addressFk: address
|
||||||
|
incotermsFk: incoterms
|
||||||
|
customsAgentFk: customs agent
|
|
@ -0,0 +1,20 @@
|
||||||
|
name: dirección
|
||||||
|
columns:
|
||||||
|
id: id
|
||||||
|
nickname: apodo
|
||||||
|
street: calle
|
||||||
|
city: ciudad
|
||||||
|
postalCode: código postal
|
||||||
|
phone: teléfono
|
||||||
|
mobile: móvil
|
||||||
|
isActive: activo
|
||||||
|
longitude: longitud
|
||||||
|
latitude: latitud
|
||||||
|
isEqualizated: igualado
|
||||||
|
isLogifloraAllowed: logiflora permitido
|
||||||
|
provinceFk: provincia
|
||||||
|
clientFk: cliente
|
||||||
|
agencyModeFk: agencia
|
||||||
|
addressFk: dirección
|
||||||
|
incotermsFk: incoterms
|
||||||
|
customsAgentFk: agente adunanas
|
|
@ -0,0 +1,6 @@
|
||||||
|
name: client contact
|
||||||
|
columns:
|
||||||
|
id: id
|
||||||
|
name: name
|
||||||
|
phone: phone
|
||||||
|
clientFk: client
|
|
@ -0,0 +1,6 @@
|
||||||
|
name: contacto cliente
|
||||||
|
columns:
|
||||||
|
id: id
|
||||||
|
name: nombre
|
||||||
|
phone: teléfono
|
||||||
|
clientFk: cliente
|
|
@ -0,0 +1,4 @@
|
||||||
|
name: client dms
|
||||||
|
columns:
|
||||||
|
dmsFk: dms
|
||||||
|
clientFk: client
|
|
@ -0,0 +1,4 @@
|
||||||
|
name: documento cliente
|
||||||
|
columns:
|
||||||
|
dmsFk: dms
|
||||||
|
clientFk: client
|
|
@ -0,0 +1,7 @@
|
||||||
|
name: client observation
|
||||||
|
columns:
|
||||||
|
id: id
|
||||||
|
clientFk: client
|
||||||
|
text: text
|
||||||
|
created: created
|
||||||
|
workerFk: worker
|
|
@ -0,0 +1,7 @@
|
||||||
|
name: observación cliente
|
||||||
|
columns:
|
||||||
|
id: id
|
||||||
|
clientFk: cliente
|
||||||
|
text: texto
|
||||||
|
created: creado
|
||||||
|
workerFk: trabajador
|
|
@ -0,0 +1,8 @@
|
||||||
|
name: client sample
|
||||||
|
columns:
|
||||||
|
id: id
|
||||||
|
created: created
|
||||||
|
clientFk: client
|
||||||
|
typeFk: type
|
||||||
|
userFk: user
|
||||||
|
companyFk: company
|
|
@ -0,0 +1,8 @@
|
||||||
|
name: muestra cliente
|
||||||
|
columns:
|
||||||
|
id: id
|
||||||
|
created: creado
|
||||||
|
clientFk: cliente
|
||||||
|
typeFk: tipo
|
||||||
|
userFk: usuario
|
||||||
|
companyFk: compañia
|
|
@ -0,0 +1,50 @@
|
||||||
|
name: client
|
||||||
|
columns:
|
||||||
|
id: id
|
||||||
|
name: name
|
||||||
|
fi: fi
|
||||||
|
socialName: socialName
|
||||||
|
contact: contact
|
||||||
|
street: street
|
||||||
|
city: city
|
||||||
|
postcode: postcode
|
||||||
|
email: email
|
||||||
|
phone: phone
|
||||||
|
mobile: mobile
|
||||||
|
isActive: active
|
||||||
|
credit: credit
|
||||||
|
creditInsurance: credit insurance
|
||||||
|
iban: iban
|
||||||
|
dueDay: due day
|
||||||
|
isEqualizated: equalizated
|
||||||
|
isFreezed: freezed
|
||||||
|
hasToInvoiceByAddress: invoice by address
|
||||||
|
hasToInvoice: has to invoice
|
||||||
|
isToBeMailed: be mailed
|
||||||
|
hasSepaVnl: sepa nnl
|
||||||
|
hasLcr: lcr
|
||||||
|
hasCoreVnl: core vnl
|
||||||
|
hasCoreVnh: core vnh
|
||||||
|
hasIncoterms: incoterms
|
||||||
|
isTaxDataChecked: tax data checked
|
||||||
|
eypbc: eypbc
|
||||||
|
quality: quality
|
||||||
|
isVies: vies
|
||||||
|
isRelevant: relevant
|
||||||
|
accountingAccount: accounting account
|
||||||
|
created: created
|
||||||
|
sageTaxTypeFk: sage tax type
|
||||||
|
sageTransactionTypeFk: sage transaction type
|
||||||
|
businessTypeFk: business type
|
||||||
|
salesPersonFk: sales person
|
||||||
|
hasElectronicInvoice: electronic invoice
|
||||||
|
payMethodFk: pay method
|
||||||
|
provinceFk: province
|
||||||
|
countryFk: country
|
||||||
|
contactChannelFk: contact channel
|
||||||
|
clientTypeFk: client type
|
||||||
|
clientFk: client
|
||||||
|
defaultAddressFk: default address
|
||||||
|
bankEntityFk: bank entity
|
||||||
|
transferorFk: transferor
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
name: cliente
|
||||||
|
columns:
|
||||||
|
id: id
|
||||||
|
name: nombre
|
||||||
|
fi: fi
|
||||||
|
socialName: nombre social
|
||||||
|
contact: contacto
|
||||||
|
street: calle
|
||||||
|
city: ciudad
|
||||||
|
postcode: código postal
|
||||||
|
email: email
|
||||||
|
phone: teléfono
|
||||||
|
mobile: móvil
|
||||||
|
isActive: activo
|
||||||
|
credit: crédito
|
||||||
|
creditInsurance: seguro crédito
|
||||||
|
iban: iban
|
||||||
|
dueDay: día vencimiento
|
||||||
|
isEqualizated: igualado
|
||||||
|
isFreezed: congelado
|
||||||
|
hasToInvoiceByAddress: factura por dirección
|
||||||
|
hasToInvoice: tiene que facturar
|
||||||
|
isToBeMailed: envío por email
|
||||||
|
hasSepaVnl: sepa nnl
|
||||||
|
hasLcr: lcr
|
||||||
|
hasCoreVnl: centro vnl
|
||||||
|
hasCoreVnh: cenrto vnh
|
||||||
|
hasIncoterms: incoterms
|
||||||
|
isTaxDataChecked: datos fiscales comprobados
|
||||||
|
eypbc: eypbc
|
||||||
|
quality: calidad
|
||||||
|
isVies: vies
|
||||||
|
isRelevant: importante
|
||||||
|
accountingAccount: cuenta contable
|
||||||
|
created: creado
|
||||||
|
sageTaxTypeFk: tipo impuesto sage
|
||||||
|
sageTransactionTypeFk: tipo transacción sage
|
||||||
|
businessTypeFk: tipo negocio
|
||||||
|
salesPersonFk: comercial
|
||||||
|
hasElectronicInvoice: factura electrónica
|
||||||
|
payMethodFk: método pago
|
||||||
|
provinceFk: provincia
|
||||||
|
countryFk: país
|
||||||
|
contactChannelFk: canal de contacto
|
||||||
|
clientTypeFk: tipo de cliente
|
||||||
|
clientFk: cliente
|
||||||
|
defaultAddressFk: dirección predeterminada
|
||||||
|
bankEntityFk: entidad bancaria
|
||||||
|
transferorFk: cedente
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
name: greuge
|
||||||
|
columns:
|
||||||
|
id: id
|
||||||
|
description: description
|
||||||
|
amount: amount
|
||||||
|
shipped: shipped
|
||||||
|
created: created
|
||||||
|
greugeTypeFk: greuge type
|
||||||
|
clientFk: client
|
||||||
|
ticketFk: ticket
|
||||||
|
userFk: user
|
|
@ -0,0 +1,11 @@
|
||||||
|
name: greuge
|
||||||
|
columns:
|
||||||
|
id: id
|
||||||
|
description: descripción
|
||||||
|
amount: cantidad
|
||||||
|
shipped: enviado
|
||||||
|
created: creado
|
||||||
|
greugeTypeFk: tipo de greuge
|
||||||
|
clientFk: cliente
|
||||||
|
ticketFk: ticket
|
||||||
|
userFk: usuario
|
|
@ -0,0 +1,8 @@
|
||||||
|
name: recovery
|
||||||
|
columns:
|
||||||
|
id: id
|
||||||
|
started: started
|
||||||
|
finished: finished
|
||||||
|
amount: amount
|
||||||
|
period: period
|
||||||
|
clientFk: client
|
|
@ -0,0 +1,8 @@
|
||||||
|
name: recuperación
|
||||||
|
columns:
|
||||||
|
id: id
|
||||||
|
started: comenzado
|
||||||
|
finished: terminado
|
||||||
|
amount: cantidad
|
||||||
|
period: período
|
||||||
|
clientFk: cliente
|
|
@ -0,0 +1,15 @@
|
||||||
|
name: tpv transaction
|
||||||
|
columns:
|
||||||
|
id: id
|
||||||
|
merchantFk: merchant
|
||||||
|
clientFk: client
|
||||||
|
receiptFk: receipt
|
||||||
|
amount: amount
|
||||||
|
response: response
|
||||||
|
errorCode: error code
|
||||||
|
status: status
|
||||||
|
created: created
|
||||||
|
merchantParameters: merchant parameters
|
||||||
|
signature: signature
|
||||||
|
signatureVersion: signature version
|
||||||
|
responseError: response error
|
|
@ -0,0 +1,15 @@
|
||||||
|
name: transacción tpv
|
||||||
|
columns:
|
||||||
|
id: id
|
||||||
|
merchantFk: comerciante
|
||||||
|
clientFk: cliente
|
||||||
|
receiptFk: recibo
|
||||||
|
amount: cantidad
|
||||||
|
response: respuesta
|
||||||
|
errorCode: código error
|
||||||
|
status: estado
|
||||||
|
created: creado
|
||||||
|
merchantParameters: parámetros comerciante
|
||||||
|
signature: firma
|
||||||
|
signatureVersion: versión firma
|
||||||
|
responseError: error de respuesta
|
|
@ -76,7 +76,7 @@ module.exports = function(Self) {
|
||||||
|
|
||||||
const date = Date.vnNew();
|
const date = Date.vnNew();
|
||||||
date.setHours(0, 0, 0, 0);
|
date.setHours(0, 0, 0, 0);
|
||||||
const query = `SELECT vn.clientGetDebt(?, ?) AS debt`;
|
const query = `SELECT vn.client_getDebt(?, ?) AS debt`;
|
||||||
const data = await Self.rawSql(query, [id, date], myOptions);
|
const data = await Self.rawSql(query, [id, date], myOptions);
|
||||||
|
|
||||||
client.debt = data[0].debt;
|
client.debt = data[0].debt;
|
||||||
|
|
|
@ -27,7 +27,7 @@ module.exports = Self => {
|
||||||
|
|
||||||
const date = Date.vnNew();
|
const date = Date.vnNew();
|
||||||
date.setHours(0, 0, 0, 0);
|
date.setHours(0, 0, 0, 0);
|
||||||
const query = `SELECT vn.clientGetDebt(?, ?) AS debt`;
|
const query = `SELECT vn.client_getDebt(?, ?) AS debt`;
|
||||||
const [debt] = await Self.rawSql(query, [clientFk, date], myOptions);
|
const [debt] = await Self.rawSql(query, [clientFk, date], myOptions);
|
||||||
|
|
||||||
return debt;
|
return debt;
|
||||||
|
|
|
@ -28,7 +28,7 @@ module.exports = Self => {
|
||||||
const isAccount = await models.Account.findById(id);
|
const isAccount = await models.Account.findById(id);
|
||||||
|
|
||||||
if (isClient && !isAccount)
|
if (isClient && !isAccount)
|
||||||
await models.VnUser.setPassword(id, newPassword);
|
await models.Account.setPassword(id, newPassword);
|
||||||
else
|
else
|
||||||
throw new UserError(`Modifiable password only via recovery or by an administrator`);
|
throw new UserError(`Modifiable password only via recovery or by an administrator`);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "ClientLog",
|
"name": "ClientLog",
|
||||||
"base": "VnModel",
|
"base": "Log",
|
||||||
"options": {
|
"options": {
|
||||||
"mysql": {
|
"mysql": {
|
||||||
"table": "clientLog"
|
"table": "clientLog"
|
||||||
|
@ -50,7 +50,7 @@
|
||||||
"type": "belongsTo",
|
"type": "belongsTo",
|
||||||
"model": "VnUser",
|
"model": "VnUser",
|
||||||
"foreignKey": "userFk"
|
"foreignKey": "userFk"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"scope": {
|
"scope": {
|
||||||
"order": ["creationDate DESC", "id DESC"]
|
"order": ["creationDate DESC", "id DESC"]
|
||||||
|
|
|
@ -14,7 +14,7 @@ module.exports = Self => {
|
||||||
Self.validatesPresenceOf('street', {
|
Self.validatesPresenceOf('street', {
|
||||||
message: 'Street cannot be empty'
|
message: 'Street cannot be empty'
|
||||||
});
|
});
|
||||||
|
|
||||||
Self.validatesPresenceOf('city', {
|
Self.validatesPresenceOf('city', {
|
||||||
message: 'City cannot be empty'
|
message: 'City cannot be empty'
|
||||||
});
|
});
|
||||||
|
@ -89,8 +89,9 @@ module.exports = Self => {
|
||||||
};
|
};
|
||||||
const country = await Self.app.models.Country.findOne(filter);
|
const country = await Self.app.models.Country.findOne(filter);
|
||||||
const code = country ? country.code.toLowerCase() : null;
|
const code = country ? country.code.toLowerCase() : null;
|
||||||
|
const countryCode = this.fi.toLowerCase().substring(0, 2);
|
||||||
|
|
||||||
if (!this.fi || !validateTin(this.fi, code))
|
if (!this.fi || !validateTin(this.fi, code) || (this.isVies && countryCode == code))
|
||||||
err();
|
err();
|
||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,7 +72,9 @@
|
||||||
<vn-horizontal>
|
<vn-horizontal>
|
||||||
<vn-check vn-one label="Has to invoice" ng-model="$ctrl.client.hasToInvoice">
|
<vn-check vn-one label="Has to invoice" ng-model="$ctrl.client.hasToInvoice">
|
||||||
</vn-check>
|
</vn-check>
|
||||||
<vn-check vn-one label="Vies" ng-model="$ctrl.client.isVies">
|
<vn-check vn-one label="Vies"
|
||||||
|
info="When activating it, do not enter the country code in the ID field."
|
||||||
|
ng-model="$ctrl.client.isVies">
|
||||||
</vn-check>
|
</vn-check>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
<vn-horizontal>
|
<vn-horizontal>
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue