Merge branch 'dev' into 4713-saleTracking
gitea/salix/pipeline/head This commit looks good
Details
gitea/salix/pipeline/head This commit looks good
Details
This commit is contained in:
commit
a2d3b79246
|
@ -52,6 +52,7 @@ pipeline {
|
|||
}}}
|
||||
environment {
|
||||
NODE_ENV = ""
|
||||
TZ = 'Europe/Madrid'
|
||||
}
|
||||
parallel {
|
||||
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
|
|
@ -8,7 +8,7 @@ CREATE DEFINER=`root`@`localhost` PROCEDURE `vn`.`invoiceOut_new`(
|
|||
BEGIN
|
||||
/**
|
||||
* 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 vInvoiceDate fecha de la factura
|
||||
|
@ -36,13 +36,13 @@ BEGIN
|
|||
|
||||
SELECT t.clientFk, t.companyFk
|
||||
INTO vClient, vCompany
|
||||
FROM ticketToInvoice tt
|
||||
FROM tmp.ticketToInvoice tt
|
||||
JOIN ticket t ON t.id = tt.id
|
||||
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.*
|
||||
FROM ticketToInvoice ti
|
||||
FROM tmp.ticketToInvoice ti
|
||||
JOIN ticket t ON t.id = ti.id
|
||||
JOIN sale s ON s.ticketFk = t.id
|
||||
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
|
||||
INTO vIsAnySaleToInvoice, vIsAnyServiceToInvoice
|
||||
FROM ticketToInvoice t
|
||||
FROM tmp.ticketToInvoice t
|
||||
LEFT JOIN sale s ON s.ticketFk = t.id
|
||||
LEFT JOIN ticketService ts ON ts.ticketFk = t.id;
|
||||
|
||||
|
@ -100,13 +100,13 @@ BEGIN
|
|||
WHERE id = vNewInvoiceId;
|
||||
|
||||
UPDATE ticket t
|
||||
JOIN ticketToInvoice ti ON ti.id = t.id
|
||||
JOIN tmp.ticketToInvoice ti ON ti.id = t.id
|
||||
SET t.refFk = vNewRef;
|
||||
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp.updateInter;
|
||||
CREATE TEMPORARY TABLE tmp.updateInter ENGINE = MEMORY
|
||||
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
|
||||
JOIN state s
|
||||
WHERE IFNULL(ts.alertLevel,0) < 3 and s.`code` = getAlert3State(ti.id);
|
||||
|
@ -116,7 +116,7 @@ BEGIN
|
|||
|
||||
INSERT INTO ticketLog (action, userFk, originFk, description)
|
||||
SELECT 'UPDATE', account.myUser_getId(), ti.id, CONCAT('Crea factura ', vNewRef)
|
||||
FROM ticketToInvoice ti;
|
||||
FROM tmp.ticketToInvoice ti;
|
||||
|
||||
CALL invoiceExpenceMake(vNewInvoiceId);
|
||||
CALL invoiceTaxMake(vNewInvoiceId,vTaxArea);
|
||||
|
@ -159,7 +159,7 @@ BEGIN
|
|||
(KEY (ticketFk))
|
||||
ENGINE = MEMORY
|
||||
SELECT id ticketFk
|
||||
FROM ticketToInvoice;
|
||||
FROM tmp.ticketToInvoice;
|
||||
|
||||
CALL `ticket_getTax`('NATIONAL');
|
||||
|
||||
|
@ -220,6 +220,6 @@ BEGIN
|
|||
|
||||
END IF;
|
||||
|
||||
DROP TEMPORARY TABLE `ticketToInvoice`;
|
||||
DROP TEMPORARY TABLE `tmp`.`ticketToInvoice`;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
|
|
@ -10,14 +10,14 @@ CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`invoiceOut_new`(
|
|||
BEGIN
|
||||
/**
|
||||
* 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 vInvoiceDate fecha de la factura
|
||||
* @param vTaxArea tipo de iva en relacion a la empresa y al cliente
|
||||
* @param vNewInvoiceId id de la factura que se acaba de generar
|
||||
* @return vNewInvoiceId
|
||||
*/
|
||||
*/
|
||||
DECLARE vIsAnySaleToInvoice BOOL;
|
||||
DECLARE vIsAnyServiceToInvoice BOOL;
|
||||
DECLARE vNewRef VARCHAR(255);
|
||||
|
@ -37,32 +37,32 @@ BEGIN
|
|||
DECLARE vMaxShipped DATE;
|
||||
|
||||
SET vInvoiceDate = IFNULL(vInvoiceDate, util.CURDATE());
|
||||
|
||||
SELECT t.clientFk,
|
||||
t.companyFk,
|
||||
|
||||
SELECT t.clientFk,
|
||||
t.companyFk,
|
||||
MAX(DATE(t.shipped)),
|
||||
DATE(vInvoiceDate) >= invoiceOut_getMaxIssued(
|
||||
vSerial,
|
||||
t.companyFk,
|
||||
vSerial,
|
||||
t.companyFk,
|
||||
YEAR(vInvoiceDate))
|
||||
INTO vClientFk,
|
||||
INTO vClientFk,
|
||||
vCompanyFk,
|
||||
vMaxShipped,
|
||||
vIsCorrectInvoiceDate
|
||||
FROM ticketToInvoice tt
|
||||
FROM tmp.ticketToInvoice tt
|
||||
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");
|
||||
END IF;
|
||||
|
||||
|
||||
IF NOT vIsCorrectInvoiceDate THEN
|
||||
CALL util.throw('Exists an invoice with a previous date');
|
||||
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.*
|
||||
FROM ticketToInvoice ti
|
||||
FROM tmp.ticketToInvoice ti
|
||||
JOIN ticket t ON t.id = ti.id
|
||||
JOIN sale s ON s.ticketFk = t.id
|
||||
JOIN item i ON i.id = s.itemFk
|
||||
|
@ -77,11 +77,11 @@ BEGIN
|
|||
|
||||
SELECT SUM(s.quantity * s.price * (100 - s.discount)/100) <> 0
|
||||
INTO vIsAnySaleToInvoice
|
||||
FROM ticketToInvoice t
|
||||
FROM tmp.ticketToInvoice t
|
||||
JOIN sale s ON s.ticketFk = t.id;
|
||||
|
||||
SELECT COUNT(*) > 0 INTO vIsAnyServiceToInvoice
|
||||
FROM ticketToInvoice t
|
||||
FROM tmp.ticketToInvoice t
|
||||
JOIN ticketService ts ON ts.ticketFk = t.id;
|
||||
|
||||
IF (vIsAnySaleToInvoice OR vIsAnyServiceToInvoice)
|
||||
|
@ -121,13 +121,13 @@ BEGIN
|
|||
WHERE id = vNewInvoiceId;
|
||||
|
||||
UPDATE ticket t
|
||||
JOIN ticketToInvoice ti ON ti.id = t.id
|
||||
JOIN tmp.ticketToInvoice ti ON ti.id = t.id
|
||||
SET t.refFk = vNewRef;
|
||||
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp.updateInter;
|
||||
CREATE TEMPORARY TABLE tmp.updateInter ENGINE = MEMORY
|
||||
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
|
||||
JOIN state s
|
||||
WHERE IFNULL(ts.alertLevel,0) < 3 and s.`code` = getAlert3State(ti.id);
|
||||
|
@ -137,7 +137,7 @@ BEGIN
|
|||
|
||||
INSERT INTO ticketLog (action, userFk, originFk, description)
|
||||
SELECT 'UPDATE', account.myUser_getId(), ti.id, CONCAT('Crea factura ', vNewRef)
|
||||
FROM ticketToInvoice ti;
|
||||
FROM tmp.ticketToInvoice ti;
|
||||
|
||||
CALL invoiceExpenceMake(vNewInvoiceId);
|
||||
CALL invoiceTaxMake(vNewInvoiceId,vTaxArea);
|
||||
|
@ -157,12 +157,12 @@ BEGIN
|
|||
WHERE io.id = vNewInvoiceId;
|
||||
|
||||
DROP TEMPORARY TABLE tmp.updateInter;
|
||||
|
||||
SELECT COUNT(*), id
|
||||
|
||||
SELECT COUNT(*), id
|
||||
INTO vIsInterCompany, vInterCompanyFk
|
||||
FROM company
|
||||
FROM company
|
||||
WHERE clientFk = vClientFk;
|
||||
|
||||
|
||||
IF (vIsInterCompany) THEN
|
||||
|
||||
INSERT INTO invoiceIn(supplierFk, supplierRef, issued, companyFk)
|
||||
|
@ -175,7 +175,7 @@ BEGIN
|
|||
(KEY (ticketFk))
|
||||
ENGINE = MEMORY
|
||||
SELECT id ticketFk
|
||||
FROM ticketToInvoice;
|
||||
FROM tmp.ticketToInvoice;
|
||||
|
||||
CALL `ticket_getTax`('NATIONAL');
|
||||
|
||||
|
@ -201,7 +201,7 @@ BEGIN
|
|||
) sub;
|
||||
|
||||
INSERT INTO invoiceInTax(invoiceInFk, taxableBase, expenceFk, taxTypeSageFk, transactionTypeSageFk)
|
||||
SELECT vNewInvoiceInFk,
|
||||
SELECT vNewInvoiceInFk,
|
||||
SUM(tt.taxableBase) - IF(tt.code = @vTaxCodeGeneral,
|
||||
@vTaxableBaseServices, 0) taxableBase,
|
||||
i.expenceFk,
|
||||
|
@ -215,13 +215,13 @@ BEGIN
|
|||
ORDER BY tt.priority;
|
||||
|
||||
CALL invoiceInDueDay_calculate(vNewInvoiceInFk);
|
||||
|
||||
SELECT COUNT(*) INTO vIsCEESerial
|
||||
|
||||
SELECT COUNT(*) INTO vIsCEESerial
|
||||
FROM invoiceOutSerial
|
||||
WHERE code = vSerial;
|
||||
|
||||
IF vIsCEESerial THEN
|
||||
|
||||
|
||||
INSERT INTO invoiceInIntrastat (
|
||||
invoiceInFk,
|
||||
intrastatFk,
|
||||
|
@ -253,6 +253,6 @@ BEGIN
|
|||
DROP TEMPORARY TABLE tmp.ticketServiceTax;
|
||||
END IF;
|
||||
END IF;
|
||||
DROP TEMPORARY TABLE `ticketToInvoice`;
|
||||
DROP TEMPORARY TABLE tmp.`ticketToInvoice`;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
DELIMITER ;
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
create or replace definer = root@localhost view User as
|
||||
select `account`.`user`.`id` AS `id`,
|
||||
`account`.`user`.`realm` AS `realm`,
|
||||
`account`.`user`.`name` AS `name`,
|
||||
`account`.`user`.`nickname` AS `nickname`,
|
||||
`account`.`user`.`bcryptPassword` AS `password`,
|
||||
`account`.`user`.`role` AS `role`,
|
||||
`account`.`user`.`active` AS `active`,
|
||||
`account`.`user`.`email` AS `email`,
|
||||
`account`.`user`.`emailVerified` AS `emailVerified`,
|
||||
`account`.`user`.`verificationToken` AS `verificationToken`,
|
||||
`account`.`user`.`lang` AS `lang`,
|
||||
`account`.`user`.`lastPassChange` AS `lastPassChange`,
|
||||
`account`.`user`.`created` AS `created`,
|
||||
`account`.`user`.`updated` AS `updated`,
|
||||
`account`.`user`.`image` AS `image`,
|
||||
`account`.`user`.`recoverPass` AS `recoverPass`,
|
||||
`account`.`user`.`sync` AS `sync`,
|
||||
`account`.`user`.`hasGrant` AS `hasGrant`
|
||||
from `account`.`user`;
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
DROP PROCEDURE `vn`.`refund`;
|
||||
DROP PROCEDURE `vn`.`ticket_doRefund`;
|
|
@ -1,5 +0,0 @@
|
|||
INSERT INTO `vn`.`companyI18n` (`companyFk`, `lang`, `footnotes`)
|
||||
VALUES (442, 'en', 'In compliance with the provisions of Organic Law 15/1999, on the Protection of Personal Data, we inform you that the personal data you provide will be included in automated files of VERDNATURA LEVANTE SL, being able at all times to exercise the rights of access, rectification, cancellation and opposition, communicating it in writing to the registered office of the entity. The purpose of the file is administrative management, accounting, and billing.'),
|
||||
(442, 'es', 'En cumplimiento de lo dispuesto en la Ley Orgánica 15/1999, de Protección de Datos de Carácter Personal, le comunicamos que los datos personales que facilite se incluirán en ficheros automatizados de VERDNATURA LEVANTE S.L., pudiendo en todo momento ejercitar los derechos de acceso, rectificación, cancelación y oposición, comunicándolo por escrito al domicilio social de la entidad. La finalidad del fichero es la gestión administrativa, contabilidad, y facturación.'),
|
||||
(442, 'fr', 'Conformément aux dispositions de la loi organique 15/1999 sur la protection des données personnelles, nous vous informons que les données personnelles que vous fournissez seront incluses dans des dossiers. VERDNATURA LEVANTE S.L., vous pouvez à tout moment, exercer les droits d``accès, de rectification, d``annulation et d``opposition, en communiquant par écrit au siège social de la société. Le dossier a pour objet la gestion administrative, la comptabilité et la facturation.'),
|
||||
(442, 'pt', 'Em cumprimento do disposto na lei Orgânica 15/1999, de Protecção de Dados de Carácter Pessoal, comunicamos que os dados pessoais que facilite se incluirão nos ficheiros automatizados de VERDNATURA LEVANTE S.L., podendo em todo momento exercer os direitos de acesso, rectificação, cancelação e oposição, comunicando por escrito ao domicílio social da entidade. A finalidade do ficheiro é a gestão administrativa, contabilidade e facturação.');
|
|
@ -0,0 +1 @@
|
|||
ALTER TABLE `vn`.`entry` DROP COLUMN `notes`;
|
|
@ -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);
|
|
@ -1409,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),
|
||||
(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
|
||||
(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'),
|
||||
(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'),
|
||||
(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'),
|
||||
(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'),
|
||||
(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'),
|
||||
(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'),
|
||||
(8, 2, DATE_ADD(util.VN_CURDATE(), INTERVAL -1 MONTH), 7, 0, 442, 'IN2008', 'Movement 8', 1, 1, '', '');
|
||||
(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, 'observation two'),
|
||||
(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, 'observation four'),
|
||||
(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, 'observation six'),
|
||||
(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, '');
|
||||
|
||||
INSERT INTO `bs`.`waste`(`buyer`, `year`, `week`, `family`, `itemFk`, `itemTypeFk`, `saleTotal`, `saleWaste`, `rate`)
|
||||
VALUES
|
||||
|
|
|
@ -42776,7 +42776,7 @@ CREATE DEFINER=`root`@`localhost` FUNCTION `hasAnyNegativeBase`() RETURNS tinyin
|
|||
BEGIN
|
||||
|
||||
/* Calcula si existe alguna base imponible negativa
|
||||
* Requiere la tabla temporal vn.ticketToInvoice(id)
|
||||
* Requiere la tabla temporal tmp.ticketToInvoice(id)
|
||||
*
|
||||
* returns BOOLEAN
|
||||
*/
|
||||
|
@ -42787,7 +42787,7 @@ BEGIN
|
|||
(KEY (ticketFk))
|
||||
ENGINE = MEMORY
|
||||
SELECT id ticketFk
|
||||
FROM ticketToInvoice;
|
||||
FROM tmp.ticketToInvoice;
|
||||
|
||||
CALL ticket_getTax(NULL);
|
||||
|
||||
|
@ -55223,7 +55223,7 @@ DELIMITER ;;
|
|||
CREATE DEFINER=`root`@`localhost` PROCEDURE `invoiceExpenceMake`(IN vInvoice INT)
|
||||
BEGIN
|
||||
/* Inserta las partidas de gasto correspondientes a la factura
|
||||
* REQUIERE tabla ticketToInvoice
|
||||
* REQUIERE tabla tmp.ticketToInvoice
|
||||
* @param vInvoice Numero de factura
|
||||
*/
|
||||
DELETE FROM invoiceOutExpence
|
||||
|
@ -55233,7 +55233,7 @@ BEGIN
|
|||
SELECT vInvoice,
|
||||
expenceFk,
|
||||
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 item i ON i.id = s.itemFk
|
||||
GROUP BY i.expenceFk
|
||||
|
@ -55243,7 +55243,7 @@ BEGIN
|
|||
SELECT vInvoice,
|
||||
tst.expenceFk,
|
||||
SUM(ROUND(ts.quantity * ts.price ,2)) amount
|
||||
FROM ticketToInvoice t
|
||||
FROM tmp.ticketToInvoice t
|
||||
JOIN ticketService ts ON ts.ticketFk = t.id
|
||||
JOIN ticketServiceType tst ON tst.id = ts.ticketServiceTypeFk
|
||||
HAVING amount != 0;
|
||||
|
@ -55270,9 +55270,9 @@ BEGIN
|
|||
|
||||
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`))
|
||||
ENGINE = MEMORY
|
||||
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 vMaxTicketDate = util.dayend(vMaxTicketDate);
|
||||
|
||||
DROP TEMPORARY TABLE IF EXISTS `ticketToInvoice`;
|
||||
CREATE TEMPORARY TABLE `ticketToInvoice`
|
||||
DROP TEMPORARY TABLE IF EXISTS `tmp`.`ticketToInvoice`;
|
||||
CREATE TEMPORARY TABLE `tmp`.`ticketToInvoice`
|
||||
(PRIMARY KEY (`id`))
|
||||
ENGINE = MEMORY
|
||||
SELECT id FROM ticket t
|
||||
|
@ -55333,9 +55333,9 @@ DELIMITER ;;
|
|||
CREATE DEFINER=`root`@`localhost` PROCEDURE `invoiceFromTicket`(IN vTicket INT)
|
||||
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`))
|
||||
ENGINE = MEMORY
|
||||
SELECT id FROM vn.ticket
|
||||
|
@ -55931,9 +55931,9 @@ BEGIN
|
|||
JOIN invoiceOut io ON io.companyFk = s.id
|
||||
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
|
||||
FROM ticket
|
||||
WHERE refFk = vInvoiceRef;
|
||||
|
@ -56408,9 +56408,9 @@ BEGIN
|
|||
JOIN client c ON c.id = io.clientFk
|
||||
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
|
||||
FROM ticket
|
||||
WHERE refFk = vInvoiceRef;
|
||||
|
@ -56456,7 +56456,7 @@ CREATE DEFINER=`root`@`localhost` PROCEDURE `invoiceOut_exportationFromClient`(
|
|||
vCompanyFk INT)
|
||||
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
|
||||
*
|
||||
* @param vMaxTicketDate Fecha hasta la cual cogerá tickets para facturar
|
||||
|
@ -56467,8 +56467,8 @@ BEGIN
|
|||
SET vMinTicketDate = util.firstDayOfYear(vMaxTicketDate - INTERVAL 1 YEAR);
|
||||
SET vMaxTicketDate = util.dayend(vMaxTicketDate);
|
||||
|
||||
DROP TEMPORARY TABLE IF EXISTS `ticketToInvoice`;
|
||||
CREATE TEMPORARY TABLE `ticketToInvoice`
|
||||
DROP TEMPORARY TABLE IF EXISTS `tmp`.`ticketToInvoice`;
|
||||
CREATE TEMPORARY TABLE `tmp`.`ticketToInvoice`
|
||||
(PRIMARY KEY (`id`))
|
||||
ENGINE = MEMORY
|
||||
SELECT t.id
|
||||
|
@ -56503,7 +56503,7 @@ CREATE DEFINER=`root`@`localhost` PROCEDURE `invoiceOut_new`(
|
|||
BEGIN
|
||||
/**
|
||||
* 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 vInvoiceDate fecha de la factura
|
||||
|
@ -56531,13 +56531,13 @@ BEGIN
|
|||
|
||||
SELECT t.clientFk, t.companyFk
|
||||
INTO vClientFk, vCompanyFk
|
||||
FROM ticketToInvoice tt
|
||||
FROM tmp.ticketToInvoice tt
|
||||
JOIN ticket t ON t.id = tt.id
|
||||
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.*
|
||||
FROM ticketToInvoice ti
|
||||
FROM tmp.ticketToInvoice ti
|
||||
JOIN ticket t ON t.id = ti.id
|
||||
JOIN sale s ON s.ticketFk = t.id
|
||||
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
|
||||
INTO vIsAnySaleToInvoice, vIsAnyServiceToInvoice
|
||||
FROM ticketToInvoice t
|
||||
FROM tmp.ticketToInvoice t
|
||||
LEFT JOIN sale s ON s.ticketFk = t.id
|
||||
LEFT JOIN ticketService ts ON ts.ticketFk = t.id;
|
||||
|
||||
|
@ -56593,13 +56593,13 @@ BEGIN
|
|||
WHERE id = vNewInvoiceId;
|
||||
|
||||
UPDATE ticket t
|
||||
JOIN ticketToInvoice ti ON ti.id = t.id
|
||||
JOIN tmp.ticketToInvoice ti ON ti.id = t.id
|
||||
SET t.refFk = vNewRef;
|
||||
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp.updateInter;
|
||||
CREATE TEMPORARY TABLE tmp.updateInter ENGINE = MEMORY
|
||||
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
|
||||
JOIN state s
|
||||
WHERE IFNULL(ts.alertLevel,0) < 3 and s.`code` = getAlert3State(ti.id);
|
||||
|
@ -56609,7 +56609,7 @@ BEGIN
|
|||
|
||||
INSERT INTO ticketLog (action, userFk, originFk, description)
|
||||
SELECT 'UPDATE', account.myUser_getId(), ti.id, CONCAT('Crea factura ', vNewRef)
|
||||
FROM ticketToInvoice ti;
|
||||
FROM tmp.ticketToInvoice ti;
|
||||
|
||||
CALL invoiceExpenceMake(vNewInvoiceId);
|
||||
CALL invoiceTaxMake(vNewInvoiceId,vTaxArea);
|
||||
|
@ -56647,7 +56647,7 @@ BEGIN
|
|||
(KEY (ticketFk))
|
||||
ENGINE = MEMORY
|
||||
SELECT id ticketFk
|
||||
FROM ticketToInvoice;
|
||||
FROM tmp.ticketToInvoice;
|
||||
|
||||
CALL `ticket_getTax`('NATIONAL');
|
||||
|
||||
|
@ -56725,7 +56725,7 @@ BEGIN
|
|||
DROP TEMPORARY TABLE tmp.ticketServiceTax;
|
||||
END IF;
|
||||
END IF;
|
||||
DROP TEMPORARY TABLE `ticketToInvoice`;
|
||||
DROP TEMPORARY TABLE `tmp`.`ticketToInvoice`;
|
||||
END ;;
|
||||
DELIMITER ;
|
||||
/*!50003 SET sql_mode = @saved_sql_mode */ ;
|
||||
|
@ -56876,7 +56876,7 @@ BEGIN
|
|||
(KEY (ticketFk))
|
||||
ENGINE = MEMORY
|
||||
SELECT id ticketFk
|
||||
FROM ticketToInvoice;
|
||||
FROM tmp.ticketToInvoice;
|
||||
|
||||
CALL ticket_getTax(vTaxArea);
|
||||
|
||||
|
@ -68689,7 +68689,7 @@ DELIMITER ;
|
|||
/*!50003 SET character_set_client = @saved_cs_client */ ;
|
||||
/*!50003 SET character_set_results = @saved_cs_results */ ;
|
||||
/*!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_results = @@character_set_results */ ;
|
||||
/*!50003 SET @saved_col_connection = @@collation_connection */ ;
|
||||
|
@ -68709,9 +68709,9 @@ BEGIN
|
|||
|
||||
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
|
||||
FROM vn.ticket
|
||||
WHERE addressFk = vAddress
|
||||
|
@ -68745,9 +68745,9 @@ BEGIN
|
|||
|
||||
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
|
||||
FROM vn.ticket
|
||||
WHERE clientFk = vClient
|
||||
|
@ -68808,9 +68808,9 @@ BEGIN
|
|||
JOIN vn.client c ON c.id = io.clientFk
|
||||
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
|
||||
FROM vn.ticket
|
||||
WHERE refFk = vInvoiceRef;
|
||||
|
|
|
@ -68,6 +68,7 @@ TABLES=(
|
|||
time
|
||||
volumeConfig
|
||||
workCenter
|
||||
companyI18n
|
||||
)
|
||||
dump_tables ${TABLES[@]}
|
||||
|
||||
|
|
|
@ -218,6 +218,23 @@ let actions = {
|
|||
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) {
|
||||
await this.waitForFunction((selector, property, minLength) => {
|
||||
const element = document.querySelector(selector);
|
||||
|
|
|
@ -283,12 +283,6 @@ export default {
|
|||
cancelEditAddressButton: 'vn-client-address-edit > form > vn-button-bar > vn-button > button',
|
||||
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: {
|
||||
addNoteFloatButton: 'vn-float-button',
|
||||
note: 'vn-textarea[ng-model="$ctrl.note.text"]',
|
||||
|
@ -312,15 +306,6 @@ export default {
|
|||
clientMandate: {
|
||||
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: {
|
||||
company: 'vn-client-balance-index vn-autocomplete[ng-model="$ctrl.companyId"]',
|
||||
newPaymentButton: `vn-float-button`,
|
||||
|
@ -755,6 +740,7 @@ export default {
|
|||
anyDocument: 'vn-ticket-dms-index > vn-data-viewer vn-tbody vn-tr'
|
||||
},
|
||||
ticketFuture: {
|
||||
searchResult: 'vn-ticket-future tbody tr',
|
||||
openAdvancedSearchButton: 'vn-searchbar .append vn-icon[icon="arrow_drop_down"]',
|
||||
originDated: 'vn-date-picker[label="Origin date"]',
|
||||
futureDated: 'vn-date-picker[label="Destination date"]',
|
||||
|
@ -770,7 +756,6 @@ export default {
|
|||
problems: 'vn-check[label="With problems"]',
|
||||
tableButtonSearch: 'vn-button[vn-tooltip="Search"]',
|
||||
moveButton: 'vn-button[vn-tooltip="Future tickets"]',
|
||||
acceptButton: '.vn-confirm.shown button[response="accept"]',
|
||||
firstCheck: 'tbody > tr:nth-child(1) > td > vn-check',
|
||||
multiCheck: 'vn-multi-check',
|
||||
tableId: 'vn-textfield[name="id"]',
|
||||
|
@ -1361,18 +1346,6 @@ export default {
|
|||
notes: 'vn-supplier-basic-data vn-textarea[ng-model="$ctrl.supplier.note"]',
|
||||
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: {
|
||||
payMethod: 'vn-supplier-billing-data vn-autocomplete[ng-model="$ctrl.supplier.payMethodFk"]',
|
||||
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.keyboard.press('Enter');
|
||||
|
||||
const result = await page.waitToGetProperty(selectors.itemFixedPrice.firstItemID, 'value');
|
||||
|
||||
expect(result).toEqual('1');
|
||||
await page.waitForTextInField(selectors.itemFixedPrice.firstItemID, '1');
|
||||
});
|
||||
|
||||
it('should order by last id, reload page and have same order', async() => {
|
||||
|
@ -91,9 +89,7 @@ describe('SmartTable SearchBar integration', () => {
|
|||
await page.reload({
|
||||
waitUntil: 'networkidle2'
|
||||
});
|
||||
const result = await page.waitToGetProperty(selectors.itemFixedPrice.firstItemID, 'value');
|
||||
|
||||
expect(result).toEqual('13');
|
||||
await page.waitForTextInField(selectors.itemFixedPrice.firstItemID, '13');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,88 +1,56 @@
|
|||
/* eslint max-len: ["error", { "code": 150 }]*/
|
||||
import selectors from '../../helpers/selectors';
|
||||
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 page;
|
||||
|
||||
beforeAll(async() => {
|
||||
browser = await getBrowser();
|
||||
page = browser.page;
|
||||
await page.loginAndModule('salesPerson', 'client');
|
||||
await page.accessToSearchResult('max');
|
||||
await page.accessToSection('client.card.webAccess');
|
||||
});
|
||||
|
||||
afterAll(async() => {
|
||||
await browser.close();
|
||||
});
|
||||
|
||||
it('should uncheck the Enable web access checkbox', async() => {
|
||||
await page.waitToClick(selectors.clientWebAccess.enableWebAccessCheckbox);
|
||||
await page.waitToClick(selectors.clientWebAccess.saveButton);
|
||||
const message = await page.waitForSnackbar();
|
||||
it('should modify and save web access attributes', async() => {
|
||||
await page.accessToSection('client.card.webAccess');
|
||||
await page.click($.enableWebAccess);
|
||||
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');
|
||||
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');
|
||||
});
|
||||
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() => {
|
||||
let namePreviousValue = await page
|
||||
.waitToGetProperty(selectors.clientLog.namePreviousValue, 'innerText');
|
||||
let nameCurrentValue = await page
|
||||
.waitToGetProperty(selectors.clientLog.nameCurrentValue, 'innerText');
|
||||
expect(enableMessage.type).toBe('success');
|
||||
expect(modifyMessage.type).toBe('success');
|
||||
|
||||
expect(namePreviousValue).toEqual('MaxEisenhardt');
|
||||
expect(nameCurrentValue).toEqual('Legion');
|
||||
});
|
||||
expect(hasAccess).toBe('unchecked');
|
||||
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() => {
|
||||
let activePreviousValue = await page
|
||||
.waitToGetProperty(selectors.clientLog.activePreviousValue, 'innerText');
|
||||
let activeCurrentValue = await page
|
||||
.waitToGetProperty(selectors.clientLog.activeCurrentValue, 'innerText');
|
||||
|
||||
expect(activePreviousValue).toEqual('✓');
|
||||
expect(activeCurrentValue).toEqual('✗');
|
||||
expect(logName).toEqual('Legion');
|
||||
expect(logActive).toEqual('✗');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -246,6 +246,7 @@ describe('Ticket Edit sale path', () => {
|
|||
it('should select the third sale and create a claim of it', async() => {
|
||||
await page.accessToSearchResult('16');
|
||||
await page.accessToSection('ticket.card.sale');
|
||||
await page.waitToClick(selectors.ticketSales.firstSaleCheckbox);
|
||||
await page.waitToClick(selectors.ticketSales.thirdSaleCheckbox);
|
||||
await page.waitToClick(selectors.ticketSales.moreMenu);
|
||||
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() => {
|
||||
await page.waitForNumberOfElements(selectors.ticketFuture.searchResult, 4);
|
||||
await page.waitToClick(selectors.ticketFuture.multiCheck);
|
||||
await page.waitToClick(selectors.ticketFuture.firstCheck);
|
||||
await page.waitToClick(selectors.ticketFuture.moveButton);
|
||||
await page.waitToClick(selectors.ticketFuture.acceptButton);
|
||||
await page.waitToClick(selectors.globalItems.acceptButton);
|
||||
const message = await page.waitForSnackbar();
|
||||
|
||||
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() => {
|
||||
await page.click(selectors.invoiceInSerial.goToIndex);
|
||||
await page.waitToClick(selectors.invoiceInSerial.goToIndex);
|
||||
const params = await page.$$(selectors.invoiceInIndex.topbarSearchParams);
|
||||
const serial = await params[0].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() => {
|
||||
await page.write(selectors.entryBasicData.reference, '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.autocompleteSearch(selectors.entryBasicData.supplier, 'Plants nick');
|
||||
await page.autocompleteSearch(selectors.entryBasicData.currency, 'eur');
|
||||
|
@ -53,12 +52,6 @@ describe('Entry basic data path', () => {
|
|||
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() => {
|
||||
const result = await page.waitToGetProperty(selectors.entryBasicData.observations, 'value');
|
||||
|
||||
|
|
|
@ -1,6 +1,20 @@
|
|||
import selectors from '../../helpers/selectors.js';
|
||||
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', () => {
|
||||
let browser;
|
||||
let page;
|
||||
|
@ -10,102 +24,44 @@ describe('Supplier fiscal data path', () => {
|
|||
page = browser.page;
|
||||
await page.loginAndModule('administrative', 'supplier');
|
||||
await page.accessToSearchResult('2');
|
||||
await page.accessToSection('supplier.card.fiscalData');
|
||||
});
|
||||
|
||||
afterAll(async() => {
|
||||
await browser.close();
|
||||
});
|
||||
|
||||
it('should attempt to edit the fiscal data but fail as the tax number is invalid', async() => {
|
||||
await page.clearInput(selectors.supplierFiscalData.city);
|
||||
await page.clearInput(selectors.supplierFiscalData.province);
|
||||
await page.clearInput(selectors.supplierFiscalData.country);
|
||||
await page.clearInput(selectors.supplierFiscalData.postCode);
|
||||
await page.write(selectors.supplierFiscalData.city, 'Valencia');
|
||||
await page.waitForTimeout(1000); // must repeat this action twice or fails. also #2699 may be a cool solution to this.
|
||||
await page.clearInput(selectors.supplierFiscalData.city);
|
||||
await page.write(selectors.supplierFiscalData.city, 'Valencia');
|
||||
await page.clearInput(selectors.supplierFiscalData.socialName);
|
||||
await page.write(selectors.supplierFiscalData.socialName, 'Farmer King SL');
|
||||
await page.clearInput(selectors.supplierFiscalData.taxNumber);
|
||||
await page.write(selectors.supplierFiscalData.taxNumber, 'Wrong tax number');
|
||||
await page.clearInput(selectors.supplierFiscalData.account);
|
||||
await page.write(selectors.supplierFiscalData.account, '0123456789');
|
||||
await page.autocompleteSearch(selectors.supplierFiscalData.sageWihholding, 'retencion estimacion objetiva');
|
||||
await page.autocompleteSearch(selectors.supplierFiscalData.sageTaxType, 'operaciones no sujetas');
|
||||
it('should attempt to edit the fiscal data and check data is saved', async() => {
|
||||
await page.accessToSection('supplier.card.fiscalData');
|
||||
await page.clearInput($inputs.province);
|
||||
await page.clearInput($inputs.country);
|
||||
await page.clearInput($inputs.postcode);
|
||||
await page.overwrite($inputs.city, 'Valencia');
|
||||
await page.overwrite($inputs.socialName, 'Farmer King SL');
|
||||
await page.overwrite($inputs.taxNumber, 'Wrong tax number');
|
||||
await page.overwrite($inputs.account, '0123456789');
|
||||
await page.autocompleteSearch($inputs.sageWithholding, 'retencion estimacion objetiva');
|
||||
await page.autocompleteSearch($inputs.sageTaxType, 'operaciones no sujetas');
|
||||
await page.click($.saveButton);
|
||||
const errorMessage = await page.waitForSnackbar();
|
||||
await page.overwrite($inputs.taxNumber, '12345678Z');
|
||||
await page.click($.saveButton);
|
||||
const successMessage = await page.waitForSnackbar();
|
||||
|
||||
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');
|
||||
});
|
||||
const values = await page.getValues($inputs);
|
||||
|
||||
it('should check the socialName was edited', async() => {
|
||||
const result = await page.waitToGetProperty(selectors.supplierFiscalData.socialName, 'value');
|
||||
|
||||
expect(result).toEqual('Farmer King SL');
|
||||
});
|
||||
|
||||
it('should check the taxNumber was edited', async() => {
|
||||
const result = await page.waitToGetProperty(selectors.supplierFiscalData.taxNumber, 'value');
|
||||
|
||||
expect(result).toEqual('12345678Z');
|
||||
});
|
||||
|
||||
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');
|
||||
expect(errorMessage.text).toContain('Invalid Tax number');
|
||||
expect(successMessage.type).toBe('success');
|
||||
expect(values).toEqual({
|
||||
province: 'Province one (España)',
|
||||
country: 'España',
|
||||
postcode: '46000',
|
||||
city: 'Valencia',
|
||||
socialName: 'Farmer King SL',
|
||||
taxNumber: '12345678Z',
|
||||
account: '0123456789',
|
||||
sageWithholding: 'RETENCION ESTIMACION OBJETIVA',
|
||||
sageTaxType: 'Operaciones no sujetas'
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -174,7 +174,6 @@ export default class Autocomplete extends Field {
|
|||
|
||||
refreshDisplayed() {
|
||||
let display = '';
|
||||
let hasTemplate = this.$transclude && this.$transclude.isSlotFilled('tplItem');
|
||||
|
||||
if (this._selection && this.showField) {
|
||||
if (this.multiple && Array.isArray(this._selection)) {
|
||||
|
@ -182,19 +181,8 @@ export default class Autocomplete extends Field {
|
|||
if (display.length > 0) display += ', ';
|
||||
display += item[this.showField];
|
||||
}
|
||||
} else {
|
||||
} else
|
||||
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;
|
||||
|
|
|
@ -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;
|
||||
event.preventDefault();
|
||||
this.field = null;
|
||||
this.input.dispatchEvent(new Event('change'));
|
||||
this.element.dispatchEvent(new Event('change'));
|
||||
}
|
||||
|
||||
buildInput(type) {
|
||||
|
|
|
@ -17,6 +17,7 @@ import './pagination/pagination';
|
|||
import './searchbar/searchbar';
|
||||
import './scroll-up/scroll-up';
|
||||
import './autocomplete';
|
||||
import './avatar';
|
||||
import './button';
|
||||
import './button-menu';
|
||||
import './calendar';
|
||||
|
@ -32,6 +33,7 @@ import './float-button';
|
|||
import './icon-menu';
|
||||
import './icon-button';
|
||||
import './input-number';
|
||||
import './json-value';
|
||||
import './label-value';
|
||||
import './range';
|
||||
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;
|
||||
height: 48px;
|
||||
}
|
||||
vn-thead, .vn-thead,
|
||||
vn-tbody, .vn-tbody,
|
||||
vn-tfoot, .vn-tfoot,
|
||||
thead, tbody, tfoot {
|
||||
& > thead,
|
||||
& > tbody,
|
||||
& > tfoot,
|
||||
& > vn-thead,
|
||||
& > vn-tbody,
|
||||
& > vn-tfoot,
|
||||
& > .vn-thead,
|
||||
& > .vn-tbody,
|
||||
& > .vn-tfoot {
|
||||
& > * {
|
||||
display: table-row;
|
||||
|
||||
|
@ -111,14 +116,14 @@ vn-table {
|
|||
color: inherit;
|
||||
}
|
||||
}
|
||||
a.vn-tbody {
|
||||
& > a.vn-tbody {
|
||||
&.clickable {
|
||||
@extend %clickable;
|
||||
}
|
||||
}
|
||||
vn-tbody > *,
|
||||
.vn-tbody > *,
|
||||
tbody > * {
|
||||
& > vn-tbody > *,
|
||||
& > .vn-tbody > *,
|
||||
& > tbody > * {
|
||||
border-bottom: $border-thin;
|
||||
|
||||
&:last-child {
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
$font-size: 11pt;
|
||||
$menu-width: 256px;
|
||||
$right-menu-width: 318px;
|
||||
$topbar-height: 56px;
|
||||
$mobile-width: 800px;
|
||||
$float-spacing: 20px;
|
||||
|
|
|
@ -88,13 +88,13 @@ vn-layout {
|
|||
}
|
||||
&.right-menu {
|
||||
& > vn-topbar > .end {
|
||||
width: 80px + $right-menu-width;
|
||||
width: 80px + $menu-width;
|
||||
}
|
||||
& > .main-view {
|
||||
padding-right: $right-menu-width;
|
||||
padding-right: $menu-width;
|
||||
}
|
||||
[fixed-bottom-right] {
|
||||
right: $right-menu-width;
|
||||
right: $menu-width;
|
||||
}
|
||||
}
|
||||
& > .main-view {
|
||||
|
|
|
@ -3,70 +3,212 @@
|
|||
url="{{$ctrl.url}}"
|
||||
filter="$ctrl.filter"
|
||||
link="{originFk: $ctrl.originId}"
|
||||
where="{changedModel: $ctrl.changedModel,
|
||||
changedModelId: $ctrl.changedModelId}"
|
||||
where="{changedModel: $ctrl.changedModel, changedModelId: $ctrl.changedModelId}"
|
||||
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">
|
||||
</vn-crud-model>
|
||||
<vn-data-viewer model="model" class="vn-w-xl">
|
||||
<vn-card>
|
||||
<vn-table model="model">
|
||||
<vn-thead>
|
||||
<vn-tr>
|
||||
<vn-th field="creationDate">Date</vn-th>
|
||||
<vn-th field="userFk" shrink>User</vn-th>
|
||||
<vn-th field="changedModel" ng-if="$ctrl.showModelName" shrink>Model</vn-th>
|
||||
<vn-th field="action" shrink>Action</vn-th>
|
||||
<vn-th field="changedModelValue" ng-if="$ctrl.showModelName">Name</vn-th>
|
||||
<vn-th expand>Changes</vn-th>
|
||||
</vn-tr>
|
||||
</vn-thead>
|
||||
<vn-tbody>
|
||||
<vn-tr ng-repeat="log in $ctrl.logs">
|
||||
<vn-td shrink-datetime>
|
||||
{{::log.creationDate | date:'dd/MM/yyyy HH:mm'}}
|
||||
</vn-td>
|
||||
<vn-td>
|
||||
<span ng-class="{'link': log.user.worker.id, 'value': !log.user.worker.id}"
|
||||
ng-click="$ctrl.showWorkerDescriptor($event, log.user.worker.id)"
|
||||
translate>{{::log.user.name || 'System' | translate}}
|
||||
<vn-data-viewer model="model" class="vn-w-md vn-px-sm">
|
||||
<div class="change vn-mb-sm" ng-repeat="log in $ctrl.logs">
|
||||
<div class="user-wrapper">
|
||||
<vn-avatar class="vn-mt-xs"
|
||||
ng-class="::{system: !log.user}"
|
||||
val="{{::log.user ? log.user.nickname : 'System'}}"
|
||||
ng-click="$ctrl.showWorkerDescriptor($event, log)">
|
||||
<img
|
||||
ng-if="::log.user.image"
|
||||
ng-src="/api/Images/user/160x160/{{::log.userFk}}/download?access_token={{::$ctrl.vnToken.token}}">
|
||||
</img>
|
||||
</vn-avatar>
|
||||
<div class="arrow bg-panel"></div>
|
||||
<div class="line"></div>
|
||||
</div>
|
||||
<vn-card class="detail vn-pa-sm">
|
||||
<div class="header vn-mb-sm">
|
||||
<div
|
||||
class="date text-secondary text-caption"
|
||||
title="{{::log.creationDate | date:'dd/MM/yyyy HH:mm'}}">
|
||||
{{::$ctrl.relativeDate(log.creationDate)}}
|
||||
</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>
|
||||
</vn-td>
|
||||
<vn-td ng-if="$ctrl.showModelName">
|
||||
{{::log.changedModel}}
|
||||
</vn-td>
|
||||
<vn-td shrink translate>
|
||||
{{::$ctrl.actionsText[log.action]}}
|
||||
</vn-td>
|
||||
<vn-td ng-if="$ctrl.showModelName">
|
||||
{{::log.changedModelValue}}
|
||||
</vn-td>
|
||||
<vn-td expand>
|
||||
<table class="attributes">
|
||||
<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 ng-if="log.expand"
|
||||
class="expanded-json">
|
||||
<div ng-repeat="prop in ::log.props">
|
||||
<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="::log.action == 'update'">
|
||||
← <vn-json-value value="::prop.old"></vn-json-value>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</vn-td>
|
||||
</vn-tr>
|
||||
</vn-tbody>
|
||||
</vn-table>
|
||||
</vn-card>
|
||||
</span>
|
||||
<span ng-if="::!log.props.length"
|
||||
class="description">
|
||||
{{::log.description}}
|
||||
</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-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>
|
||||
|
|
|
@ -13,11 +13,17 @@ export default class Controller extends Section {
|
|||
delete: 'Deletes',
|
||||
select: 'Views'
|
||||
};
|
||||
this.actionsClass = {
|
||||
insert: 'success',
|
||||
update: 'warning',
|
||||
delete: 'alert',
|
||||
select: 'notice'
|
||||
};
|
||||
this.filter = {
|
||||
include: [{
|
||||
relation: 'user',
|
||||
scope: {
|
||||
fields: ['name'],
|
||||
fields: ['nickname', 'name', 'image'],
|
||||
include: {
|
||||
relation: 'worker',
|
||||
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() {
|
||||
|
@ -42,6 +62,7 @@ export default class Controller extends Section {
|
|||
const oldValues = log.oldInstance || empty;
|
||||
const newValues = log.newInstance || empty;
|
||||
const locale = validations[log.changedModel]?.locale || empty;
|
||||
log.changedModelI18n = locale.name || log.changedModel;
|
||||
|
||||
let props = Object.keys(oldValues).concat(Object.keys(newValues));
|
||||
props = [...new Set(props)];
|
||||
|
@ -49,9 +70,10 @@ export default class Controller extends Section {
|
|||
log.props = [];
|
||||
for (const prop of props) {
|
||||
log.props.push({
|
||||
name: locale[prop] || prop,
|
||||
old: this.formatValue(oldValues[prop]),
|
||||
new: this.formatValue(newValues[prop])
|
||||
name: prop,
|
||||
nameI18n: locale.columns?.[prop] || 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);
|
||||
}
|
||||
|
||||
formatValue(value) {
|
||||
let type = typeof value;
|
||||
castJsonValue(value) {
|
||||
return typeof value === 'string' && validDate.test(value)
|
||||
? new Date(value)
|
||||
: value;
|
||||
}
|
||||
|
||||
if (type === 'string' && validDate.test(value)) {
|
||||
value = new Date(value);
|
||||
type = typeof value;
|
||||
mainVal(prop, action) {
|
||||
return action == 'delete' ? prop.old : prop.new;
|
||||
}
|
||||
|
||||
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) {
|
||||
case 'boolean':
|
||||
return value ? '✓' : '✗';
|
||||
case 'object':
|
||||
if (value instanceof Date) {
|
||||
const hasZeroTime =
|
||||
value.getHours() === 0 &&
|
||||
value.getMinutes() === 0 &&
|
||||
value.getSeconds() === 0;
|
||||
const format = hasZeroTime ? 'dd/MM/yyyy' : 'dd/MM/yyyy HH:mm:ss';
|
||||
return this.$filter('date')(value, format);
|
||||
}
|
||||
else
|
||||
return value;
|
||||
default:
|
||||
return value;
|
||||
const and = [];
|
||||
for (const prop in filter) {
|
||||
const param = getParam(prop, filter[prop]);
|
||||
if (param) and.push(param);
|
||||
}
|
||||
|
||||
const lbFilter = and.length ? {where: {and}} : null;
|
||||
return this.$.model.applyFilter(lbFilter);
|
||||
}
|
||||
|
||||
searchUser(search) {
|
||||
if (/^[0-9]+$/.test(search)) {
|
||||
return {id: search};
|
||||
} else {
|
||||
return {or: [
|
||||
{name: search},
|
||||
{nickname: {like: `%${search}%`}}
|
||||
]}
|
||||
}
|
||||
}
|
||||
|
||||
showWorkerDescriptor(event, workerId) {
|
||||
if (!workerId) return;
|
||||
this.$.workerDescriptor.show(event.target, workerId);
|
||||
showWorkerDescriptor(event, log) {
|
||||
if (log.user?.worker)
|
||||
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
|
||||
note: nota
|
||||
Changes: Cambios
|
||||
No changes: No hay cambios
|
||||
today: hoy
|
||||
yesterday: ayer
|
||||
|
|
|
@ -1,66 +1,152 @@
|
|||
@import "variables";
|
||||
|
||||
vn-log {
|
||||
vn-td {
|
||||
vertical-align: initial !important;
|
||||
}
|
||||
.changes {
|
||||
display: none;
|
||||
}
|
||||
.label {
|
||||
color: $color-font-secondary;
|
||||
}
|
||||
.value {
|
||||
color: $color-font;
|
||||
}
|
||||
.change {
|
||||
display: flex;
|
||||
|
||||
@media screen and (max-width: 1570px) {
|
||||
vn-table .expendable {
|
||||
& > .user-wrapper {
|
||||
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;
|
||||
}
|
||||
.changes {
|
||||
padding-top: 10px;
|
||||
display: block;
|
||||
.detail {
|
||||
position: relative;
|
||||
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 {
|
||||
width: 100%;
|
||||
.changes {
|
||||
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 {
|
||||
height: 10px;
|
||||
& > .expand-button,
|
||||
& > .shrink-button {
|
||||
display: none;
|
||||
}
|
||||
&.props {
|
||||
padding-right: 24px;
|
||||
|
||||
& > td {
|
||||
padding: 2px;
|
||||
& > .expand-button,
|
||||
& > .shrink-button {
|
||||
position: absolute;
|
||||
top: 6px;
|
||||
right: 8px;
|
||||
font-size: inherit;
|
||||
float: right;
|
||||
cursor: pointer;
|
||||
}
|
||||
& > td.field,
|
||||
& > th.field {
|
||||
width: 20%;
|
||||
color: gray;
|
||||
& > .expand-button {
|
||||
display: block;
|
||||
}
|
||||
& > td.before,
|
||||
& > th.before,
|
||||
& > td.after,
|
||||
& > th.after {
|
||||
width: 40%;
|
||||
white-space: pre-line;
|
||||
&.expanded {
|
||||
max-height: 500px;
|
||||
padding-right: 0;
|
||||
|
||||
& > .changes-wrapper {
|
||||
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
|
||||
/* 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('patchOrCreate', ctx => this.checkInsertAcls(ctx));
|
||||
this.beforeRemote('create', 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', {
|
||||
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",
|
||||
"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",
|
||||
"company": "Company",
|
||||
"country": "Country",
|
||||
"clientId": "Id client",
|
||||
"clientSocialName": "Client",
|
||||
"amount": "Amount",
|
||||
"taxableBase": "Taxable base",
|
||||
"ticketFk": "Id ticket",
|
||||
"isActive": "Active",
|
||||
"hasToInvoice": "Invoice",
|
||||
"isTaxDataChecked": "Data checked",
|
||||
"comercialId": "Id Comercial",
|
||||
"comercialName": "Comercial",
|
||||
"company": "Company",
|
||||
"country": "Country",
|
||||
"clientId": "Id client",
|
||||
"clientSocialName": "Client",
|
||||
"amount": "Amount",
|
||||
"taxableBase": "Taxable base",
|
||||
"ticketFk": "Id ticket",
|
||||
"isActive": "Active",
|
||||
"hasToInvoice": "Invoice",
|
||||
"isTaxDataChecked": "Data checked",
|
||||
"comercialId": "Id Comercial",
|
||||
"comercialName": "Comercial",
|
||||
"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}}",
|
||||
"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",
|
||||
"country": "País",
|
||||
"clientId": "Id cliente",
|
||||
"clientSocialName": "Cliente",
|
||||
"amount": "Importe",
|
||||
"taxableBase": "Base",
|
||||
"ticketFk": "Id ticket",
|
||||
"isActive": "Activo",
|
||||
"hasToInvoice": "Facturar",
|
||||
"isTaxDataChecked": "Datos comprobados",
|
||||
"comercialId": "Id comercial",
|
||||
"comercialName": "Comercial"
|
||||
}
|
||||
"country": "País",
|
||||
"clientId": "Id cliente",
|
||||
"clientSocialName": "Cliente",
|
||||
"amount": "Importe",
|
||||
"taxableBase": "Base",
|
||||
"ticketFk": "Id ticket",
|
||||
"isActive": "Activo",
|
||||
"hasToInvoice": "Facturar",
|
||||
"isTaxDataChecked": "Datos comprobados",
|
||||
"comercialId": "Id comercial",
|
||||
"comercialName": "Comercial",
|
||||
"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",
|
||||
"base": "VnModel",
|
||||
"base": "Log",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "account.roleLog"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "UserLog",
|
||||
"base": "VnModel",
|
||||
"base": "Log",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "account.userLog"
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
</vn-crud-model>
|
||||
<vn-portal slot="topbar">
|
||||
<vn-searchbar
|
||||
vn-focus
|
||||
panel="vn-user-search-panel"
|
||||
info="Search user by id, name or nickname"
|
||||
model="model"
|
||||
|
@ -15,4 +16,4 @@
|
|||
<vn-portal slot="menu">
|
||||
<vn-left-menu></vn-left-menu>
|
||||
</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
|
||||
}, myOptions);
|
||||
|
||||
await models.TicketRefund.create({
|
||||
refundTicketFk: newRefundTicket.id,
|
||||
originalTicketFk: claim.ticket().id
|
||||
}, myOptions);
|
||||
|
||||
await saveObservation({
|
||||
description: `Reclama ticket: ${claim.ticketFk}`,
|
||||
ticketFk: newRefundTicket.id,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "ClaimLog",
|
||||
"base": "VnModel",
|
||||
"base": "Log",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "claimLog"
|
||||
|
@ -50,7 +50,7 @@
|
|||
"type": "belongsTo",
|
||||
"model": "VnUser",
|
||||
"foreignKey": "userFk"
|
||||
}
|
||||
}
|
||||
},
|
||||
"scope": {
|
||||
"order": ["creationDate DESC", "id DESC"]
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
value="{{$ctrl.claimedTotal | currency: 'EUR':2}}">
|
||||
</vn-label-value>
|
||||
</vn-card>
|
||||
<vn-card class="vn-pa-lg vn-w-lg">
|
||||
<vn-card class="vn-pa-md vn-w-lg">
|
||||
<smart-table
|
||||
model="model"
|
||||
options="$ctrl.smartTableOptions"
|
||||
|
@ -31,10 +31,10 @@
|
|||
translate-attr="{title: 'Imports claim details'}">
|
||||
</vn-button>
|
||||
<vn-button
|
||||
label="Change destination"
|
||||
disabled="$ctrl.checked.length == 0"
|
||||
ng-click="changeDestination.show()">
|
||||
</vn-button>
|
||||
label="Change destination"
|
||||
disabled="$ctrl.checked.length == 0"
|
||||
ng-click="changeDestination.show()">
|
||||
</vn-button>
|
||||
<vn-range
|
||||
label="Responsability"
|
||||
min-label="Company"
|
||||
|
@ -45,15 +45,15 @@
|
|||
step="1"
|
||||
on-change="$ctrl.save({responsibility: value})">
|
||||
</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-check class="right"
|
||||
vn-one
|
||||
label="Is paid with mana"
|
||||
ng-model="$ctrl.claim.isChargedToMana"
|
||||
on-change="$ctrl.save({isChargedToMana: value})">
|
||||
</vn-check>
|
||||
</section>
|
||||
</slot-actions>
|
||||
</slot-actions>
|
||||
<slot-table>
|
||||
<table model="model">
|
||||
<thead>
|
||||
|
|
|
@ -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();
|
||||
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);
|
||||
|
||||
client.debt = data[0].debt;
|
||||
|
|
|
@ -27,7 +27,7 @@ module.exports = Self => {
|
|||
|
||||
const date = Date.vnNew();
|
||||
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);
|
||||
|
||||
return debt;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "ClientLog",
|
||||
"base": "VnModel",
|
||||
"base": "Log",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "clientLog"
|
||||
|
@ -50,7 +50,7 @@
|
|||
"type": "belongsTo",
|
||||
"model": "VnUser",
|
||||
"foreignKey": "userFk"
|
||||
}
|
||||
}
|
||||
},
|
||||
"scope": {
|
||||
"order": ["creationDate DESC", "id DESC"]
|
||||
|
|
|
@ -14,7 +14,7 @@ module.exports = Self => {
|
|||
Self.validatesPresenceOf('street', {
|
||||
message: 'Street cannot be empty'
|
||||
});
|
||||
|
||||
|
||||
Self.validatesPresenceOf('city', {
|
||||
message: 'City cannot be empty'
|
||||
});
|
||||
|
@ -89,8 +89,9 @@ module.exports = Self => {
|
|||
};
|
||||
const country = await Self.app.models.Country.findOne(filter);
|
||||
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();
|
||||
done();
|
||||
}
|
||||
|
|
|
@ -72,7 +72,9 @@
|
|||
<vn-horizontal>
|
||||
<vn-check vn-one label="Has to invoice" ng-model="$ctrl.client.hasToInvoice">
|
||||
</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-horizontal>
|
||||
<vn-horizontal>
|
||||
|
|
|
@ -12,3 +12,5 @@ Previous client: Cliente anterior
|
|||
In case of a company succession, specify the grantor company: En el caso de que haya habido una sucesión de empresa, indicar la empresa cedente
|
||||
Incoterms authorization: Autorización incoterms
|
||||
Electronic invoice: Factura electrónica
|
||||
When activating it, do not enter the country code in the IF.: Al activarlo, no informar el código del país en el campo IF
|
||||
The first two values are letters: Los dos primeros valores son letras
|
|
@ -0,0 +1,18 @@
|
|||
name: buy
|
||||
columns:
|
||||
id: id
|
||||
quantity: quantity
|
||||
buyingValue: buying value
|
||||
freightValue: freight value
|
||||
packing: packing
|
||||
grouping: grouping
|
||||
stickers: stickers
|
||||
groupingMode: grouping mode
|
||||
comissionValue: comission value
|
||||
packageValue: package value
|
||||
price2: price2
|
||||
price3: price3
|
||||
weight: weight
|
||||
entryFk: entry
|
||||
itemFk: item
|
||||
packageFk: package
|
|
@ -0,0 +1,18 @@
|
|||
name: compra
|
||||
columns:
|
||||
id: id
|
||||
quantity: cantidad
|
||||
buyingValue: valor compra
|
||||
freightValue: valor flete
|
||||
packing: embalaje
|
||||
grouping: agrupación
|
||||
stickers: pegatinas
|
||||
groupingMode: modo agrupación
|
||||
comissionValue: valor comisión
|
||||
packageValue: valor paquete
|
||||
price2: precio2
|
||||
price3: precio3
|
||||
weight: peso
|
||||
entryFk: entrada
|
||||
itemFk: artículo
|
||||
packageFk: paquete
|
|
@ -0,0 +1,6 @@
|
|||
name: entry observation
|
||||
columns:
|
||||
id: id
|
||||
description: description
|
||||
entryFk: entry
|
||||
observationTypeFk: observation type
|
|
@ -0,0 +1,6 @@
|
|||
name: observación entrada
|
||||
columns:
|
||||
id: id
|
||||
description: descripción
|
||||
entryFk: entrada
|
||||
observationTypeFk: tipo observación
|
|
@ -0,0 +1,23 @@
|
|||
name: entry
|
||||
columns:
|
||||
id: id
|
||||
dated: dated
|
||||
reference: reference
|
||||
invoiceNumber: invoice number
|
||||
isBooked: booked
|
||||
isExcludedFromAvailable: excluded from available
|
||||
notes: notes
|
||||
isConfirmed: confirmed
|
||||
isVirtual: virtual
|
||||
isRaid: raid
|
||||
commission: commission
|
||||
isOrdered: price3
|
||||
created: created
|
||||
observation: observation
|
||||
isBlocked: blocked
|
||||
loadPriority: load priority
|
||||
supplierFk: supplier
|
||||
travelFk: travel
|
||||
companyFk: company
|
||||
observationEditorFk: observation editor
|
||||
currencyFk: currency
|
|
@ -0,0 +1,23 @@
|
|||
name: entrada
|
||||
columns:
|
||||
id: id
|
||||
dated: fecha
|
||||
reference: referencia
|
||||
invoiceNumber: número factura
|
||||
isBooked: reservado
|
||||
isExcludedFromAvailable: excluido del disponible
|
||||
notes: notas
|
||||
isConfirmed: confirmado
|
||||
isVirtual: virtual
|
||||
isRaid: incursión
|
||||
commission: comisión
|
||||
isOrdered: precio3
|
||||
created: creado
|
||||
observation: observación
|
||||
isBlocked: bloqueado
|
||||
loadPriority: prioridad de carga
|
||||
supplierFk: proveedor
|
||||
travelFk: envío
|
||||
companyFk: empresa
|
||||
observationEditorFk: editor observación
|
||||
currencyFk: moneda
|
|
@ -158,7 +158,6 @@ module.exports = Self => {
|
|||
e.invoiceNumber,
|
||||
e.isBooked,
|
||||
e.isExcludedFromAvailable,
|
||||
e.notes,
|
||||
e.evaNotes AS observation,
|
||||
e.isConfirmed,
|
||||
e.isOrdered,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "EntryLog",
|
||||
"base": "VnModel",
|
||||
"base": "Log",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "entryLog"
|
||||
|
@ -55,4 +55,4 @@
|
|||
"scope": {
|
||||
"order": ["creationDate DESC", "id DESC"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,9 +27,6 @@
|
|||
"isExcludedFromAvailable": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"notes": {
|
||||
"type": "string"
|
||||
},
|
||||
"isConfirmed": {
|
||||
"type": "boolean"
|
||||
},
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue