Merge branch 'dev' into 2883-invoiceIn-Booking
gitea/salix/pipeline/head This commit looks good
Details
gitea/salix/pipeline/head This commit looks good
Details
This commit is contained in:
commit
b936272898
|
@ -9,7 +9,7 @@ env:
|
|||
rules:
|
||||
require-jsdoc: 0
|
||||
no-undef: 0
|
||||
max-len: 0
|
||||
max-len: ["error", {code: 120}]
|
||||
eqeqeq: 0
|
||||
operator-linebreak: 0
|
||||
radix: 0
|
||||
|
@ -17,7 +17,7 @@ rules:
|
|||
camelcase: 0
|
||||
default-case: 0
|
||||
no-eq-null: 0
|
||||
no-console: 0
|
||||
no-console: ["error"]
|
||||
no-warning-comments: 0
|
||||
no-empty: [error, allowEmptyCatch: true]
|
||||
complexity: 0
|
||||
|
|
|
@ -40,7 +40,7 @@ pipeline {
|
|||
NODE_ENV = ""
|
||||
}
|
||||
steps {
|
||||
nodejs('node-v12') {
|
||||
nodejs('node-v14') {
|
||||
sh 'npm install --no-audit --prefer-offline'
|
||||
sh 'gulp install --ci'
|
||||
}
|
||||
|
@ -57,14 +57,14 @@ pipeline {
|
|||
parallel {
|
||||
stage('Frontend') {
|
||||
steps {
|
||||
nodejs('node-v12') {
|
||||
nodejs('node-v14') {
|
||||
sh 'jest --ci --reporters=default --reporters=jest-junit --maxWorkers=2'
|
||||
}
|
||||
}
|
||||
}
|
||||
// stage('Backend') {
|
||||
// steps {
|
||||
// nodejs('node-v12') {
|
||||
// nodejs('node-v14') {
|
||||
// sh 'gulp launchBackTest --ci'
|
||||
// }
|
||||
// }
|
||||
|
@ -80,7 +80,7 @@ pipeline {
|
|||
CREDENTIALS = credentials('docker-registry')
|
||||
}
|
||||
steps {
|
||||
nodejs('node-v12') {
|
||||
nodejs('node-v14') {
|
||||
sh 'gulp build'
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@ Required applications.
|
|||
* Node.js = 14.x LTS
|
||||
* Docker
|
||||
* Git
|
||||
* Docker
|
||||
|
||||
You will need to install globally the following items.
|
||||
```
|
||||
|
|
|
@ -89,6 +89,7 @@ module.exports = Self => {
|
|||
await uploadNewFile(ctx, dms, myOptions);
|
||||
|
||||
if (tx) await tx.commit();
|
||||
|
||||
return dms;
|
||||
} catch (e) {
|
||||
if (tx) await tx.rollback();
|
||||
|
|
|
@ -96,6 +96,7 @@ module.exports = Self => {
|
|||
}
|
||||
|
||||
if (tx) await tx.commit();
|
||||
|
||||
return addedDms;
|
||||
} catch (e) {
|
||||
if (tx) await tx.rollback();
|
||||
|
|
|
@ -7,8 +7,7 @@ module.exports = function(Self) {
|
|||
required: true,
|
||||
description: `Code of the table you ask its configuration`,
|
||||
http: {source: 'body'}
|
||||
}
|
||||
],
|
||||
}],
|
||||
returns: {
|
||||
type: 'object',
|
||||
root: true
|
||||
|
@ -29,6 +28,6 @@ module.exports = function(Self) {
|
|||
|
||||
config.userFk = ctx.req.accessToken.userId;
|
||||
|
||||
return await Self.app.models.UserConfigView.create(config);
|
||||
return Self.app.models.UserConfigView.create(config);
|
||||
};
|
||||
};
|
||||
|
|
|
@ -29,6 +29,9 @@
|
|||
"ChatConfig": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"DefaultViewConfig": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"Delivery": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
|
|
|
@ -25,6 +25,9 @@
|
|||
},
|
||||
"isAutoConciliated": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"maxAmount": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"acls": [{
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"name": "DefaultViewConfig",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "salix.defaultViewConfig"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"tableCode": {
|
||||
"id": true,
|
||||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
"columns": {
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"acls": [{
|
||||
"accessType": "READ",
|
||||
"principalType": "ROLE",
|
||||
"principalId": "$everyone",
|
||||
"permission": "ALLOW"
|
||||
}]
|
||||
}
|
|
@ -23,5 +23,13 @@
|
|||
"model": "Account",
|
||||
"foreignKey": "userFk"
|
||||
}
|
||||
}
|
||||
},
|
||||
"acls": [
|
||||
{
|
||||
"accessType": "READ",
|
||||
"principalType": "ROLE",
|
||||
"principalId": "$everyone",
|
||||
"permission": "ALLOW"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -151,6 +151,7 @@ module.exports = Self => {
|
|||
await fs.unlink(srcFilePath);
|
||||
|
||||
await tx.commit();
|
||||
|
||||
return newImage;
|
||||
} catch (e) {
|
||||
await tx.rollback();
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
CREATE TABLE `vn`.`invoiceInLog` (
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`originFk` MEDIUMINT UNSIGNED NOT NULL,
|
||||
`userFk` int(10) unsigned DEFAULT NULL,
|
||||
`action` set('insert','update','delete') COLLATE utf8_unicode_ci NOT NULL,
|
||||
`creationDate` timestamp NULL DEFAULT current_timestamp(),
|
||||
`description` text CHARACTER SET utf8 DEFAULT NULL,
|
||||
`changedModel` varchar(45) COLLATE utf8_unicode_ci DEFAULT NULL,
|
||||
`oldInstance` text COLLATE utf8_unicode_ci DEFAULT NULL,
|
||||
`newInstance` text COLLATE utf8_unicode_ci DEFAULT NULL,
|
||||
`changedModelId` int(11) DEFAULT NULL,
|
||||
`changedModelValue` varchar(45) COLLATE utf8_unicode_ci DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `originFk` (`originFk`),
|
||||
KEY `userFk` (`userFk`),
|
||||
CONSTRAINT `invoiceInLog_ibfk_1` FOREIGN KEY (`originFk`) REFERENCES `vn`.`invoiceIn` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT `invoiceInLog_ibfk_2` FOREIGN KEY (`userFk`) REFERENCES `account`.`user` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
|
|
@ -1,192 +0,0 @@
|
|||
DROP PROCEDURE IF EXISTS `vn`.`sale_getProblems`;
|
||||
|
||||
DELIMITER $$
|
||||
$$
|
||||
CREATE
|
||||
DEFINER = root@`%` PROCEDURE `vn`.`sale_getProblems`(IN vIsTodayRelative TINYINT(1))
|
||||
BEGIN
|
||||
/**
|
||||
* Calcula los problemas de cada venta
|
||||
* para un conjunto de tickets.
|
||||
*
|
||||
* @table tmp.sale_getProblems(ticketFk, clientFk, warehouseFk, shipped) Identificadores de los tickets a calcular
|
||||
* @return tmp.sale_problems
|
||||
*/
|
||||
DECLARE vWarehouse INT;
|
||||
DECLARE vDate DATE;
|
||||
DECLARE vAvailableCache INT;
|
||||
DECLARE vDone INT DEFAULT 0;
|
||||
DECLARE vComponentCount INT;
|
||||
|
||||
DECLARE vCursor CURSOR FOR
|
||||
SELECT DISTINCT tt.warehouseFk, IF(vIsTodayRelative, CURDATE(), date(tt.shipped))
|
||||
FROM tmp.sale_getProblems tt
|
||||
WHERE DATE(tt.shipped) BETWEEN CURDATE()
|
||||
AND TIMESTAMPADD(DAY, IF(vIsTodayRelative, 9.9, 1.9), CURDATE());
|
||||
|
||||
DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = 1;
|
||||
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp.sale_problems;
|
||||
CREATE TEMPORARY TABLE tmp.sale_problems (
|
||||
ticketFk INT(11),
|
||||
saleFk INT(11),
|
||||
isFreezed INTEGER(1) DEFAULT 0,
|
||||
risk DECIMAL(10,2) DEFAULT 0,
|
||||
hasTicketRequest INTEGER(1) DEFAULT 0,
|
||||
isAvailable INTEGER(1) DEFAULT 1,
|
||||
itemShortage VARCHAR(250),
|
||||
isTaxDataChecked INTEGER(1) DEFAULT 1,
|
||||
itemDelay VARCHAR(250),
|
||||
hasComponentLack INTEGER(1),
|
||||
PRIMARY KEY (ticketFk, saleFk)
|
||||
) ENGINE = MEMORY;
|
||||
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp.ticket_list;
|
||||
CREATE TEMPORARY TABLE tmp.ticket_list
|
||||
(PRIMARY KEY (ticketFk))
|
||||
ENGINE = MEMORY
|
||||
SELECT tp.ticketFk, c.id clientFk
|
||||
FROM tmp.sale_getProblems tp
|
||||
JOIN vn.client c ON c.id = tp.clientFk;
|
||||
|
||||
SELECT COUNT(*) INTO vComponentCount
|
||||
FROM vn.component c
|
||||
WHERE c.isRequired;
|
||||
|
||||
INSERT INTO tmp.sale_problems(ticketFk, hasComponentLack, saleFk)
|
||||
SELECT tl.ticketFk, (COUNT(DISTINCT s.id) * vComponentCount > COUNT(c.id)), s.id
|
||||
FROM tmp.ticket_list tl
|
||||
JOIN vn.sale s ON s.ticketFk = tl.ticketFk
|
||||
LEFT JOIN vn.saleComponent sc ON sc.saleFk = s.id
|
||||
LEFT JOIN vn.component c ON c.id = sc.componentFk AND c.isRequired
|
||||
GROUP BY tl.ticketFk, s.id;
|
||||
|
||||
INSERT INTO tmp.sale_problems(ticketFk, isFreezed)
|
||||
SELECT DISTINCT tl.ticketFk, TRUE
|
||||
FROM tmp.ticket_list tl
|
||||
JOIN vn.client c ON c.id = tl.clientFk
|
||||
WHERE c.isFreezed
|
||||
ON DUPLICATE KEY UPDATE
|
||||
isFreezed = c.isFreezed;
|
||||
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp.clientGetDebt;
|
||||
CREATE TEMPORARY TABLE tmp.clientGetDebt
|
||||
(PRIMARY KEY (clientFk))
|
||||
ENGINE = MEMORY
|
||||
SELECT DISTINCT clientFk
|
||||
FROM tmp.ticket_list;
|
||||
|
||||
CALL clientGetDebt(CURDATE());
|
||||
|
||||
INSERT INTO tmp.sale_problems(ticketFk, risk)
|
||||
SELECT DISTINCT tl.ticketFk, r.risk
|
||||
FROM tmp.ticket_list tl
|
||||
JOIN vn.ticket t ON t.id = tl.ticketFk
|
||||
JOIN vn.agencyMode a ON t.agencyModeFk = a.id
|
||||
JOIN tmp.risk r ON r.clientFk = t.clientFk
|
||||
JOIN vn.client c ON c.id = t.clientFk
|
||||
JOIN vn.clientConfig cc
|
||||
WHERE r.risk > c.credit + 10
|
||||
AND a.isRiskFree = FALSE
|
||||
ON DUPLICATE KEY UPDATE
|
||||
risk = r.risk;
|
||||
|
||||
INSERT INTO tmp.sale_problems(ticketFk, hasTicketRequest)
|
||||
SELECT DISTINCT tl.ticketFk, TRUE
|
||||
FROM tmp.ticket_list tl
|
||||
JOIN vn.ticketRequest tr ON tr.ticketFk = tl.ticketFk
|
||||
WHERE tr.isOK IS NULL
|
||||
ON DUPLICATE KEY UPDATE
|
||||
hasTicketRequest = TRUE;
|
||||
|
||||
OPEN vCursor;
|
||||
|
||||
WHILE NOT vDone
|
||||
DO
|
||||
FETCH vCursor INTO vWarehouse, vDate;
|
||||
|
||||
CALL cache.available_refresh(vAvailableCache, FALSE, vWarehouse, vDate);
|
||||
|
||||
INSERT INTO tmp.sale_problems(ticketFk, isAvailable, saleFk)
|
||||
SELECT tl.ticketFk, FALSE, s.id
|
||||
FROM tmp.ticket_list tl
|
||||
JOIN vn.ticket t ON t.id = tl.ticketFk
|
||||
JOIN vn.sale s ON s.ticketFk = t.id
|
||||
JOIN vn.item i ON i.id = s.itemFk
|
||||
JOIN vn.itemType it on it.id = i.typeFk
|
||||
LEFT JOIN cache.available av ON av.item_id = i.id
|
||||
AND av.calc_id = vAvailableCache
|
||||
WHERE date(t.shipped) = vDate
|
||||
AND it.categoryFk != 6
|
||||
AND IFNULL(av.available, 0) < 0
|
||||
AND s.isPicked = FALSE
|
||||
AND NOT i.generic
|
||||
AND vWarehouse = t.warehouseFk
|
||||
GROUP BY tl.ticketFk
|
||||
ON DUPLICATE KEY UPDATE
|
||||
isAvailable = FALSE, saleFk = VALUE(saleFk);
|
||||
|
||||
INSERT INTO tmp.sale_problems(ticketFk, itemShortage, saleFk)
|
||||
SELECT ticketFk, problem, saleFk
|
||||
FROM (
|
||||
SELECT tl.ticketFk, CONCAT('F: ',GROUP_CONCAT(i.id, ' ', i.longName, ' ')) problem, s.id AS saleFk
|
||||
FROM tmp.ticket_list tl
|
||||
JOIN vn.ticket t ON t.id = tl.ticketFk
|
||||
JOIN vn.sale s ON s.ticketFk = t.id
|
||||
JOIN vn.item i ON i.id = s.itemFk
|
||||
JOIN vn.itemType it on it.id = i.typeFk
|
||||
LEFT JOIN vn.itemShelvingStock_byWarehouse issw ON issw.itemFk = i.id AND issw.warehouseFk = t.warehouseFk
|
||||
LEFT JOIN cache.available av ON av.item_id = i.id AND av.calc_id = vAvailableCache
|
||||
WHERE IFNULL(av.available, 0) < 0
|
||||
AND s.quantity > IFNULL(issw.visible, 0)
|
||||
AND s.quantity > 0
|
||||
AND s.isPicked = FALSE
|
||||
AND s.reserved = FALSE
|
||||
AND it.categoryFk != 6
|
||||
AND IF(vIsTodayRelative, TRUE, date(t.shipped) = vDate)
|
||||
AND NOT i.generic
|
||||
AND CURDATE() = vDate
|
||||
AND t.warehouseFk = vWarehouse
|
||||
GROUP BY tl.ticketFk LIMIT 1) sub
|
||||
ON DUPLICATE KEY UPDATE
|
||||
itemShortage = sub.problem, saleFk = sub.saleFk;
|
||||
|
||||
INSERT INTO tmp.sale_problems(ticketFk, itemDelay, saleFk)
|
||||
SELECT ticketFk, problem, saleFk
|
||||
FROM (
|
||||
SELECT tl.ticketFk, GROUP_CONCAT('I: ',i.id, ' ', i.longName, ' ') problem, s.id AS saleFk
|
||||
FROM tmp.ticket_list tl
|
||||
JOIN vn.ticket t ON t.id = tl.ticketFk
|
||||
JOIN vn.sale s ON s.ticketFk = t.id
|
||||
JOIN vn.item i ON i.id = s.itemFk
|
||||
JOIN vn.itemType it on it.id = i.typeFk
|
||||
LEFT JOIN vn.itemShelvingStock_byWarehouse issw ON issw.itemFk = i.id AND issw.warehouseFk = t.warehouseFk
|
||||
WHERE s.quantity > IFNULL(issw.visible, 0)
|
||||
AND s.quantity > 0
|
||||
AND s.isPicked = FALSE
|
||||
AND s.reserved = FALSE
|
||||
AND it.categoryFk != 6
|
||||
AND IF(vIsTodayRelative, TRUE, date(t.shipped) = vDate)
|
||||
AND NOT i.generic
|
||||
AND CURDATE() = vDate
|
||||
AND t.warehouseFk = vWarehouse
|
||||
GROUP BY tl.ticketFk LIMIT 1) sub
|
||||
ON DUPLICATE KEY UPDATE
|
||||
itemDelay = sub.problem, saleFk = sub.saleFk;
|
||||
END WHILE;
|
||||
|
||||
CLOSE vCursor;
|
||||
|
||||
INSERT INTO tmp.sale_problems(ticketFk, isTaxDataChecked)
|
||||
SELECT DISTINCT tl.ticketFk, FALSE
|
||||
FROM tmp.ticket_list tl
|
||||
JOIN vn.client c ON c.id = tl.clientFk
|
||||
WHERE c.isTaxDataChecked = FALSE
|
||||
ON DUPLICATE KEY UPDATE
|
||||
isTaxDataChecked = FALSE;
|
||||
|
||||
DROP TEMPORARY TABLE
|
||||
tmp.clientGetDebt,
|
||||
tmp.ticket_list;
|
||||
END;;$$
|
||||
DELIMITER ;
|
|
@ -1,95 +0,0 @@
|
|||
DROP PROCEDURE IF EXISTS `vn`.`ticket_componentMakeUpdate`;
|
||||
|
||||
DELIMITER $$
|
||||
$$
|
||||
|
||||
CREATE
|
||||
DEFINER = root@`%` PROCEDURE `vn`.`ticket_componentMakeUpdate`(IN vTicketFk INT, IN vClientFk INT,
|
||||
IN vNickname VARCHAR(50), IN vAgencyModeFk INT,
|
||||
IN vAddressFk INT, IN vZoneFk INT, IN vWarehouseFk TINYINT,
|
||||
IN vCompanyFk SMALLINT, IN vShipped DATETIME,
|
||||
IN vLanded DATE, IN vIsDeleted TINYINT(1),
|
||||
IN vHasToBeUnrouted TINYINT(1), IN vOption INT)
|
||||
BEGIN
|
||||
/**
|
||||
* Modifica en el ticket los campos que se le pasan por parámetro
|
||||
* y cambia sus componentes
|
||||
*
|
||||
* @param vTicketFk Id del ticket a modificar
|
||||
* @param vClientFk nuevo cliente
|
||||
* @param vNickname nuevo alias
|
||||
* @param vAgencyModeFk nueva agencia
|
||||
* @param vAddressFk nuevo consignatario
|
||||
* @param vZoneFk nueva zona
|
||||
* @param vWarehouseFk nuevo almacen
|
||||
* @param vCompanyFk nueva empresa
|
||||
* @param vShipped nueva fecha del envio de mercancia
|
||||
* @param vLanded nueva fecha de recepcion de mercancia
|
||||
* @param vIsDeleted si se borra el ticket
|
||||
* @param vHasToBeUnrouted si se le elimina la ruta al ticket
|
||||
* @param vOption opcion para el case del proc ticketComponentUpdateSale
|
||||
*/
|
||||
DECLARE vPrice DECIMAL(10,2);
|
||||
DECLARE vBonus DECIMAL(10,2);
|
||||
|
||||
CALL ticket_componentPreview (vTicketFk, vLanded, vAddressFk, vZoneFk, vWarehouseFk);
|
||||
|
||||
IF (SELECT addressFk FROM ticket WHERE id = vTicketFk) <> vAddressFk THEN
|
||||
|
||||
UPDATE ticket t
|
||||
JOIN address a ON a.id = vAddressFk
|
||||
SET t.nickname = a.nickname
|
||||
WHERE t.id = vTicketFk;
|
||||
|
||||
END IF;
|
||||
|
||||
CALL zone_getShippedWarehouse(vlanded, vAddressFk, vAgencyModeFk);
|
||||
|
||||
SELECT zoneFk, price, bonus INTO vZoneFk, vPrice, vBonus
|
||||
FROM tmp.zoneGetShipped
|
||||
WHERE shipped BETWEEN DATE(vShipped) AND util.dayEnd(vShipped) AND warehouseFk = vWarehouseFk LIMIT 1;
|
||||
|
||||
UPDATE ticket t
|
||||
SET
|
||||
t.clientFk = vClientFk,
|
||||
t.nickname = vNickname,
|
||||
t.agencyModeFk = vAgencyModeFk,
|
||||
t.addressFk = vAddressFk,
|
||||
t.zoneFk = vZoneFk,
|
||||
t.zonePrice = vPrice,
|
||||
t.zoneBonus = vBonus,
|
||||
t.warehouseFk = vWarehouseFk,
|
||||
t.companyFk = vCompanyFk,
|
||||
t.landed = vLanded,
|
||||
t.shipped = vShipped,
|
||||
t.isDeleted = vIsDeleted
|
||||
WHERE
|
||||
t.id = vTicketFk;
|
||||
|
||||
IF vHasToBeUnrouted THEN
|
||||
UPDATE ticket t SET t.routeFk = NULL
|
||||
WHERE t.id = vTicketFk;
|
||||
END IF;
|
||||
|
||||
IF vOption <> 8 THEN
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp.sale;
|
||||
CREATE TEMPORARY TABLE tmp.sale
|
||||
(PRIMARY KEY (saleFk))
|
||||
ENGINE = MEMORY
|
||||
SELECT id AS saleFk, vWarehouseFk warehouseFk
|
||||
FROM sale s WHERE s.ticketFk = vTicketFk;
|
||||
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp.ticketComponent;
|
||||
CREATE TEMPORARY TABLE tmp.ticketComponent
|
||||
SELECT * FROM tmp.ticketComponentPreview;
|
||||
|
||||
CALL ticketComponentUpdateSale (vOption);
|
||||
|
||||
DROP TEMPORARY TABLE tmp.sale;
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp.ticketComponent;
|
||||
END IF;
|
||||
|
||||
DROP TEMPORARY TABLE tmp.zoneGetShipped, tmp.ticketComponentPreview;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
DELETE FROM `salix`.`ACL` WHERE id = 189;
|
||||
DELETE FROM `salix`.`ACL` WHERE id = 188;
|
||||
UPDATE `salix`.`ACL` tdms SET tdms.accessType = '*'
|
||||
WHERE tdms.id = 165;
|
||||
|
||||
INSERT INTO `salix`.`ACL` (model, principalId, property, accessType)
|
||||
VALUES
|
||||
('InvoiceInTax','administrative', '*', '*'),
|
||||
('InvoiceInLog','administrative', '*', 'READ');
|
||||
|
||||
INSERT INTO `salix`.`ACL` (model, property, accessType, permission, principalType, principalId)
|
||||
VALUES
|
||||
('InvoiceOut', 'createManualInvoice', 'WRITE', 'ALLOW', 'ROLE', 'invoicing'),
|
||||
('InvoiceOut', 'globalInvoicing', 'WRITE', 'ALLOW', 'ROLE', 'invoicing');
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
create table `vn`.`itemMatchProperties`
|
||||
(
|
||||
itemFk int not null,
|
||||
name varchar(80) not null,
|
||||
producer varchar(80) not null,
|
||||
size int not null,
|
||||
constraint itemMatchProperties_pk
|
||||
primary key (itemFk, name, producer, size),
|
||||
constraint itemFk___fk
|
||||
foreign key (itemFk) references item (id)
|
||||
on update cascade on delete cascade
|
||||
)
|
||||
comment 'Propiedades para encontrar articulos equivalentes en verdnatura';
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
drop procedure `vn`.`invoiceFromClient`;
|
||||
|
||||
DELIMITER $$
|
||||
$$
|
||||
create
|
||||
definer = root@`%` procedure `vn`.`invoiceFromClient`(IN vMaxTicketDate datetime, IN vClientFk INT, IN vCompanyFk INT)
|
||||
BEGIN
|
||||
DECLARE vMinTicketDate DATE DEFAULT TIMESTAMPADD(YEAR, -3, CURDATE());
|
||||
SET vMaxTicketDate = util.dayend(vMaxTicketDate);
|
||||
|
||||
DROP TEMPORARY TABLE IF EXISTS `ticketToInvoice`;
|
||||
CREATE TEMPORARY TABLE `ticketToInvoice`
|
||||
(PRIMARY KEY (`id`))
|
||||
ENGINE = MEMORY
|
||||
SELECT id FROM ticket t
|
||||
WHERE t.clientFk = vClientFk
|
||||
AND t.refFk IS NULL
|
||||
AND t.companyFk = vCompanyFk
|
||||
AND (t.shipped BETWEEN vMinTicketDate AND vMaxTicketDate);
|
||||
END;;$$
|
||||
DELIMITER ;
|
|
@ -1,45 +0,0 @@
|
|||
drop procedure `vn`.`invoiceOut_newFromClient`;
|
||||
|
||||
DELIMITER $$
|
||||
$$
|
||||
create
|
||||
definer = root@`%` procedure `vn`.`invoiceOut_newFromClient`(IN vClientFk int, IN vSerial char(2), IN vMaxShipped date,
|
||||
IN vCompanyFk int, IN vTaxArea varchar(25),
|
||||
IN vRef varchar(25), OUT vInvoiceId int)
|
||||
BEGIN
|
||||
/**
|
||||
* Factura los tickets de un cliente hasta una fecha dada
|
||||
* @param vClientFk Id del cliente a facturar
|
||||
* @param vSerial Serie de factura
|
||||
* @param vMaxShipped Fecha hasta la cual cogera tickets para facturar
|
||||
* @param vCompanyFk Id de la empresa desde la que se factura
|
||||
* @param vTaxArea Tipo de iva en relacion a la empresa y al cliente, NULL por defecto
|
||||
* @param vRef Referencia de la factura en caso que se quiera forzar, NULL por defecto
|
||||
* @return vInvoiceId factura
|
||||
*/
|
||||
|
||||
DECLARE vIsRefEditable BOOLEAN;
|
||||
|
||||
IF vRef IS NOT NULL THEN
|
||||
SELECT isRefEditable INTO vIsRefEditable
|
||||
FROM invoiceOutSerial
|
||||
WHERE code = vSerial;
|
||||
|
||||
IF NOT vIsRefEditable THEN
|
||||
CALL util.throw('serial non editable');
|
||||
END IF;
|
||||
END IF;
|
||||
|
||||
CALL invoiceFromClient(vMaxShipped, vClientFk, vCompanyFk);
|
||||
CALL invoiceOut_new(vSerial, CURDATE(), vTaxArea, vInvoiceId);
|
||||
|
||||
UPDATE invoiceOut
|
||||
SET `ref` = vRef
|
||||
WHERE id = vInvoiceId
|
||||
AND vRef IS NOT NULL;
|
||||
|
||||
IF vSerial <> 'R' AND NOT ISNULL(vInvoiceId) AND vInvoiceId <> 0 THEN
|
||||
CALL invoiceOutBooking(vInvoiceId);
|
||||
END IF;
|
||||
END;;$$
|
||||
DELIMITER ;
|
|
@ -1,38 +0,0 @@
|
|||
drop procedure `vn`.`invoiceOut_newFromTicket`;
|
||||
|
||||
DELIMITER $$
|
||||
$$
|
||||
create
|
||||
definer = root@`%` procedure `vn`.`invoiceOut_newFromTicket`(IN vTicketFk int, IN vSerial char(2), IN vTaxArea varchar(25),
|
||||
IN vRef varchar(25), OUT vInvoiceId int)
|
||||
BEGIN
|
||||
/**
|
||||
* Factura un ticket
|
||||
* @param vTicketFk Id del ticket
|
||||
* @param vSerial Serie de factura
|
||||
* @param vTaxArea Area de la factura en caso de querer forzarlo,
|
||||
* en la mayoria de los casos poner NULL
|
||||
* @return vInvoiceId
|
||||
*/
|
||||
DECLARE vIsRefEditable BOOLEAN;
|
||||
CALL invoiceFromTicket(vTicketFk);
|
||||
CALL invoiceOut_new(vSerial, CURDATE(), vTaxArea, vInvoiceId);
|
||||
|
||||
IF vRef IS NOT NULL THEN
|
||||
SELECT isRefEditable INTO vIsRefEditable
|
||||
FROM invoiceOutSerial
|
||||
WHERE code = vSerial;
|
||||
IF NOT vIsRefEditable THEN
|
||||
CALL util.throw('serial non editable');
|
||||
END IF;
|
||||
|
||||
UPDATE invoiceOut
|
||||
SET `ref` = vRef
|
||||
WHERE id = vInvoiceId;
|
||||
END IF;
|
||||
|
||||
IF vSerial <> 'R' AND NOT ISNULL(vInvoiceId) AND vInvoiceId <> 0 THEN
|
||||
CALL invoiceOutBooking(vInvoiceId);
|
||||
END IF;
|
||||
END;;$$
|
||||
DELIMITER ;
|
|
@ -1,7 +0,0 @@
|
|||
ALTER TABLE `vn`.`sample` ADD COLUMN
|
||||
(`datepickerEnabled` TINYINT(1) NOT NULL DEFAULT 0);
|
||||
|
||||
ALTER TABLE `vn`.`sample` MODIFY code VARCHAR(25) charset utf8 NOT NULL;
|
||||
|
||||
INSERT INTO `vn`.`sample` (code, description, isVisible, hasCompany, hasPreview, datepickerEnabled)
|
||||
VALUES ('client-debt-statement', 'Extracto del cliente', 1, 0, 1, 1);
|
|
@ -1,109 +0,0 @@
|
|||
drop procedure `vn`.`ticket_close`;
|
||||
|
||||
DELIMITER $$
|
||||
$$
|
||||
create
|
||||
definer = root@`%` procedure `vn`.`ticket_close`()
|
||||
BEGIN
|
||||
/**
|
||||
* Realiza el cierre de todos los
|
||||
* tickets de la tabla tmp.ticket_close.
|
||||
*
|
||||
* @table tmp.ticket_close(ticketFk) Identificadores de los tickets a cerrar
|
||||
*/
|
||||
DECLARE vDone BOOL;
|
||||
DECLARE vClientFk INT;
|
||||
DECLARE vCurTicketFk INT;
|
||||
DECLARE vIsTaxDataChecked BOOL;
|
||||
DECLARE vCompanyFk INT;
|
||||
DECLARE vShipped DATE;
|
||||
DECLARE vNewInvoiceId INT;
|
||||
DECLARE vHasDailyInvoice BOOL;
|
||||
DECLARE vWithPackage BOOL;
|
||||
DECLARE vHasToInvoice BOOL;
|
||||
|
||||
DECLARE cur CURSOR FOR
|
||||
SELECT ticketFk FROM tmp.ticket_close;
|
||||
|
||||
DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = TRUE;
|
||||
DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN
|
||||
RESIGNAL;
|
||||
END;
|
||||
|
||||
OPEN cur;
|
||||
|
||||
proc: LOOP
|
||||
SET vDone = FALSE;
|
||||
|
||||
FETCH cur INTO vCurTicketFk;
|
||||
|
||||
IF vDone THEN
|
||||
LEAVE proc;
|
||||
END IF;
|
||||
|
||||
-- Fetch ticket data
|
||||
SELECT
|
||||
c.id,
|
||||
c.isTaxDataChecked,
|
||||
t.companyFk,
|
||||
t.shipped,
|
||||
co.hasDailyInvoice,
|
||||
w.isManaged,
|
||||
c.hasToInvoice
|
||||
INTO vClientFk,
|
||||
vIsTaxDataChecked,
|
||||
vCompanyFk,
|
||||
vShipped,
|
||||
vHasDailyInvoice,
|
||||
vWithPackage,
|
||||
vHasToInvoice
|
||||
FROM ticket t
|
||||
JOIN `client` c ON c.id = t.clientFk
|
||||
JOIN province p ON p.id = c.provinceFk
|
||||
JOIN country co ON co.id = p.countryFk
|
||||
JOIN warehouse w ON w.id = t.warehouseFk
|
||||
WHERE t.id = vCurTicketFk;
|
||||
|
||||
INSERT INTO ticketPackaging (ticketFk, packagingFk, quantity)
|
||||
(SELECT vCurTicketFk, p.id, COUNT(*)
|
||||
FROM expedition e
|
||||
JOIN packaging p ON p.itemFk = e.itemFk
|
||||
WHERE e.ticketFk = vCurTicketFk AND p.isPackageReturnable
|
||||
AND vWithPackage
|
||||
GROUP BY p.itemFk);
|
||||
|
||||
-- No retornables o no catalogados
|
||||
INSERT INTO sale (itemFk, ticketFk, concept, quantity, price, isPriceFixed)
|
||||
(SELECT e.itemFk, vCurTicketFk, i.name, COUNT(*) AS amount, getSpecialPrice(e.itemFk, vClientFk), 1
|
||||
FROM expedition e
|
||||
JOIN item i ON i.id = e.itemFk
|
||||
LEFT JOIN packaging p ON p.itemFk = i.id
|
||||
WHERE e.ticketFk = vCurTicketFk AND IFNULL(p.isPackageReturnable, 0) = 0
|
||||
AND getSpecialPrice(e.itemFk, vClientFk) > 0
|
||||
GROUP BY e.itemFk);
|
||||
|
||||
CALL vn.zonePromo_Make();
|
||||
|
||||
IF(vHasDailyInvoice) AND vHasToInvoice THEN
|
||||
|
||||
-- Facturacion rapida
|
||||
CALL ticketTrackingAdd(vCurTicketFk, 'DELIVERED', NULL);
|
||||
-- Facturar si está contabilizado
|
||||
IF vIsTaxDataChecked THEN
|
||||
CALL invoiceOut_newFromClient(
|
||||
vClientFk,
|
||||
(SELECT invoiceSerial(vClientFk, vCompanyFk, 'M')),
|
||||
vShipped,
|
||||
vCompanyFk,
|
||||
NULL,
|
||||
NULL,
|
||||
vNewInvoiceId);
|
||||
END IF;
|
||||
ELSE
|
||||
CALL ticketTrackingAdd(vCurTicketFk, (SELECT vn.getAlert3State(vCurTicketFk)), NULL);
|
||||
END IF;
|
||||
END LOOP;
|
||||
|
||||
CLOSE cur;
|
||||
END;;$$
|
||||
DELIMITER ;
|
|
@ -1,118 +0,0 @@
|
|||
drop procedure `vn`.`ticket_closeAll`;
|
||||
|
||||
DELIMITER $$
|
||||
$$
|
||||
create definer = root@`%` procedure `vn`.`ticket_closeAll__`()
|
||||
BEGIN
|
||||
/**
|
||||
* Realiza el cierre de todos los
|
||||
* tickets de la tabla tmp.ticketClosure.
|
||||
*
|
||||
* @param vTicketFk Id del ticket
|
||||
*/
|
||||
DECLARE vDone BOOL;
|
||||
DECLARE vClientFk INT;
|
||||
DECLARE vCurTicketFk INT;
|
||||
DECLARE vIsTaxDataChecked BOOL;
|
||||
DECLARE vCompanyFk INT;
|
||||
DECLARE vShipped DATE;
|
||||
DECLARE vNewInvoiceId INT;
|
||||
DECLARE vHasDailyInvoice BOOL;
|
||||
DECLARE vWithPackage BOOL;
|
||||
DECLARE vHasToInvoice BOOL;
|
||||
|
||||
DECLARE cur CURSOR FOR
|
||||
SELECT ticketFk FROM tmp.ticketClosure;
|
||||
|
||||
DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = TRUE;
|
||||
DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN
|
||||
RESIGNAL;
|
||||
END;
|
||||
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp.ticketClosure2;
|
||||
CREATE TEMPORARY TABLE tmp.ticketClosure2
|
||||
SELECT ticketFk FROM tmp.ticketClosure;
|
||||
|
||||
INSERT INTO tmp.ticketClosure
|
||||
SELECT id FROM stowaway s
|
||||
JOIN tmp.ticketClosure2 tc ON s.shipFk = tc.ticketFk;
|
||||
OPEN cur;
|
||||
|
||||
proc: LOOP
|
||||
SET vDone = FALSE;
|
||||
|
||||
FETCH cur INTO vCurTicketFk;
|
||||
|
||||
IF vDone THEN
|
||||
LEAVE proc;
|
||||
END IF;
|
||||
|
||||
-- ticketClosure start
|
||||
SELECT
|
||||
c.id,
|
||||
c.isTaxDataChecked,
|
||||
t.companyFk,
|
||||
t.shipped,
|
||||
co.hasDailyInvoice,
|
||||
w.isManaged,
|
||||
c.hasToInvoice
|
||||
INTO vClientFk,
|
||||
vIsTaxDataChecked,
|
||||
vCompanyFk,
|
||||
vShipped,
|
||||
vHasDailyInvoice,
|
||||
vWithPackage,
|
||||
vHasToInvoice
|
||||
FROM ticket t
|
||||
JOIN `client` c ON c.id = t.clientFk
|
||||
JOIN province p ON p.id = c.provinceFk
|
||||
JOIN country co ON co.id = p.countryFk
|
||||
JOIN warehouse w ON w.id = t.warehouseFk
|
||||
WHERE t.id = vCurTicketFk;
|
||||
|
||||
INSERT INTO ticketPackaging (ticketFk, packagingFk, quantity)
|
||||
(SELECT vCurTicketFk, p.id, COUNT(*)
|
||||
FROM expedition e
|
||||
JOIN packaging p ON p.itemFk = e.itemFk
|
||||
WHERE e.ticketFk = vCurTicketFk AND p.isPackageReturnable
|
||||
AND vWithPackage
|
||||
GROUP BY p.itemFk);
|
||||
|
||||
-- No retornables o no catalogados
|
||||
INSERT INTO sale (itemFk, ticketFk, concept, quantity, price, isPriceFixed)
|
||||
(SELECT e.itemFk, vCurTicketFk, i.name, COUNT(*) AS amount, getSpecialPrice(e.itemFk, vClientFk), 1
|
||||
FROM expedition e
|
||||
JOIN item i ON i.id = e.itemFk
|
||||
LEFT JOIN packaging p ON p.itemFk = i.id
|
||||
WHERE e.ticketFk = vCurTicketFk AND IFNULL(p.isPackageReturnable, 0) = 0
|
||||
AND getSpecialPrice(e.itemFk, vClientFk) > 0
|
||||
GROUP BY e.itemFk);
|
||||
|
||||
CALL vn.zonePromo_Make();
|
||||
|
||||
IF(vHasDailyInvoice) AND vHasToInvoice THEN
|
||||
|
||||
-- Facturacion rapida
|
||||
CALL ticketTrackingAdd(vCurTicketFk, 'DELIVERED', NULL);
|
||||
-- Facturar si está contabilizado
|
||||
IF vIsTaxDataChecked THEN
|
||||
CALL invoiceOut_newFromClient(
|
||||
vClientFk,
|
||||
(SELECT invoiceSerial(vClientFk, vCompanyFk, 'M')),
|
||||
vShipped,
|
||||
vCompanyFk,
|
||||
NULL,
|
||||
NULL,
|
||||
vNewInvoiceId);
|
||||
END IF;
|
||||
ELSE
|
||||
CALL ticketTrackingAdd(vCurTicketFk, (SELECT vn.getAlert3State(vCurTicketFk)), NULL);
|
||||
END IF;
|
||||
END LOOP;
|
||||
|
||||
CLOSE cur;
|
||||
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp.ticketClosure;
|
||||
END;;$$
|
||||
DELIMITER ;
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
drop procedure `vn`.`ticket_closeByTicket`;
|
||||
|
||||
DELIMITER $$
|
||||
$$
|
||||
create
|
||||
definer = root@`%` procedure `vn`.`ticket_closeByTicket`(IN vTicketFk int)
|
||||
BEGIN
|
||||
|
||||
/**
|
||||
* Inserta el ticket en la tabla temporal
|
||||
* para ser cerrado.
|
||||
*
|
||||
* @param vTicketFk Id del ticket
|
||||
*/
|
||||
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp.ticket_close;
|
||||
CREATE TEMPORARY TABLE tmp.ticket_close ENGINE = MEMORY (
|
||||
SELECT
|
||||
t.id AS ticketFk
|
||||
FROM expedition e
|
||||
INNER JOIN ticket t ON t.id = e.ticketFk
|
||||
LEFT JOIN ticketState ts ON ts.ticketFk = t.id
|
||||
JOIN alertLevel al ON al.id = ts.alertLevel
|
||||
WHERE
|
||||
al.code = 'PACKED'
|
||||
AND t.id = vTicketFk
|
||||
AND t.refFk IS NULL
|
||||
GROUP BY e.ticketFk);
|
||||
|
||||
CALL ticket_close();
|
||||
|
||||
DROP TEMPORARY TABLE tmp.ticket_close;
|
||||
END;;$$
|
||||
DELIMITER ;
|
|
@ -1,2 +0,0 @@
|
|||
INSERT INTO `vn`.`sample` (`code`, `description`, `isVisible`, `hasCompany`, `hasPreview`)
|
||||
VALUES ('credit-request', 'Solicitud de crédito', 1, 1, 1);
|
|
@ -1 +0,0 @@
|
|||
DROP TRIGGER vn.supplierAccount_AfterInsert;
|
|
@ -1,33 +0,0 @@
|
|||
DROP TRIGGER IF EXISTS vn.ticket_afterUpdate;
|
||||
|
||||
DELIMITER $$
|
||||
$$
|
||||
CREATE DEFINER=`root`@`%` TRIGGER vn.`ticket_afterUpdate`
|
||||
AFTER UPDATE ON `ticket`
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
|
||||
IF !(NEW.id <=> OLD.id)
|
||||
OR !(NEW.warehouseFk <=> OLD.warehouseFk)
|
||||
OR !(NEW.shipped <=> OLD.shipped) THEN
|
||||
CALL stock.log_add('ticket', NEW.id, OLD.id);
|
||||
END IF;
|
||||
|
||||
IF !(NEW.clientFk <=> OLD.clientFk)
|
||||
OR !(NEW.addressFk <=> OLD.addressFk)
|
||||
OR !(NEW.companyFk <=> OLD.companyFk) THEN
|
||||
CALL ticket_requestRecalc(NEW.id);
|
||||
END IF;
|
||||
|
||||
IF NEW.clientFk = 2067 AND !(NEW.clientFk <=> OLD.clientFk) THEN
|
||||
-- Fallo que se insertan no se sabe como tickets en este cliente
|
||||
INSERT INTO vn.mail SET
|
||||
`sender` = 'jgallego@verdnatura.es',
|
||||
`replyTo` = 'jgallego@verdnatura.es',
|
||||
`subject` = 'Modificado ticket al cliente 2067',
|
||||
`body` = CONCAT(account.myUserGetName(), ' ha modificado el ticket ',
|
||||
NEW.id);
|
||||
END IF;
|
||||
|
||||
END$$
|
||||
DELIMITER ;
|
|
@ -0,0 +1 @@
|
|||
UPDATE salix.ACL t SET t.principalId = 'employee' WHERE t.id = 269;
|
|
@ -0,0 +1,3 @@
|
|||
ALTER TABLE vn.accountingType ADD maxAmount INT DEFAULT NULL NULL;
|
||||
|
||||
UPDATE vn.accountingType SET maxAmount = 1000 WHERE code = 'cash';
|
|
@ -0,0 +1,144 @@
|
|||
DROP PROCEDURE IF EXISTS vn.item_getBalance;
|
||||
|
||||
DELIMITER $$
|
||||
$$
|
||||
CREATE
|
||||
definer = root@`%` procedure vn.item_getBalance(IN vItemId int, IN vWarehouse int)
|
||||
BEGIN
|
||||
DECLARE vDateInventory DATETIME;
|
||||
DECLARE vCurdate DATE DEFAULT CURDATE();
|
||||
DECLARE vDayEnd DATETIME DEFAULT util.dayEnd(vCurdate);
|
||||
|
||||
SELECT inventoried INTO vDateInventory FROM config;
|
||||
SET @a = 0;
|
||||
SET @currentLineFk = 0;
|
||||
SET @shipped = '';
|
||||
|
||||
SELECT DATE(@shipped:= shipped) shipped,
|
||||
alertLevel,
|
||||
stateName,
|
||||
origin,
|
||||
reference,
|
||||
clientFk,
|
||||
name,
|
||||
`in` AS invalue,
|
||||
`out`,
|
||||
@a := @a + IFNULL(`in`,0) - IFNULL(`out`,0) as balance,
|
||||
@currentLineFk := IF (@shipped < CURDATE()
|
||||
OR (@shipped = CURDATE() AND (isPicked OR alertLevel >= 2)),
|
||||
lineFk,@currentLineFk) lastPreparedLineFk,
|
||||
isTicket,
|
||||
lineFk,
|
||||
isPicked,
|
||||
clientType,
|
||||
claimFk
|
||||
FROM
|
||||
( SELECT tr.landed AS shipped,
|
||||
b.quantity AS `in`,
|
||||
NULL AS `out`,
|
||||
al.id AS alertLevel,
|
||||
st.name AS stateName,
|
||||
s.name AS name,
|
||||
e.ref AS reference,
|
||||
e.id AS origin,
|
||||
s.id AS clientFk,
|
||||
IF(al.id = 3, TRUE, FALSE) isPicked,
|
||||
FALSE AS isTicket,
|
||||
b.id lineFk,
|
||||
NULL `order`,
|
||||
NULL AS clientType,
|
||||
NULL AS claimFk
|
||||
FROM buy b
|
||||
JOIN entry e ON e.id = b.entryFk
|
||||
JOIN travel tr ON tr.id = e.travelFk
|
||||
JOIN supplier s ON s.id = e.supplierFk
|
||||
JOIN alertLevel al ON al.id =
|
||||
CASE
|
||||
WHEN tr.shipped < CURDATE() THEN 3
|
||||
WHEN tr.shipped = CURDATE() AND tr.isReceived = TRUE THEN 3
|
||||
ELSE 0
|
||||
END
|
||||
JOIN state st ON st.code = al.code
|
||||
WHERE tr.landed >= vDateInventory
|
||||
AND vWarehouse = tr.warehouseInFk
|
||||
AND b.itemFk = vItemId
|
||||
AND e.isInventory = FALSE
|
||||
AND e.isRaid = FALSE
|
||||
UNION ALL
|
||||
|
||||
SELECT tr.shipped,
|
||||
NULL,
|
||||
b.quantity,
|
||||
al.id,
|
||||
st.name,
|
||||
s.name,
|
||||
e.ref,
|
||||
e.id,
|
||||
s.id,
|
||||
IF(al.id = 3, TRUE, FALSE),
|
||||
FALSE,
|
||||
b.id,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
FROM buy b
|
||||
JOIN entry e ON e.id = b.entryFk
|
||||
JOIN travel tr ON tr.id = e.travelFk
|
||||
JOIN warehouse w ON w.id = tr.warehouseOutFk
|
||||
JOIN supplier s ON s.id = e.supplierFk
|
||||
JOIN alertLevel al ON al.id =
|
||||
CASE
|
||||
WHEN tr.shipped < CURDATE() THEN 3
|
||||
WHEN tr.shipped = CURDATE() AND tr.isReceived = TRUE THEN 3
|
||||
ELSE 0
|
||||
END
|
||||
JOIN state st ON st.code = al.code
|
||||
WHERE tr.shipped >= vDateInventory
|
||||
AND vWarehouse =tr.warehouseOutFk
|
||||
AND s.id <> 4
|
||||
AND b.itemFk = vItemId
|
||||
AND e.isInventory = FALSE
|
||||
AND w.isFeedStock = FALSE
|
||||
AND e.isRaid = FALSE
|
||||
UNION ALL
|
||||
|
||||
SELECT DATE(t.shipped),
|
||||
NULL,
|
||||
s.quantity,
|
||||
al.id,
|
||||
st.name,
|
||||
t.nickname,
|
||||
t.refFk,
|
||||
t.id,
|
||||
t.clientFk,
|
||||
stk.id,
|
||||
TRUE,
|
||||
s.id,
|
||||
st.`order`,
|
||||
ct.code,
|
||||
cl.id
|
||||
FROM sale s
|
||||
JOIN ticket t ON t.id = s.ticketFk
|
||||
LEFT JOIN ticketState ts ON ts.ticket = t.id
|
||||
LEFT JOIN state st ON st.code = ts.code
|
||||
JOIN client c ON c.id = t.clientFk
|
||||
JOIN clientType ct ON ct.id = c.clientTypeFk
|
||||
JOIN alertLevel al ON al.id =
|
||||
CASE
|
||||
WHEN t.shipped < curdate() THEN 3
|
||||
WHEN t.shipped > util.dayEnd(curdate()) THEN 0
|
||||
ELSE IFNULL(ts.alertLevel, 0)
|
||||
END
|
||||
LEFT JOIN state stPrep ON stPrep.`code` = 'PREPARED'
|
||||
LEFT JOIN saleTracking stk ON stk.saleFk = s.id AND stk.stateFk = stPrep.id
|
||||
LEFT JOIN claim cl ON cl.ticketFk = t.id
|
||||
WHERE t.shipped >= vDateInventory
|
||||
AND s.itemFk = vItemId
|
||||
AND vWarehouse =t.warehouseFk
|
||||
ORDER BY shipped, alertLevel DESC, isTicket, `order` DESC, isPicked DESC, `in` DESC, `out` DESC
|
||||
) AS itemDiary;
|
||||
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
ALTER TABLE vn.payMethod CHANGE ibanRequired ibanRequiredForClients tinyint(3) DEFAULT 0 NULL;
|
||||
ALTER TABLE vn.payMethod ADD ibanRequiredForSuppliers tinyint(3) DEFAULT 0 NULL;
|
||||
ALTER TABLE vn.payMethod CHANGE ibanRequiredForSuppliers ibanRequiredForSuppliers tinyint(3) DEFAULT 0 NULL AFTER ibanRequiredForClients;
|
||||
UPDATE vn.payMethod SET ibanRequiredForSuppliers = 1 WHERE code = 'wireTransfer';
|
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE vn.silexACL MODIFY module VARCHAR(50) NOT NULL;
|
||||
ALTER TABLE vn.silexACL MODIFY method VARCHAR(50) NOT NULL;
|
|
@ -0,0 +1,48 @@
|
|||
drop procedure `vn`.`ticket_getProblems`;
|
||||
|
||||
DELIMITER $$
|
||||
$$
|
||||
create
|
||||
definer = root@`%` procedure `vn`.`ticket_getProblems`(IN vIsTodayRelative tinyint(1))
|
||||
BEGIN
|
||||
/**
|
||||
* Calcula los problemas para un conjunto de tickets.
|
||||
* Agrupados por ticket
|
||||
*
|
||||
* @table tmp.sale_getProblems(ticketFk, clientFk, warehouseFk, shipped) Identificadores de los tickets a calcular
|
||||
* @return tmp.ticket_problems
|
||||
*/
|
||||
CALL sale_getProblems(vIsTodayRelative);
|
||||
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp.ticket_problems;
|
||||
CREATE TEMPORARY TABLE tmp.ticket_problems
|
||||
(PRIMARY KEY (ticketFk))
|
||||
ENGINE = MEMORY
|
||||
SELECT
|
||||
ticketFk,
|
||||
MAX(p.isFreezed) AS isFreezed,
|
||||
MAX(p.risk) AS risk,
|
||||
MAX(p.hasHighRisk) AS hasHighRisk,
|
||||
MAX(p.hasTicketRequest) AS hasTicketRequest,
|
||||
MIN(p.isAvailable) AS isAvailable,
|
||||
MAX(p.itemShortage) AS itemShortage,
|
||||
MIN(p.isTaxDataChecked) AS isTaxDataChecked,
|
||||
MAX(p.hasComponentLack) AS hasComponentLack,
|
||||
0 AS totalProblems
|
||||
FROM tmp.sale_problems p
|
||||
GROUP BY ticketFk;
|
||||
|
||||
UPDATE tmp.ticket_problems tp
|
||||
SET tp.totalProblems = (
|
||||
(tp.isFreezed) +
|
||||
IF(tp.risk, TRUE, FALSE) +
|
||||
(tp.hasTicketRequest) +
|
||||
(tp.isAvailable = 0) +
|
||||
(tp.isTaxDataChecked = 0) +
|
||||
(tp.hasComponentLack)
|
||||
);
|
||||
|
||||
DROP TEMPORARY TABLE
|
||||
tmp.sale_problems;
|
||||
END;;$$
|
||||
DELIMITER ;
|
|
@ -0,0 +1,14 @@
|
|||
CREATE TABLE `salix`.`defaultViewConfig`
|
||||
(
|
||||
tableCode VARCHAR(25) not null,
|
||||
columns JSON not null
|
||||
)
|
||||
comment 'The default configuration of columns for views';
|
||||
|
||||
INSERT INTO `salix`.`defaultViewConfig` (tableCode, columns)
|
||||
VALUES
|
||||
('itemsIndex', '{"intrastat":false,"stemMultiplier":false,"landed":false}'),
|
||||
('latestBuys', '{"intrastat":false,"description":false,"density":false,"isActive":false,"freightValue":false,"packageValue":false,"isIgnored":false,"price2":false,"minPrice":true,"ektFk":false,"weight":false,"id":true,"packing":true,"grouping":true,"quantity":true,"size":false,"name":true,"code":true,"origin":true,"family":true,"entryFk":true,"buyingValue":true,"comissionValue":false,"price3":true,"packageFk":true,"packingOut":true}'),
|
||||
('ticketsMonitor', '{"id":false}');
|
||||
|
||||
|
File diff suppressed because one or more lines are too long
|
@ -7,7 +7,7 @@ ALTER TABLE `vn`.`zoneGeo` AUTO_INCREMENT = 1;
|
|||
ALTER TABLE `vn`.`ticket` AUTO_INCREMENT = 1;
|
||||
|
||||
INSERT INTO `salix`.`AccessToken` (`id`, `ttl`, `created`, `userId`)
|
||||
VALUES
|
||||
VALUES
|
||||
('TOTALLY_SECURE_TOKEN', '1209600', CURDATE(), 66);
|
||||
|
||||
|
||||
|
@ -154,16 +154,16 @@ INSERT INTO `vn`.`shelving` (`code`, `parkingFk`, `isPrinted`, `priority`, `park
|
|||
('GVC', '1', '0', '1', '0', '1106'),
|
||||
('HEJ', '2', '0', '1', '0', '1106');
|
||||
|
||||
INSERT INTO `vn`.`accountingType`(`id`, `description`, `receiptDescription`,`code`)
|
||||
INSERT INTO `vn`.`accountingType`(`id`, `description`, `receiptDescription`,`code`, `maxAmount`)
|
||||
VALUES
|
||||
(1, 'CC y Polizas de crédito', NULL, NULL),
|
||||
(2, 'Cash', 'Cash', 'cash'),
|
||||
(3, 'Credit card', 'Credit Card', 'creditCard'),
|
||||
(4, 'Finalcial lines', NULL, NULL),
|
||||
(5, 'Other products', NULL, NULL),
|
||||
(6, 'Loans', NULL, NULL),
|
||||
(7, 'Leasing', NULL, NULL),
|
||||
(8, 'Compensations', 'Compensations', 'compensation');
|
||||
(1, 'CC y Polizas de crédito', NULL, NULL, NULL),
|
||||
(2, 'Cash', 'Cash', 'cash', 1000),
|
||||
(3, 'Credit card', 'Credit Card', 'creditCard', NULL),
|
||||
(4, 'Finalcial lines', NULL, NULL, NULL),
|
||||
(5, 'Other products', NULL, NULL, NULL),
|
||||
(6, 'Loans', NULL, NULL, NULL),
|
||||
(7, 'Leasing', NULL, NULL, NULL),
|
||||
(8, 'Compensations', 'Compensations', 'compensation', NULL);
|
||||
|
||||
INSERT INTO `vn`.`bank`(`id`, `bank`, `account`, `cash`, `entityFk`, `isActive`, `currencyFk`)
|
||||
VALUES
|
||||
|
@ -217,14 +217,14 @@ UPDATE `vn`.`agencyMode` SET `web` = 1, `reportMail` = 'no-reply@gothamcity.com'
|
|||
|
||||
UPDATE `vn`.`agencyMode` SET `code` = 'refund' WHERE `id` = 23;
|
||||
|
||||
INSERT INTO `vn`.`payMethod`(`id`,`code`, `name`, `graceDays`, `outstandingDebt`, `ibanRequired`)
|
||||
INSERT INTO `vn`.`payMethod`(`id`,`code`, `name`, `graceDays`, `outstandingDebt`, `ibanRequiredForClients`, `ibanRequiredForSuppliers`)
|
||||
VALUES
|
||||
(1, NULL, 'PayMethod one', 0, 001, 0),
|
||||
(2, NULL, 'PayMethod two', 10, 001, 0),
|
||||
(3, 'compensation', 'PayMethod three', 0, 001, 0),
|
||||
(4, NULL, 'PayMethod with IBAN', 0, 001, 1),
|
||||
(5, NULL, 'PayMethod five', 10, 001, 0),
|
||||
(8,'wireTransfer', 'WireTransfer', 5, 001, 1);
|
||||
(1, NULL, 'PayMethod one', 0, 001, 0, 0),
|
||||
(2, NULL, 'PayMethod two', 10, 001, 0, 0),
|
||||
(3, 'compensation', 'PayMethod three', 0, 001, 0, 0),
|
||||
(4, NULL, 'PayMethod with IBAN', 0, 001, 1, 0),
|
||||
(5, NULL, 'PayMethod five', 10, 001, 0, 0),
|
||||
(8,'wireTransfer', 'WireTransfer', 5, 001, 1, 1);
|
||||
|
||||
INSERT INTO `vn`.`payDem`(`id`, `payDem`)
|
||||
VALUES
|
||||
|
@ -485,15 +485,16 @@ INSERT INTO `vn`.`invoiceOutSerial` (`code`, `description`, `isTaxed`, `taxAreaF
|
|||
VALUES
|
||||
('A', 'Global nacional', 1, 'NATIONAL', 0),
|
||||
('T', 'Española rapida', 1, 'NATIONAL', 0),
|
||||
('V', 'Intracomunitaria global', 0, 'CEE', 1);
|
||||
('V', 'Intracomunitaria global', 0, 'CEE', 1),
|
||||
('M', 'Múltiple nacional', 1, 'NATIONAL', 0);
|
||||
|
||||
INSERT INTO `vn`.`invoiceOut`(`id`, `serial`, `amount`, `issued`,`clientFk`, `created`, `companyFk`, `dued`, `booked`, `bankFk`, `hasPdf`)
|
||||
VALUES
|
||||
(1, 'T', 1014.24, CURDATE(), 1101, CURDATE(), 442, CURDATE(), CURDATE(), 1, 1),
|
||||
(2, 'T', 121.36, CURDATE(), 1102, CURDATE(), 442, CURDATE(), CURDATE(), 1, 1),
|
||||
(3, 'T', 8.88, CURDATE(), 1103, CURDATE(), 442, CURDATE(), CURDATE(), 1, 1),
|
||||
(4, 'T', 8.88, CURDATE(), 1103, CURDATE(), 442, CURDATE(), CURDATE(), 1, 1),
|
||||
(5, 'A', 8.88, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 1103, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 442, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 1, 1);
|
||||
(1, 'T', 1014.24, CURDATE(), 1101, CURDATE(), 442, CURDATE(), CURDATE(), 1, 0),
|
||||
(2, 'T', 121.36, CURDATE(), 1102, CURDATE(), 442, CURDATE(), CURDATE(), 1, 0),
|
||||
(3, 'T', 8.88, CURDATE(), 1103, CURDATE(), 442, CURDATE(), CURDATE(), 1, 0),
|
||||
(4, 'T', 8.88, CURDATE(), 1103, CURDATE(), 442, CURDATE(), CURDATE(), 1, 0),
|
||||
(5, 'A', 8.88, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 1103, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 442, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 1, 0);
|
||||
|
||||
UPDATE `vn`.`invoiceOut` SET ref = 'T1111111' WHERE id = 1;
|
||||
UPDATE `vn`.`invoiceOut` SET ref = 'T2222222' WHERE id = 2;
|
||||
|
@ -532,21 +533,21 @@ INSERT INTO `vn`.`invoiceOutExpence`(`id`, `invoiceOutFk`, `amount`, `expenceFk`
|
|||
(6, 4, 8.07, 2000000000, CURDATE()),
|
||||
(7, 5, 8.07, 2000000000, CURDATE());
|
||||
|
||||
INSERT INTO `vn`.`zone` (`id`, `name`, `hour`, `agencyModeFk`, `travelingDays`, `price`, `bonus`, `m3Max`)
|
||||
INSERT INTO `vn`.`zone` (`id`, `name`, `hour`, `agencyModeFk`, `travelingDays`, `price`, `bonus`, `itemMaxSize`)
|
||||
VALUES
|
||||
(1, 'Zone pickup A', CONCAT(CURRENT_DATE(), ' ', TIME('23:59')), 1, 0, 0, 0, 30.50),
|
||||
(2, 'Zone pickup B', CONCAT(CURRENT_DATE(), ' ', TIME('23:59')), 1, 0, 0, 0, 30.50),
|
||||
(3, 'Zone 247 A', CONCAT(CURRENT_DATE(), ' ', TIME('23:59')), 7, 1, 2, 0, 40.50),
|
||||
(4, 'Zone 247 B', CONCAT(CURRENT_DATE(), ' ', TIME('23:59')), 7, 1, 2, 0, 40.50),
|
||||
(5, 'Zone expensive A', CONCAT(CURRENT_DATE(), ' ', TIME('23:59')), 8, 1, 1000, 0, 50.50),
|
||||
(6, 'Zone expensive B', CONCAT(CURRENT_DATE(), ' ', TIME('23:59')), 8, 1, 1000, 0, 50.50),
|
||||
(7, 'Zone refund', CONCAT(CURRENT_DATE(), ' ', TIME('23:59')), 23, 0, 0, 0, 60.50),
|
||||
(8, 'Zone others', CONCAT(CURRENT_DATE(), ' ', TIME('23:59')), 10, 0, 0, 0, 60.50),
|
||||
(9, 'Zone superMan', CONCAT(CURRENT_DATE(), ' ', TIME('23:59')), 2, 0, 0, 0, NULL),
|
||||
(10, 'Zone teleportation', CONCAT(CURRENT_DATE(), ' ', TIME('23:59')), 3, 0, 0, 0, NULL),
|
||||
(11, 'Zone pickup C', CONCAT(CURRENT_DATE(), ' ', TIME('23:59')), 1, 0, 0, 0, NULL),
|
||||
(12, 'Zone entanglement', CONCAT(CURRENT_DATE(), ' ', TIME('23:59')), 4, 0, 0, 0, NULL),
|
||||
(13, 'Zone quantum break', CONCAT(CURRENT_DATE(), ' ', TIME('23:59')), 5, 0, 0, 0, NULL);
|
||||
(1, 'Zone pickup A', CONCAT(CURRENT_DATE(), ' ', TIME('23:59')), 1, 0, 0, 0, 100),
|
||||
(2, 'Zone pickup B', CONCAT(CURRENT_DATE(), ' ', TIME('23:59')), 1, 0, 0, 0, 100),
|
||||
(3, 'Zone 247 A', CONCAT(CURRENT_DATE(), ' ', TIME('23:59')), 7, 1, 2, 0, 100),
|
||||
(4, 'Zone 247 B', CONCAT(CURRENT_DATE(), ' ', TIME('23:59')), 7, 1, 2, 0, 100),
|
||||
(5, 'Zone expensive A', CONCAT(CURRENT_DATE(), ' ', TIME('23:59')), 8, 1, 1000, 0, 100),
|
||||
(6, 'Zone expensive B', CONCAT(CURRENT_DATE(), ' ', TIME('23:59')), 8, 1, 1000, 0, 100),
|
||||
(7, 'Zone refund', CONCAT(CURRENT_DATE(), ' ', TIME('23:59')), 23, 0, 0, 0, 100),
|
||||
(8, 'Zone others', CONCAT(CURRENT_DATE(), ' ', TIME('23:59')), 10, 0, 0, 0, 100),
|
||||
(9, 'Zone superMan', CONCAT(CURRENT_DATE(), ' ', TIME('23:59')), 2, 0, 0, 0, 100),
|
||||
(10, 'Zone teleportation', CONCAT(CURRENT_DATE(), ' ', TIME('23:59')), 3, 0, 0, 0, 100),
|
||||
(11, 'Zone pickup C', CONCAT(CURRENT_DATE(), ' ', TIME('23:59')), 1, 0, 0, 0, 100),
|
||||
(12, 'Zone entanglement', CONCAT(CURRENT_DATE(), ' ', TIME('23:59')), 4, 0, 0, 0, 100),
|
||||
(13, 'Zone quantum break', CONCAT(CURRENT_DATE(), ' ', TIME('23:59')), 5, 0, 0, 0, 100);
|
||||
|
||||
INSERT INTO `vn`.`zoneWarehouse` (`id`, `zoneFk`, `warehouseFk`)
|
||||
VALUES
|
||||
|
@ -795,25 +796,25 @@ INSERT INTO `vn`.`itemFamily`(`code`, `description`)
|
|||
('SER', 'Services'),
|
||||
('VT', 'Sales');
|
||||
|
||||
INSERT INTO `vn`.`item`(`id`, `typeFk`, `size`, `inkFk`, `stems`, `originFk`, `description`, `producerFk`, `intrastatFk`, `isOnOffer`, `expenceFk`, `isBargain`, `comment`, `relevancy`, `image`, `subName`, `minPrice`, `stars`, `family`)
|
||||
INSERT INTO `vn`.`item`(`id`, `typeFk`, `size`, `inkFk`, `stems`, `originFk`, `description`, `producerFk`, `intrastatFk`, `expenceFk`, `comment`, `relevancy`, `image`, `subName`, `minPrice`, `stars`, `family`)
|
||||
VALUES
|
||||
(1, 2, 70, 'YEL', 1, 1, NULL, 1, 06021010, 0, 2000000000, 0, NULL, 0, '1', NULL, 0, 1, 'VT'),
|
||||
(2, 2, 70, 'BLU', 1, 2, NULL, 1, 06021010, 0, 2000000000, 0, NULL, 0, '2', NULL, 0, 2, 'VT'),
|
||||
(3, 1, 60, 'YEL', 1, 3, NULL, 1, 05080000, 0, 4751000000, 0, NULL, 0, '3', NULL, 0, 5, 'VT'),
|
||||
(4, 1, 60, 'YEL', 1, 1, 'Increases block', 1, 05080000, 1, 4751000000, 0, NULL, 0, '4', NULL, 0, 3, 'VT'),
|
||||
(5, 3, 30, 'RED', 1, 2, NULL, 2, 06021010, 1, 4751000000, 0, NULL, 0, '5', NULL, 0, 3, 'VT'),
|
||||
(6, 5, 30, 'RED', 1, 2, NULL, NULL, 06021010, 0, 4751000000, 0, NULL, 0, '6', NULL, 0, 4, 'VT'),
|
||||
(7, 5, 90, 'BLU', 1, 2, NULL, NULL, 06021010, 0, 4751000000, 0, NULL, 0, '7', NULL, 0, 4, 'VT'),
|
||||
(8, 2, 70, 'YEL', 1, 1, NULL, 1, 06021010, 0, 2000000000, 0, NULL, 0, '8', NULL, 0, 5, 'VT'),
|
||||
(9, 2, 70, 'BLU', 1, 2, NULL, 1, 06021010, 0, 2000000000, 0, NULL, 0, '9', NULL, 0, 4, 'VT'),
|
||||
(10, 1, 60, 'YEL', 1, 3, NULL, 1, 05080000, 0, 4751000000, 0, NULL, 0, '10', NULL, 0, 4, 'VT'),
|
||||
(11, 1, 60, 'YEL', 1, 1, NULL, 1, 05080000, 1, 4751000000, 0, NULL, 0, '11', NULL, 0, 4, 'VT'),
|
||||
(12, 3, 30, 'RED', 1, 2, NULL, 2, 06021010, 1, 4751000000, 0, NULL, 0, '12', NULL, 0, 3, 'VT'),
|
||||
(13, 5, 30, 'RED', 1, 2, NULL, NULL, 06021010, 0, 4751000000, 0, NULL, 0, '13', NULL, 0, 2, 'VT'),
|
||||
(14, 5, 90, 'BLU', 1, 2, NULL, NULL, 06021010, 0, 4751000000, 0, NULL, 0, '', NULL, 0, 4, 'VT'),
|
||||
(15, 4, NULL, NULL, NULL, 1, NULL, NULL, 06021010, 0, 4751000000, 0, NULL, 0, '', NULL, 0, 0, 'EMB'),
|
||||
(16, 4, NULL, NULL, NULL, 1, NULL, NULL, 06021010, 0, 4751000000, 0, NULL, 0, '', NULL, 0, 0, 'EMB'),
|
||||
(71, 4, NULL, NULL, NULL, 1, NULL, NULL, 06021010, 1, 4751000000, 0, NULL, 0, '', NULL, 0, 0, 'VT');
|
||||
(1, 2, 70, 'YEL', 1, 1, NULL, 1, 06021010, 2000000000, NULL, 0, '1', NULL, 0, 1, 'VT'),
|
||||
(2, 2, 70, 'BLU', 1, 2, NULL, 1, 06021010, 2000000000, NULL, 0, '2', NULL, 0, 2, 'VT'),
|
||||
(3, 1, 60, 'YEL', 1, 3, NULL, 1, 05080000, 4751000000, NULL, 0, '3', NULL, 0, 5, 'VT'),
|
||||
(4, 1, 60, 'YEL', 1, 1, 'Increases block', 1, 05080000, 4751000000, NULL, 0, '4', NULL, 0, 3, 'VT'),
|
||||
(5, 3, 30, 'RED', 1, 2, NULL, 2, 06021010, 4751000000, NULL, 0, '5', NULL, 0, 3, 'VT'),
|
||||
(6, 5, 30, 'RED', 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '6', NULL, 0, 4, 'VT'),
|
||||
(7, 5, 90, 'BLU', 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '7', NULL, 0, 4, 'VT'),
|
||||
(8, 2, 70, 'YEL', 1, 1, NULL, 1, 06021010, 2000000000, NULL, 0, '8', NULL, 0, 5, 'VT'),
|
||||
(9, 2, 70, 'BLU', 1, 2, NULL, 1, 06021010, 2000000000, NULL, 0, '9', NULL, 0, 4, 'VT'),
|
||||
(10, 1, 60, 'YEL', 1, 3, NULL, 1, 05080000, 4751000000, NULL, 0, '10', NULL, 0, 4, 'VT'),
|
||||
(11, 1, 60, 'YEL', 1, 1, NULL, 1, 05080000, 4751000000, NULL, 0, '11', NULL, 0, 4, 'VT'),
|
||||
(12, 3, 30, 'RED', 1, 2, NULL, 2, 06021010, 4751000000, NULL, 0, '12', NULL, 0, 3, 'VT'),
|
||||
(13, 5, 30, 'RED', 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '13', NULL, 0, 2, 'VT'),
|
||||
(14, 5, 90, 'BLU', 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 4, 'VT'),
|
||||
(15, 4, NULL, NULL, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 0, 'EMB'),
|
||||
(16, 4, NULL, NULL, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 0, 'EMB'),
|
||||
(71, 4, NULL, NULL, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 0, 'VT');
|
||||
|
||||
-- Update the taxClass after insert of the items
|
||||
UPDATE `vn`.`itemTaxCountry` SET `taxClassFk` = 2
|
||||
|
@ -1284,11 +1285,11 @@ INSERT INTO `vn`.`supplierAddress`(`id`, `supplierFk`, `nickname`, `street`, `pr
|
|||
(5, 442, 'GCR building', 'Bristol district', 1, '46000', 'Gotham', '111111111', '222222222'),
|
||||
(6, 442, 'The Gotham Tonight building', 'Bristol district', 1, '46000', 'Gotham', '111111111', '222222222');
|
||||
|
||||
INSERT INTO `vn`.`supplier`(`id`, `name`, `nickname`,`account`,`countryFk`,`nif`,`isFarmer`,`commission`, `created`, `isActive`, `street`, `city`, `provinceFk`, `postCode`, `payMethodFk`, `payDemFk`, `payDay`, `taxTypeSageFk`, `withholdingSageFk`, `transactionTypeSageFk`, `workerFk`, `supplierActivityFk`)
|
||||
INSERT INTO `vn`.`supplier`(`id`, `name`, `nickname`,`account`,`countryFk`,`nif`,`isFarmer`,`commission`, `created`, `isActive`, `street`, `city`, `provinceFk`, `postCode`, `payMethodFk`, `payDemFk`, `payDay`, `taxTypeSageFk`, `withholdingSageFk`, `transactionTypeSageFk`, `workerFk`, `supplierActivityFk`, `isPayMethodChecked`)
|
||||
VALUES
|
||||
(1, 'Plants SL', 'Plants nick', 4100000001, 1, '06089160W', 0, 0, CURDATE(), 1, 'supplier address 1', 'PONTEVEDRA', 1, 15214, 1, 1, 15, 4, 1, 1, 18, 'flowerPlants'),
|
||||
(2, 'Farmer King', 'The farmer', 4000020002, 1, '87945234L', 1, 0, CURDATE(), 1, 'supplier address 2', 'SILLA', 2, 43022, 1, 2, 10, 93, 2, 8, 18, 'animals'),
|
||||
(442, 'Verdnatura Levante SL', 'Verdnatura', 5115000442, 1, '06815934E', 0, 0, CURDATE(), 1, 'supplier address 3', 'SILLA', 1, 43022, 1, 2, 15, 6, 9, 3, 18, 'flowerPlants');
|
||||
(1, 'Plants SL', 'Plants nick', 4100000001, 1, '06089160W', 0, 0, CURDATE(), 1, 'supplier address 1', 'PONTEVEDRA', 1, 15214, 1, 1, 15, 4, 1, 1, 18, 'flowerPlants', 1),
|
||||
(2, 'Farmer King', 'The farmer', 4000020002, 1, '87945234L', 1, 0, CURDATE(), 1, 'supplier address 2', 'SILLA', 2, 43022, 1, 2, 10, 93, 2, 8, 18, 'animals', 1),
|
||||
(442, 'Verdnatura Levante SL', 'Verdnatura', 5115000442, 1, '06815934E', 0, 0, CURDATE(), 1, 'supplier address 3', 'SILLA', 1, 43022, 1, 2, 15, 6, 9, 3, 18, 'flowerPlants', 1);
|
||||
|
||||
INSERT INTO `vn`.`supplierContact`(`id`, `supplierFk`, `phone`, `mobile`, `email`, `observation`, `name`)
|
||||
VALUES
|
||||
|
@ -1765,16 +1766,16 @@ INSERT INTO `vn`.`orderTicket`(`orderFk`, `ticketFk`)
|
|||
INSERT INTO `vn`.`userConfig` (`userFk`, `warehouseFk`, `companyFk`)
|
||||
VALUES
|
||||
(1, 1, 69),
|
||||
(5, 1, 442),
|
||||
(5, 1, 442),
|
||||
(9, 1, 442),
|
||||
(18, 3, 567);
|
||||
|
||||
INSERT INTO `vn`.`receipt`(`id`, `invoiceFk`, `amountPaid`, `amountUnpaid`, `payed`, `workerFk`, `bankFk`, `clientFk`, `created`, `companyFk`, `isConciliate`)
|
||||
|
||||
INSERT INTO `vn`.`receipt`(`id`, `invoiceFk`, `amountPaid`, `payed`, `workerFk`, `bankFk`, `clientFk`, `created`, `companyFk`, `isConciliate`)
|
||||
VALUES
|
||||
(1, 'Cobro web', 100.50, 0.00, CURDATE(), 9, 1, 1101, CURDATE(), 442, 1),
|
||||
(2, 'Cobro web', 200.50, 0.00, DATE_ADD(CURDATE(), INTERVAL -5 DAY), 9, 1, 1101, DATE_ADD(CURDATE(), INTERVAL -5 DAY), 442, 1),
|
||||
(3, 'Cobro en efectivo', 300.00, 100.00, DATE_ADD(CURDATE(), INTERVAL -10 DAY), 9, 1, 1102, DATE_ADD(CURDATE(), INTERVAL -10 DAY), 442, 0),
|
||||
(4, 'Cobro en efectivo', 400.00, -50.00, DATE_ADD(CURDATE(), INTERVAL -15 DAY), 9, 1, 1103, DATE_ADD(CURDATE(), INTERVAL -15 DAY), 442, 0);
|
||||
(1, 'Cobro web', 100.50, CURDATE(), 9, 1, 1101, CURDATE(), 442, 1),
|
||||
(2, 'Cobro web', 200.50, DATE_ADD(CURDATE(), INTERVAL -5 DAY), 9, 1, 1101, DATE_ADD(CURDATE(), INTERVAL -5 DAY), 442, 1),
|
||||
(3, 'Cobro en efectivo', 300.00, DATE_ADD(CURDATE(), INTERVAL -10 DAY), 9, 1, 1102, DATE_ADD(CURDATE(), INTERVAL -10 DAY), 442, 0),
|
||||
(4, 'Cobro en efectivo', 400.00, DATE_ADD(CURDATE(), INTERVAL -15 DAY), 9, 1, 1103, DATE_ADD(CURDATE(), INTERVAL -15 DAY), 442, 0);
|
||||
|
||||
INSERT INTO `vn`.`workerTeam`(`id`, `team`, `workerFk`)
|
||||
VALUES
|
||||
|
@ -2232,8 +2233,8 @@ INSERT IGNORE INTO `vn`.`greugeConfig` (`id`, `freightPickUpPrice`) VALUES ('1',
|
|||
|
||||
INSERT INTO `vn`.`temperature`(`code`, `name`, `description`)
|
||||
VALUES
|
||||
('WARM', 'Warm', 'Warm'),
|
||||
('COOL', 'Cool', 'Cool');
|
||||
('warm', 'Warm', 'Warm'),
|
||||
('cool', 'Cool', 'Cool');
|
||||
|
||||
INSERT INTO `vn`.`thermograph`(`id`, `model`)
|
||||
VALUES
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -29,9 +29,9 @@ services:
|
|||
- source: print_local
|
||||
target: /etc/salix/print.local.json
|
||||
volumes:
|
||||
- /mnt/storage/pdfs:/var/lib/salix/pdfs
|
||||
- /mnt/storage/dms:/var/lib/salix/dms
|
||||
- /mnt/storage/image:/var/lib/salix/image
|
||||
- /mnt/appdata/pdfs:/var/lib/salix/pdfs
|
||||
- /mnt/appdata/dms:/var/lib/salix/dms
|
||||
- /mnt/appdata/image:/var/lib/salix/image
|
||||
deploy:
|
||||
replicas: ${BACK_REPLICAS:?}
|
||||
placement:
|
||||
|
|
|
@ -94,6 +94,19 @@ let actions = {
|
|||
login: async function(userName) {
|
||||
await this.doLogin(userName);
|
||||
await this.waitForState('home');
|
||||
await this.addStyleTag({
|
||||
content: `
|
||||
*,
|
||||
*::after,
|
||||
*::before {
|
||||
transition-delay: 0s !important;
|
||||
transition-duration: 0s !important;
|
||||
animation-delay: -0.0001s !important;
|
||||
animation-duration: 0s !important;
|
||||
animation-play-state: paused !important;
|
||||
caret-color: transparent !important;
|
||||
}`
|
||||
});
|
||||
},
|
||||
|
||||
selectModule: async function(moduleName) {
|
||||
|
@ -108,7 +121,7 @@ let actions = {
|
|||
},
|
||||
|
||||
getState: async function() {
|
||||
return await this.evaluate(() => {
|
||||
return this.evaluate(() => {
|
||||
let $state = angular.element(document.body).injector().get('$state');
|
||||
return $state.current.name;
|
||||
});
|
||||
|
@ -194,7 +207,7 @@ let actions = {
|
|||
},
|
||||
|
||||
getProperty: async function(selector, property) {
|
||||
return await this.evaluate((selector, property) => {
|
||||
return this.evaluate((selector, property) => {
|
||||
return document.querySelector(selector)[property].replace(/\s+/g, ' ').trim();
|
||||
}, selector, property);
|
||||
},
|
||||
|
@ -202,15 +215,16 @@ let actions = {
|
|||
getClassName: async function(selector) {
|
||||
const element = await this.$(selector);
|
||||
const handle = await element.getProperty('className');
|
||||
return await handle.jsonValue();
|
||||
return handle.jsonValue();
|
||||
},
|
||||
|
||||
waitPropertyLength: async function(selector, property, minLength) {
|
||||
await this.waitForFunction((selector, property, minLength) => {
|
||||
const element = document.querySelector(selector);
|
||||
return element && element[property] != null && element[property] !== '' && element[property].length >= minLength;
|
||||
const isValidElement = element && element[property] != null && element[property] !== '';
|
||||
return isValidElement && element[property].length >= minLength;
|
||||
}, {}, selector, property, minLength);
|
||||
return await this.getProperty(selector, property);
|
||||
return this.getProperty(selector, property);
|
||||
},
|
||||
|
||||
expectPropertyValue: async function(selector, property, value) {
|
||||
|
@ -219,7 +233,7 @@ let actions = {
|
|||
builtSelector = await this.selectorFormater(selector);
|
||||
|
||||
try {
|
||||
return await this.waitForFunction((selector, property, value) => {
|
||||
return this.waitForFunction((selector, property, value) => {
|
||||
const element = document.querySelector(selector);
|
||||
return element[property] == value;
|
||||
}, {}, builtSelector, property, value);
|
||||
|
@ -239,7 +253,7 @@ let actions = {
|
|||
|
||||
return element && element[property] != null && element[property] !== '';
|
||||
}, {}, builtSelector, property);
|
||||
return await this.getProperty(builtSelector, property);
|
||||
return this.getProperty(builtSelector, property);
|
||||
} catch (error) {
|
||||
throw new Error(`couldn't get property: ${property} of ${builtSelector}, ${error}`);
|
||||
}
|
||||
|
@ -261,7 +275,7 @@ let actions = {
|
|||
await this.waitForSelector(selector);
|
||||
await this.waitForFunction(checkVisibility, {}, selector);
|
||||
|
||||
return await this.click(selector);
|
||||
return this.click(selector);
|
||||
},
|
||||
|
||||
writeOnEditableTD: async function(selector, text) {
|
||||
|
@ -274,7 +288,7 @@ let actions = {
|
|||
|
||||
focusElement: async function(selector) {
|
||||
await this.waitForSelector(selector);
|
||||
return await this.evaluate(selector => {
|
||||
return this.evaluate(selector => {
|
||||
let element = document.querySelector(selector);
|
||||
element.focus();
|
||||
}, selector);
|
||||
|
@ -282,19 +296,19 @@ let actions = {
|
|||
|
||||
isVisible: async function(selector) {
|
||||
await this.waitForSelector(selector);
|
||||
return await this.evaluate(checkVisibility, selector);
|
||||
return this.evaluate(checkVisibility, selector);
|
||||
},
|
||||
|
||||
waitImgLoad: async function(selector) {
|
||||
await this.waitForSelector(selector);
|
||||
return await this.waitForFunction(selector => {
|
||||
return this.waitForFunction(selector => {
|
||||
const imageReady = document.querySelector(selector).complete;
|
||||
return imageReady;
|
||||
}, {}, selector);
|
||||
},
|
||||
|
||||
countElement: async function(selector) {
|
||||
return await this.evaluate(selector => {
|
||||
return this.evaluate(selector => {
|
||||
return document.querySelectorAll(selector).length;
|
||||
}, selector);
|
||||
},
|
||||
|
@ -312,7 +326,7 @@ let actions = {
|
|||
|
||||
waitForClassNotPresent: async function(selector, className) {
|
||||
await this.waitForSelector(selector);
|
||||
return await this.waitForFunction((selector, className) => {
|
||||
return this.waitForFunction((selector, className) => {
|
||||
if (!document.querySelector(selector).classList.contains(className))
|
||||
return true;
|
||||
}, {}, selector, className);
|
||||
|
@ -320,55 +334,39 @@ let actions = {
|
|||
|
||||
waitForClassPresent: async function(selector, className) {
|
||||
await this.waitForSelector(selector);
|
||||
return await this.waitForFunction((elementSelector, targetClass) => {
|
||||
return this.waitForFunction((elementSelector, targetClass) => {
|
||||
if (document.querySelector(elementSelector).classList.contains(targetClass))
|
||||
return true;
|
||||
}, {}, selector, className);
|
||||
},
|
||||
|
||||
waitForTextInElement: async function(selector, text) {
|
||||
const expectedText = text.toLowerCase();
|
||||
return new Promise((resolve, reject) => {
|
||||
let attempts = 0;
|
||||
const interval = setInterval(async() => {
|
||||
const currentText = await this.evaluate(selector => {
|
||||
return document.querySelector(selector).innerText.toLowerCase();
|
||||
}, selector);
|
||||
|
||||
if (currentText === expectedText || attempts === 40) {
|
||||
clearInterval(interval);
|
||||
resolve(currentText);
|
||||
}
|
||||
attempts += 1;
|
||||
}, 100);
|
||||
}).then(result => {
|
||||
return expect(result).toContain(expectedText);
|
||||
});
|
||||
await this.waitForFunction((selector, text) => {
|
||||
if (document.querySelector(selector)) {
|
||||
const innerText = document.querySelector(selector).innerText.toLowerCase();
|
||||
const expectedText = text.toLowerCase();
|
||||
if (innerText.includes(expectedText))
|
||||
return innerText;
|
||||
}
|
||||
}, {}, selector, text);
|
||||
},
|
||||
|
||||
waitForTextInField: async function(selector, text) {
|
||||
let builtSelector = await this.selectorFormater(selector);
|
||||
await this.waitForSelector(builtSelector);
|
||||
const expectedText = text.toLowerCase();
|
||||
return new Promise((resolve, reject) => {
|
||||
let attempts = 0;
|
||||
const interval = setInterval(async() => {
|
||||
const currentText = await this.evaluate(selector => {
|
||||
return document.querySelector(selector).value.toLowerCase();
|
||||
}, builtSelector);
|
||||
const builtSelector = await this.selectorFormater(selector);
|
||||
const expectedValue = text.toLowerCase();
|
||||
|
||||
if (currentText === expectedText || attempts === 40) {
|
||||
clearInterval(interval);
|
||||
resolve(currentText);
|
||||
try {
|
||||
await this.waitForFunction((selector, text) => {
|
||||
const element = document.querySelector(selector);
|
||||
if (element) {
|
||||
const value = element.value.toLowerCase();
|
||||
if (value.includes(text))
|
||||
return true;
|
||||
}
|
||||
attempts += 1;
|
||||
}, 100);
|
||||
}).then(result => {
|
||||
if (result === '')
|
||||
return expect(result).toEqual(expectedText);
|
||||
|
||||
return expect(result).toContain(expectedText);
|
||||
});
|
||||
}, {}, builtSelector, expectedValue);
|
||||
} catch (error) {
|
||||
throw new Error(`${text} wasn't the value of ${builtSelector}, ${error}`);
|
||||
}
|
||||
},
|
||||
|
||||
selectorFormater: function(selector) {
|
||||
|
@ -387,13 +385,13 @@ let actions = {
|
|||
const innerText = document.querySelector(selector).innerText;
|
||||
return innerText != null && innerText != '';
|
||||
}, {}, selector);
|
||||
return await this.evaluate(selector => {
|
||||
return this.evaluate(selector => {
|
||||
return document.querySelector(selector).innerText;
|
||||
}, selector);
|
||||
},
|
||||
|
||||
waitForEmptyInnerText: async function(selector) {
|
||||
return await this.waitFunction(selector => {
|
||||
return this.waitFunction(selector => {
|
||||
return document.querySelector(selector).innerText == '';
|
||||
}, selector);
|
||||
},
|
||||
|
@ -521,7 +519,7 @@ let actions = {
|
|||
|
||||
checkboxState: async function(selector) {
|
||||
await this.waitForSelector(selector);
|
||||
return await this.evaluate(selector => {
|
||||
return this.evaluate(selector => {
|
||||
let checkbox = document.querySelector(selector);
|
||||
switch (checkbox.$ctrl.field) {
|
||||
case null:
|
||||
|
@ -536,14 +534,14 @@ let actions = {
|
|||
|
||||
isDisabled: async function(selector) {
|
||||
await this.waitForSelector(selector);
|
||||
return await this.evaluate(selector => {
|
||||
return this.evaluate(selector => {
|
||||
let element = document.querySelector(selector);
|
||||
return element.$ctrl.disabled;
|
||||
}, selector);
|
||||
},
|
||||
|
||||
waitForStylePresent: async function(selector, property, value) {
|
||||
return await this.waitForFunction((selector, property, value) => {
|
||||
return this.waitForFunction((selector, property, value) => {
|
||||
const element = document.querySelector(selector);
|
||||
return element.style[property] == value;
|
||||
}, {}, selector, property, value);
|
||||
|
@ -631,7 +629,7 @@ export function extendPage(page) {
|
|||
for (let name in actions) {
|
||||
page[name] = async(...args) => {
|
||||
try {
|
||||
return await actions[name].apply(page, args);
|
||||
return actions[name].apply(page, args);
|
||||
} catch (err) {
|
||||
let stringArgs = args
|
||||
.map(i => typeof i == 'function' ? 'Function' : i)
|
||||
|
|
|
@ -5,11 +5,17 @@ import {url as defaultURL} from './config';
|
|||
|
||||
export async function getBrowser() {
|
||||
const args = [
|
||||
`--no-sandbox`,
|
||||
`--window-size=${ 1920 },${ 1080 }`
|
||||
`--window-size=${ 1920 },${ 1080 }`,
|
||||
// '--disable-gpu'
|
||||
// '--no-sandbox',
|
||||
// '--single-process',
|
||||
// '--no-zygote',
|
||||
// '--disable-dev-shm-usage'
|
||||
// '--full-memory-crash-report',
|
||||
// '--unlimited-storage'
|
||||
];
|
||||
|
||||
let env = process.env;
|
||||
const env = process.env;
|
||||
|
||||
if (env.E2E_DEBUG) {
|
||||
args.push('--auto-open-devtools-for-tabs');
|
||||
|
@ -21,7 +27,10 @@ export async function getBrowser() {
|
|||
args,
|
||||
defaultViewport: null,
|
||||
headless: headless,
|
||||
slowMo: 0, // slow down by ms
|
||||
slowMo: 5, // slow down by ms
|
||||
// ignoreDefaultArgs: ['--disable-extensions'],
|
||||
// executablePath: '/usr/bin/google-chrome-stable',
|
||||
// executablePath: '/usr/bin/firefox-developer-edition',
|
||||
});
|
||||
|
||||
let page = (await browser.pages())[0];
|
||||
|
@ -38,7 +47,8 @@ export async function getBrowser() {
|
|||
});
|
||||
});
|
||||
page = extendPage(page);
|
||||
page.setDefaultTimeout(4000);
|
||||
page.setDefaultTimeout(5000);
|
||||
|
||||
await page.goto(defaultURL, {waitUntil: 'load'});
|
||||
return {page, close: browser.close.bind(browser)};
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* eslint max-len: ["error", { "ignoreStrings": true }]*/
|
||||
|
||||
export default {
|
||||
globalItems: {
|
||||
|
@ -118,6 +119,7 @@ export default {
|
|||
name: 'vn-client-create vn-textfield[ng-model="$ctrl.client.name"]',
|
||||
taxNumber: 'vn-client-create vn-textfield[ng-model="$ctrl.client.fi"]',
|
||||
socialName: 'vn-client-create vn-textfield[ng-model="$ctrl.client.socialName"]',
|
||||
businessType: 'vn-client-create vn-autocomplete[ng-model="$ctrl.client.businessTypeFk"]',
|
||||
street: 'vn-client-create vn-textfield[ng-model="$ctrl.client.street"]',
|
||||
addPostCode: 'vn-client-create vn-datalist[ng-model="$ctrl.client.postcode"] vn-icon-button[icon="add_circle"]',
|
||||
addProvince: 'vn-autocomplete[ng-model="$ctrl.location.provinceFk"] vn-icon-button[icon="add_circle"]',
|
||||
|
@ -273,6 +275,7 @@ export default {
|
|||
deliveredAmount: '.vn-dialog vn-input-number[ng-model="$ctrl.deliveredAmount"]',
|
||||
refundAmount: '.vn-dialog vn-input-number[ng-model="$ctrl.amountToReturn"]',
|
||||
saveButton: '.vn-dialog.shown [response="accept"]',
|
||||
anyBalanceLine: 'vn-client-balance-index vn-tbody > vn-tr',
|
||||
firstLineBalance: 'vn-client-balance-index vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(8)',
|
||||
firstLineReference: 'vn-client-balance-index vn-tbody > vn-tr:nth-child(1) > vn-td-editable',
|
||||
firstLineReferenceInput: 'vn-client-balance-index vn-tbody > vn-tr:nth-child(1) > vn-td-editable > div > field > vn-textfield'
|
||||
|
@ -310,27 +313,26 @@ export default {
|
|||
},
|
||||
itemsIndex: {
|
||||
createItemButton: `vn-float-button`,
|
||||
firstSearchResult: 'vn-item-index a:nth-child(1)',
|
||||
searchResult: 'vn-item-index a.vn-tr',
|
||||
firstResultPreviewButton: 'vn-item-index vn-tbody > :nth-child(1) .buttons > [icon="preview"]',
|
||||
firstSearchResult: 'vn-item-index tbody tr:nth-child(1)',
|
||||
searchResult: 'vn-item-index tbody tr:not(.empty-rows)',
|
||||
firstResultPreviewButton: 'vn-item-index tbody > :nth-child(1) .buttons > [icon="preview"]',
|
||||
searchResultCloneButton: 'vn-item-index .buttons > [icon="icon-clone"]',
|
||||
acceptClonationAlertButton: '.vn-confirm.shown [response="accept"]',
|
||||
closeItemSummaryPreview: '.vn-popup.shown',
|
||||
fieldsToShowButton: 'vn-item-index vn-table > div > div > vn-icon-button[icon="more_vert"]',
|
||||
fieldsToShowForm: '.vn-popover.shown .content',
|
||||
firstItemImage: 'vn-item-index vn-tbody > a:nth-child(1) > vn-td:nth-child(1) > img',
|
||||
firstItemImageTd: 'vn-item-index vn-table a:nth-child(1) vn-td:nth-child(1)',
|
||||
firstItemId: 'vn-item-index vn-tbody > a:nth-child(1) > vn-td:nth-child(2)',
|
||||
idCheckbox: '.vn-popover.shown vn-horizontal:nth-child(1) > vn-check',
|
||||
stemsCheckbox: '.vn-popover.shown vn-horizontal:nth-child(2) > vn-check',
|
||||
sizeCheckbox: '.vn-popover.shown vn-horizontal:nth-child(3) > vn-check',
|
||||
typeCheckbox: '.vn-popover.shown vn-horizontal:nth-child(5) > vn-check',
|
||||
categoryCheckbox: '.vn-popover.shown vn-horizontal:nth-child(6) > vn-check',
|
||||
intrastadCheckbox: '.vn-popover.shown vn-horizontal:nth-child(7) > vn-check',
|
||||
originCheckbox: '.vn-popover.shown vn-horizontal:nth-child(8) > vn-check',
|
||||
buyerCheckbox: '.vn-popover.shown vn-horizontal:nth-child(9) > vn-check',
|
||||
destinyCheckbox: '.vn-popover.shown vn-horizontal:nth-child(10) > vn-check',
|
||||
taxClassCheckbox: '.vn-popover.shown vn-horizontal:nth-child(11) > vn-check',
|
||||
shownColumns: 'vn-item-index vn-button[id="shownColumns"]',
|
||||
shownColumnsList: '.vn-popover.shown .content',
|
||||
firstItemImage: 'vn-item-index tbody > tr:nth-child(1) > td:nth-child(1) > img',
|
||||
firstItemImageTd: 'vn-item-index smart-table tr:nth-child(1) td:nth-child(1)',
|
||||
firstItemId: 'vn-item-index tbody > tr:nth-child(1) > td:nth-child(2)',
|
||||
idCheckbox: '.vn-popover.shown vn-horizontal:nth-child(3) > vn-check[label="Identifier"]',
|
||||
stemsCheckbox: '.vn-popover.shown vn-horizontal:nth-child(3) > vn-check[label="Stems"]',
|
||||
sizeCheckbox: '.vn-popover.shown vn-horizontal:nth-child(3) > vn-check[label="Size"]',
|
||||
typeCheckbox: '.vn-popover.shown vn-horizontal:nth-child(3) > vn-check[label="Type"]',
|
||||
categoryCheckbox: '.vn-popover.shown vn-horizontal:nth-child(3) > vn-check[label="Category"]',
|
||||
intrastadCheckbox: '.vn-popover.shown vn-horizontal:nth-child(3) > vn-check[label="Intrastat"]',
|
||||
originCheckbox: '.vn-popover.shown vn-horizontal:nth-child(3) > vn-check[label="Origin"]',
|
||||
buyerCheckbox: '.vn-popover.shown vn-horizontal:nth-child(3) > vn-check[label="Buyer"]',
|
||||
densityCheckbox: '.vn-popover.shown vn-horizontal:nth-child(3) > vn-check[label="Density"]',
|
||||
saveFieldsButton: '.vn-popover.shown vn-button[label="Save"] > button'
|
||||
},
|
||||
itemFixedPrice: {
|
||||
|
@ -470,6 +472,7 @@ export default {
|
|||
firstTicketCheckbox: 'vn-ticket-index vn-tbody > a:nth-child(1) > vn-td:nth-child(1) > vn-check',
|
||||
secondTicketCheckbox: 'vn-ticket-index vn-tbody > a:nth-child(2) > vn-td:nth-child(1) > vn-check',
|
||||
thirdTicketCheckbox: 'vn-ticket-index vn-tbody > a:nth-child(3) > vn-td:nth-child(1) > vn-check',
|
||||
fifthTicketCheckbox: 'vn-ticket-index vn-tbody > a:nth-child(5) > vn-td:nth-child(1) > vn-check',
|
||||
sixthTicketCheckbox: 'vn-ticket-index vn-tbody > a:nth-child(6) > vn-td:nth-child(1) > vn-check',
|
||||
payoutButton: 'vn-ticket-index vn-button[icon="icon-recovery"]',
|
||||
payoutCompany: '.vn-dialog vn-autocomplete[ng-model="$ctrl.companyFk"]',
|
||||
|
@ -544,7 +547,7 @@ export default {
|
|||
},
|
||||
ticketSales: {
|
||||
setOk: 'vn-ticket-sale vn-tool-bar > vn-button[label="Ok"] > button',
|
||||
saleLine: 'vn-table div > vn-tbody > vn-tr',
|
||||
saleLine: 'vn-table div > vn-tbody > vn-tr vn-check',
|
||||
saleDescriptorPopover: '.vn-popover.shown vn-item-descriptor',
|
||||
saleDescriptorPopoverSummaryButton: '.vn-popover.shown vn-item-descriptor a[ui-sref="item.card.summary({id: $ctrl.descriptor.id})"]',
|
||||
newItemButton: 'vn-ticket-sale vn-card vn-icon-button[icon="add_circle"]',
|
||||
|
@ -1039,7 +1042,7 @@ export default {
|
|||
zoneBasicData: {
|
||||
name: 'vn-zone-basic-data vn-textfield[ng-model="$ctrl.zone.name"]',
|
||||
agency: 'vn-zone-basic-data vn-autocomplete[ng-model="$ctrl.zone.agencyModeFk"]',
|
||||
maxVolume: 'vn-zone-basic-data vn-input-number[ng-model="$ctrl.zone.m3Max"]',
|
||||
maxVolume: 'vn-zone-basic-data vn-input-number[ng-model="$ctrl.zone.itemMaxSize"]',
|
||||
travelingDays: 'vn-zone-basic-data vn-input-number[ng-model="$ctrl.zone.travelingDays"]',
|
||||
closing: 'vn-zone-basic-data vn-input-time[ng-model="$ctrl.zone.hour"]',
|
||||
price: 'vn-zone-basic-data vn-input-number[ng-model="$ctrl.zone.price"]',
|
||||
|
@ -1083,7 +1086,7 @@ export default {
|
|||
allBuyCheckbox: 'vn-entry-buy-index thead vn-check',
|
||||
firstBuyCheckbox: 'vn-entry-buy-index tbody:nth-child(2) vn-check',
|
||||
deleteBuysButton: 'vn-entry-buy-index vn-button[icon="delete"]',
|
||||
addBuyButton: 'vn-entry-buy-index vn-icon[icon="add_circle"]',
|
||||
addBuyButton: 'vn-entry-buy-index vn-icon[icon="add"]',
|
||||
secondBuyPackingPrice: 'vn-entry-buy-index tbody:nth-child(3) > tr:nth-child(1) vn-input-number[ng-model="buy.price3"]',
|
||||
secondBuyGroupingPrice: 'vn-entry-buy-index tbody:nth-child(3) > tr:nth-child(1) vn-input-number[ng-model="buy.price2"]',
|
||||
secondBuyPrice: 'vn-entry-buy-index tbody:nth-child(3) > tr:nth-child(1) vn-input-number[ng-model="buy.buyingValue"]',
|
||||
|
@ -1105,9 +1108,9 @@ export default {
|
|||
importBuysButton: 'vn-entry-buy-import button[type="submit"]'
|
||||
},
|
||||
entryLatestBuys: {
|
||||
firstBuy: 'vn-entry-latest-buys vn-tbody > a:nth-child(1)',
|
||||
allBuysCheckBox: 'vn-entry-latest-buys vn-thead vn-check',
|
||||
secondBuyCheckBox: 'vn-entry-latest-buys a:nth-child(2) vn-check[ng-model="buy.checked"]',
|
||||
firstBuy: 'vn-entry-latest-buys tbody > tr:nth-child(1)',
|
||||
allBuysCheckBox: 'vn-entry-latest-buys thead vn-check',
|
||||
secondBuyCheckBox: 'vn-entry-latest-buys tbody tr:nth-child(2) vn-check[ng-model="buy.$checked"]',
|
||||
editBuysButton: 'vn-entry-latest-buys vn-button[icon="edit"]',
|
||||
fieldAutocomplete: 'vn-autocomplete[ng-model="$ctrl.editedColumn.field"]',
|
||||
newValueInput: 'vn-textfield[ng-model="$ctrl.editedColumn.newValue"]',
|
||||
|
@ -1144,6 +1147,7 @@ export default {
|
|||
alias: 'vn-supplier-basic-data vn-textfield[ng-model="$ctrl.supplier.nickname"]',
|
||||
isSerious: 'vn-supplier-basic-data vn-check[ng-model="$ctrl.supplier.isSerious"]',
|
||||
isActive: 'vn-supplier-basic-data vn-check[ng-model="$ctrl.supplier.isActive"]',
|
||||
isPayMethodChecked: 'vn-supplier-basic-data vn-check[ng-model="$ctrl.supplier.isPayMethodChecked"]',
|
||||
notes: 'vn-supplier-basic-data vn-textarea[ng-model="$ctrl.supplier.note"]',
|
||||
saveButton: 'vn-supplier-basic-data button[type="submit"]',
|
||||
},
|
||||
|
|
|
@ -19,7 +19,9 @@ describe('Login path', async() => {
|
|||
const message = await page.waitForSnackbar();
|
||||
const state = await page.getState();
|
||||
|
||||
expect(message.text).toContain('Invalid login, remember that distinction is made between uppercase and lowercase');
|
||||
const errorMessage = 'Invalid login, remember that distinction is made between uppercase and lowercase';
|
||||
|
||||
expect(message.text).toContain(errorMessage);
|
||||
expect(state).toBe('login');
|
||||
});
|
||||
|
||||
|
@ -28,7 +30,9 @@ describe('Login path', async() => {
|
|||
const message = await page.waitForSnackbar();
|
||||
const state = await page.getState();
|
||||
|
||||
expect(message.text).toContain('Invalid login, remember that distinction is made between uppercase and lowercase');
|
||||
const errorMessage = 'Invalid login, remember that distinction is made between uppercase and lowercase';
|
||||
|
||||
expect(message.text).toContain(errorMessage);
|
||||
expect(state).toBe('login');
|
||||
});
|
||||
|
||||
|
|
|
@ -27,16 +27,19 @@ describe('Client create path', () => {
|
|||
await page.waitForState('client.create');
|
||||
});
|
||||
|
||||
it('should receive an error when clicking the create button having name and Business name fields empty', async() => {
|
||||
await page.write(selectors.createClientView.taxNumber, '74451390E');
|
||||
await page.write(selectors.createClientView.userName, 'CaptainMarvel');
|
||||
await page.write(selectors.createClientView.email, 'CarolDanvers@verdnatura.es');
|
||||
await page.autocompleteSearch(selectors.createClientView.salesPerson, 'salesPerson');
|
||||
await page.waitToClick(selectors.createClientView.createButton);
|
||||
const message = await page.waitForSnackbar();
|
||||
it('should receive an error when clicking the create button having name and Business name fields empty',
|
||||
async() => {
|
||||
await page.write(selectors.createClientView.taxNumber, '74451390E');
|
||||
await page.write(selectors.createClientView.userName, 'CaptainMarvel');
|
||||
await page.write(selectors.createClientView.email, 'CarolDanvers@verdnatura.es');
|
||||
await page.autocompleteSearch(selectors.createClientView.salesPerson, 'salesPerson');
|
||||
await page.autocompleteSearch(selectors.createClientView.businessType, 'florist');
|
||||
await page.waitToClick(selectors.createClientView.createButton);
|
||||
const message = await page.waitForSnackbar();
|
||||
|
||||
expect(message.text).toContain('Some fields are invalid');
|
||||
});
|
||||
expect(message.text).toContain('Some fields are invalid');
|
||||
}
|
||||
);
|
||||
|
||||
it(`should create a new province`, async() => {
|
||||
await page.waitToClick(selectors.createClientView.addPostCode);
|
||||
|
@ -80,9 +83,22 @@ describe('Client create path', () => {
|
|||
expect(message.text).toContain('Some fields are invalid');
|
||||
});
|
||||
|
||||
/* Tarea #3370
|
||||
it(`should attempt to create a new user with all it's data but wrong business type`, async() => {
|
||||
await page.clearInput(selectors.createClientView.email);
|
||||
await page.write(selectors.createClientView.email, 'CarolDanvers@verdnatura.es');
|
||||
await page.clearInput(selectors.createClientView.businessType);
|
||||
await page.waitToClick(selectors.createClientView.createButton);
|
||||
const message = await page.waitForSnackbar();
|
||||
|
||||
expect(message.text).toContain('Some fields are invalid');
|
||||
});*/
|
||||
|
||||
it(`should attempt to create a new user with all it's data but wrong postal code`, async() => {
|
||||
await page.clearInput(selectors.createClientView.email);
|
||||
await page.write(selectors.createClientView.email, 'CarolDanvers@verdnatura.es');
|
||||
|
||||
await page.autocompleteSearch(selectors.createClientView.businessType, 'florist');
|
||||
await page.clearInput(selectors.createClientView.postcode);
|
||||
await page.write(selectors.createClientView.postcode, '479999');
|
||||
await page.waitToClick(selectors.createClientView.createButton);
|
||||
|
|
|
@ -112,7 +112,7 @@ describe('Client Edit fiscalData path', () => {
|
|||
expect(message.text).toContain('Cannot check Equalization Tax in this NIF/CIF');
|
||||
});
|
||||
|
||||
it('should finally edit the fixcal data correctly as VIES isnt checked and fiscal id is valid for EQtax', async() => {
|
||||
it('should edit the fiscal data correctly as VIES isnt checked and fiscal id is valid for EQtax', async() => {
|
||||
await page.clearInput(selectors.clientFiscalData.fiscalId);
|
||||
await page.write(selectors.clientFiscalData.fiscalId, '94980061C');
|
||||
await page.waitToClick(selectors.clientFiscalData.saveButton);
|
||||
|
|
|
@ -38,10 +38,13 @@ describe('Client Edit billing data path', () => {
|
|||
await page.autocompleteSearch(selectors.clientBillingData.newBankEntityCountry, 'España');
|
||||
await page.write(selectors.clientBillingData.newBankEntityCode, '9999');
|
||||
await page.waitToClick(selectors.clientBillingData.acceptBankEntityButton);
|
||||
const message = await page.waitForSnackbar();
|
||||
await page.waitForTextInField(selectors.clientBillingData.swiftBic, 'Gotham City Bank');
|
||||
const newcode = await page.waitToGetProperty(selectors.clientBillingData.swiftBic, 'value');
|
||||
|
||||
expect(newcode).toEqual('GTHMCT Gotham City Bank');
|
||||
|
||||
expect(message.text).toContain('Data saved!');
|
||||
});
|
||||
|
||||
it(`should confirm the IBAN pay method was sucessfully saved`, async() => {
|
||||
|
|
|
@ -105,7 +105,23 @@ describe('Client balance path', () => {
|
|||
expect(result).toContain('-€100.00');
|
||||
});
|
||||
|
||||
it('should create a new payment and check the cash exceeded the maximum', async() => {
|
||||
const amountPaid = '1001';
|
||||
|
||||
await page.closePopup();
|
||||
await page.waitToClick(selectors.clientBalance.newPaymentButton);
|
||||
await page.autocompleteSearch(selectors.clientBalance.newPaymentBank, 'Cash');
|
||||
await page.write(selectors.clientBalance.newPaymentAmount, amountPaid);
|
||||
await page.clearInput(selectors.clientBalance.newDescription);
|
||||
await page.write(selectors.clientBalance.newDescription, 'Payment');
|
||||
await page.waitToClick(selectors.clientBalance.saveButton);
|
||||
const message = await page.waitForSnackbar();
|
||||
|
||||
expect(message.text).toContain('Amount exceeded');
|
||||
});
|
||||
|
||||
it('should create a new payment that sets the balance back to the original negative value', async() => {
|
||||
await page.closePopup();
|
||||
await page.waitToClick(selectors.clientBalance.newPaymentButton);
|
||||
await page.autocompleteSearch(selectors.clientBalance.newPaymentBank, 'Pay on receipt');
|
||||
await page.overwrite(selectors.clientBalance.newPaymentAmount, '-150');
|
||||
|
|
|
@ -16,13 +16,13 @@ describe('Item summary path', () => {
|
|||
|
||||
it('should search for an item', async() => {
|
||||
await page.doSearch('Ranged weapon');
|
||||
const nResults = await page.countElement(selectors.itemsIndex.searchResult);
|
||||
const resultsCount = await page.countElement(selectors.itemsIndex.searchResult);
|
||||
|
||||
await page.waitForTextInElement(selectors.itemsIndex.searchResult, 'Ranged weapon');
|
||||
await page.waitToClick(selectors.itemsIndex.firstResultPreviewButton);
|
||||
const isVisible = await page.isVisible(selectors.itemSummary.basicData);
|
||||
|
||||
expect(nResults).toBe(3);
|
||||
expect(resultsCount).toBe(3);
|
||||
expect(isVisible).toBeTruthy();
|
||||
});
|
||||
|
||||
|
@ -61,12 +61,12 @@ describe('Item summary path', () => {
|
|||
|
||||
it('should search for other item', async() => {
|
||||
await page.doSearch('Melee Reinforced');
|
||||
const nResults = await page.countElement(selectors.itemsIndex.searchResult);
|
||||
const resultsCount = await page.countElement(selectors.itemsIndex.searchResult);
|
||||
|
||||
await page.waitToClick(selectors.itemsIndex.firstResultPreviewButton);
|
||||
await page.waitForSelector(selectors.itemSummary.basicData, {visible: true});
|
||||
|
||||
expect(nResults).toBe(2);
|
||||
expect(resultsCount).toBe(2);
|
||||
});
|
||||
|
||||
it(`should now check the item summary preview shows fields from basic data`, async() => {
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
import selectors from '../../helpers/selectors.js';
|
||||
import getBrowser from '../../helpers/puppeteer';
|
||||
|
||||
describe('Item Create', () => {
|
||||
let browser;
|
||||
let page;
|
||||
beforeAll(async() => {
|
||||
browser = await getBrowser();
|
||||
page = browser.page;
|
||||
await page.loginAndModule('buyer', 'item');
|
||||
});
|
||||
|
||||
afterAll(async() => {
|
||||
await browser.close();
|
||||
});
|
||||
|
||||
it(`should search for the item Infinity Gauntlet to confirm it isn't created yet`, async() => {
|
||||
await page.doSearch('Infinity Gauntlet');
|
||||
const resultsCount = await page.countElement(selectors.itemsIndex.searchResult);
|
||||
|
||||
expect(resultsCount).toEqual(0);
|
||||
});
|
||||
|
||||
it('should access to the create item view by clicking the create floating button', async() => {
|
||||
await page.waitToClick(selectors.itemsIndex.createItemButton);
|
||||
await page.waitForState('item.create');
|
||||
});
|
||||
|
||||
it('should return to the item index by clickig the cancel button', async() => {
|
||||
await page.waitToClick(selectors.itemCreateView.cancelButton);
|
||||
await page.waitForState('item.index');
|
||||
});
|
||||
|
||||
it('should now access to the create item view by clicking the create floating button', async() => {
|
||||
await page.waitToClick(selectors.itemsIndex.createItemButton);
|
||||
await page.waitForState('item.create');
|
||||
});
|
||||
|
||||
it('should create the Infinity Gauntlet item', async() => {
|
||||
await page.write(selectors.itemCreateView.temporalName, 'Infinity Gauntlet');
|
||||
await page.autocompleteSearch(selectors.itemCreateView.type, 'Crisantemo');
|
||||
await page.autocompleteSearch(selectors.itemCreateView.intrastat, 'Coral y materiales similares');
|
||||
await page.autocompleteSearch(selectors.itemCreateView.origin, 'Holand');
|
||||
await page.waitToClick(selectors.itemCreateView.createButton);
|
||||
const message = await page.waitForSnackbar();
|
||||
|
||||
expect(message.text).toContain('Data saved!');
|
||||
});
|
||||
|
||||
it('should confirm Infinity Gauntlet item was created', async() => {
|
||||
let result = await page
|
||||
.waitToGetProperty(selectors.itemBasicData.name, 'value');
|
||||
|
||||
expect(result).toEqual('Infinity Gauntlet');
|
||||
|
||||
result = await page
|
||||
.waitToGetProperty(selectors.itemBasicData.type, 'value');
|
||||
|
||||
expect(result).toEqual('Crisantemo');
|
||||
|
||||
result = await page
|
||||
.waitToGetProperty(selectors.itemBasicData.intrastat, 'value');
|
||||
|
||||
expect(result).toEqual('5080000 Coral y materiales similares');
|
||||
|
||||
result = await page
|
||||
.waitToGetProperty(selectors.itemBasicData.origin, 'value');
|
||||
|
||||
expect(result).toEqual('Holand');
|
||||
});
|
||||
});
|
|
@ -1,105 +0,0 @@
|
|||
import selectors from '../../helpers/selectors.js';
|
||||
import getBrowser from '../../helpers/puppeteer';
|
||||
|
||||
describe('Item Create/Clone path', () => {
|
||||
let browser;
|
||||
let page;
|
||||
beforeAll(async() => {
|
||||
browser = await getBrowser();
|
||||
page = browser.page;
|
||||
await page.loginAndModule('buyer', 'item');
|
||||
});
|
||||
|
||||
afterAll(async() => {
|
||||
await browser.close();
|
||||
});
|
||||
|
||||
describe('create', () => {
|
||||
it(`should search for the item Infinity Gauntlet to confirm it isn't created yet`, async() => {
|
||||
await page.doSearch('Infinity Gauntlet');
|
||||
const nResults = await page.countElement(selectors.itemsIndex.searchResult);
|
||||
|
||||
expect(nResults).toEqual(0);
|
||||
});
|
||||
|
||||
it('should access to the create item view by clicking the create floating button', async() => {
|
||||
await page.waitToClick(selectors.itemsIndex.createItemButton);
|
||||
await page.waitForState('item.create');
|
||||
});
|
||||
|
||||
it('should return to the item index by clickig the cancel button', async() => {
|
||||
await page.waitToClick(selectors.itemCreateView.cancelButton);
|
||||
await page.waitForState('item.index');
|
||||
});
|
||||
|
||||
it('should now access to the create item view by clicking the create floating button', async() => {
|
||||
await page.waitToClick(selectors.itemsIndex.createItemButton);
|
||||
await page.waitForState('item.create');
|
||||
});
|
||||
|
||||
it('should create the Infinity Gauntlet item', async() => {
|
||||
await page.write(selectors.itemCreateView.temporalName, 'Infinity Gauntlet');
|
||||
await page.autocompleteSearch(selectors.itemCreateView.type, 'Crisantemo');
|
||||
await page.autocompleteSearch(selectors.itemCreateView.intrastat, 'Coral y materiales similares');
|
||||
await page.autocompleteSearch(selectors.itemCreateView.origin, 'Holand');
|
||||
await page.waitToClick(selectors.itemCreateView.createButton);
|
||||
const message = await page.waitForSnackbar();
|
||||
|
||||
expect(message.text).toContain('Data saved!');
|
||||
});
|
||||
|
||||
it('should confirm Infinity Gauntlet item was created', async() => {
|
||||
let result = await page
|
||||
.waitToGetProperty(selectors.itemBasicData.name, 'value');
|
||||
|
||||
expect(result).toEqual('Infinity Gauntlet');
|
||||
|
||||
result = await page
|
||||
.waitToGetProperty(selectors.itemBasicData.type, 'value');
|
||||
|
||||
expect(result).toEqual('Crisantemo');
|
||||
|
||||
result = await page
|
||||
.waitToGetProperty(selectors.itemBasicData.intrastat, 'value');
|
||||
|
||||
expect(result).toEqual('5080000 Coral y materiales similares');
|
||||
|
||||
result = await page
|
||||
.waitToGetProperty(selectors.itemBasicData.origin, 'value');
|
||||
|
||||
expect(result).toEqual('Holand');
|
||||
});
|
||||
});
|
||||
|
||||
// Issue #2201
|
||||
// When there is just one result you're redirected automatically to it, so
|
||||
// it's not possible to use the clone option.
|
||||
xdescribe('clone', () => {
|
||||
it('should return to the items index by clicking the return to items button', async() => {
|
||||
await page.waitToClick(selectors.itemBasicData.goToItemIndexButton);
|
||||
await page.waitForSelector(selectors.itemsIndex.createItemButton);
|
||||
await page.waitForState('item.index');
|
||||
});
|
||||
|
||||
it(`should search for the item Infinity Gauntlet`, async() => {
|
||||
await page.doSearch('Infinity Gauntlet');
|
||||
const nResults = await page.countElement(selectors.itemsIndex.searchResult);
|
||||
|
||||
expect(nResults).toEqual(1);
|
||||
});
|
||||
|
||||
it(`should clone the Infinity Gauntlet`, async() => {
|
||||
await page.waitForTextInElement(selectors.itemsIndex.searchResult, 'Infinity Gauntlet');
|
||||
await page.waitToClick(selectors.itemsIndex.searchResultCloneButton);
|
||||
await page.waitToClick(selectors.itemsIndex.acceptClonationAlertButton);
|
||||
await page.waitForState('item.tags');
|
||||
});
|
||||
|
||||
it('should search for the item Infinity Gauntlet and find two', async() => {
|
||||
await page.doSearch('Infinity Gauntlet');
|
||||
const nResults = await page.countElement(selectors.itemsIndex.searchResult);
|
||||
|
||||
expect(nResults).toEqual(2);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -16,8 +16,8 @@ describe('Item index path', () => {
|
|||
});
|
||||
|
||||
it('should click on the fields to show button to open the list of columns to show', async() => {
|
||||
await page.waitToClick(selectors.itemsIndex.fieldsToShowButton);
|
||||
const visible = await page.isVisible(selectors.itemsIndex.fieldsToShowForm);
|
||||
await page.waitToClick(selectors.itemsIndex.shownColumns);
|
||||
const visible = await page.isVisible(selectors.itemsIndex.shownColumnsList);
|
||||
|
||||
expect(visible).toBeTruthy();
|
||||
});
|
||||
|
@ -31,7 +31,7 @@ describe('Item index path', () => {
|
|||
await page.waitToClick(selectors.itemsIndex.intrastadCheckbox);
|
||||
await page.waitToClick(selectors.itemsIndex.originCheckbox);
|
||||
await page.waitToClick(selectors.itemsIndex.buyerCheckbox);
|
||||
await page.waitToClick(selectors.itemsIndex.destinyCheckbox);
|
||||
await page.waitToClick(selectors.itemsIndex.densityCheckbox);
|
||||
await page.waitToClick(selectors.itemsIndex.saveFieldsButton);
|
||||
const message = await page.waitForSnackbar();
|
||||
|
||||
|
@ -39,6 +39,7 @@ describe('Item index path', () => {
|
|||
});
|
||||
|
||||
it('should navigate forth and back to see the images column is still visible', async() => {
|
||||
await page.closePopup();
|
||||
await page.waitToClick(selectors.itemsIndex.firstSearchResult);
|
||||
await page.waitToClick(selectors.itemDescriptor.goBackToModuleIndexButton);
|
||||
await page.waitToClick(selectors.globalItems.searchButton);
|
||||
|
@ -54,7 +55,7 @@ describe('Item index path', () => {
|
|||
});
|
||||
|
||||
it('should mark all unchecked boxes to leave the index as it was', async() => {
|
||||
await page.waitToClick(selectors.itemsIndex.fieldsToShowButton);
|
||||
await page.waitToClick(selectors.itemsIndex.shownColumns);
|
||||
await page.waitToClick(selectors.itemsIndex.idCheckbox);
|
||||
await page.waitToClick(selectors.itemsIndex.stemsCheckbox);
|
||||
await page.waitToClick(selectors.itemsIndex.sizeCheckbox);
|
||||
|
@ -63,7 +64,7 @@ describe('Item index path', () => {
|
|||
await page.waitToClick(selectors.itemsIndex.intrastadCheckbox);
|
||||
await page.waitToClick(selectors.itemsIndex.originCheckbox);
|
||||
await page.waitToClick(selectors.itemsIndex.buyerCheckbox);
|
||||
await page.waitToClick(selectors.itemsIndex.destinyCheckbox);
|
||||
await page.waitToClick(selectors.itemsIndex.densityCheckbox);
|
||||
await page.waitToClick(selectors.itemsIndex.saveFieldsButton);
|
||||
const message = await page.waitForSnackbar();
|
||||
|
||||
|
@ -71,6 +72,7 @@ describe('Item index path', () => {
|
|||
});
|
||||
|
||||
it('should now navigate forth and back to see the ids column is now visible', async() => {
|
||||
await page.closePopup();
|
||||
await page.waitToClick(selectors.itemsIndex.firstSearchResult);
|
||||
await page.waitToClick(selectors.itemDescriptor.goBackToModuleIndexButton);
|
||||
await page.waitToClick(selectors.globalItems.searchButton);
|
||||
|
|
|
@ -340,9 +340,10 @@ describe('Ticket Edit sale path', () => {
|
|||
});
|
||||
|
||||
it('should confirm the new ticket received the line', async() => {
|
||||
const expectedLines = 1;
|
||||
const result = await page.countElement(selectors.ticketSales.saleLine);
|
||||
|
||||
expect(result).toEqual(1);
|
||||
expect(result).toEqual(expectedLines);
|
||||
});
|
||||
|
||||
it('should check the first sale reserved icon isnt visible', async() => {
|
||||
|
@ -353,6 +354,7 @@ describe('Ticket Edit sale path', () => {
|
|||
|
||||
it('should mark the first sale as reserved', async() => {
|
||||
await page.waitToClick(selectors.ticketSales.firstSaleCheckbox);
|
||||
|
||||
await page.waitToClick(selectors.ticketSales.moreMenu);
|
||||
await page.waitToClick(selectors.ticketSales.moreMenuReserve);
|
||||
await page.closePopup();
|
||||
|
|
|
@ -62,7 +62,7 @@ describe('Ticket Create packages path', () => {
|
|||
expect(result).toEqual('7 : Container medical box 1m');
|
||||
});
|
||||
|
||||
it(`should confirm the first quantity is just a number and the string part was ignored by the imput number`, async() => {
|
||||
it(`should confirm quantity is just a number and the string part was ignored by the imput number`, async() => {
|
||||
await page.waitForTextInField(selectors.ticketPackages.firstQuantity, '-99');
|
||||
const result = await page.waitToGetProperty(selectors.ticketPackages.firstQuantity, 'value');
|
||||
|
||||
|
|
|
@ -177,7 +177,6 @@ describe('Ticket descriptor path', () => {
|
|||
describe('SMS', () => {
|
||||
it('should send the payment SMS using the descriptor menu', async() => {
|
||||
await page.waitToClick(selectors.ticketDescriptor.moreMenu);
|
||||
await page.waitForContentLoaded();
|
||||
await page.waitToClick(selectors.ticketDescriptor.moreMenuPaymentSMS);
|
||||
await page.waitForSelector(selectors.ticketDescriptor.SMStext);
|
||||
await page.waitPropertyLength(selectors.ticketDescriptor.SMStext, 'value', 128);
|
||||
|
|
|
@ -21,8 +21,8 @@ describe('Ticket index payout path', () => {
|
|||
|
||||
it('should check the second ticket from a client and 1 of another', async() => {
|
||||
await page.waitToClick(selectors.globalItems.searchButton);
|
||||
await page.waitToClick(selectors.ticketsIndex.secondTicketCheckbox);
|
||||
await page.waitToClick(selectors.ticketsIndex.thirdTicketCheckbox);
|
||||
await page.waitToClick(selectors.ticketsIndex.fifthTicketCheckbox);
|
||||
await page.waitToClick(selectors.ticketsIndex.payoutButton);
|
||||
const message = await page.waitForSnackbar();
|
||||
|
||||
|
@ -58,9 +58,11 @@ describe('Ticket index payout path', () => {
|
|||
await page.selectModule('client');
|
||||
await page.accessToSearchResult('1101');
|
||||
await page.accessToSection('client.card.balance.index');
|
||||
await page.waitForSelector('vn-client-balance-index vn-tbody > vn-tr');
|
||||
let result = await page.countElement('vn-client-balance-index vn-tbody > vn-tr');
|
||||
await page.waitForSelector(selectors.clientBalance.anyBalanceLine);
|
||||
const count = await page.countElement(selectors.clientBalance.anyBalanceLine);
|
||||
const reference = await page.waitToGetProperty(selectors.clientBalance.firstLineReference, 'innerText');
|
||||
|
||||
expect(result).toEqual(4);
|
||||
expect(count).toEqual(4);
|
||||
expect(reference).toContain('Cash, Albaran: 7, 8Payment');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -25,6 +25,7 @@ describe('Zone basic data path', () => {
|
|||
await page.clearInput(selectors.zoneBasicData.name);
|
||||
await page.write(selectors.zoneBasicData.name, 'Brimstone teleportation');
|
||||
await page.autocompleteSearch(selectors.zoneBasicData.agency, 'Quantum break device');
|
||||
await page.clearInput(selectors.zoneBasicData.maxVolume);
|
||||
await page.write(selectors.zoneBasicData.maxVolume, '10');
|
||||
await page.clearInput(selectors.zoneBasicData.travelingDays);
|
||||
await page.write(selectors.zoneBasicData.travelingDays, '1');
|
||||
|
|
|
@ -31,7 +31,7 @@ describe('Entry lastest buys path', () => {
|
|||
await page.waitForSelector(selectors.entryLatestBuys.fieldAutocomplete, {visible: true});
|
||||
});
|
||||
|
||||
it('should search for the "Description" field and type a new description for the items in each selected buy', async() => {
|
||||
it('should search for the "Description" and type a new one for the items in each selected buy', async() => {
|
||||
await page.autocompleteSearch(selectors.entryLatestBuys.fieldAutocomplete, 'Description');
|
||||
await page.write(selectors.entryLatestBuys.newValueInput, 'Crafted item');
|
||||
await page.waitToClick(selectors.entryLatestBuys.acceptEditBuysDialog);
|
||||
|
|
|
@ -28,7 +28,7 @@ describe('Entry import, create and edit buys path', () => {
|
|||
await page.waitForState('entry.card.buy.import');
|
||||
});
|
||||
|
||||
it('should fill the form, import the designated JSON file and select items for each import and confirm import', async() => {
|
||||
it('should fill the form, import the a JSON file and select items for each import and confirm import', async() => {
|
||||
let currentDir = process.cwd();
|
||||
let filePath = `${currentDir}/e2e/assets/07_import_buys.json`;
|
||||
|
||||
|
@ -42,7 +42,8 @@ describe('Entry import, create and edit buys path', () => {
|
|||
await page.waitForTextInField(selectors.entryBuys.observation, '729-6340 2846');
|
||||
|
||||
await page.autocompleteSearch(selectors.entryBuys.firstImportedItem, 'Ranged Reinforced weapon pistol 9mm');
|
||||
await page.autocompleteSearch(selectors.entryBuys.secondImportedItem, 'Melee Reinforced weapon heavy shield 1x0.5m');
|
||||
const itemName = 'Melee Reinforced weapon heavy shield 1x0.5m';
|
||||
await page.autocompleteSearch(selectors.entryBuys.secondImportedItem, itemName);
|
||||
await page.autocompleteSearch(selectors.entryBuys.thirdImportedItem, 'Container medical box 1m');
|
||||
await page.autocompleteSearch(selectors.entryBuys.fourthImportedItem, 'Container ammo box 1m');
|
||||
|
||||
|
@ -88,37 +89,37 @@ describe('Entry import, create and edit buys path', () => {
|
|||
|
||||
it('should edit the newest buy', async() => {
|
||||
await page.clearInput(selectors.entryBuys.secondBuyPackingPrice);
|
||||
await page.waitForTextInField(selectors.entryBuys.secondBuyPackingPrice, '');
|
||||
await page.waitForTimeout(250);
|
||||
await page.write(selectors.entryBuys.secondBuyPackingPrice, '100');
|
||||
await page.waitForSnackbar();
|
||||
|
||||
await page.clearInput(selectors.entryBuys.secondBuyGroupingPrice);
|
||||
await page.waitForTextInField(selectors.entryBuys.secondBuyGroupingPrice, '');
|
||||
await page.waitForTimeout(250);
|
||||
await page.write(selectors.entryBuys.secondBuyGroupingPrice, '200');
|
||||
await page.waitForSnackbar();
|
||||
|
||||
await page.clearInput(selectors.entryBuys.secondBuyPrice);
|
||||
await page.waitForTextInField(selectors.entryBuys.secondBuyPrice, '');
|
||||
await page.waitForTimeout(250);
|
||||
await page.write(selectors.entryBuys.secondBuyPrice, '300');
|
||||
await page.waitForSnackbar();
|
||||
|
||||
await page.clearInput(selectors.entryBuys.secondBuyGrouping);
|
||||
await page.waitForTextInField(selectors.entryBuys.secondBuyGrouping, '');
|
||||
await page.waitForTimeout(250);
|
||||
await page.write(selectors.entryBuys.secondBuyGrouping, '400');
|
||||
await page.waitForSnackbar();
|
||||
|
||||
await page.clearInput(selectors.entryBuys.secondBuyPacking);
|
||||
await page.waitForTextInField(selectors.entryBuys.secondBuyPacking, '');
|
||||
await page.waitForTimeout(250);
|
||||
await page.write(selectors.entryBuys.secondBuyPacking, '500');
|
||||
await page.waitForSnackbar();
|
||||
|
||||
await page.clearInput(selectors.entryBuys.secondBuyWeight);
|
||||
await page.waitForTextInField(selectors.entryBuys.secondBuyWeight, '');
|
||||
await page.waitForTimeout(250);
|
||||
await page.write(selectors.entryBuys.secondBuyWeight, '600');
|
||||
await page.waitForSnackbar();
|
||||
|
||||
await page.clearInput(selectors.entryBuys.secondBuyStickers);
|
||||
await page.waitForTextInField(selectors.entryBuys.secondBuyStickers, '');
|
||||
await page.waitForTimeout(250);
|
||||
await page.write(selectors.entryBuys.secondBuyStickers, '700');
|
||||
await page.waitForSnackbar();
|
||||
|
||||
|
@ -126,7 +127,7 @@ describe('Entry import, create and edit buys path', () => {
|
|||
await page.waitForSnackbar();
|
||||
|
||||
await page.clearInput(selectors.entryBuys.secondBuyQuantity);
|
||||
await page.waitForTextInField(selectors.entryBuys.secondBuyQuantity, '');
|
||||
await page.waitForTimeout(250);
|
||||
await page.write(selectors.entryBuys.secondBuyQuantity, '800');
|
||||
});
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ describe('Supplier basic data path', () => {
|
|||
await page.write(selectors.supplierBasicData.alias, 'Plants Nick SL');
|
||||
await page.waitToClick(selectors.supplierBasicData.isSerious);
|
||||
await page.waitToClick(selectors.supplierBasicData.isActive);
|
||||
await page.waitToClick(selectors.supplierBasicData.isPayMethodChecked);
|
||||
await page.write(selectors.supplierBasicData.notes, 'Some notes');
|
||||
|
||||
await page.waitToClick(selectors.supplierBasicData.saveButton);
|
||||
|
@ -52,6 +53,12 @@ describe('Supplier basic data path', () => {
|
|||
expect(result).toBe('unchecked');
|
||||
});
|
||||
|
||||
it('should check the isPayMethodChecked checkbox is now unchecked', async() => {
|
||||
const result = await page.checkboxState(selectors.supplierBasicData.isPayMethodChecked);
|
||||
|
||||
expect(result).toBe('unchecked');
|
||||
});
|
||||
|
||||
it('should check the notes were edited', async() => {
|
||||
const result = await page.waitToGetProperty(selectors.supplierBasicData.notes, 'value');
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ export default class Contextmenu {
|
|||
get rowIndex() {
|
||||
if (!this.row) return null;
|
||||
|
||||
const table = this.row.closest('vn-table, .vn-table');
|
||||
const table = this.row.closest('table, vn-table, .vn-table');
|
||||
const rows = table.querySelectorAll('[ng-repeat]');
|
||||
|
||||
return Array.from(rows).findIndex(
|
||||
|
@ -67,13 +67,13 @@ export default class Contextmenu {
|
|||
get cell() {
|
||||
if (!this.target) return null;
|
||||
|
||||
return this.target.closest('vn-td, .vn-td, vn-td-editable');
|
||||
return this.target.closest('td, vn-td, .vn-td, vn-td-editable');
|
||||
}
|
||||
|
||||
get cellIndex() {
|
||||
if (!this.row) return null;
|
||||
|
||||
const cells = this.row.querySelectorAll('vn-td, .vn-td, vn-td-editable');
|
||||
const cells = this.row.querySelectorAll('td, vn-td, .vn-td, vn-td-editable');
|
||||
return Array.from(cells).findIndex(
|
||||
cellItem => cellItem == this.cell
|
||||
);
|
||||
|
@ -82,8 +82,8 @@ export default class Contextmenu {
|
|||
get rowHeader() {
|
||||
if (!this.row) return null;
|
||||
|
||||
const table = this.row.closest('vn-table, .vn-table');
|
||||
const headerCells = table && table.querySelectorAll('vn-thead vn-th');
|
||||
const table = this.row.closest('table, vn-table, .vn-table');
|
||||
const headerCells = table && table.querySelectorAll('thead th, vn-thead vn-th');
|
||||
const headerCell = headerCells && headerCells[this.cellIndex];
|
||||
|
||||
return headerCell;
|
||||
|
@ -147,7 +147,7 @@ export default class Contextmenu {
|
|||
*/
|
||||
isActionAllowed() {
|
||||
if (!this.target) return false;
|
||||
const isTableCell = this.target.closest('vn-td, .vn-td');
|
||||
const isTableCell = this.target.closest('td, vn-td, .vn-td');
|
||||
|
||||
return isTableCell && this.fieldName;
|
||||
}
|
||||
|
@ -172,9 +172,28 @@ export default class Contextmenu {
|
|||
excludeSelection() {
|
||||
let where = {[this.fieldName]: {neq: this.fieldValue}};
|
||||
if (this.exprBuilder) {
|
||||
where = buildFilter(where, (param, value) =>
|
||||
this.exprBuilder({param, value})
|
||||
);
|
||||
where = {[this.fieldName]: this.fieldValue};
|
||||
where = buildFilter(where, (param, value) => {
|
||||
const expr = this.exprBuilder({param, value});
|
||||
const props = Object.keys(expr);
|
||||
let newExpr = {};
|
||||
for (let prop of props) {
|
||||
if (expr[prop].like) {
|
||||
const operator = expr[prop].like;
|
||||
newExpr[prop] = {nlike: operator};
|
||||
} else if (expr[prop].between) {
|
||||
const operator = expr[prop].between;
|
||||
newExpr = {
|
||||
or: [
|
||||
{[prop]: {lt: operator[0]}},
|
||||
{[prop]: {gt: operator[1]}},
|
||||
]
|
||||
};
|
||||
} else
|
||||
newExpr[prop] = {neq: this.fieldValue};
|
||||
}
|
||||
return newExpr;
|
||||
});
|
||||
}
|
||||
|
||||
this.model.addFilter({where});
|
||||
|
@ -208,15 +227,22 @@ export default class Contextmenu {
|
|||
if (prop == findProp)
|
||||
delete instance[prop];
|
||||
|
||||
if (prop === 'and') {
|
||||
for (let [index, param] of instance[prop].entries()) {
|
||||
if (prop === 'and' || prop === 'or') {
|
||||
const instanceCopy = instance[prop].slice();
|
||||
for (let param of instanceCopy) {
|
||||
const [key] = Object.keys(param);
|
||||
const index = instance[prop].findIndex(param => {
|
||||
return Object.keys(param)[0] == key;
|
||||
});
|
||||
if (key == findProp)
|
||||
instance[prop].splice(index, 1);
|
||||
|
||||
if (param[key] instanceof Array)
|
||||
removeProp(param, filterKey, key);
|
||||
}
|
||||
|
||||
if (instance[prop].length == 0)
|
||||
delete instance[prop];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -52,3 +52,4 @@ import './wday-picker';
|
|||
import './datalist';
|
||||
import './contextmenu';
|
||||
import './rating';
|
||||
import './smart-table';
|
||||
|
|
|
@ -3,8 +3,8 @@ import Popover from '../popover';
|
|||
import './style.scss';
|
||||
|
||||
export default class Menu extends Popover {
|
||||
show(parent) {
|
||||
super.show(parent);
|
||||
show(parent, direction) {
|
||||
super.show(parent, direction);
|
||||
this.windowEl.addEventListener('click', () => this.hide());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,18 @@
|
|||
@import "./effects";
|
||||
@import "variables";
|
||||
|
||||
.vn-menu {
|
||||
vn-item, .vn-item {
|
||||
@extend %clickable;
|
||||
}
|
||||
|
||||
vn-item.dropdown:after,
|
||||
.vn-item.dropdown:after {
|
||||
font-family: 'Material Icons';
|
||||
content: 'keyboard_arrow_right';
|
||||
position: absolute;
|
||||
color: $color-spacer;
|
||||
font-size: 1.5em;
|
||||
right: 0
|
||||
}
|
||||
}
|
||||
|
|
|
@ -145,9 +145,8 @@ export default class MultiCheck extends FormInput {
|
|||
toggle() {
|
||||
const data = this.model.data;
|
||||
if (!data) return;
|
||||
data.forEach(el => {
|
||||
for (let el of data)
|
||||
el[this.checkField] = this.checkAll;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -156,8 +155,9 @@ ngModule.vnComponent('vnMultiCheck', {
|
|||
controller: MultiCheck,
|
||||
bindings: {
|
||||
model: '<',
|
||||
checkField: '<?',
|
||||
checkField: '@?',
|
||||
checkAll: '=?',
|
||||
checked: '=?',
|
||||
disabled: '<?'
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
<div ng-if="$ctrl.model.moreRows">
|
||||
<vn-button
|
||||
<div ng-if="$ctrl.model.moreRows" class="vn-py-md">
|
||||
<div
|
||||
ng-if="!$ctrl.model.isPaging"
|
||||
label="Load more results"
|
||||
ng-click="$ctrl.onLoadClick()">
|
||||
</vn-button>
|
||||
<vn-button label="Load more results"></vn-button>
|
||||
<vn-icon icon="arrow_drop_down"/>
|
||||
</div>
|
||||
<vn-spinner
|
||||
ng-if="$ctrl.model.isPaging"
|
||||
enable="::true">
|
||||
|
|
|
@ -1,7 +1,13 @@
|
|||
@import "variables";
|
||||
|
||||
vn-pagination {
|
||||
display: block;
|
||||
text-align: center;
|
||||
color: $color-primary;
|
||||
|
||||
vn-button, vn-icon {
|
||||
display: block
|
||||
}
|
||||
|
||||
& > div > vn-icon-button {
|
||||
font-size: 2rem;
|
||||
|
|
|
@ -23,12 +23,15 @@ export default class Popover extends Popup {
|
|||
* it is shown in a visible relative position to it.
|
||||
*
|
||||
* @param {HTMLElement|Event} parent Overrides the parent property
|
||||
* @param {String} direction - Direction [left]
|
||||
*/
|
||||
show(parent) {
|
||||
show(parent, direction) {
|
||||
if (parent instanceof Event)
|
||||
parent = event.target;
|
||||
|
||||
if (parent) this.parent = parent;
|
||||
if (direction) this.direction = direction;
|
||||
|
||||
super.show();
|
||||
this.content = this.popup.querySelector('.content');
|
||||
this.$timeout(() => this.relocate(), 10);
|
||||
|
@ -89,21 +92,40 @@ export default class Popover extends Popup {
|
|||
let width = clamp(popoverRect.width, parentRect.width, maxWith);
|
||||
let height = popoverRect.height;
|
||||
|
||||
let left = parentRect.left + parentRect.width / 2 - width / 2;
|
||||
left = clamp(left, margin, maxRight - width);
|
||||
let left;
|
||||
if (this.direction == 'left') {
|
||||
left = parentRect.left + parentRect.width;
|
||||
left = clamp(left, margin, maxRight - width);
|
||||
} else {
|
||||
left = parentRect.left + parentRect.width / 2 - width / 2;
|
||||
left = clamp(left, margin, maxRight - width);
|
||||
}
|
||||
|
||||
let top = parentRect.top + parentRect.height + arrowOffset;
|
||||
let top;
|
||||
if (this.direction == 'left')
|
||||
top = parentRect.top;
|
||||
else
|
||||
top = parentRect.top + parentRect.height + arrowOffset;
|
||||
let showTop = top + height > maxBottom;
|
||||
if (showTop) top = parentRect.top - height - arrowOffset;
|
||||
top = Math.max(top, margin);
|
||||
|
||||
if (showTop)
|
||||
if (this.direction == 'left')
|
||||
arrowStyle.left = `0`;
|
||||
else if (showTop)
|
||||
arrowStyle.bottom = `0`;
|
||||
else
|
||||
arrowStyle.top = `0`;
|
||||
|
||||
let arrowLeft = (parentRect.left - left) + parentRect.width / 2;
|
||||
arrowLeft = clamp(arrowLeft, arrowHeight, width - arrowHeight);
|
||||
let arrowLeft;
|
||||
if (this.direction == 'left') {
|
||||
arrowLeft = 0;
|
||||
let arrowTop = arrowOffset;
|
||||
arrowStyle.top = `${arrowTop}px`;
|
||||
} else {
|
||||
arrowLeft = (parentRect.left - left) + parentRect.width / 2;
|
||||
arrowLeft = clamp(arrowLeft, arrowHeight, width - arrowHeight);
|
||||
}
|
||||
arrowStyle.left = `${arrowLeft}px`;
|
||||
|
||||
style.top = `${top}px`;
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
<div class="vn-pa-md">
|
||||
<vn-horizontal class="actions">
|
||||
<div class="actions-left">
|
||||
<vn-button icon="view_column"
|
||||
id="shownColumns"
|
||||
ng-if="$ctrl.options.activeButtons.shownColumns"
|
||||
ng-click="smartTableColumns.show($event)"
|
||||
vn-tooltip="Shown columns">
|
||||
</vn-button>
|
||||
<div ng-transclude="actions"></div>
|
||||
</div>
|
||||
<div class="actions-right">
|
||||
<div class="totalRows" ng-if="$ctrl.model.data">
|
||||
{{model.data.length}}
|
||||
<span translate>results</span>
|
||||
</div>
|
||||
<vn-button icon="search"
|
||||
ng-if="$ctrl.options.activeButtons.search"
|
||||
ng-click="$ctrl.displaySearch()"
|
||||
vn-tooltip="Search">
|
||||
</vn-button>
|
||||
<div class="button-group"
|
||||
ng-if="$ctrl.options.activeButtons.crud">
|
||||
<vn-button icon="add"
|
||||
ng-click="$ctrl.createRow()"
|
||||
vn-tooltip="Add new row">
|
||||
</vn-button>
|
||||
<vn-button icon="undo"
|
||||
ng-click="$ctrl.model.undoChanges()"
|
||||
vn-tooltip="Undo">
|
||||
</vn-button>
|
||||
<vn-button icon="delete"
|
||||
ng-click="deleteConfirmation.show($event)"
|
||||
ng-show="$ctrl.checkedRows.length > 0"
|
||||
vn-tooltip="Remove selected rows">
|
||||
</vn-button>
|
||||
<vn-button icon="save"
|
||||
ng-click="$ctrl.saveAll()"
|
||||
vn-tooltip="Save data">
|
||||
</vn-button>
|
||||
</div>
|
||||
<vn-button icon="refresh"
|
||||
ng-click="$ctrl.model.refresh()"
|
||||
vn-tooltip="Refresh">
|
||||
</vn-button>
|
||||
</div>
|
||||
</vn-horizontal>
|
||||
<div id="table"></div>
|
||||
<vn-pagination
|
||||
ng-if="$ctrl.model"
|
||||
model="$ctrl.model"
|
||||
class="vn-pt-md">
|
||||
</vn-pagination>
|
||||
</div>
|
||||
|
||||
<vn-confirm
|
||||
vn-id="deleteConfirmation"
|
||||
on-accept="$ctrl.deleteAll()"
|
||||
question="Are you sure you want to continue?"
|
||||
message="Remove selected rows">
|
||||
</vn-confirm>
|
||||
|
||||
<vn-crud-model
|
||||
ng-if="$ctrl.viewConfigId"
|
||||
vn-id="userViewModel"
|
||||
url="UserConfigViews"
|
||||
link="{tableCode: $ctrl.viewConfigId, userFk: $ctrl.currentUserId}"
|
||||
data="$ctrl.viewConfig"
|
||||
auto-load="true">
|
||||
</vn-crud-model>
|
||||
<vn-popover vn-id="smart-table-columns" message="Fields to show">
|
||||
<tpl-body>
|
||||
<div class="smart-table-columns vn-pa-md vn-w-sm">
|
||||
<vn-horizontal>
|
||||
<h6 translate style="margin:0">Shown columns</h6>
|
||||
<vn-icon
|
||||
vn-none
|
||||
icon="info"
|
||||
color-marginal
|
||||
vn-tooltip="Check the columns you want to see"/>
|
||||
</vn-horizontal>
|
||||
<div class="vn-mb-md">
|
||||
<vn-check label="Tick all"
|
||||
ng-model="$ctrl.checkAll">
|
||||
</vn-check>
|
||||
</div>
|
||||
|
||||
<vn-horizontal class="vn-mb-md">
|
||||
<vn-check ng-repeat="column in $ctrl.columns"
|
||||
label="{{column.caption}}"
|
||||
ng-model="$ctrl.viewConfig[0].configuration[column.field]">
|
||||
</vn-check>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-button
|
||||
label="Save"
|
||||
ng-click="$ctrl.saveViewConfig()">
|
||||
</vn-button>
|
||||
</vn-horizontal>
|
||||
</div>
|
||||
</tpl-body>
|
||||
</vn-popover>
|
|
@ -0,0 +1,454 @@
|
|||
import ngModule from '../../module';
|
||||
import Component from '../../lib/component';
|
||||
import {buildFilter} from 'vn-loopback/util/filter';
|
||||
import angular from 'angular';
|
||||
import {camelToKebab} from '../../lib/string';
|
||||
import './style.scss';
|
||||
import './table.scss';
|
||||
|
||||
export default class SmartTable extends Component {
|
||||
constructor($element, $, $transclude) {
|
||||
super($element, $);
|
||||
this.currentUserId = window.localStorage.currentUserWorkerId;
|
||||
this.$transclude = $transclude;
|
||||
this.sortCriteria = [];
|
||||
this.$inputsScope;
|
||||
this.columns = [];
|
||||
this.autoSave = false;
|
||||
this.transclude();
|
||||
}
|
||||
|
||||
$onDestroy() {
|
||||
const styleElement = document.querySelector('style[id="smart-table"]');
|
||||
if (this.$.css && styleElement)
|
||||
styleElement.parentNode.removeChild(styleElement);
|
||||
}
|
||||
|
||||
get options() {
|
||||
return this._options;
|
||||
}
|
||||
|
||||
set options(options) {
|
||||
this._options = options;
|
||||
if (!options) return;
|
||||
|
||||
const activeButtons = options.activeButtons;
|
||||
const missingId = activeButtons && activeButtons.shownColumns && !this.viewConfigId;
|
||||
if (missingId)
|
||||
throw new Error('vnSmartTable: View identifier not defined');
|
||||
}
|
||||
|
||||
get model() {
|
||||
return this._model;
|
||||
}
|
||||
|
||||
set model(value) {
|
||||
this._model = value;
|
||||
if (value)
|
||||
this.$.model = value;
|
||||
}
|
||||
|
||||
get viewConfigId() {
|
||||
return this._viewConfigId;
|
||||
}
|
||||
|
||||
set viewConfigId(value) {
|
||||
this._viewConfigId = value;
|
||||
|
||||
/* if (value) {
|
||||
this.defaultViewConfig = {};
|
||||
|
||||
const url = 'DefaultViewConfigs';
|
||||
const filter = {where: {tableCode: value}};
|
||||
this.$http.get(url, {filter})
|
||||
.then(res => {
|
||||
if (res && res.data.length) {
|
||||
const columns = res.data[0].columns;
|
||||
this.defaultViewConfig = columns;
|
||||
}
|
||||
});
|
||||
} */
|
||||
}
|
||||
|
||||
getDefaultViewConfig() {
|
||||
const url = 'DefaultViewConfigs';
|
||||
const filter = {where: {tableCode: this.viewConfigId}};
|
||||
return this.$http.get(url, {filter})
|
||||
.then(res => {
|
||||
if (res && res.data.length)
|
||||
return res.data[0].columns;
|
||||
});
|
||||
}
|
||||
|
||||
get viewConfig() {
|
||||
return this._viewConfig;
|
||||
}
|
||||
|
||||
set viewConfig(value) {
|
||||
this._viewConfig = value;
|
||||
|
||||
if (!value) return;
|
||||
|
||||
if (!value.length) {
|
||||
this.getDefaultViewConfig().then(columns => {
|
||||
const defaultViewConfig = columns ? columns : {};
|
||||
|
||||
const userViewModel = this.$.userViewModel;
|
||||
for (const column of this.columns) {
|
||||
if (defaultViewConfig[column.field] == undefined)
|
||||
defaultViewConfig[column.field] = true;
|
||||
}
|
||||
|
||||
userViewModel.insert({
|
||||
userFk: this.currentUserId,
|
||||
tableConfig: this.viewConfigId,
|
||||
configuration: defaultViewConfig
|
||||
});
|
||||
}).finally(() => this.applyViewConfig());
|
||||
} else
|
||||
this.applyViewConfig();
|
||||
}
|
||||
|
||||
get checkedRows() {
|
||||
const model = this.model;
|
||||
if (model && model.data)
|
||||
return model.data.filter(row => row.$checked);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
get checkAll() {
|
||||
return this._checkAll;
|
||||
}
|
||||
|
||||
set checkAll(value) {
|
||||
this._checkAll = value;
|
||||
if (value !== undefined) {
|
||||
const shownColumns = this.viewConfig[0].configuration;
|
||||
for (let param in shownColumns)
|
||||
shownColumns[param] = value;
|
||||
}
|
||||
}
|
||||
|
||||
transclude() {
|
||||
const slotTable = this.element.querySelector('#table');
|
||||
this.$transclude($clone => {
|
||||
const table = $clone[0];
|
||||
slotTable.appendChild(table);
|
||||
this.registerColumns();
|
||||
this.emptyDataRows();
|
||||
}, null, 'table');
|
||||
}
|
||||
|
||||
saveViewConfig() {
|
||||
const userViewModel = this.$.userViewModel;
|
||||
const [viewConfig] = userViewModel.data;
|
||||
viewConfig.configuration = Object.assign({}, viewConfig.configuration);
|
||||
userViewModel.save()
|
||||
.then(() => this.vnApp.showSuccess(this.$t('Data saved!')))
|
||||
.then(() => this.applyViewConfig())
|
||||
.then(() => this.$.smartTableColumns.hide());
|
||||
}
|
||||
|
||||
applyViewConfig() {
|
||||
const userViewModel = this.$.userViewModel;
|
||||
const [viewConfig] = userViewModel.data;
|
||||
|
||||
const selectors = [];
|
||||
for (const column of this.columns) {
|
||||
if (viewConfig.configuration[column.field] == false) {
|
||||
const baseSelector = `smart-table[view-config-id="${this.viewConfigId}"] table`;
|
||||
selectors.push(`${baseSelector} thead > tr > th:nth-child(${column.index + 1})`);
|
||||
selectors.push(`${baseSelector} tbody > tr > td:nth-child(${column.index + 1})`);
|
||||
}
|
||||
}
|
||||
|
||||
let styleElement = document.querySelector('style[id="smart-table"]');
|
||||
|
||||
if (styleElement)
|
||||
styleElement.parentNode.removeChild(styleElement);
|
||||
|
||||
if (selectors.length) {
|
||||
const rule = selectors.join(', ') + '{display: none}';
|
||||
this.$.css = document.createElement('style');
|
||||
this.$.css.setAttribute('id', 'smart-table');
|
||||
document.head.appendChild(this.$.css);
|
||||
this.$.css.appendChild(document.createTextNode(rule));
|
||||
}
|
||||
}
|
||||
|
||||
registerColumns() {
|
||||
const header = this.element.querySelector('thead > tr');
|
||||
if (!header) return;
|
||||
const columns = header.querySelectorAll('th');
|
||||
|
||||
// Click handler
|
||||
for (const [index, column] of columns.entries()) {
|
||||
const field = column.getAttribute('field');
|
||||
if (field) {
|
||||
const columnElement = angular.element(column);
|
||||
const caption = columnElement.text().trim();
|
||||
|
||||
this.columns.push({field, caption, index});
|
||||
|
||||
column.addEventListener('click', () => this.orderHandler(column));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
emptyDataRows() {
|
||||
const header = this.element.querySelector('thead > tr');
|
||||
const columns = header.querySelectorAll('th');
|
||||
const tbody = this.element.querySelector('tbody');
|
||||
if (tbody) {
|
||||
const noSearch = this.$compile(`
|
||||
<tr class="empty-rows" ng-if="!model.data">
|
||||
<td colspan="${columns.length}" translate>Enter a new search</td>
|
||||
</tr>
|
||||
`)(this.$);
|
||||
tbody.appendChild(noSearch[0]);
|
||||
|
||||
const noRows = this.$compile(`
|
||||
<tr class="empty-rows" ng-if="model.data.length == 0">
|
||||
<td colspan="${columns.length}" translate>No data</td>
|
||||
</tr>
|
||||
`)(this.$);
|
||||
tbody.appendChild(noRows[0]);
|
||||
}
|
||||
}
|
||||
|
||||
orderHandler(element) {
|
||||
const field = element.getAttribute('field');
|
||||
const existingCriteria = this.sortCriteria.find(criteria => {
|
||||
return criteria.field == field;
|
||||
});
|
||||
|
||||
const isASC = existingCriteria && existingCriteria.sortType == 'ASC';
|
||||
const isDESC = existingCriteria && existingCriteria.sortType == 'DESC';
|
||||
|
||||
if (!existingCriteria) {
|
||||
this.sortCriteria.push({field: field, sortType: 'ASC'});
|
||||
element.classList.remove('desc');
|
||||
element.classList.add('asc');
|
||||
}
|
||||
|
||||
if (isDESC) {
|
||||
this.sortCriteria.splice(this.sortCriteria.findIndex(criteria => {
|
||||
return criteria.field == field;
|
||||
}), 1);
|
||||
element.classList.remove('desc');
|
||||
element.classList.remove('asc');
|
||||
}
|
||||
|
||||
if (isASC) {
|
||||
existingCriteria.sortType = 'DESC';
|
||||
element.classList.remove('asc');
|
||||
element.classList.add('desc');
|
||||
}
|
||||
|
||||
this.applySort();
|
||||
}
|
||||
|
||||
displaySearch() {
|
||||
const header = this.element.querySelector('thead > tr');
|
||||
if (!header) return;
|
||||
|
||||
const tbody = this.element.querySelector('tbody');
|
||||
const columns = header.querySelectorAll('th');
|
||||
|
||||
const hasSearchRow = tbody.querySelector('tr#searchRow');
|
||||
if (hasSearchRow) {
|
||||
if (this.$inputsScope)
|
||||
this.$inputsScope.$destroy();
|
||||
|
||||
return hasSearchRow.remove();
|
||||
}
|
||||
|
||||
const searchRow = document.createElement('tr');
|
||||
searchRow.setAttribute('id', 'searchRow');
|
||||
|
||||
this.$inputsScope = this.$.$new();
|
||||
|
||||
for (let column of columns) {
|
||||
const field = column.getAttribute('field');
|
||||
const cell = document.createElement('td');
|
||||
if (field) {
|
||||
let input;
|
||||
let options;
|
||||
const columnOptions = this.options && this.options.columns;
|
||||
|
||||
if (columnOptions)
|
||||
options = columnOptions.find(column => column.field == field);
|
||||
|
||||
if (options && options.searchable == false) {
|
||||
searchRow.appendChild(cell);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (options && options.autocomplete) {
|
||||
let props = ``;
|
||||
|
||||
const autocomplete = options.autocomplete;
|
||||
for (const prop in autocomplete)
|
||||
props += `${camelToKebab(prop)}="${autocomplete[prop]}"\n`;
|
||||
input = this.$compile(`
|
||||
<vn-autocomplete
|
||||
class="dense"
|
||||
name="${field}"
|
||||
ng-model="searchProps['${field}']"
|
||||
${props}
|
||||
on-change="$ctrl.searchByColumn('${field}')"
|
||||
clear-disabled="true"
|
||||
/>`)(this.$inputsScope);
|
||||
} else {
|
||||
input = this.$compile(`
|
||||
<vn-textfield
|
||||
class="dense"
|
||||
name="${field}"
|
||||
ng-model="searchProps['${field}']"
|
||||
ng-keydown="$ctrl.searchWithEvent($event, '${field}')"
|
||||
clear-disabled="true"
|
||||
/>`)(this.$inputsScope);
|
||||
}
|
||||
cell.appendChild(input[0]);
|
||||
}
|
||||
searchRow.appendChild(cell);
|
||||
}
|
||||
|
||||
tbody.prepend(searchRow);
|
||||
}
|
||||
|
||||
searchWithEvent($event, field) {
|
||||
if ($event.key != 'Enter') return;
|
||||
|
||||
this.searchByColumn(field);
|
||||
}
|
||||
|
||||
searchByColumn(field) {
|
||||
const searchCriteria = this.$inputsScope.searchProps[field];
|
||||
const emptySearch = searchCriteria == '' || null;
|
||||
|
||||
const filters = this.filterSanitizer(field);
|
||||
|
||||
if (filters && filters.userFilter)
|
||||
this.model.userFilter = filters.userFilter;
|
||||
|
||||
if (!emptySearch)
|
||||
this.addFilter(field, this.$inputsScope.searchProps[field]);
|
||||
else this.model.refresh();
|
||||
}
|
||||
|
||||
addFilter(field, value) {
|
||||
let where = {[field]: value};
|
||||
|
||||
if (this.exprBuilder) {
|
||||
where = buildFilter(where, (param, value) =>
|
||||
this.exprBuilder({param, value})
|
||||
);
|
||||
}
|
||||
|
||||
this.model.addFilter({where});
|
||||
}
|
||||
|
||||
applySort() {
|
||||
let order = this.sortCriteria.map(criteria => `${criteria.field} ${criteria.sortType}`);
|
||||
order = order.join(', ');
|
||||
|
||||
if (order)
|
||||
this.model.order = order;
|
||||
|
||||
this.model.refresh();
|
||||
}
|
||||
|
||||
filterSanitizer(field) {
|
||||
const userFilter = this.model.userFilter;
|
||||
const userParams = this.model.userParams;
|
||||
const where = userFilter && userFilter.where;
|
||||
|
||||
if (this.exprBuilder) {
|
||||
const param = this.exprBuilder({
|
||||
param: field,
|
||||
value: null
|
||||
});
|
||||
if (param) [field] = Object.keys(param);
|
||||
}
|
||||
|
||||
if (!where) return;
|
||||
|
||||
const whereKeys = Object.keys(where);
|
||||
for (let key of whereKeys) {
|
||||
removeProp(where, field, key);
|
||||
|
||||
if (!Object.keys(where))
|
||||
delete userFilter.where;
|
||||
}
|
||||
|
||||
function removeProp(instance, findProp, prop) {
|
||||
if (prop == findProp)
|
||||
delete instance[prop];
|
||||
|
||||
if (prop === 'and') {
|
||||
for (let [index, param] of instance[prop].entries()) {
|
||||
const [key] = Object.keys(param);
|
||||
if (key == findProp)
|
||||
instance[prop].splice(index, 1);
|
||||
|
||||
if (param[key] instanceof Array)
|
||||
removeProp(param, field, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {userFilter, userParams};
|
||||
}
|
||||
|
||||
removeFilter() {
|
||||
this.model.applyFilter(userFilter, userParams);
|
||||
}
|
||||
|
||||
createRow() {
|
||||
let data = {};
|
||||
|
||||
if (this.defaultNewData)
|
||||
data = this.defaultNewData();
|
||||
|
||||
this.model.insert(data);
|
||||
}
|
||||
|
||||
deleteAll() {
|
||||
for (let row of this.checkedRows)
|
||||
this.model.removeRow(row);
|
||||
|
||||
if (this.autoSave)
|
||||
this.saveAll();
|
||||
}
|
||||
|
||||
saveAll() {
|
||||
const model = this.model;
|
||||
|
||||
if (!model.isChanged)
|
||||
return this.vnApp.showError(this.$t('No changes to save'));
|
||||
|
||||
this.model.save()
|
||||
.then(() => this.vnApp.showSuccess(this.$t('Data saved!')));
|
||||
}
|
||||
}
|
||||
|
||||
SmartTable.$inject = ['$element', '$scope', '$transclude'];
|
||||
|
||||
ngModule.vnComponent('smartTable', {
|
||||
template: require('./index.html'),
|
||||
controller: SmartTable,
|
||||
transclude: {
|
||||
table: '?slotTable',
|
||||
actions: '?slotActions'
|
||||
},
|
||||
bindings: {
|
||||
model: '<?',
|
||||
viewConfigId: '@?',
|
||||
autoSave: '<?',
|
||||
exprBuilder: '&?',
|
||||
defaultNewData: '&?',
|
||||
options: '<?'
|
||||
}
|
||||
});
|
|
@ -0,0 +1,9 @@
|
|||
Remove selected rows: Eliminar líneas seleccionadas
|
||||
Add new row: Añadir nueva fila
|
||||
Undo: Deshacer
|
||||
Save data: Guardar datos
|
||||
Shown columns: Columnas visibles
|
||||
Check the columns you want to see: Marca las columnas que quieres ver
|
||||
Showing: Mostrando
|
||||
results: resultados
|
||||
Tick all: Marcar todas
|
|
@ -0,0 +1,146 @@
|
|||
@import "effects";
|
||||
@import "variables";
|
||||
|
||||
smart-table {
|
||||
th[field] {
|
||||
overflow: visible;
|
||||
cursor: pointer;
|
||||
align-items: center;
|
||||
|
||||
}
|
||||
th[field][number] {
|
||||
& > :before {
|
||||
vertical-align: middle;
|
||||
font-family: 'Material Icons';
|
||||
content: 'arrow_downward';
|
||||
color: $color-spacer;
|
||||
margin-right: 2px;
|
||||
opacity: 0
|
||||
|
||||
}
|
||||
|
||||
&.asc > :before, &.desc > :before {
|
||||
color: $color-font;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&.asc > :before {
|
||||
content: 'arrow_upward';
|
||||
}
|
||||
|
||||
&.desc > :before {
|
||||
content: 'arrow_downward';
|
||||
}
|
||||
|
||||
&:hover > :before {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
th[field]:not([number]) {
|
||||
& > :after {
|
||||
vertical-align: middle;
|
||||
font-family: 'Material Icons';
|
||||
content: 'arrow_downward';
|
||||
color: $color-spacer;
|
||||
margin-left: 2px;
|
||||
opacity: 0
|
||||
|
||||
}
|
||||
|
||||
&.asc > :after, &.desc > :after {
|
||||
color: $color-font;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&.asc > :after {
|
||||
content: 'arrow_upward';
|
||||
}
|
||||
|
||||
&.desc > :after {
|
||||
content: 'arrow_downward';
|
||||
}
|
||||
|
||||
&:hover > :after {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
tr[vn-anchor] {
|
||||
@extend %clickable;
|
||||
}
|
||||
|
||||
.totalRows {
|
||||
color: $color-font-secondary;
|
||||
}
|
||||
|
||||
.actions-left,
|
||||
.actions-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.button-group {
|
||||
display: flex;
|
||||
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .3);
|
||||
|
||||
& > vn-button {
|
||||
box-shadow: 0 0 0 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.actions-left {
|
||||
justify-content: flex-start;
|
||||
|
||||
slot-actions > vn-button,
|
||||
& > vn-button,
|
||||
.button-group {
|
||||
margin-right: 10px
|
||||
}
|
||||
|
||||
slot-actions {
|
||||
display: flex
|
||||
}
|
||||
}
|
||||
|
||||
.actions-right {
|
||||
justify-content: flex-end;
|
||||
& > vn-button,
|
||||
.button-group {
|
||||
margin-left: 10px
|
||||
}
|
||||
}
|
||||
|
||||
#table {
|
||||
overflow-x: auto;
|
||||
margin-top: 15px
|
||||
}
|
||||
|
||||
vn-tbody a[ng-repeat].vn-tr:focus {
|
||||
background-color: $color-primary-light
|
||||
}
|
||||
|
||||
.new-row {
|
||||
background-color: $color-success-light
|
||||
}
|
||||
|
||||
.changed-row {
|
||||
background-color: $color-primary-light
|
||||
}
|
||||
}
|
||||
|
||||
.smart-table-columns {
|
||||
h6 {
|
||||
color: $color-font-secondary
|
||||
}
|
||||
|
||||
& > vn-horizontal {
|
||||
align-items: flex-start;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
vn-check {
|
||||
flex: initial;
|
||||
width: 33%
|
||||
}
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
@import "effects";
|
||||
@import "variables";
|
||||
|
||||
smart-table table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
|
||||
& > thead {
|
||||
border-bottom: 2px solid $color-spacer;
|
||||
|
||||
& > * > th {
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
& > tfoot {
|
||||
border-top: 2px solid $color-spacer;
|
||||
}
|
||||
thead, tbody, tfoot {
|
||||
& > * {
|
||||
& > th {
|
||||
color: $color-font-light;
|
||||
}
|
||||
& > th,
|
||||
& > td {
|
||||
overflow: hidden;
|
||||
}
|
||||
& > th,
|
||||
& > td {
|
||||
text-align: left;
|
||||
padding: 9px 5px;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
&[number] {
|
||||
text-align: right;
|
||||
}
|
||||
&[centered] {
|
||||
text-align: center;
|
||||
}
|
||||
&[shrink] {
|
||||
width: 1px;
|
||||
text-align: center;
|
||||
}
|
||||
&[shrink-date] {
|
||||
width: 100px;
|
||||
max-width: 100px;
|
||||
}
|
||||
&[shrink-datetime] {
|
||||
width: 150px;
|
||||
max-width: 150px;
|
||||
}
|
||||
&[expand] {
|
||||
max-width: 400px;
|
||||
min-width: 0;
|
||||
}
|
||||
&[actions] {
|
||||
width: 1px;
|
||||
|
||||
& > * {
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
vn-icon.bright, i.bright {
|
||||
color: #f7931e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
tbody > * {
|
||||
border-bottom: 1px solid $color-spacer-light;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
& > td {
|
||||
.chip {
|
||||
padding: 4px;
|
||||
border-radius: 4px;
|
||||
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: $color-alert-medium;
|
||||
}
|
||||
&.message {
|
||||
color: $color-font-dark;
|
||||
background-color: $color-bg-dark
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.vn-check {
|
||||
margin: 0;
|
||||
}
|
||||
.empty-rows > td {
|
||||
color: $color-font-secondary;
|
||||
font-size: 1.375rem;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
|
@ -96,24 +96,6 @@ vn-table {
|
|||
max-width: 400px;
|
||||
min-width: 0;
|
||||
}
|
||||
&[vn-fetched-tags] {
|
||||
min-width: 155px;
|
||||
& > vn-one {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
& > vn-one:nth-child(2) h3 {
|
||||
color: $color-font-secondary;
|
||||
text-transform: uppercase;
|
||||
line-height: initial;
|
||||
font-size: 0.75rem
|
||||
}
|
||||
}
|
||||
&[vn-fetched-tags][wide] {
|
||||
width: 430px;
|
||||
}
|
||||
vn-icon.bright, i.bright {
|
||||
color: #f7931e;
|
||||
}
|
||||
|
|
|
@ -16,3 +16,4 @@ import './droppable';
|
|||
import './http-click';
|
||||
import './http-submit';
|
||||
import './anchor';
|
||||
|
||||
|
|
|
@ -18,6 +18,18 @@ class Email {
|
|||
return this.$http.get(`email/${template}`, {params})
|
||||
.then(() => this.vnApp.showMessage(this.$t('Notification sent!')));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an email displaying a notification when it's sent.
|
||||
*
|
||||
* @param {String} template The email report name
|
||||
* @param {Object} params The email parameters
|
||||
* @return {Promise} Promise resolved when it's sent
|
||||
*/
|
||||
sendCsv(template, params) {
|
||||
return this.$http.get(`csv/${template}/send`, {params})
|
||||
.then(() => this.vnApp.showMessage(this.$t('Notification sent!')));
|
||||
}
|
||||
}
|
||||
Email.$inject = ['$http', '$translate', 'vnApp'];
|
||||
|
||||
|
|
|
@ -20,6 +20,21 @@ class Report {
|
|||
const serializedParams = this.$httpParamSerializer(params);
|
||||
window.open(`api/report/${report}?${serializedParams}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a report in another window, automatically adds the authorization
|
||||
* token to params.
|
||||
*
|
||||
* @param {String} report The report name
|
||||
* @param {Object} params The report parameters
|
||||
*/
|
||||
showCsv(report, params) {
|
||||
params = Object.assign({
|
||||
authorization: this.vnToken.token
|
||||
}, params);
|
||||
const serializedParams = this.$httpParamSerializer(params);
|
||||
window.open(`api/csv/${report}/download?${serializedParams}`);
|
||||
}
|
||||
}
|
||||
Report.$inject = ['$httpParamSerializer', 'vnToken'];
|
||||
|
||||
|
|
|
@ -1,133 +0,0 @@
|
|||
{
|
||||
"name": "salix-front",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"@uirouter/angularjs": {
|
||||
"version": "1.0.29",
|
||||
"resolved": "https://registry.npmjs.org/@uirouter/angularjs/-/angularjs-1.0.29.tgz",
|
||||
"integrity": "sha512-RImWnBarNixkMto0o8stEaGwZmvhv5cnuOLXyMU2pY8MP2rgEF74ZNJTLeJCW14LR7XDUxVH8Mk8bPI6lxedmQ==",
|
||||
"requires": {
|
||||
"@uirouter/core": "6.0.7"
|
||||
}
|
||||
},
|
||||
"@uirouter/core": {
|
||||
"version": "6.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@uirouter/core/-/core-6.0.7.tgz",
|
||||
"integrity": "sha512-KUTJxL+6q0PiBnFx4/Z+Hsyg0pSGiaW5yZQeJmUxknecjpTbnXkLU8H2EqRn9N2B+qDRa7Jg8RcgeNDPY72O1w=="
|
||||
},
|
||||
"angular": {
|
||||
"version": "1.8.2",
|
||||
"resolved": "https://registry.npmjs.org/angular/-/angular-1.8.2.tgz",
|
||||
"integrity": "sha512-IauMOej2xEe7/7Ennahkbb5qd/HFADiNuLSESz9Q27inmi32zB0lnAsFeLEWcox3Gd1F6YhNd1CP7/9IukJ0Gw=="
|
||||
},
|
||||
"angular-animate": {
|
||||
"version": "1.8.2",
|
||||
"resolved": "https://registry.npmjs.org/angular-animate/-/angular-animate-1.8.2.tgz",
|
||||
"integrity": "sha512-Jbr9+grNMs9Kj57xuBU3Ju3NOPAjS1+g2UAwwDv7su1lt0/PLDy+9zEwDiu8C8xJceoTbmBNKiWGPJGBdCQLlA=="
|
||||
},
|
||||
"angular-moment": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/angular-moment/-/angular-moment-1.3.0.tgz",
|
||||
"integrity": "sha512-KG8rvO9MoaBLwtGnxTeUveSyNtrL+RNgGl1zqWN36+HDCCVGk2DGWOzqKWB6o+eTTbO3Opn4hupWKIElc8XETA==",
|
||||
"requires": {
|
||||
"moment": ">=2.8.0 <3.0.0"
|
||||
}
|
||||
},
|
||||
"angular-translate": {
|
||||
"version": "2.18.4",
|
||||
"resolved": "https://registry.npmjs.org/angular-translate/-/angular-translate-2.18.4.tgz",
|
||||
"integrity": "sha512-KohNrkH6J9PK+VW0L/nsRTcg5Fw70Ajwwe3Jbfm54Pf9u9Fd+wuingoKv+h45mKf38eT+Ouu51FPua8VmZNoCw==",
|
||||
"requires": {
|
||||
"angular": "^1.8.0"
|
||||
}
|
||||
},
|
||||
"angular-translate-loader-partial": {
|
||||
"version": "2.18.4",
|
||||
"resolved": "https://registry.npmjs.org/angular-translate-loader-partial/-/angular-translate-loader-partial-2.18.4.tgz",
|
||||
"integrity": "sha512-bsjR+FbB0sdA2528E/ugwKdlPPQhA1looxLxI3otayBTFXBpED33besfSZhYAISLgNMSL038vSssfRUen9qD8w==",
|
||||
"requires": {
|
||||
"angular-translate": "~2.18.4"
|
||||
}
|
||||
},
|
||||
"argparse": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
|
||||
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
|
||||
"requires": {
|
||||
"sprintf-js": "~1.0.2"
|
||||
}
|
||||
},
|
||||
"croppie": {
|
||||
"version": "2.6.5",
|
||||
"resolved": "https://registry.npmjs.org/croppie/-/croppie-2.6.5.tgz",
|
||||
"integrity": "sha512-IlChnVUGG5T3w2gRZIaQgBtlvyuYnlUWs2YZIXXR3H9KrlO1PtBT3j+ykxvy9eZIWhk+V5SpBmhCQz5UXKrEKQ=="
|
||||
},
|
||||
"esprima": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
|
||||
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
|
||||
},
|
||||
"js-yaml": {
|
||||
"version": "3.14.1",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
|
||||
"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
|
||||
"requires": {
|
||||
"argparse": "^1.0.7",
|
||||
"esprima": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"mg-crud": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/mg-crud/-/mg-crud-1.1.2.tgz",
|
||||
"integrity": "sha1-p6AWGzWSPK7/8ZpIBpS2V1vDggw=",
|
||||
"requires": {
|
||||
"angular": "^1.6.1"
|
||||
}
|
||||
},
|
||||
"moment": {
|
||||
"version": "2.29.1",
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
|
||||
"integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ=="
|
||||
},
|
||||
"oclazyload": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/oclazyload/-/oclazyload-0.6.3.tgz",
|
||||
"integrity": "sha1-Kjirv/QJDAihEBZxkZRbWfLoJ5w="
|
||||
},
|
||||
"require-yaml": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/require-yaml/-/require-yaml-0.0.1.tgz",
|
||||
"integrity": "sha1-LhsY2RPDuqcqWk03O28Tjd0sMr0=",
|
||||
"requires": {
|
||||
"js-yaml": "^4.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"argparse": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
|
||||
},
|
||||
"js-yaml": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz",
|
||||
"integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==",
|
||||
"requires": {
|
||||
"argparse": "^2.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"sprintf-js": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
|
||||
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
|
||||
},
|
||||
"validator": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/validator/-/validator-6.3.0.tgz",
|
||||
"integrity": "sha1-R84j7Y1Ord+p1LjvAHG2zxB418g="
|
||||
}
|
||||
}
|
||||
}
|
|
@ -34,8 +34,10 @@ export default class Controller extends Component {
|
|||
|
||||
for (let starredModule of res.data) {
|
||||
const module = this.modules.find(mod => mod.name === starredModule.moduleFk);
|
||||
module.starred = true;
|
||||
module.position = starredModule.position;
|
||||
if (module) {
|
||||
module.starred = true;
|
||||
module.position = starredModule.position;
|
||||
}
|
||||
}
|
||||
this.countModules();
|
||||
});
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
icon="menu"
|
||||
class="show-menu"
|
||||
ng-if="$ctrl.leftMenu"
|
||||
ng-click="$ctrl.leftMenu.show()">
|
||||
ng-click="$ctrl.leftMenu.toggle()">
|
||||
</vn-icon-button>
|
||||
<div class="side start">
|
||||
<a class="logo" ui-sref="home" title="{{'Home' | translate}}">
|
||||
|
|
|
@ -48,6 +48,10 @@ vn-layout {
|
|||
.show-menu {
|
||||
display: none;
|
||||
}
|
||||
& > .show-menu {
|
||||
margin-right: 5px;
|
||||
display: block
|
||||
}
|
||||
.vn-button {
|
||||
color: inherit;
|
||||
font-size: 1.05rem;
|
||||
|
@ -71,6 +75,10 @@ vn-layout {
|
|||
& > .main-view {
|
||||
padding-left: $menu-width;
|
||||
}
|
||||
|
||||
&.shown > .main-view {
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
&.right-menu {
|
||||
& > vn-topbar > .end {
|
||||
|
@ -85,6 +93,8 @@ vn-layout {
|
|||
}
|
||||
& > .main-view {
|
||||
padding-top: $topbar-height;
|
||||
|
||||
transition: padding-left 200ms ease-out;
|
||||
}
|
||||
ui-view {
|
||||
& > * {
|
||||
|
@ -134,7 +144,8 @@ vn-layout {
|
|||
& > vn-topbar {
|
||||
left: 0;
|
||||
}
|
||||
& > .main-view {
|
||||
& > .main-view,
|
||||
&.shown > .main-view {
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
<vn-crud-model vn-id="model" url="{{$ctrl.url}}" filter="$ctrl.filter" link="{originFk: $ctrl.originId}"
|
||||
data="$ctrl.logs" limit="20" auto-load="true">
|
||||
<vn-crud-model
|
||||
vn-id="model"
|
||||
url="{{$ctrl.url}}"
|
||||
filter="$ctrl.filter"
|
||||
link="{originFk: $ctrl.originId}"
|
||||
data="$ctrl.logs"
|
||||
limit="20"
|
||||
auto-load="true">
|
||||
</vn-crud-model>
|
||||
<vn-data-viewer model="model" class="vn-w-xl">
|
||||
<vn-card>
|
||||
|
|
|
@ -52,12 +52,18 @@ export default class SideMenu extends Component {
|
|||
this.hide();
|
||||
}
|
||||
|
||||
toggle() {
|
||||
if (this.shown) this.hide();
|
||||
else this.show();
|
||||
}
|
||||
|
||||
show() {
|
||||
if (this.shown) return;
|
||||
this.shown = true;
|
||||
this.handler = e => this.onEscape(e);
|
||||
this.$window.addEventListener('keydown', this.handler);
|
||||
this.stateHandler = this.$transitions.onStart({}, t => this.onTransition(t));
|
||||
this.layout.element.classList.add('shown');
|
||||
}
|
||||
|
||||
hide() {
|
||||
|
@ -65,6 +71,7 @@ export default class SideMenu extends Component {
|
|||
this.$window.removeEventListener('keydown', this.handler);
|
||||
this.stateHandler();
|
||||
this.shown = false;
|
||||
this.layout.element.classList.remove('shown');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,16 +14,20 @@ vn-side-menu > .menu {
|
|||
box-shadow: 0 1px 3px $color-shadow;
|
||||
overflow: auto;
|
||||
top: $topbar-height;
|
||||
transition: transform 200ms ease-out;
|
||||
|
||||
&.left {
|
||||
left: 0;
|
||||
left: 0
|
||||
}
|
||||
&.right {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
&.shown {
|
||||
transform: translateZ(0) translateX(-$menu-width);
|
||||
}
|
||||
|
||||
@media screen and (max-width: $mobile-width) {
|
||||
transition: transform 200ms ease-out;
|
||||
z-index: 15;
|
||||
top: 0;
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@
|
|||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-autocomplete
|
||||
label="Type"
|
||||
label="Orientation"
|
||||
ng-model="$ctrl.viewportType"
|
||||
data="$ctrl.viewportTypes"
|
||||
selection="$ctrl.viewportSelection"
|
||||
|
|
|
@ -36,6 +36,18 @@ export default class UploadPhoto extends Component {
|
|||
width: 1350,
|
||||
height: 900
|
||||
}
|
||||
},
|
||||
{
|
||||
code: 'vertical',
|
||||
description: this.$t('Vertical'),
|
||||
viewport: {
|
||||
width: 306.66,
|
||||
height: 533.33
|
||||
},
|
||||
output: {
|
||||
width: 460,
|
||||
height: 800
|
||||
}
|
||||
}
|
||||
];
|
||||
this.viewportType = 'normal';
|
||||
|
@ -103,8 +115,17 @@ export default class UploadPhoto extends Component {
|
|||
const reader = new FileReader();
|
||||
reader.onload = e => this.editor.bind({url: e.target.result});
|
||||
reader.readAsDataURL(value);
|
||||
} else if (this.uploadMethod == 'URL')
|
||||
this.editor.bind({url: value});
|
||||
} else if (this.uploadMethod == 'URL') {
|
||||
const img = new Image();
|
||||
img.crossOrigin = 'Anonymous';
|
||||
img.src = value;
|
||||
img.onload = () => this.editor.bind({url: value});
|
||||
img.onerror = () => {
|
||||
this.vnApp.showError(
|
||||
this.$t(`This photo provider doesn't allow remote downloads`)
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@ Select an image: Selecciona una imagen
|
|||
File name: Nombre del fichero
|
||||
Rotate left: Girar a la izquierda
|
||||
Rotate right: Girar a la derecha
|
||||
Panoramic: Panorámico
|
||||
Panoramic: Panorámica
|
||||
Orientation: Orientación
|
||||
Select from computer: Seleccionar desde ordenador
|
||||
Import from external URL: Importar desde URL externa
|
||||
Import from external URL: Importar desde URL externa
|
||||
This photo provider doesn't allow remote downloads: Este proveedor de fotos no permite descargas remotas
|
|
@ -94,8 +94,11 @@ async function launchBackTest(done) {
|
|||
await new Promise((resolve, reject) => {
|
||||
const jasmine = require('gulp-jasmine');
|
||||
|
||||
let options = {
|
||||
const options = {
|
||||
verbose: false,
|
||||
includeStackTrace: false,
|
||||
errorOnFail: false,
|
||||
timeout: 5000,
|
||||
config: {}
|
||||
};
|
||||
|
||||
|
@ -125,7 +128,8 @@ async function launchBackTest(done) {
|
|||
if (err)
|
||||
throw err;
|
||||
}
|
||||
launchBackTest.description = `Runs the backend tests once using a random container, can receive --ci arg to save reports on a xml file`;
|
||||
launchBackTest.description = `
|
||||
Runs the backend tests once using a random container, can receive --ci arg to save reports on a xml file`;
|
||||
|
||||
// Backend tests
|
||||
|
||||
|
|
|
@ -8,11 +8,12 @@ describe('Model getEnumValues()', () => {
|
|||
});
|
||||
|
||||
it('should return an array of enum values from a given column', async() => {
|
||||
let result = await app.models.TravelThermograph.getSetValues('temperature');
|
||||
let result = await app.models.TpvTransaction.getSetValues('status');
|
||||
|
||||
expect(result.length).toEqual(3);
|
||||
expect(result.length).toEqual(4);
|
||||
expect(result[0].value).toEqual('enum');
|
||||
expect(result[1].value).toEqual('COOL');
|
||||
expect(result[2].value).toEqual('WARM');
|
||||
expect(result[1].value).toEqual('started');
|
||||
expect(result[2].value).toEqual('ok');
|
||||
expect(result[3].value).toEqual('ko');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -115,5 +115,8 @@
|
|||
"A ticket with a negative base can't be invoiced": "A ticket with a negative base can't be invoiced",
|
||||
"This client is not invoiceable": "This client is not invoiceable",
|
||||
"INACTIVE_PROVIDER": "Inactive provider",
|
||||
"reference duplicated": "reference duplicated"
|
||||
"reference duplicated": "reference duplicated",
|
||||
"The PDF document does not exists": "The PDF document does not exists. Try regenerating it from 'Regenerate invoice PDF' option",
|
||||
"This item is not available": "This item is not available",
|
||||
"Deny buy request": "Purchase request for ticket id [{{ticketId}}]({{{url}}}) has been rejected. Reason: {{observation}}"
|
||||
}
|
|
@ -133,6 +133,7 @@
|
|||
"reserved": "reservado",
|
||||
"Changed sale reserved state": "He cambiado el estado reservado de las siguientes lineas al ticket [{{ticketId}}]({{{ticketUrl}}}): {{{changes}}}",
|
||||
"Bought units from buy request": "Se ha comprado {{quantity}} unidades de [{{itemId}} {{concept}}]({{{urlItem}}}) para el ticket id [{{ticketId}}]({{{url}}})",
|
||||
"Deny buy request":"Se ha rechazado la petición de compra para el ticket id [{{ticketId}}]({{{url}}}). Motivo: {{observation}}",
|
||||
"MESSAGE_INSURANCE_CHANGE": "He cambiado el crédito asegurado del cliente [{{clientName}} ({{clientId}})]({{{url}}}) a *{{credit}} €*",
|
||||
"Changed client paymethod": "He cambiado la forma de pago del cliente [{{clientName}} ({{clientId}})]({{{url}}})",
|
||||
"Sent units from ticket": "Envio *{{quantity}}* unidades de [{{concept}} ({{itemId}})]({{{itemUrl}}}) a *\"{{nickname}}\"* provenientes del ticket id [{{ticketId}}]({{{ticketUrl}}})",
|
||||
|
@ -210,5 +211,6 @@
|
|||
"Can't verify data unless the client has a business type": "No se puede verificar datos de un cliente que no tiene tipo de negocio",
|
||||
"You don't have enough privileges to set this credit amount": "No tienes suficientes privilegios para establecer esta cantidad de crédito",
|
||||
"You can't change the credit set to zero from a manager": "No puedes cambiar el cŕedito establecido a cero por un gerente",
|
||||
"Amounts do not match": "Amounts do not match"
|
||||
"Amounts do not match": "Amounts do not match",
|
||||
"The PDF document does not exists": "El documento PDF no existe. Prueba a regenerarlo desde la opción 'Regenerar PDF factura'"
|
||||
}
|
|
@ -9,19 +9,19 @@
|
|||
"properties": {
|
||||
"id": {
|
||||
"id": true,
|
||||
"type": "Number"
|
||||
"type": "number"
|
||||
},
|
||||
"sender": {
|
||||
"type": "String"
|
||||
"receiver": {
|
||||
"type": "string"
|
||||
},
|
||||
"replyTo": {
|
||||
"type": "String"
|
||||
"type": "string"
|
||||
},
|
||||
"subject": {
|
||||
"type": "String"
|
||||
"type": "string"
|
||||
},
|
||||
"body": {
|
||||
"type": "String"
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"acls": [
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
url="Workers/activeWithRole"
|
||||
search-function="{firstName: $search}"
|
||||
value-field="id"
|
||||
where="{role: 'salesPerson'}"
|
||||
where="{role: {inq: ['salesPerson', 'officeBoss']}}"
|
||||
label="Salesperson">
|
||||
<tpl-item>{{firstName}} {{name}}</tpl-item>
|
||||
</vn-autocomplete>
|
||||
|
|
|
@ -50,7 +50,8 @@ module.exports = function(Self) {
|
|||
city: data.city,
|
||||
provinceFk: data.provinceFk,
|
||||
countryFk: data.countryFk,
|
||||
isEqualizated: data.isEqualizated
|
||||
isEqualizated: data.isEqualizated,
|
||||
businessTypeFk: data.businessTypeFk
|
||||
}, myOptions);
|
||||
|
||||
const address = await models.Address.create({
|
||||
|
|
|
@ -19,7 +19,7 @@ module.exports = Self => {
|
|||
}
|
||||
});
|
||||
|
||||
Self.hasCustomerRole = (id, options) => {
|
||||
Self.hasCustomerRole = async(id, options) => {
|
||||
const myOptions = {};
|
||||
|
||||
if (typeof options == 'object')
|
||||
|
@ -31,7 +31,9 @@ module.exports = Self => {
|
|||
JOIN salix.Role r ON r.id = A.roleFK
|
||||
WHERE r.name = 'customer'
|
||||
AND A.id IN (?)`;
|
||||
const [result] = await Self.rawSql(query, [id], myOptions);
|
||||
const {isCustomer} = result;
|
||||
|
||||
return Self.rawSql(query, [id], myOptions);
|
||||
return isCustomer;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -8,12 +8,10 @@ describe('client canBeInvoiced()', () => {
|
|||
accessToken: {userId: userId}
|
||||
};
|
||||
|
||||
beforeAll(async done => {
|
||||
beforeAll(async() => {
|
||||
spyOn(LoopBackContext, 'getCurrentContext').and.returnValue({
|
||||
active: activeCtx
|
||||
});
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
it('should return falsy for a client without the data checked', async() => {
|
||||
|
|
|
@ -8,7 +8,8 @@ describe('Client Create', () => {
|
|||
name: 'Wade',
|
||||
socialName: 'Deadpool Marvel',
|
||||
street: 'Wall Street',
|
||||
city: 'New York'
|
||||
city: 'New York',
|
||||
businessTypeFk: 'florist'
|
||||
};
|
||||
|
||||
it(`should not find Deadpool as he's not created yet`, async() => {
|
||||
|
@ -45,6 +46,7 @@ describe('Client Create', () => {
|
|||
expect(client.email).toEqual(newAccount.email);
|
||||
expect(client.fi).toEqual(newAccount.fi);
|
||||
expect(client.socialName).toEqual(newAccount.socialName);
|
||||
expect(client.businessTypeFk).toEqual(newAccount.businessTypeFk);
|
||||
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
||||
|
|
|
@ -9,9 +9,9 @@ describe('Client hasCustomerRole', () => {
|
|||
|
||||
const id = 1101;
|
||||
|
||||
const [result] = await models.Client.hasCustomerRole(id, options);
|
||||
const result = await models.Client.hasCustomerRole(id, options);
|
||||
|
||||
expect(result).toEqual(jasmine.objectContaining({isCustomer: 1}));
|
||||
expect(result).toBeTruthy();
|
||||
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
||||
|
@ -27,9 +27,9 @@ describe('Client hasCustomerRole', () => {
|
|||
const options = {transaction: tx};
|
||||
|
||||
const id = 8;
|
||||
const [result] = await models.Client.hasCustomerRole(id, options);
|
||||
const result = await models.Client.hasCustomerRole(id, options);
|
||||
|
||||
expect(result).toEqual(jasmine.objectContaining({isCustomer: 0}));
|
||||
expect(result).toBeFalsy();
|
||||
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
||||
|
@ -46,9 +46,9 @@ describe('Client hasCustomerRole', () => {
|
|||
|
||||
const id = 999;
|
||||
|
||||
const [result] = await models.Client.hasCustomerRole(id, options);
|
||||
const result = await models.Client.hasCustomerRole(id, options);
|
||||
|
||||
expect(result).toEqual(jasmine.objectContaining({isCustomer: 0}));
|
||||
expect(result).toBeFalsy();
|
||||
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
||||
|
@ -65,9 +65,9 @@ describe('Client hasCustomerRole', () => {
|
|||
|
||||
const id = 'WRONG!';
|
||||
|
||||
const [result] = await models.Client.hasCustomerRole(id, options);
|
||||
const result = await models.Client.hasCustomerRole(id, options);
|
||||
|
||||
expect(result).toEqual(jasmine.objectContaining({isCustomer: 0}));
|
||||
expect(result).toBeFalsy();
|
||||
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
||||
|
|
|
@ -129,7 +129,7 @@ module.exports = Self => {
|
|||
|
||||
function hasIban(err, done) {
|
||||
Self.app.models.PayMethod.findById(this.payMethodFk, (_, instance) => {
|
||||
if (instance && instance.ibanRequired && !this.iban)
|
||||
if (instance && instance.ibanRequiredForClients && !this.iban)
|
||||
err();
|
||||
done();
|
||||
});
|
||||
|
|
|
@ -130,6 +130,12 @@
|
|||
"mysql": {
|
||||
"columnName": "transactionTypeSageFk"
|
||||
}
|
||||
},
|
||||
"businessTypeFk": {
|
||||
"type": "string",
|
||||
"mysql": {
|
||||
"columnName": "businessTypeFk"
|
||||
}
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
|
|
|
@ -25,7 +25,10 @@
|
|||
"outstandingDebt": {
|
||||
"type": "Number"
|
||||
},
|
||||
"ibanRequired": {
|
||||
"ibanRequiredForClients": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"ibanRequiredForSuppliers": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,13 +4,11 @@ describe('loopback model address', () => {
|
|||
let createdAddressId;
|
||||
const clientId = 1101;
|
||||
|
||||
afterAll(async done => {
|
||||
afterAll(async() => {
|
||||
let client = await app.models.Client.findById(clientId);
|
||||
|
||||
await app.models.Address.destroyById(createdAddressId);
|
||||
await client.updateAttribute('isEqualizated', false);
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
describe('observe()', () => {
|
||||
|
|
|
@ -44,7 +44,8 @@
|
|||
label="Amount"
|
||||
ng-model="$ctrl.amountPaid"
|
||||
step="0.01"
|
||||
required="true">
|
||||
required="true"
|
||||
max="$ctrl.maxAmount">
|
||||
</vn-input-number>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue