2883-invoiceIn-Booking #786

Merged
carlosjr merged 17 commits from 2883-invoiceIn-Booking into dev 2022-01-24 15:29:57 +00:00
163 changed files with 11896 additions and 26157 deletions
Showing only changes of commit 3c8e6a16a2 - Show all commits

View File

@ -120,7 +120,7 @@ module.exports = Self => {
}
const defaultOptions = {
body: params
form: params
};
if (options) Object.assign(defaultOptions, options);

View File

@ -1,4 +0,0 @@
DELETE FROM `salix`.`ACL` WHERE id = 48;
DELETE FROM `salix`.`ACL` WHERE id = 49;
DELETE FROM `salix`.`ACL` WHERE id = 50;
DELETE FROM `salix`.`ACL` WHERE id = 107;

View File

@ -1,197 +0,0 @@
drop procedure `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,
hasHighRisk TINYINT(1) 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
JOIN vn.ticket t ON t.id = tl.ticketFk
JOIN vn.agencyMode am ON am.id = t.agencyModeFk
JOIN vn.deliveryMethod dm ON dm.id = am.deliveryMethodFk
WHERE dm.code IN('AGENCY','DELIVERY','PICKUP')
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, hasHighRisk)
SELECT DISTINCT tl.ticketFk, r.risk, ((r.risk - cc.riskTolerance) > c.credit + 10)
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, hasHighRisk = ((r.risk - cc.riskTolerance) > c.credit + 10);
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 = VALUES(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 ;

View File

@ -1,48 +0,0 @@
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
(INDEX (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 ;

View File

@ -1 +0,0 @@
alter table `vn`.`travelThermograph` modify `temperature` enum('COOL', 'WARM') null;

View File

@ -1 +0,0 @@
UPDATE salix.ACL t SET t.principalId = 'employee' WHERE t.id = 269;

View File

@ -1,3 +0,0 @@
ALTER TABLE vn.accountingType ADD maxAmount INT DEFAULT NULL NULL;
UPDATE vn.accountingType SET maxAmount = 1000 WHERE code = 'cash';

View File

@ -1,4 +0,0 @@
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';

View File

@ -1,2 +0,0 @@
ALTER TABLE vn.silexACL MODIFY module VARCHAR(50) NOT NULL;
ALTER TABLE vn.silexACL MODIFY method VARCHAR(50) NOT NULL;

View File

@ -1,48 +0,0 @@
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 ;

View File

@ -1,14 +0,0 @@
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}');

View File

@ -130,8 +130,7 @@ BEGIN
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
LEFT JOIN claimBeginning cb ON cl.id = cb.claimFk AND s.id = cb.saleFk
LEFT JOIN claimBeginning cb ON s.id = cb.saleFk
WHERE t.shipped >= vDateInventory
AND s.itemFk = vItemId
AND vWarehouse =t.warehouseFk

View File

@ -0,0 +1,2 @@
INSERT INTO salix.ACL (model,property,accessType,permission,principalType,principalId)
VALUES ('Sale','payBack','WRITE','ALLOW','ROLE','employee');

View File

@ -0,0 +1 @@
ALTER TABLE `vn`.`payMethod` ADD hasVerified TINYINT(1) DEFAULT 0 NULL;

View File

@ -0,0 +1,90 @@
DROP PROCEDURE IF EXISTS `vn`.`ticket_doRefund`;
DELIMITER $$
$$
CREATE DEFINER=`root`@`localhost` PROCEDURE `vn`.`ticket_doRefund`(IN vOriginTicket INT, OUT vNewTicket INT)
BEGIN
DECLARE vDone BIT DEFAULT 0;
DECLARE vCustomer MEDIUMINT;
DECLARE vWarehouse TINYINT;
DECLARE vCompany MEDIUMINT;
DECLARE vAddress MEDIUMINT;
DECLARE vRefundAgencyMode INT;
DECLARE vItemFk INT;
DECLARE vQuantity DECIMAL (10,2);
DECLARE vConcept VARCHAR(50);
DECLARE vPrice DECIMAL (10,2);
DECLARE vDiscount TINYINT;
DECLARE vSaleNew INT;
DECLARE vSaleMain INT;
DECLARE vZoneFk INT;
DECLARE vRsMainTicket CURSOR FOR
SELECT *
FROM tmp.sale;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = 1;
SELECT id INTO vRefundAgencyMode
FROM agencyMode WHERE `name` = 'ABONO';
SELECT clientFk, warehouseFk, companyFk, addressFk
INTO vCustomer, vWarehouse, vCompany, vAddress
FROM ticket
WHERE id = vOriginTicket;
SELECT id INTO vZoneFk
FROM zone WHERE agencyModeFk = vRefundAgencyMode
LIMIT 1;
INSERT INTO vn.ticket (
clientFk,
shipped,
addressFk,
agencyModeFk,
nickname,
warehouseFk,
companyFk,
landed,
zoneFk
)
SELECT
vCustomer,
CURDATE(),
vAddress,
vRefundAgencyMode,
a.nickname,
vWarehouse,
vCompany,
CURDATE(),
vZoneFk
FROM address a
WHERE a.id = vAddress;
SET vNewTicket = LAST_INSERT_ID();
SET vDone := 0;
OPEN vRsMainTicket ;
FETCH vRsMainTicket INTO vSaleMain, vItemFk, vQuantity, vConcept, vPrice, vDiscount;
WHILE NOT vDone DO
INSERT INTO vn.sale(ticketFk, itemFk, quantity, concept, price, discount)
VALUES( vNewTicket, vItemFk, vQuantity, vConcept, vPrice, vDiscount );
SET vSaleNew = LAST_INSERT_ID();
INSERT INTO vn.saleComponent(saleFk,componentFk,`value`)
SELECT vSaleNew,componentFk,`value`
FROM vn.saleComponent
WHERE saleFk = vSaleMain;
FETCH vRsMainTicket INTO vSaleMain, vItemFk, vQuantity, vConcept, vPrice, vDiscount;
END WHILE;
CLOSE vRsMainTicket;
END;
$$
DELIMITER ;

View File

@ -0,0 +1,3 @@
UPDATE `vn`.`department`
SET `notificationEmail` = 'finanzas@verdnatura.es'
WHERE `name` = 'FINANZAS';

View File

@ -0,0 +1,2 @@
UPDATE `vn`.`supplier`
SET isPayMethodChecked = TRUE;

View File

@ -0,0 +1,33 @@
DELIMITER $$
$$
CREATE DEFINER=`root`@`%` TRIGGER `vn`.`payment_afterInsert` AFTER INSERT ON `payment` FOR EACH ROW
BEGIN
DECLARE vIsPayMethodChecked BOOLEAN;
DECLARE vEmail VARCHAR(150);
SELECT isPayMethodChecked INTO vIsPayMethodChecked
FROM supplier
WHERE id = NEW.supplierFk;
IF vIsPayMethodChecked = FALSE THEN
SELECT notificationEmail INTO vEmail
FROM department
WHERE name = 'FINANZAS';
CALL mail_insert(
vEmail,
NULL,
'Pago con método sin verificar',
CONCAT(
'Se ha realizado el pago ',
NEW.id,
' al proveedor ',
NEW.supplierFk,
' con el método de pago sin verificar.'
)
);
END IF;
END$$
DELIMITER ;

View File

@ -0,0 +1,26 @@
DROP TRIGGER IF EXISTS `vn`.`supplier_beforeUpdate`;
DELIMITER $$
$$
CREATE DEFINER=`root`@`%` TRIGGER `vn`.`supplier_beforeUpdate`
BEFORE UPDATE ON `vn`.`supplier` FOR EACH ROW
BEGIN
DECLARE vHasChange BOOL DEFAULT FALSE;
DECLARE vPayMethodHasVerified BOOL;
SELECT hasVerified INTO vPayMethodHasVerified
FROM payMethod
WHERE id = NEW.payMethodFk;
SET vHasChange = (NEW.payDemFk <> OLD.payDemFk) OR (NEW.payDay <> OLD.payDay);
IF vPayMethodHasVerified AND !vHasChange THEN
SET vHasChange = (NEW.payMethodFk <> OLD.payMethodFk);
END IF;
IF vHasChange THEN
SET NEW.isPayMethodChecked = FALSE;
END IF;
END$$
DELIMITER ;

View File

@ -0,0 +1,38 @@
USE vn;
DELIMITER $$
$$
CREATE OR REPLACE
ALGORITHM = UNDEFINED VIEW `vn`.`saleVolume` AS
select
`s`.`ticketFk` AS `ticketFk`,
`s`.`id` AS `saleFk`,
round(`ic`.`cm3delivery` * `s`.`quantity` / 1000, 0) AS `litros`,
`t`.`routeFk` AS `routeFk`,
`t`.`shipped` AS `shipped`,
`t`.`landed` AS `landed`,
`s`.`quantity` * `ic`.`cm3delivery` / 1000000 AS `volume`,
`s`.`quantity` * `ic`.`grams` / 1000 AS `physicalWeight`,
`s`.`quantity` * `ic`.`cm3delivery` * greatest(`i`.`density`, 167) / 1000000 AS `weight`,
`s`.`quantity` * `ic`.`cm3delivery` / 1000000 AS `physicalVolume`,
`s`.`quantity` * `ic`.`cm3delivery` * ifnull(`t`.`zonePrice`, `z`.`price`) / (`vc`.`standardFlowerBox` * 1000) AS `freight`,
`t`.`zoneFk` AS `zoneFk`,
`t`.`clientFk` AS `clientFk`,
`s`.`isPicked` AS `isPicked`,
`s`.`quantity` * `s`.`price` * (100 - `s`.`discount`) / 100 AS `eurosValue`,
`i`.`itemPackingTypeFk` AS `itemPackingTypeFk`
from
(((((`sale` `s`
join `item` `i` on
(`i`.`id` = `s`.`itemFk`))
join `ticket` `t` on
(`t`.`id` = `s`.`ticketFk`))
join `zone` `z` on
(`z`.`id` = `t`.`zoneFk`))
join `volumeConfig` `vc`)
join `itemCost` `ic` on
(`ic`.`itemFk` = `s`.`itemFk`
and `ic`.`warehouseFk` = `t`.`warehouseFk`))
where
`s`.`quantity` > 0;
$$
DELIMITER ;

View File

@ -0,0 +1,5 @@
ALTER TABLE `vn`.`smsConfig` ADD apiKey varchar(50) NULL;
ALTER TABLE `vn`.`smsConfig` CHANGE `user` user__ varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL;
ALTER TABLE `vn`.`smsConfig` CHANGE password password__ varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL;
ALTER TABLE `vn`.`sms` MODIFY COLUMN statusCode smallint(9) DEFAULT 0 NULL;
ALTER TABLE `vn`.`sms` MODIFY COLUMN status varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT 'OK' NULL;

View File

@ -0,0 +1,25 @@
ALTER TABLE `postgresql`.`business` ADD payedHolidays INT NULL;
ALTER TABLE `postgresql`.`business` CHANGE payedHolidays payedHolidays INT NULL AFTER reasonEndFk;
CREATE OR REPLACE
ALGORITHM = UNDEFINED VIEW `vn`.`workerLabour` AS
select
`b`.`business_id` AS `businessFk`,
`p`.`id_trabajador` AS `workerFk`,
`bl`.`workcenter_id` AS `workCenterFk`,
`b`.`date_start` AS `started`,
`b`.`date_end` AS `ended`,
`d`.`id` AS `departmentFk`,
`b`.`payedHolidays` AS `payedHolidays`
from
((((`postgresql`.`person` `p`
join `postgresql`.`profile` `pr` on
((`pr`.`person_id` = `p`.`person_id`)))
join `postgresql`.`business` `b` on
((`b`.`client_id` = `pr`.`profile_id`)))
join `postgresql`.`business_labour` `bl` on
((`b`.`business_id` = `bl`.`business_id`)))
join `vn`.`department` `d` on
((`d`.`id` = `bl`.`department_id`)))
order by
`b`.`date_start` desc

View File

@ -0,0 +1,7 @@
UPDATE `vn`.`smsConfig`
SET `uri` = 'https://api.gateway360.com/api/3.0/sms/send'
WHERE `id` = 1;
UPDATE `vn`.`smsConfig`
SET `apiKey` = '5715476da95b46d686a5a255e6459523'
WHERE `id` = 1;

File diff suppressed because one or more lines are too long

View File

@ -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`, `isIbanRequiredForClients`, `isIbanRequiredForSuppliers`)
INSERT INTO `vn`.`payMethod`(`id`,`code`, `name`, `graceDays`, `outstandingDebt`, `isIbanRequiredForClients`, `isIbanRequiredForSuppliers`, `hasVerified`)
VALUES
(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);
(1, NULL, 'PayMethod one', 0, 001, 0, 0, 0),
(2, NULL, 'PayMethod two', 10, 001, 0, 0, 1),
(3, 'compensation', 'PayMethod three', 0, 001, 0, 0, 0),
(4, NULL, 'PayMethod with IBAN', 0, 001, 1, 0, 0),
(5, NULL, 'PayMethod five', 10, 001, 0, 0, 0),
(8,'wireTransfer', 'WireTransfer', 5, 001, 1, 1, 0);
INSERT INTO `vn`.`payDem`(`id`, `payDem`)
VALUES
@ -606,7 +606,7 @@ INSERT INTO `vn`.`ticket`(`id`, `priority`, `agencyModeFk`,`warehouseFk`,`routeF
(9 , NULL, 7, 1, 6, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 1104, 'Stark tower', 124, NULL, 0, 3, 5, 1, CURDATE()),
(10, 1, 1, 5, 1, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 1102, 'Ingram Street', 2, NULL, 0, 1, 5, 1, CURDATE()),
(11, 1, 7, 1, 6, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 1102, 'NY roofs', 122, NULL, 0, 3, 5, 1, CURDATE()),
(12, 1, 1, 1, 1, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 1103, 'Phone Box', 123, NULL, 0, 1, 5, 1, CURDATE()),
(12, 1, 8, 1, 1, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 1103, 'Phone Box', 123, NULL, 0, 1, 5, 1, CURDATE()),
(13, 1, 7, 1, 6, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 1103, 'Phone Box', 123, NULL, 0, 3, 5, 1, CURDATE()),
(14, 1, 2, 1, NULL, CURDATE(), CURDATE(), 1104, 'Malibu Point', 4, NULL, 0, 9, 5, 1, CURDATE()),
(15, 1, 7, 1, 6, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 1105, 'An incredibly long alias for testing purposes', 125, NULL, 0, 3, 5, 1, CURDATE()),
@ -618,8 +618,10 @@ INSERT INTO `vn`.`ticket`(`id`, `priority`, `agencyModeFk`,`warehouseFk`,`routeF
(21, NULL, 5, 5, 5, DATE_ADD(CURDATE(), INTERVAL +1 MONTH), DATE_ADD(DATE_ADD(CURDATE(),INTERVAL +1 MONTH), INTERVAL +1 DAY), 1109, 'Somewhere in Holland', 102, NULL, 0, 13, 5, 1, DATE_ADD(CURDATE(), INTERVAL +1 MONTH)),
(22, NULL, 5, 5, 5, DATE_ADD(CURDATE(), INTERVAL +1 MONTH), DATE_ADD(DATE_ADD(CURDATE(),INTERVAL +1 MONTH), INTERVAL +1 DAY), 1109, 'Somewhere in Japan', 103, NULL, 0, 13, 5, 1, DATE_ADD(CURDATE(), INTERVAL +1 MONTH)),
(23, NULL, 8, 1, 7, CURDATE(), DATE_ADD(CURDATE(), INTERVAL + 1 DAY), 1101, 'address 21', 121, NULL, 0, 5, 5, 1, CURDATE()),
(24 ,NULL, 8, 1, 7, CURDATE(), CURDATE(), 1101, 'Bruce Wayne', 1, NULL, 0, 5, 5, 1, CURDATE());
(24 ,NULL, 8, 1, 7, CURDATE(), CURDATE(), 1101, 'Bruce Wayne', 1, NULL, 0, 5, 5, 1, CURDATE()),
(25 ,NULL, 8, 1, NULL, CURDATE(), CURDATE(), 1101, 'Bruce Wayne', 1, NULL, 0, 1, 5, 1, CURDATE()),
(26 ,NULL, 8, 1, NULL, CURDATE(), CURDATE(), 1101, 'An incredibly long alias for testing purposes', 1, NULL, 0, 1, 5, 1, CURDATE()),
(27 ,NULL, 8, 1, NULL, CURDATE(), CURDATE(), 1101, 'Wolverine', 1, NULL, 0, 1, 5, 1, CURDATE());
INSERT INTO `vn`.`ticketObservation`(`id`, `ticketFk`, `observationTypeFk`, `description`)
VALUES
(1, 11, 1, 'ready'),
@ -797,25 +799,25 @@ INSERT INTO `vn`.`itemFamily`(`code`, `description`)
('VT', 'Sales');
INSERT INTO `vn`.`item`(`id`, `typeFk`, `size`, `inkFk`, `stems`, `originFk`, `description`, `producerFk`, `intrastatFk`, `expenceFk`,
`comment`, `relevancy`, `image`, `subName`, `minPrice`, `stars`, `family`, `isFloramondo`, `genericFk`)
`comment`, `relevancy`, `image`, `subName`, `minPrice`, `stars`, `family`, `isFloramondo`, `genericFk`, `itemPackingTypeFk`)
VALUES
(1, 2, 70, 'YEL', 1, 1, NULL, 1, 06021010, 2000000000, NULL, 0, '1', NULL, 0, 1, 'VT', 0, NULL),
(2, 2, 70, 'BLU', 1, 2, NULL, 1, 06021010, 2000000000, NULL, 0, '2', NULL, 0, 2, 'VT', 0, NULL),
(3, 1, 60, 'YEL', 1, 3, NULL, 1, 05080000, 4751000000, NULL, 0, '3', NULL, 0, 5, 'VT', 0, NULL),
(4, 1, 60, 'YEL', 1, 1, 'Increases block', 1, 05080000, 4751000000, NULL, 0, '4', NULL, 0, 3, 'VT', 0, NULL),
(5, 3, 30, 'RED', 1, 2, NULL, 2, 06021010, 4751000000, NULL, 0, '5', NULL, 0, 3, 'VT', 0, NULL),
(6, 5, 30, 'RED', 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '6', NULL, 0, 4, 'VT', 0, NULL),
(7, 5, 90, 'BLU', 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '7', NULL, 0, 4, 'VT', 0, NULL),
(8, 2, 70, 'YEL', 1, 1, NULL, 1, 06021010, 2000000000, NULL, 0, '8', NULL, 0, 5, 'VT', 0, NULL),
(9, 2, 70, 'BLU', 1, 2, NULL, 1, 06021010, 2000000000, NULL, 0, '9', NULL, 0, 4, 'VT', 1, NULL),
(10, 1, 60, 'YEL', 1, 3, NULL, 1, 05080000, 4751000000, NULL, 0, '10', NULL, 0, 4, 'VT', 0, NULL),
(11, 1, 60, 'YEL', 1, 1, NULL, 1, 05080000, 4751000000, NULL, 0, '11', NULL, 0, 4, 'VT', 0, NULL),
(12, 3, 30, 'RED', 1, 2, NULL, 2, 06021010, 4751000000, NULL, 0, '12', NULL, 0, 3, 'VT', 0, NULL),
(13, 5, 30, 'RED', 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '13', NULL, 0, 2, 'VT', 1, NULL),
(14, 5, 90, 'BLU', 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 4, 'VT', 1, NULL),
(15, 4, NULL, NULL, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 0, 'EMB', 0, NULL),
(16, 6, NULL, NULL, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 0, 'EMB', 0, NULL),
(71, 6, NULL, NULL, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 0, 'VT', 0, NULL);
(1, 2, 70, 'YEL', 1, 1, NULL, 1, 06021010, 2000000000, NULL, 0, '1', NULL, 0, 1, 'VT', 0, NULL, 'V'),
(2, 2, 70, 'BLU', 1, 2, NULL, 1, 06021010, 2000000000, NULL, 0, '2', NULL, 0, 2, 'VT', 0, NULL, 'H'),
(3, 1, 60, 'YEL', 1, 3, NULL, 1, 05080000, 4751000000, NULL, 0, '3', NULL, 0, 5, 'VT', 0, NULL, NULL),
(4, 1, 60, 'YEL', 1, 1, 'Increases block', 1, 05080000, 4751000000, NULL, 0, '4', NULL, 0, 3, 'VT', 0, NULL, NULL),
(5, 3, 30, 'RED', 1, 2, NULL, 2, 06021010, 4751000000, NULL, 0, '5', NULL, 0, 3, 'VT', 0, NULL, NULL),
(6, 5, 30, 'RED', 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '6', NULL, 0, 4, 'VT', 0, NULL, NULL),
(7, 5, 90, 'BLU', 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '7', NULL, 0, 4, 'VT', 0, NULL, NULL),
(8, 2, 70, 'YEL', 1, 1, NULL, 1, 06021010, 2000000000, NULL, 0, '8', NULL, 0, 5, 'VT', 0, NULL, NULL),
(9, 2, 70, 'BLU', 1, 2, NULL, 1, 06021010, 2000000000, NULL, 0, '9', NULL, 0, 4, 'VT', 1, NULL, NULL),
(10, 1, 60, 'YEL', 1, 3, NULL, 1, 05080000, 4751000000, NULL, 0, '10', NULL, 0, 4, 'VT', 0, NULL, NULL),
(11, 1, 60, 'YEL', 1, 1, NULL, 1, 05080000, 4751000000, NULL, 0, '11', NULL, 0, 4, 'VT', 0, NULL, NULL),
(12, 3, 30, 'RED', 1, 2, NULL, 2, 06021010, 4751000000, NULL, 0, '12', NULL, 0, 3, 'VT', 0, NULL, NULL),
(13, 5, 30, 'RED', 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '13', NULL, 0, 2, 'VT', 1, NULL, NULL),
(14, 5, 90, 'BLU', 1, 2, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 4, 'VT', 1, NULL, NULL),
(15, 4, NULL, NULL, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 0, 'EMB', 0, NULL, NULL),
(16, 6, NULL, NULL, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 0, 'EMB', 0, NULL, NULL),
(71, 6, NULL, NULL, NULL, 1, NULL, NULL, 06021010, 4751000000, NULL, 0, '', NULL, 0, 0, 'VT', 0, NULL, NULL);
-- Update the taxClass after insert of the items
UPDATE `vn`.`itemTaxCountry` SET `taxClassFk` = 2
@ -1074,11 +1076,15 @@ INSERT INTO `vn`.`itemPlacement`(`id`, `itemFk`, `warehouseFk`, `code`)
(3, 1, 3, 'A33'),
(4, 2, 1, 'A44');
INSERT INTO `vn`.`collection`(`id`, `workerFk`, `stateFk`, `created`)
INSERT INTO `vn`.`train`(`id`, `name`)
VALUES
(1, 1106, 5, DATE_ADD(CURDATE(),INTERVAL +1 DAY)),
(2, 1106, 14, CURDATE());
(1, 'Train1'),
(2, 'Train2');
INSERT INTO `vn`.`collection`(`id`, `workerFk`, `stateFk`, `created`, `trainFk`)
VALUES
(1, 1106, 5, DATE_ADD(CURDATE(),INTERVAL +1 DAY), 1),
(2, 1106, 14, CURDATE(), 1);
INSERT INTO `vn`.`ticketCollection`(`id`, `ticketFk`, `collectionFk`)
VALUES
@ -1286,11 +1292,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`, `isPayMethodChecked`)
INSERT INTO `vn`.`supplier`(`id`, `name`, `nickname`,`account`,`countryFk`,`nif`, `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', 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);
(1, 'Plants SL', 'Plants nick', 4100000001, 1, '06089160W', 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', 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, 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
@ -1870,7 +1876,7 @@ INSERT INTO `vn`.`workCenterHoliday` (`workCenterFk`, `days`, `year`)
VALUES
('1', '27.5', YEAR(CURDATE())),
('5', '22', YEAR(CURDATE())),
('1', '24.5', YEAR(DATE_ADD(CURDATE(), INTERVAL -1 YEAR))),
('1', '24.5', YEAR(DATE_ADD(CURDATE(), INTERVAL -1 YEAR))),
('5', '23', YEAR(DATE_ADD(CURDATE(), INTERVAL -1 YEAR)));
INSERT INTO `postgresql`.`calendar_state` (`calendar_state_id`, `type`, `rgb`, `code`, `holidayEntitlementRate`)
@ -1900,9 +1906,9 @@ INSERT INTO `postgresql`.`calendar_employee` (`business_id`, `calendar_state_id`
(1107, 1, IF(MONTH(CURDATE()) >= 1 AND DAY(CURDATE()) > 20, DATE_ADD(CURDATE(), INTERVAL -14 DAY), DATE_ADD(CURDATE(), INTERVAL 9 DAY))),
(1107, 2, IF(MONTH(CURDATE()) >= 1 AND DAY(CURDATE()) > 20, DATE_ADD(CURDATE(), INTERVAL -15 DAY), DATE_ADD(CURDATE(), INTERVAL 7 DAY)));
INSERT INTO `vn`.`smsConfig` (`id`, `uri`, `title`)
INSERT INTO `vn`.`smsConfig` (`id`, `uri`, `title`, `apiKey`)
VALUES
('1', 'https://websms.xtratelecom.es/api_php/server.wsdl', 'Verdnatura');
('1', 'https://api.gateway360.com/api/3.0/sms/send', 'Verdnatura', '5715476da95b46d686a5a255e6459523');
INSERT INTO `vn`.`sharingClient`(`id`, `workerFk`, `started`, `ended`, `clientFk`)
VALUES

File diff suppressed because it is too large Load Diff

View File

@ -458,7 +458,8 @@ export default {
firstSaleQuantity: 'vn-ticket-summary [name="sales"] vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(5)',
firstSaleDiscount: 'vn-ticket-summary [name="sales"] vn-table > div > vn-tbody > vn-tr > vn-td:nth-child(8)',
invoiceOutRef: 'vn-ticket-summary > vn-card > vn-horizontal > vn-one:nth-child(1) > vn-label-value:nth-child(7) > section > span',
setOk: 'vn-ticket-summary vn-button[label="SET OK"] > button',
stateButton: 'vn-ticket-summary vn-button-menu > button ',
stateAutocomplete: 'div.filter.ng-scope > vn-textfield > div.container > div.infix > div.control',
descriptorTicketId: 'vn-ticket-descriptor > vn-descriptor-content > div > div.body > div.top > div'
},
ticketsIndex: {
@ -524,7 +525,7 @@ export default {
saturdayButton: '.vn-popup.shown vn-tool-bar > vn-button:nth-child(6)',
acceptDialog: '.vn-dialog.shown button[response="accept"]',
acceptChangeHourButton: '.vn-dialog.shown button[response="accept"]',
descriptorDeliveryDate: 'vn-ticket-descriptor slot-body > .attributes > vn-label-value:nth-child(3) > section > span',
descriptorDeliveryDate: 'vn-ticket-descriptor slot-body > .attributes > vn-label-value:nth-child(4) > section > span',
acceptInvoiceOutButton: '.vn-confirm.shown button[response="accept"]',
acceptDeleteStowawayButton: '.vn-dialog.shown button[response="accept"]'
},
@ -558,6 +559,7 @@ export default {
moreMenuUnmarkReseved: 'vn-item[name="unreserve"]',
moreMenuUpdateDiscount: 'vn-item[name="discount"]',
moreMenuRecalculatePrice: 'vn-item[name="calculatePrice"]',
moreMenuPayBack: 'vn-item[name="payBack"]',
moreMenuUpdateDiscountInput: 'vn-input-number[ng-model="$ctrl.edit.discount"] input',
transferQuantityInput: '.vn-popover.shown vn-table > div > vn-tbody > vn-tr > vn-td-editable > span > text',
transferQuantityCell: '.vn-popover.shown vn-table > div > vn-tbody > vn-tr > vn-td-editable',

View File

@ -127,8 +127,8 @@ describe('Item regularize path', () => {
await page.waitForState('ticket.index');
});
it('should search for the ticket with id 25 once again', async() => {
await page.accessToSearchResult('25');
it('should search for the ticket with id 28 once again', async() => {
await page.accessToSearchResult('28');
await page.waitForState('ticket.card.summary');
});

View File

@ -206,7 +206,16 @@ describe('Ticket Edit sale path', () => {
expect(message.text).toContain('Data saved!');
});
it('should select the third sale and create a pay back', async() => {
await page.waitToClick(selectors.ticketSales.firstSaleCheckbox);
await page.waitToClick(selectors.ticketSales.moreMenu);
await page.waitToClick(selectors.ticketSales.moreMenuPayBack);
await page.waitForState('ticket.card.sale');
});
it('should select the third sale and create a claim of it', async() => {
await page.accessToSearchResult('16');
await page.accessToSection('ticket.card.sale');
await page.waitToClick(selectors.ticketSales.thirdSaleCheckbox);
await page.waitToClick(selectors.ticketSales.moreMenu);
await page.waitToClick(selectors.ticketSales.moreMenuCreateClaim);

View File

@ -76,8 +76,24 @@ describe('Ticket Summary path', () => {
await page.waitForState('ticket.card.summary');
});
it('should click on the SET OK button', async() => {
await page.waitToClick(selectors.ticketSummary.setOk);
it('should set the ticket state to OK using the top right button', async() => {
const searchValue = 'OK';
await page.waitToClick(selectors.ticketSummary.stateButton);
await page.write(selectors.ticketSummary.stateAutocomplete, searchValue);
try {
await page.waitForFunction(text => {
const element = document.querySelector('li.active');
if (element)
return element.innerText.toLowerCase().includes(text.toLowerCase());
}, {}, searchValue);
} catch (error) {
const state = await page.evaluate(() => {
const stateSelector = 'vn-ticket-summary vn-label-value:nth-child(1) > section > span';
return document.querySelector(stateSelector).value;
});
throw new Error(`${stateSelector} innerText is ${state}! ${error}`);
}
await page.keyboard.press('Enter');
const message = await page.waitForSnackbar();
expect(message.text).toContain('Data saved!');

View File

@ -33,7 +33,7 @@ describe('Ticket index payout path', () => {
await page.waitToClick(selectors.ticketsIndex.openAdvancedSearchButton);
await page.write(selectors.ticketsIndex.advancedSearchClient, '1101');
await page.keyboard.press('Enter');
await page.waitForNumberOfElements(selectors.ticketsIndex.anySearchResult, 6);
await page.waitForNumberOfElements(selectors.ticketsIndex.anySearchResult, 9);
await page.waitToClick(selectors.ticketsIndex.firstTicketCheckbox);
await page.waitToClick(selectors.ticketsIndex.secondTicketCheckbox);

View File

@ -8,7 +8,7 @@ describe('Supplier basic data path', () => {
beforeAll(async() => {
browser = await getBrowser();
page = browser.page;
await page.loginAndModule('administrative', 'supplier');
await page.loginAndModule('financial', 'supplier');
await page.accessToSearchResult('1');
await page.accessToSection('supplier.card.basicData');
});

View File

@ -55,8 +55,8 @@ vn-chip {
&.message,
&.message.clickable:hover,
&.message.clickable:focus {
color: $color-font-dark;
background-color: $color-bg-dark;
background-color: $color-font-bg-dark;
color: $color-font-bg;
}
&.clickable {
@extend %clickable;

View File

@ -1,7 +1,7 @@
@import "variables";
vn-label {
color: $color-font-secondary;
color: $color-font-light;
&::after {
content: ':';

View File

@ -44,16 +44,10 @@ export default class SmartTable extends Component {
set model(value) {
this._model = value;
if (value)
if (value) {
this.$.model = value;
}
get viewConfigId() {
return this._viewConfigId;
}
set viewConfigId(value) {
this._viewConfigId = value;
this.defaultOrder();
}
}
getDefaultViewConfig() {
@ -163,6 +157,40 @@ export default class SmartTable extends Component {
}
}
defaultOrder() {
const order = this.model.order;
if (!order) return;
const orderFields = order.split(', ');
for (const fieldString of orderFields) {
const field = fieldString.split(' ');
const fieldName = field[0];
let sortType = 'ASC';
if (field.length === 2)
sortType = field[1];
const column = this.columns.find(column => column.field == fieldName);
if (column) {
this.sortCriteria.push({field: fieldName, sortType: sortType});
const isASC = sortType == 'ASC';
const isDESC = sortType == 'DESC';
if (isDESC) {
column.element.classList.remove('asc');
column.element.classList.add('desc');
}
if (isASC) {
column.element.classList.remove('desc');
column.element.classList.add('asc');
}
}
}
}
registerColumns() {
const header = this.element.querySelector('thead > tr');
if (!header) return;
@ -175,7 +203,7 @@ export default class SmartTable extends Component {
const columnElement = angular.element(column);
const caption = columnElement.text().trim();
this.columns.push({field, caption, index});
this.columns.push({field, caption, index, element: column});
column.addEventListener('click', () => this.orderHandler(column));
}

View File

@ -80,6 +80,45 @@ describe('Component smartTable', () => {
});
});
describe('defaultOrder', () => {
it('should insert a new object to the controller sortCriteria with a sortType value of "ASC"', () => {
const element = document.createElement('div');
controller.model = {order: 'id'};
controller.columns = [
{field: 'id', element: element},
{field: 'test1', element: element},
{field: 'test2', element: element}
];
controller.defaultOrder();
const firstSortCriteria = controller.sortCriteria[0];
expect(firstSortCriteria.field).toEqual('id');
expect(firstSortCriteria.sortType).toEqual('ASC');
});
it('should insert two new objects to the controller sortCriteria with a sortType values of "ASC" and "DESC"', () => {
const element = document.createElement('div');
controller.model = {order: 'test1, id DESC'};
controller.columns = [
{field: 'id', element: element},
{field: 'test1', element: element},
{field: 'test2', element: element}
];
controller.defaultOrder();
const firstSortCriteria = controller.sortCriteria[0];
const secondSortCriteria = controller.sortCriteria[1];
expect(firstSortCriteria.field).toEqual('test1');
expect(firstSortCriteria.sortType).toEqual('ASC');
expect(secondSortCriteria.field).toEqual('id');
expect(secondSortCriteria.sortType).toEqual('DESC');
});
});
describe('addFilter()', () => {
it('should call the model addFilter() with a basic where filter if exprBuilder() was not received', () => {
controller.model = {addFilter: jest.fn()};

View File

@ -94,8 +94,8 @@ smart-table table {
color: $color-font-bg;
}
&.message {
background-color: $color-bg-dark;
color: $color-font-dark;
background-color: $color-font-bg-dark;
color: $color-font-bg;
}
}
}

View File

@ -150,8 +150,8 @@ vn-table {
color: $color-font-bg;
}
&.message {
background-color: $color-bg-dark;
color: $color-font-dark;
background-color: $color-font-bg-dark;
color: $color-font-bg;
}
}
vn-icon-menu {

View File

@ -23,371 +23,398 @@
-moz-osx-font-smoothing: grayscale;
}
.icon-100:before {
content: "\e976";
}
.icon-account:before {
content: "\e900";
}
.icon-actions:before {
content: "\e901";
}
.icon-addperson:before {
content: "\e902";
}
.icon-agency:before {
content: "\e903";
}
.icon-albaran:before {
content: "\e904";
}
.icon-anonymous:before {
content: "\e905";
}
.icon-apps:before {
content: "\e906";
}
.icon-artificial:before {
content: "\e907";
}
.icon-attach:before {
content: "\e908";
}
.icon-barcode:before {
content: "\e909";
}
.icon-basket:before {
content: "\e90a";
}
.icon-basketadd:before {
content: "\e90b";
}
.icon-bin:before {
content: "\e90c";
}
.icon-botanical:before {
content: "\e90d";
}
.icon-bucket:before {
content: "\e90e";
}
.icon-buscaman:before {
content: "\e90f";
}
.icon-buyrequest:before {
content: "\e910";
}
.icon-calc_volum .path1:before {
content: "\e911";
color: rgb(0, 0, 0);
}
.icon-calc_volum .path2:before {
content: "\e912";
margin-left: -1em;
color: rgb(0, 0, 0);
}
.icon-calc_volum .path3:before {
content: "\e913";
margin-left: -1em;
color: rgb(0, 0, 0);
}
.icon-calc_volum .path4:before {
content: "\e914";
margin-left: -1em;
color: rgb(0, 0, 0);
}
.icon-calc_volum .path5:before {
content: "\e915";
margin-left: -1em;
color: rgb(0, 0, 0);
}
.icon-calc_volum .path6:before {
content: "\e916";
margin-left: -1em;
color: rgb(255, 255, 255);
}
.icon-calendar:before {
content: "\e917";
}
.icon-catalog:before {
content: "\e918";
}
.icon-claims:before {
content: "\e919";
}
.icon-client:before {
content: "\e91a";
}
.icon-clone:before {
.icon-isTooLittle:before {
content: "\e91b";
}
.icon-columnadd:before {
content: "\e91c";
}
.icon-columndelete:before {
content: "\e91d";
}
.icon-accessory:before {
content: "\e91e";
}
.icon-components:before {
content: "\e91f";
}
.icon-handmade:before {
content: "\e920";
}
.icon-consignatarios:before {
content: "\e921";
}
.icon-control:before {
content: "\e922";
}
.icon-credit:before {
content: "\e923";
}
.icon-deletedTicketCross:before {
content: "\e924";
}
.icon-deleteline:before {
content: "\e925";
}
.icon-delivery:before {
content: "\e926";
}
.icon-deliveryprices:before {
content: "\e927";
}
.icon-details:before {
content: "\e928";
}
.icon-dfiscales:before {
content: "\e929";
}
.icon-doc:before {
content: "\e92a";
}
.icon-entry:before {
content: "\e92b";
}
.icon-exit:before {
content: "\e92c";
}
.icon-eye:before {
content: "\e92d";
}
.icon-fixedPrice:before {
content: "\e92e";
}
.icon-flower:before {
content: "\e92f";
}
.icon-frozen:before {
content: "\e930";
}
.icon-fruit:before {
content: "\e931";
}
.icon-funeral:before {
content: "\e932";
}
.icon-greuge:before {
content: "\e933";
}
.icon-grid:before {
content: "\e934";
}
.icon-handmadeArtificial:before {
content: "\e935";
}
.icon-headercol:before {
content: "\e936";
}
.icon-history:before {
content: "\e937";
}
.icon-disabled:before {
content: "\e938";
}
.icon-info:before {
content: "\e939";
}
.icon-inventory:before {
content: "\e93a";
}
.icon-invoice:before {
content: "\e93b";
}
.icon-invoice-in:before {
content: "\e93c";
}
.icon-invoice-in-create:before {
content: "\e93d";
}
.icon-invoice-out:before {
content: "\e93e";
}
.icon-item:before {
content: "\e93f";
}
.icon-languaje:before {
content: "\e940";
}
.icon-lines:before {
content: "\e941";
}
.icon-linesprepaired:before {
content: "\e942";
}
.icon-logout:before {
content: "\e943";
}
.icon-mana:before {
content: "\e944";
}
.icon-mandatory:before {
content: "\e945";
}
.icon-net:before {
content: "\e946";
}
.icon-niche:before {
content: "\e947";
}
.icon-no036:before {
content: "\e948";
}
.icon-notes:before {
content: "\e949";
}
.icon-noweb:before {
content: "\e94a";
}
.icon-onlinepayment:before {
content: "\e94b";
}
.icon-package:before {
content: "\e94c";
}
.icon-payment:before {
content: "\e94d";
}
.icon-pbx:before {
content: "\e94e";
content: "\e900";
}
.icon-Person:before {
content: "\e94f";
content: "\e901";
}
.icon-pets:before {
content: "\e950";
.icon-handmadeArtificial:before {
content: "\e902";
}
.icon-photo:before {
content: "\e951";
.icon-fruit:before {
content: "\e903";
}
.icon-plant:before {
content: "\e952";
}
.icon-stowaway:before {
content: "\e953";
}
.icon-preserved:before {
content: "\e954";
}
.icon-recovery:before {
content: "\e955";
}
.icon-regentry:before {
content: "\e956";
}
.icon-reserve:before {
content: "\e957";
}
.icon-revision:before {
content: "\e958";
}
.icon-risk:before {
content: "\e959";
}
.icon-services:before {
content: "\e95a";
}
.icon-settings:before {
content: "\e95b";
}
.icon-shipment-01 .path1:before {
content: "\e95c";
color: rgb(225, 225, 225);
}
.icon-shipment-01 .path2:before {
content: "\e95d";
margin-left: -1em;
color: rgb(0, 0, 0);
}
.icon-sign:before {
content: "\e95e";
}
.icon-sms:before {
content: "\e95f";
}
.icon-solclaim:before {
content: "\e960";
}
.icon-solunion:before {
content: "\e961";
}
.icon-splitline:before {
content: "\e962";
}
.icon-splur:before {
content: "\e963";
}
.icon-supplier:before {
content: "\e965";
}
.icon-supplierfalse:before {
content: "\e966";
}
.icon-tags:before {
content: "\e967";
}
.icon-tax:before {
content: "\e968";
}
.icon-thermometer:before {
content: "\e969";
}
.icon-ticket:before {
content: "\e96a";
}
.icon-traceability:before {
content: "\e96b";
}
.icon-transaction:before {
content: "\e96c";
.icon-funeral:before {
content: "\e904";
}
.icon-treatments:before {
content: "\e96d";
content: "\e905";
}
.icon-unavailable:before {
content: "\e96e";
.icon-preserved:before {
content: "\e906";
}
.icon-greenery:before {
content: "\e96f";
content: "\e907";
}
.icon-volume:before {
content: "\e970";
.icon-plant:before {
content: "\e908";
}
.icon-wand:before {
content: "\e971";
.icon-handmade:before {
content: "\e909";
}
.icon-web:before {
content: "\e972";
.icon-accessory:before {
content: "\e90a";
}
.icon-wiki:before {
content: "\e973";
.icon-artificial:before {
content: "\e90b";
}
.icon-worker:before {
content: "\e974";
.icon-flower:before {
content: "\e90c";
}
.icon-fixedPrice:before {
content: "\e90d";
}
.icon-addperson:before {
content: "\e90e";
}
.icon-supplierfalse:before {
content: "\e90f";
}
.icon-invoice-out:before {
content: "\e910";
}
.icon-invoice-in:before {
content: "\e911";
}
.icon-invoice-in-create:before {
content: "\e912";
}
.icon-basketadd:before {
content: "\e913";
}
.icon-basket:before {
content: "\e914";
}
.icon-calc_volum .path1:before {
content: "\e915";
}
.icon-calc_volum .path2:before {
content: "\e916";
margin-left: -1em;
}
.icon-calc_volum .path3:before {
content: "\e917";
margin-left: -1em;
}
.icon-calc_volum .path4:before {
content: "\e918";
margin-left: -1em;
}
.icon-calc_volum .path5:before {
content: "\e919";
margin-left: -1em;
}
.icon-calc_volum .path6:before {
content: "\e91a";
margin-left: -1em;
}
.icon-deliveryprices:before {
content: "\e91c";
}
.icon-onlinepayment:before {
content: "\e91d";
}
.icon-risk:before {
content: "\e91e";
}
.icon-noweb:before {
content: "\e91f";
}
.icon-no036:before {
content: "\e920";
}
.icon-inactive:before {
content: "\e921";
}
.icon-unavailable:before {
content: "\e922";
}
.icon-invoice-01:before {
content: "\e923";
}
.icon-invoice:before {
content: "\e924";
}
.icon-supplier:before {
content: "\e925";
}
.icon-client2:before {
content: "\e926";
}
.icon-supplier2:before {
content: "\e927";
}
.icon-client:before {
content: "\e928";
}
.icon-shipment-01:before {
content: "\e929";
}
.icon-inventory:before {
content: "\e92b";
}
.icon-zone:before {
content: "\e92c";
}
.icon-wiki:before {
content: "\e92d";
}
.icon-attach:before {
content: "\e92e";
}
.icon-zone2:before {
content: "\e92f";
}
.icon-anonymous:before {
content: "\e930";
}
.icon-net:before {
content: "\e931";
}
.icon-buyrequest:before {
content: "\e932";
}
.icon-thermometer:before {
content: "\e933";
}
.icon-entry:before {
content: "\e934";
}
.icon-deletedTicket:before {
content: "\e935";
}
.icon-deliveryprices-01:before {
content: "\e936";
}
.icon-catalog:before {
content: "\e937";
}
.icon-agency:before {
content: "\e938";
}
.icon-delivery:before {
content: "\e939";
}
.icon-wand:before {
content: "\e93a";
}
.icon-buscaman:before {
content: "\e93b";
}
.icon-pbx:before {
content: "\e93c";
}
.icon-calendar:before {
content: "\e93d";
}
.icon-splitline:before {
content: "\e93e";
}
.icon-consignatarios:before {
content: "\e93f";
}
.icon-tax:before {
content: "\e940";
}
.icon-notes:before {
content: "\e941";
}
.icon-lines:before {
content: "\e942";
}
.icon-languaje:before {
content: "\e943";
}
.icon-greuge:before {
content: "\e944";
}
.icon-credit:before {
content: "\e945";
}
.icon-components:before {
content: "\e946";
}
.icon-pets:before {
content: "\e947";
}
.icon-linesprepaired:before {
content: "\e948";
}
.icon-control:before {
content: "\e949";
}
.icon-revision:before {
content: "\e94a";
}
.icon-newinvoices:before {
content: "\e94b";
}
.icon-services:before {
content: "\e94c";
}
.icon-newalbaran:before {
content: "\e94d";
}
.icon-solunion:before {
content: "\e94e";
}
.icon-stowaway:before {
content: "\e94f";
}
.icon-exit:before {
content: "\e950";
}
.icon-apps:before {
content: "\e951";
}
.icon-info:before {
content: "\e952";
}
.icon-columndelete:before {
content: "\e953";
}
.icon-columnadd:before {
content: "\e954";
}
.icon-deleteline:before {
content: "\e955";
}
.icon-item:before {
content: "\e956";
}
.icon-worker:before {
content: "\e957";
}
.icon-headercol:before {
content: "\e958";
}
.icon-reserva:before {
content: "\e959";
}
.icon-100:before {
content: "\e95a";
}
.icon-noweb1:before {
content: "\e95b";
}
.icon-settings1:before {
content: "\e95c";
}
.icon-sign:before {
content: "\e95d";
}
.icon-polizon:before {
content: "\e95e";
}
.icon-solclaim:before {
content: "\e95f";
}
.icon-actions:before {
content: "\e960";
}
.icon-details:before {
content: "\e961";
}
.icon-traceability:before {
content: "\e962";
}
.icon-claims:before {
content: "\e963";
}
.icon-regentry:before {
content: "\e964";
}
.icon-regentry-1:before {
content: "\e965";
}
.icon-transaction:before {
content: "\e966";
}
.icon-history:before {
content: "\e968";
}
.icon-entry:before {
content: "\e969";
}
.icon-mana:before {
content: "\e96a";
}
.icon-ticket:before {
content: "\e96b";
}
.icon-niche:before {
content: "\e96c";
}
.icon-tags:before {
content: "\e96d";
}
.icon-volume:before {
content: "\e96e";
}
.icon-bin:before {
content: "\e96f";
}
.icon-splur:before {
content: "\e970";
}
.icon-barcode:before {
content: "\e971";
}
.icon-botanical:before {
content: "\e972";
}
.icon-clone:before {
content: "\e973";
}
.icon-photo:before {
content: "\e974";
}
.icon-sms:before {
content: "\e975";
}
.icon-eye:before {
content: "\e976";
}
.icon-doc:before {
content: "\e977";
}
.icon-package:before {
content: "\e978";
}
.icon-settings:before {
content: "\e979";
}
.icon-bucket:before {
content: "\e97a";
}
.icon-mandatory:before {
content: "\e97b";
}
.icon-recovery:before {
content: "\e97c";
}
.icon-payment:before {
content: "\e97e";
}
.icon-invoices:before {
content: "\e97f";
}
.icon-grid:before {
content: "\e980";
}
.icon-logout:before {
content: "\e981";
}
.icon-web:before {
content: "\e982";
}
.icon-albaran:before {
content: "\e983";
}
.icon-dfiscales:before {
content: "\e984";
}

Binary file not shown.

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 162 KiB

After

Width:  |  Height:  |  Size: 162 KiB

View File

@ -51,7 +51,7 @@ h1, h2, h3, h4, h5, h6 {
color: $color-main;
}
.text-secondary {
color: $color-font-secondary;
color: $color-font-light;
}
/* Helpers */

View File

@ -52,8 +52,6 @@
"Agency cannot be blank": "La agencia no puede quedar en blanco",
"You can't make changes on a client with verified data": "No puedes hacer cambios en un cliente con datos comprobados",
"This address doesn't exist": "Este consignatario no existe",
"You can't create an order for a inactive client": "You can't create an order for a inactive client",
"You can't create an order for a client that doesn't has tax data verified": "You can't create an order for a client that doesn't has tax data verified",
"You must delete the claim id %d first": "Antes debes borrar la reclamación %d",
"You don't have enough privileges": "No tienes suficientes permisos",
"Cannot check Equalization Tax in this NIF/CIF": "No se puede marcar RE en este NIF/CIF",
@ -98,13 +96,13 @@
"This postcode already exists": "Este código postal ya existe",
"Concept cannot be blank": "El concepto no puede quedar en blanco",
"File doesn't exists": "El archivo no existe",
"You don't have privileges to change the zone": "No tienes permisos para cambiar la zona",
"You don't have privileges to change the zone or for these parameters there are more than one shipping options, talk to agencies": "No tienes permisos para cambiar la zona o para esos parámetros hay más de una opción de envío, hable con las agencias",
"This ticket is already on weekly tickets": "Este ticket ya está en tickets programados",
"Ticket id cannot be blank": "El id de ticket no puede quedar en blanco",
"Weekday cannot be blank": "El día de la semana no puede quedar en blanco",
"You can't delete a confirmed order": "No puedes borrar un pedido confirmado",
"Can't create stowaway for this ticket": "No se puede crear un polizon para este ticket",
"The socialName has an invalid format": "El nombre fiscal tiene un formato incorrecto",
"The social name has an invalid format": "El nombre fiscal tiene un formato incorrecto",
"Invalid quantity": "Cantidad invalida",
"This postal code is not valid": "This postal code is not valid",
"is invalid": "is invalid",
@ -217,5 +215,7 @@
"The type of business must be filled in basic data": "El tipo de negocio debe estar rellenado en datos básicos",
"You can't create a claim from a ticket delivered more than seven days ago": "No puedes crear una reclamación de un ticket entregado hace más de siete días",
"The worker has hours recorded that day": "El trabajador tiene horas fichadas ese día",
"The worker has a marked absence that day": "El trabajador tiene marcada una ausencia ese día"
}
"The worker has a marked absence that day": "El trabajador tiene marcada una ausencia ese día",
"You can not modify is pay method checked": "No se puede modificar el campo método de pago validado",
"Can't transfer claimed sales": "No puedes transferir lineas reclamadas"
}

View File

@ -59,11 +59,12 @@ module.exports = Self => {
const landedPlusWeek = new Date(ticket.landed);
landedPlusWeek.setDate(landedPlusWeek.getDate() + 7);
const hasClaimManagerRole = await models.Account.hasRole(userId, 'claimManager', myOptions);
const isClaimable = landedPlusWeek >= new Date();
if (ticket.isDeleted)
throw new UserError(`You can't create a claim for a removed ticket`);
if (!isClaimable)
if (!isClaimable && !hasClaimManagerRole)
throw new UserError(`You can't create a claim from a ticket delivered more than seven days ago`);
const newClaim = await Self.create({

View File

@ -46,9 +46,40 @@ describe('Claim createFromSales()', () => {
}
});
it('should be able to create a claim for a ticket delivered more than seven days ago as claimManager', async() => {
const tx = await models.Claim.beginTransaction({});
const claimManagerId = 72;
activeCtx.accessToken.userId = claimManagerId;
try {
const options = {transaction: tx};
const todayMinusEightDays = new Date();
todayMinusEightDays.setDate(todayMinusEightDays.getDate() - 8);
const ticket = await models.Ticket.findById(ticketId, options);
await ticket.updateAttribute('landed', todayMinusEightDays, options);
const claim = await models.Claim.createFromSales(ctx, ticketId, newSale, options);
expect(claim.ticketFk).toEqual(ticketId);
const claimBeginning = await models.ClaimBeginning.findOne({where: {claimFk: claim.id}}, options);
expect(claimBeginning.saleFk).toEqual(newSale[0].id);
expect(claimBeginning.quantity).toEqual(newSale[0].quantity);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should not be able to create a claim for a ticket delivered more than seven days ago', async() => {
const tx = await models.Claim.beginTransaction({});
activeCtx.accessToken.userId = 1;
let error;
try {

View File

@ -1,5 +1,4 @@
const soap = require('soap');
const xmlParser = require('xml2js').parseString;
const got = require('got');
const UserError = require('vn-loopback/util/user-error');
module.exports = Self => {
@ -35,57 +34,49 @@ module.exports = Self => {
Self.send = async(ctx, destinationFk, destination, message) => {
const userId = ctx.req.accessToken.userId;
const smsConfig = await Self.app.models.SmsConfig.findOne();
const soapClient = await soap.createClientAsync(smsConfig.uri);
if (destination.length == 9) {
const spainPrefix = '0034';
destination = spainPrefix + destination;
}
const params = {
user: smsConfig.user,
pass: smsConfig.password,
src: smsConfig.title,
dst: destination,
msg: message
api_key: smsConfig.apiKey,
messages: [{
from: smsConfig.title,
to: destination,
text: message
}]
};
let xmlResponse;
let xmlResult;
let xmlParsed;
let status;
let response;
try {
if (process.env.NODE_ENV !== 'production') {
status = {
codigo: [200],
descripcion: ['Fake response']
if (process.env.NODE_ENV !== 'production')
response = {result: [{status: 'ok'}]};
else {
const jsonTest = {
json: params
};
} else {
[xmlResponse] = await soapClient.sendSMSAsync(params);
xmlResult = xmlResponse.result.$value;
xmlParsed = await new Promise((resolve, reject) => {
xmlParser(xmlResult, (err, result) => {
if (err)
reject(err);
resolve(result);
});
});
[status] = xmlParsed['xtratelecom-sms-response'].sms;
response = await got.post(smsConfig.uri, jsonTest).json();
}
} catch (e) {
console.error(e);
}
const statusCode = status.codigo[0];
const statusDescription = status.descripcion[0];
const [result] = response.result;
const error = result.error_id;
const newSms = {
senderFk: userId,
destinationFk: destinationFk || null,
destination: destination,
message: message,
statusCode: statusCode,
status: statusDescription
status: error
};
const sms = await Self.create(newSms);
if (statusCode != 200)
if (error)
throw new UserError(`We weren't able to send this SMS`);
return sms;

View File

@ -1,14 +1,10 @@
const app = require('vn-loopback/server/server');
const soap = require('soap');
describe('sms send()', () => {
it('should return the expected message and status code', async() => {
const code = 200;
spyOn(soap, 'createClientAsync').and.returnValue('a so fake client');
let ctx = {req: {accessToken: {userId: 1}}};
let result = await app.models.Sms.send(ctx, 1105, 'destination', 'My SMS Body');
it('should not return status error', async() => {
const ctx = {req: {accessToken: {userId: 1}}};
const result = await app.models.Sms.send(ctx, 1105, '123456789', 'My SMS Body');
expect(result.statusCode).toEqual(code);
expect(result.status).toContain('Fake response');
expect(result.status).toBeUndefined();
});
});

View File

@ -55,15 +55,6 @@ module.exports = Self => {
with: /^[\w|.|-]+@[\w|-]+(\.[\w|-]+)*(,[\w|.|-]+@[\w|-]+(\.[\w|-]+)*)*$/
});
Self.validate('businessTypeFk', hasBusinessType, {
message: `The type of business must be filled in basic data`
});
function hasBusinessType(err) {
if (!this.businessTypeFk)
err();
}
Self.validatesLengthOf('postcode', {
allowNull: true,
allowBlank: true,
@ -189,6 +180,32 @@ module.exports = Self => {
return regexp.test(value);
}
Self.observe('before save', async ctx => {
const changes = ctx.data || ctx.instance;
const orgData = ctx.currentInstance;
const businessTypeFk = changes && changes.businessTypeFk || orgData && orgData.businessTypeFk;
const isTaxDataChecked = changes && changes.isTaxDataChecked || orgData && orgData.isTaxDataChecked;
let invalidBusinessType = false;
if (!ctx.isNewInstance) {
const isWorker = await Self.app.models.UserAccount.findById(orgData.id);
const changedFields = Object.keys(changes);
const hasChangedOtherFields = changedFields.some(key => key !== 'businessTypeFk');
if (!businessTypeFk && !isTaxDataChecked && !isWorker && !hasChangedOtherFields)
invalidBusinessType = true;
}
if (ctx.isNewInstance) {
if (!businessTypeFk && !isTaxDataChecked)
invalidBusinessType = true;
}
if (invalidBusinessType)
throw new UserError(`The type of business must be filled in basic data`);
});
Self.observe('before save', async function(ctx) {
const changes = ctx.data || ctx.instance;
const orgData = ctx.currentInstance;
@ -206,7 +223,7 @@ module.exports = Self => {
&& orgData.isTaxDataChecked != isTaxDataChecked;
if ((socialNameChanged || dataCheckedChanged) && !isAlpha(socialName))
throw new UserError('The socialName has an invalid format');
throw new UserError(`The social name has an invalid format`);
if (changes.salesPerson === null) {
changes.credit = 0;
@ -267,7 +284,7 @@ module.exports = Self => {
replyTo: worker.email
};
await got.get(`${origin}/api/email/payment-update`, {
query: params
searchParams: params
});
}

View File

@ -16,10 +16,7 @@
"uri": {
"type": "String"
},
"user": {
"type": "String"
},
"password": {
"apiKey": {
"type": "String"
},
"title": {

View File

@ -26,8 +26,7 @@
"required": true
},
"statusCode": {
"type": "Number",
"required": true
"type": "Number"
},
"status": {
"type": "String"

View File

@ -82,7 +82,7 @@ class Controller extends Dialog {
}
set amountToReturn(value) {
if (!value) return;
if (isNaN(value)) return;
value = value.toFixed(2);

View File

@ -1,4 +1,4 @@
const app = require('vn-loopback/server/server');
const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context');
describe('entry addBuy()', () => {
@ -25,11 +25,11 @@ describe('entry addBuy()', () => {
packageFk: 3
};
const tx = await app.models.Entry.beginTransaction({});
const tx = await models.Entry.beginTransaction({});
const options = {transaction: tx};
try {
const newBuy = await app.models.Entry.addBuy(ctx, options);
const newBuy = await models.Entry.addBuy(ctx, options);
expect(newBuy.itemFk).toEqual(itemId);

View File

@ -1,4 +1,4 @@
const app = require('vn-loopback/server/server');
const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context');
describe('sale deleteBuys()', () => {
@ -15,13 +15,13 @@ describe('sale deleteBuys()', () => {
active: activeCtx
});
const tx = await app.models.Entry.beginTransaction({});
const tx = await models.Entry.beginTransaction({});
const options = {transaction: tx};
ctx.args = {buys: [{id: 1}]};
try {
const result = await app.models.Buy.deleteBuys(ctx, options);
const result = await models.Buy.deleteBuys(ctx, options);
expect(result).toEqual([{count: 1}]);
await tx.rollback();

View File

@ -1,9 +1,8 @@
const app = require('vn-loopback/server/server');
const model = app.models.Buy;
const models = require('vn-loopback/server/server').models;
describe('Buy editLatestsBuys()', () => {
it('should change the value of a given column for the selected buys', async() => {
const tx = await app.models.Entry.beginTransaction({});
const tx = await models.Buy.beginTransaction({});
const options = {transaction: tx};
try {
@ -13,15 +12,15 @@ describe('Buy editLatestsBuys()', () => {
}
};
const [original] = await model.latestBuysFilter(ctx, null, options);
const [original] = await models.Buy.latestBuysFilter(ctx, null, options);
const field = 'size';
const newValue = 99;
const lines = [{itemFk: original.itemFk, id: original.id}];
await model.editLatestBuys(field, newValue, lines, options);
await models.Buy.editLatestBuys(field, newValue, lines, options);
const [result] = await model.latestBuysFilter(ctx, null, options);
const [result] = await models.Buy.latestBuysFilter(ctx, null, options);
expect(result[field]).toEqual(newValue);

View File

@ -1,77 +1,137 @@
const app = require('vn-loopback/server/server');
const models = require('vn-loopback/server/server').models;
describe('Entry filter()', () => {
it('should return the entry matching "search"', async() => {
let ctx = {
args: {
search: 1
}
};
const tx = await models.Entry.beginTransaction({});
const options = {transaction: tx};
let result = await app.models.Entry.filter(ctx);
try {
const ctx = {
args: {
search: 1
}
};
expect(result.length).toEqual(1);
expect(result[0].id).toEqual(1);
const result = await models.Entry.filter(ctx, options);
expect(result.length).toEqual(1);
expect(result[0].id).toEqual(1);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should return the entry matching the currency', async() => {
let ctx = {
args: {
currencyFk: 1
}
};
const tx = await models.Entry.beginTransaction({});
const options = {transaction: tx};
let result = await app.models.Entry.filter(ctx);
try {
const ctx = {
args: {
currencyFk: 1
}
};
expect(result.length).toEqual(8);
const result = await models.Entry.filter(ctx, options);
expect(result.length).toEqual(8);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should return the entry matching the supplier', async() => {
let ctx = {
args: {
supplierFk: 2
}
};
const tx = await models.Entry.beginTransaction({});
const options = {transaction: tx};
let result = await app.models.Entry.filter(ctx);
try {
const ctx = {
args: {
supplierFk: 2
}
};
expect(result.length).toEqual(6);
const result = await models.Entry.filter(ctx, options);
expect(result.length).toEqual(6);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should return the entry matching the company', async() => {
let ctx = {
args: {
companyFk: 442
}
};
const tx = await models.Entry.beginTransaction({});
const options = {transaction: tx};
let result = await app.models.Entry.filter(ctx);
try {
const ctx = {
args: {
companyFk: 442
}
};
expect(result.length).toEqual(7);
const result = await models.Entry.filter(ctx, options);
expect(result.length).toEqual(7);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should return the entries matching isBooked', async() => {
let ctx = {
args: {
isBooked: true,
}
};
const tx = await models.Entry.beginTransaction({});
const options = {transaction: tx};
let result = await app.models.Entry.filter(ctx);
try {
const ctx = {
args: {
isBooked: true,
}
};
expect(result.length).toEqual(0);
const result = await models.Entry.filter(ctx, options);
expect(result.length).toEqual(0);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should return the routes matching the reference and travel', async() => {
let ctx = {
args: {
reference: 'movement',
travelFk: '2'
}
};
const tx = await models.Entry.beginTransaction({});
const options = {transaction: tx};
let result = await app.models.Entry.filter(ctx);
try {
const ctx = {
args: {
reference: 'movement',
travelFk: '2'
}
};
expect(result.length).toEqual(2);
const result = await models.Entry.filter(ctx, options);
expect(result.length).toEqual(2);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});

View File

@ -1,14 +1,24 @@
const app = require('vn-loopback/server/server');
const models = require('vn-loopback/server/server').models;
describe('entry getBuys()', () => {
const entryId = 4;
it('should get the buys and items of an entry', async() => {
const result = await app.models.Entry.getBuys(entryId);
const tx = await models.Entry.beginTransaction({});
const options = {transaction: tx};
const length = result.length;
const anyResult = result[Math.floor(Math.random() * Math.floor(length))];
try {
const result = await models.Entry.getBuys(entryId, options);
expect(result.length).toEqual(4);
expect(anyResult.item).toBeDefined();
const length = result.length;
const anyResult = result[Math.floor(Math.random() * Math.floor(length))];
expect(result.length).toEqual(4);
expect(anyResult.item).toBeDefined();
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});

View File

@ -1,31 +1,71 @@
const app = require('vn-loopback/server/server');
const models = require('vn-loopback/server/server').models;
describe('travel getEntry()', () => {
const entryId = 1;
it('should check the entry contains the id', async() => {
const entry = await app.models.Entry.getEntry(entryId);
const tx = await models.Entry.beginTransaction({});
const options = {transaction: tx};
expect(entry.id).toEqual(entryId);
try {
const entry = await models.Entry.getEntry(entryId, options);
expect(entry.id).toEqual(entryId);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should check the entry contains the supplier name', async() => {
const entry = await app.models.Entry.getEntry(entryId);
const supplierName = entry.supplier().nickname;
const tx = await models.Entry.beginTransaction({});
const options = {transaction: tx};
expect(supplierName).toEqual('Plants nick');
try {
const entry = await models.Entry.getEntry(entryId, options);
const supplierName = entry.supplier().nickname;
expect(supplierName).toEqual('Plants nick');
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should check the entry contains the receiver warehouse name', async() => {
const entry = await app.models.Entry.getEntry(entryId);
const receiverWarehouseName = entry.travel().warehouseIn().name;
const tx = await models.Entry.beginTransaction({});
const options = {transaction: tx};
expect(receiverWarehouseName).toEqual('Warehouse One');
try {
const entry = await models.Entry.getEntry(entryId, options);
const receiverWarehouseName = entry.travel().warehouseIn().name;
expect(receiverWarehouseName).toEqual('Warehouse One');
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should check the entry contains the company code', async() => {
const entry = await app.models.Entry.getEntry(entryId);
const companyCode = entry.company().code;
const tx = await models.Entry.beginTransaction({});
const options = {transaction: tx};
expect(companyCode).toEqual('VNL');
try {
const entry = await models.Entry.getEntry(entryId, options);
const companyCode = entry.company().code;
expect(companyCode).toEqual('VNL');
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});

View File

@ -1,4 +1,4 @@
const app = require('vn-loopback/server/server');
const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context');
describe('entry import()', () => {
@ -48,10 +48,10 @@ describe('entry import()', () => {
]
}
};
const tx = await app.models.Entry.beginTransaction({});
const tx = await models.Entry.beginTransaction({});
try {
const options = {transaction: tx};
const newEntry = await app.models.Entry.create({
const newEntry = await models.Entry.create({
dated: new Date(),
supplierFk: supplierId,
travelFk: travelId,
@ -60,10 +60,10 @@ describe('entry import()', () => {
ref: 'Entry ref'
}, options);
await app.models.Entry.importBuys(ctx, newEntry.id, options);
await models.Entry.importBuys(ctx, newEntry.id, options);
const updatedEntry = await app.models.Entry.findById(newEntry.id, null, options);
const entryBuys = await app.models.Buy.find({
const updatedEntry = await models.Entry.findById(newEntry.id, null, options);
const entryBuys = await models.Buy.find({
where: {entryFk: newEntry.id}
}, options);

View File

@ -1,4 +1,4 @@
const app = require('vn-loopback/server/server');
const models = require('vn-loopback/server/server').models;
const LoopBackContext = require('loopback-context');
describe('entry importBuysPreview()', () => {
@ -10,30 +10,40 @@ describe('entry importBuysPreview()', () => {
});
it('should return the buys with the calculated packageFk', async() => {
const expectedPackageFk = '3';
const buys = [
{
itemFk: 1,
buyingValue: 5.77,
description: 'Bow',
grouping: 1,
size: 1,
volume: 1200
},
{
itemFk: 4,
buyingValue: 2.16,
description: 'Arrow',
grouping: 1,
size: 25,
volume: 1125
}
];
const tx = await models.Entry.beginTransaction({});
const options = {transaction: tx};
const result = await app.models.Entry.importBuysPreview(entryId, buys);
const randomIndex = Math.floor(Math.random() * result.length);
const buy = result[randomIndex];
try {
const expectedPackageFk = '3';
const buys = [
{
itemFk: 1,
buyingValue: 5.77,
description: 'Bow',
grouping: 1,
size: 1,
volume: 1200
},
{
itemFk: 4,
buyingValue: 2.16,
description: 'Arrow',
grouping: 1,
size: 25,
volume: 1125
}
];
expect(buy.packageFk).toEqual(expectedPackageFk);
const result = await models.Entry.importBuysPreview(entryId, buys, options);
const randomIndex = Math.floor(Math.random() * result.length);
const buy = result[randomIndex];
expect(buy.packageFk).toEqual(expectedPackageFk);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});

View File

@ -1,195 +1,345 @@
const app = require('vn-loopback/server/server');
const models = require('vn-loopback/server/server').models;
describe('Buy latests buys filter()', () => {
it('should return the entry matching "search"', async() => {
let ctx = {
args: {
search: 'Ranged weapon longbow 2m'
}
};
const tx = await models.Buy.beginTransaction({});
const options = {transaction: tx};
let results = await app.models.Buy.latestBuysFilter(ctx);
let firstBuy = results[0];
try {
const ctx = {
args: {
search: 'Ranged weapon longbow 2m'
}
};
expect(results.length).toEqual(1);
expect(firstBuy.size).toEqual(70);
const results = await models.Buy.latestBuysFilter(ctx);
const firstBuy = results[0];
expect(results.length).toEqual(1);
expect(firstBuy.size).toEqual(70);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should return the entry matching "id"', async() => {
let ctx = {
args: {
id: 1
}
};
const tx = await models.Buy.beginTransaction({});
const options = {transaction: tx};
let results = await app.models.Buy.latestBuysFilter(ctx);
try {
const ctx = {
args: {
id: 1
}
};
expect(results.length).toEqual(1);
const results = await models.Buy.latestBuysFilter(ctx, options);
expect(results.length).toEqual(1);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should return results matching "tags"', async() => {
let ctx = {
args: {
tags: [
{tagFk: 27, value: '2m'}
]
}
};
const tx = await models.Buy.beginTransaction({});
const options = {transaction: tx};
let results = await app.models.Buy.latestBuysFilter(ctx);
try {
const ctx = {
args: {
tags: [
{tagFk: 27, value: '2m'}
]
}
};
expect(results.length).toBe(2);
const results = await models.Buy.latestBuysFilter(ctx, options);
expect(results.length).toBe(2);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should return results matching "categoryFk"', async() => {
let ctx = {
args: {
categoryFk: 1
}
};
const tx = await models.Buy.beginTransaction({});
const options = {transaction: tx};
let results = await app.models.Buy.latestBuysFilter(ctx);
try {
const ctx = {
args: {
categoryFk: 1
}
};
expect(results.length).toBe(4);
const results = await models.Buy.latestBuysFilter(ctx, options);
expect(results.length).toBe(4);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should return results matching "typeFk"', async() => {
let ctx = {
args: {
typeFk: 2
}
};
const tx = await models.Buy.beginTransaction({});
const options = {transaction: tx};
let results = await app.models.Buy.latestBuysFilter(ctx);
try {
const ctx = {
args: {
typeFk: 2
}
};
expect(results.length).toBe(4);
const results = await models.Buy.latestBuysFilter(ctx, options);
expect(results.length).toBe(4);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should return results matching "active"', async() => {
let ctx = {
args: {
active: true
}
};
const tx = await models.Buy.beginTransaction({});
const options = {transaction: tx};
let results = await app.models.Buy.latestBuysFilter(ctx);
try {
const ctx = {
args: {
active: true
}
};
expect(results.length).toBe(6);
const results = await models.Buy.latestBuysFilter(ctx, options);
expect(results.length).toBe(6);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should return results matching "not active"', async() => {
let ctx = {
args: {
active: false
}
};
const tx = await models.Buy.beginTransaction({});
const options = {transaction: tx};
let results = await app.models.Buy.latestBuysFilter(ctx);
try {
const ctx = {
args: {
active: false
}
};
expect(results.length).toBe(0);
const results = await models.Buy.latestBuysFilter(ctx, options);
expect(results.length).toBe(0);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should return results matching "visible"', async() => {
let ctx = {
args: {
visible: true
}
};
const tx = await models.Buy.beginTransaction({});
const options = {transaction: tx};
let results = await app.models.Buy.latestBuysFilter(ctx);
try {
const ctx = {
args: {
visible: true
}
};
expect(results.length).toBe(5);
const results = await models.Buy.latestBuysFilter(ctx, options);
expect(results.length).toBe(5);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should return results matching "not visible"', async() => {
let ctx = {
args: {
visible: false
}
};
const tx = await models.Buy.beginTransaction({});
const options = {transaction: tx};
let results = await app.models.Buy.latestBuysFilter(ctx);
try {
const ctx = {
args: {
visible: false
}
};
expect(results.length).toBe(0);
const results = await models.Buy.latestBuysFilter(ctx, options);
expect(results.length).toBe(0);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should return results matching "floramondo"', async() => {
let ctx = {
args: {
floramondo: true
}
};
const tx = await models.Buy.beginTransaction({});
const options = {transaction: tx};
let results = await app.models.Buy.latestBuysFilter(ctx);
try {
const ctx = {
args: {
floramondo: true
}
};
expect(results.length).toBe(1);
const results = await models.Buy.latestBuysFilter(ctx, options);
expect(results.length).toBe(1);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should return results matching "not floramondo"', async() => {
let ctx = {
args: {
floramondo: false
}
};
const tx = await models.Buy.beginTransaction({});
const options = {transaction: tx};
let results = await app.models.Buy.latestBuysFilter(ctx);
try {
const ctx = {
args: {
floramondo: false
}
};
expect(results.length).toBe(5);
const results = await models.Buy.latestBuysFilter(ctx, options);
expect(results.length).toBe(5);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should return results matching "salesPersonFk"', async() => {
let ctx = {
args: {
salesPersonFk: 35
}
};
const tx = await models.Buy.beginTransaction({});
const options = {transaction: tx};
let results = await app.models.Buy.latestBuysFilter(ctx);
try {
const ctx = {
args: {
salesPersonFk: 35
}
};
expect(results.length).toBe(6);
const results = await models.Buy.latestBuysFilter(ctx, options);
expect(results.length).toBe(6);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should return results matching "description"', async() => {
let ctx = {
args: {
description: 'Increases block'
}
};
const tx = await models.Buy.beginTransaction({});
const options = {transaction: tx};
let results = await app.models.Buy.latestBuysFilter(ctx);
try {
const ctx = {
args: {
description: 'Increases block'
}
};
expect(results.length).toBe(1);
const results = await models.Buy.latestBuysFilter(ctx, options);
expect(results.length).toBe(1);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should return results matching "supplierFk"', async() => {
let ctx = {
args: {
supplierFk: 1
}
};
const tx = await models.Buy.beginTransaction({});
const options = {transaction: tx};
let results = await app.models.Buy.latestBuysFilter(ctx);
try {
const ctx = {
args: {
supplierFk: 1
}
};
expect(results.length).toBe(2);
const results = await models.Buy.latestBuysFilter(ctx, options);
expect(results.length).toBe(2);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should return results matching "from" and "to"', async() => {
const from = new Date();
from.setHours(0, 0, 0, 0);
const tx = await models.Buy.beginTransaction({});
const options = {transaction: tx};
const to = new Date();
to.setHours(23, 59, 59, 999);
try {
const from = new Date();
from.setHours(0, 0, 0, 0);
let ctx = {
args: {
from: from,
to: to
}
};
const to = new Date();
to.setHours(23, 59, 59, 999);
let results = await app.models.Buy.latestBuysFilter(ctx);
const ctx = {
args: {
from: from,
to: to
}
};
expect(results.length).toBe(2);
const results = await models.Buy.latestBuysFilter(ctx, options);
expect(results.length).toBe(2);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});

View File

@ -179,7 +179,7 @@
ng-click="$ctrl.selectItem(item.id)">
<vn-td shrink>
<span
ng-click="itemDescriptor.show($event, item.id)"
vn-click-stop="itemDescriptor.show($event, item.id)"
class="link">
{{::item.id}}
</span>

View File

@ -1,6 +1,7 @@
<vn-crud-model
vn-id="model"
url="Buys/latestBuysFilter"
order="itemFk DESC"
limit="20"
data="$ctrl.buys"
auto-load="true">
@ -34,8 +35,8 @@
</vn-multi-check>
</th>
<th translate>Picture</th>
<th field="id">
<span translate>Identifier</span>
<th field="itemFk">
<span translate>Item ID</span>
</th>
<th field="packing" number>
<span translate>Packing</span>

View File

@ -58,7 +58,7 @@ module.exports = Self => {
}, myOptions);
const response = got.stream(`${origin}/api/report/invoice`, {
query: {
searchParams: {
authorization: auth.id,
invoiceId: id
}

View File

@ -23,6 +23,6 @@ describe('InvoiceOut download()', () => {
const result = await models.InvoiceOut.download(ctx, invoiceId);
expect(result[1]).toEqual('application/pdf');
expect(result[2]).toEqual('filename="2021T1111111.pdf"');
expect(result[2]).toMatch(/filename="\d{4}T1111111.pdf"/);
});
});

View File

@ -112,7 +112,10 @@ module.exports = Self => {
case 'search':
return /^\d+$/.test(value)
? {or: [{'i.id': value}, codeWhere]}
: {or: [{'i.name': {like: `%${value}%`}}, codeWhere]};
: {or: [
{'i.name': {like: `%${value}%`}},
{'i.longName': {like: `%${value}%`}},
codeWhere]};
case 'id':
case 'isActive':
case 'typeFk':

View File

@ -296,7 +296,7 @@
ng-click="$ctrl.selectItem(item.id)">
<vn-td shrink>
<span
ng-click="itemDescriptor.show($event, item.id)"
vn-click-stop="itemDescriptor.show($event, item.id)"
class="link">
{{::item.id}}
</span>

View File

@ -160,7 +160,7 @@ module.exports = Self => {
stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.filter');
stmt = new ParameterizedSQL(
`CREATE TEMPORARY TABLE tmp.filter
(INDEX (id))
(PRIMARY KEY (id))
ENGINE = MEMORY
SELECT
t.id,
@ -221,7 +221,7 @@ module.exports = Self => {
stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.clientGetDebt');
stmts.push(`
CREATE TEMPORARY TABLE tmp.clientGetDebt
(INDEX (clientFk))
(PRIMARY KEY (clientFk))
ENGINE = MEMORY
SELECT DISTINCT clientFk FROM tmp.filter`);
@ -232,7 +232,7 @@ module.exports = Self => {
stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.tickets');
stmt = new ParameterizedSQL(`
CREATE TEMPORARY TABLE tmp.tickets
(INDEX (id))
(PRIMARY KEY (id))
ENGINE = MEMORY
SELECT f.*, r.risk AS debt
FROM tmp.filter f

View File

@ -11,7 +11,7 @@ describe('SalesMonitor salesFilter()', () => {
const filter = {order: 'id DESC'};
const result = await models.SalesMonitor.salesFilter(ctx, filter, options);
expect(result.length).toEqual(24);
expect(result.length).toEqual(27);
await tx.rollback();
} catch (e) {
@ -39,7 +39,7 @@ describe('SalesMonitor salesFilter()', () => {
const filter = {};
const result = await models.SalesMonitor.salesFilter(ctx, filter, options);
expect(result.length).toEqual(13);
expect(result.length).toEqual(16);
await tx.rollback();
} catch (e) {
@ -87,7 +87,7 @@ describe('SalesMonitor salesFilter()', () => {
const filter = {};
const result = await models.SalesMonitor.salesFilter(ctx, filter, options);
expect(result.length).toEqual(24);
expect(result.length).toEqual(27);
await tx.rollback();
} catch (e) {
@ -130,7 +130,7 @@ describe('SalesMonitor salesFilter()', () => {
const length = result.length;
const anyResult = result[Math.floor(Math.random() * Math.floor(length))];
expect(length).toEqual(7);
expect(length).toEqual(10);
expect(anyResult.state).toMatch(/(Libre|Arreglar)/);
await tx.rollback();
@ -175,7 +175,7 @@ describe('SalesMonitor salesFilter()', () => {
const filter = {};
const result = await models.SalesMonitor.salesFilter(ctx, filter, options);
expect(result.length).toEqual(20);
expect(result.length).toEqual(23);
await tx.rollback();
} catch (e) {

View File

@ -5,6 +5,7 @@ Search tickets: Buscar tickets
Delete selected elements: Eliminar los elementos seleccionados
All the selected elements will be deleted. Are you sure you want to continue?: Todos los elementos seleccionados serán eliminados. ¿Seguro que quieres continuar?
Component lack: Faltan componentes
Ticket too little: Ticket demasiado pequeño
Minimize/Maximize: Minimizar/Maximizar
Problems: Problemas
Theoretical: Teórica

View File

@ -2,7 +2,7 @@
vn-id="model"
url="SalesMonitors/salesFilter"
limit="20"
order="shippedDate DESC, preparationHour ASC, zoneLanding ASC, id">
order="shipped DESC, theoreticalHour, id">
</vn-crud-model>
<vn-portal slot="topbar">
<vn-searchbar
@ -27,11 +27,13 @@
view-config-id="ticketsMonitor"
options="$ctrl.smartTableOptions"
expr-builder="$ctrl.exprBuilder(param, value)">
<slot-actions><vn-check
label="Auto-refresh"
vn-tooltip="Toggle auto-refresh every 2 minutes"
on-change="$ctrl.autoRefresh(value)">
</vn-check></slot-actions>
<slot-actions>
<vn-check
label="Auto-refresh"
vn-tooltip="Toggle auto-refresh every 2 minutes"
on-change="$ctrl.autoRefresh(value)">
</vn-check>
</slot-actions>
<slot-table>
<table>
<thead>
@ -120,6 +122,12 @@
class="bright"
icon="icon-components">
</vn-icon>
<vn-icon
ng-show="::ticket.isTooLittle"
translate-attr="{title: 'Ticket too little'}"
class="bright"
icon="icon-isTooLittle">
</vn-icon>
</td>
<td>
<span
@ -167,7 +175,7 @@
{{::ticket.state}}
</span>
</td>
<td>
<td name="zone">
<span
title="{{::ticket.zoneName}}"
vn-click-stop="zoneDescriptor.show($event, ticket.zoneFk)"

View File

@ -29,11 +29,19 @@ vn-monitor-sales-tickets {
height: 736px
}
vn-tbody a[ng-repeat].vn-tr:focus {
tbody tr[ng-repeat]:focus {
background-color: $color-primary-light
}
.highRisk i {
color: $color-alert
}
td[name="nickname"] {
max-width: 200px
}
td[name="zone"] {
max-width: 150px
}
}

View File

@ -10,7 +10,12 @@
],
"card": []
},
"keybindings": [],
"keybindings": [
{
"key": "m",
"state": "monitor.index"
}
],
"routes": [
{
"url": "/monitor",

View File

@ -21,22 +21,42 @@ module.exports = Self => {
}
});
Self.addToOrder = async params => {
let isEditable = await Self.app.models.Order.isEditable(params.orderFk);
Self.addToOrder = async(params, options) => {
const myOptions = {};
let tx;
if (!isEditable)
throw new UserError('This order is not editable');
if (typeof options == 'object')
Object.assign(myOptions, options);
let promises = [];
params.items.forEach(item => {
promises.push(
Self.rawSql(
`CALL hedera.order_addItem(?, ?, ?, ?)`,
[params.orderFk, item.warehouseFk, item.itemFk, item.quantity]
)
);
});
await Promise.all(promises);
return true;
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
try {
const isEditable = await Self.app.models.Order.isEditable(params.orderFk, myOptions);
if (!isEditable)
throw new UserError('This order is not editable');
const promises = [];
for (const item of params.items) {
promises.push(
Self.rawSql(
`CALL hedera.order_addItem(?, ?, ?, ?)`,
[params.orderFk, item.warehouseFk, item.itemFk, item.quantity],
myOptions
)
);
}
await Promise.all(promises);
if (tx) await tx.commit();
return true;
} catch (e) {
if (tx) await tx.rollback();
throw e;
}
};
};

View File

@ -21,19 +21,39 @@ module.exports = Self => {
}
});
Self.removes = async params => {
if (!params.rows || !params.rows.length)
throw new UserError('There is nothing to delete');
Self.removes = async(params, options) => {
const myOptions = {};
let tx;
let isEditable = await Self.app.models.Order.isEditable(params.actualOrderId);
if (typeof options == 'object')
Object.assign(myOptions, options);
if (!isEditable)
throw new UserError('This order is not editable');
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
let promises = [];
for (let i = 0; i < params.rows.length; i++)
promises.push(Self.app.models.OrderRow.destroyById(params.rows[i]));
try {
if (!params.rows || !params.rows.length)
throw new UserError('There is nothing to delete');
return await Promise.all(promises);
const isEditable = await Self.app.models.Order.isEditable(params.actualOrderId, myOptions);
if (!isEditable)
throw new UserError('This order is not editable');
const promises = [];
for (let i = 0; i < params.rows.length; i++)
promises.push(Self.app.models.OrderRow.destroyById(params.rows[i], myOptions));
const deletions = await Promise.all(promises);
if (tx) await tx.commit();
return deletions;
} catch (e) {
if (tx) await tx.rollback();
throw e;
}
};
};

View File

@ -1,32 +1,36 @@
const app = require('vn-loopback/server/server');
const models = require('vn-loopback/server/server').models;
describe('order addToOrder()', () => {
const orderId = 8;
let rowToDelete;
afterAll(async() => {
await app.models.OrderRow.removes({rows: [rowToDelete], actualOrderId: orderId});
});
it('should add a row to a given order', async() => {
let unmodifiedRows = await app.models.OrderRow.find({where: {orderFk: orderId}});
const tx = await models.Order.beginTransaction({});
expect(unmodifiedRows.length).toBe(2);
try {
const options = {transaction: tx};
let params = {
orderFk: orderId,
items: [{
itemFk: 1,
quantity: 10,
warehouseFk: 1
}]
};
const unmodifiedRows = await models.OrderRow.find({where: {orderFk: orderId}}, options);
await app.models.OrderRow.addToOrder(params);
expect(unmodifiedRows.length).toBe(2);
let modifiedRows = await app.models.OrderRow.find({where: {orderFk: orderId}});
const params = {
orderFk: orderId,
items: [{
itemFk: 1,
quantity: 10,
warehouseFk: 1
}]
};
rowToDelete = modifiedRows[modifiedRows.length - 1].id;
await models.OrderRow.addToOrder(params, options);
expect(modifiedRows.length).toBe(3);
const modifiedRows = await models.OrderRow.find({where: {orderFk: orderId}}, options);
expect(modifiedRows.length).toBe(3);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});

View File

@ -1,20 +1,18 @@
const app = require('vn-loopback/server/server');
const models = require('vn-loopback/server/server').models;
describe('order removes()', () => {
let row;
let newRow;
beforeAll(async() => {
row = await app.models.OrderRow.findOne({where: {id: 12}});
row.id = null;
newRow = await app.models.OrderRow.create(row);
});
it('should throw an error if rows property is empty', async() => {
const tx = await models.Order.beginTransaction({});
let error;
try {
await app.models.OrderRow.removes({rows: []});
const options = {transaction: tx};
await models.OrderRow.removes({rows: []}, options);
await tx.rollback();
} catch (e) {
await tx.rollback();
error = e;
}
@ -22,10 +20,17 @@ describe('order removes()', () => {
});
it('should throw an error if the row selected is not editable', async() => {
const tx = await models.Order.beginTransaction({});
let error;
try {
await app.models.OrderRow.removes({rows: [2]});
const options = {transaction: tx};
await models.OrderRow.removes({rows: [2]}, options);
await tx.rollback();
} catch (e) {
await tx.rollback();
error = e;
}
@ -33,13 +38,24 @@ describe('order removes()', () => {
});
it('should delete the row', async() => {
let params = {
rows: [newRow.id],
actualOrderId: 16
};
const tx = await models.Order.beginTransaction({});
let res = await app.models.OrderRow.removes(params);
try {
const options = {transaction: tx};
expect(res).toEqual([{count: 1}]);
const params = {
rows: [12],
actualOrderId: 16
};
const res = await models.OrderRow.removes(params, options);
expect(res).toEqual([{count: 1}]);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});

View File

@ -7,28 +7,28 @@ module.exports = Self => {
accepts: [
{
arg: 'orderFk',
type: 'Number',
type: 'number',
required: true
},
{
arg: 'orderBy',
type: 'Object',
type: 'object',
description: 'Items order',
required: true
},
{
arg: 'filter',
type: 'Object',
type: 'object',
description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string'
},
{
arg: 'tagGroups',
type: ['Object'],
type: ['object'],
description: 'Filter by tag'
},
],
returns: {
type: ['Object'],
type: ['object'],
root: true,
},
http: {
@ -37,8 +37,13 @@ module.exports = Self => {
},
});
Self.catalogFilter = async(orderFk, orderBy, filter, tagGroups) => {
let conn = Self.dataSource.connector;
Self.catalogFilter = async(orderFk, orderBy, filter, tagGroups, options) => {
const conn = Self.dataSource.connector;
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
const stmts = [];
let stmt;
@ -85,7 +90,7 @@ module.exports = Self => {
stmts.push(stmt);
// Calculate items
const order = await Self.findById(orderFk);
const order = await Self.findById(orderFk, null, myOptions);
stmts.push(new ParameterizedSQL(
'CALL vn.catalog_calculate(?, ?, ?)', [
order.landed,
@ -131,9 +136,9 @@ module.exports = Self => {
params: [orderBy.field],
});
let way = orderBy.way == 'DESC' ? 'DESC' : 'ASC';
let tag = await Self.app.models.Tag.findById(orderBy.field);
let orderSql = `
const way = orderBy.way == 'DESC' ? 'DESC' : 'ASC';
const tag = await Self.app.models.Tag.findById(orderBy.field, null, myOptions);
const orderSql = `
ORDER BY
itg.value IS NULL,
${tag.isQuantitative ? 'CAST(itg.value AS SIGNED)' : 'itg.value'}
@ -181,7 +186,7 @@ module.exports = Self => {
stmts.push('CALL vn.ticketCalculatePurge()');
const sql = ParameterizedSQL.join(stmts, ';');
const result = await conn.executeStmt(sql);
const result = await conn.executeStmt(sql, myOptions);
// Add prices to items
result[itemsIndex].forEach(item => {

View File

@ -21,7 +21,10 @@ module.exports = Self => {
Self.confirm = async(ctx, orderFk) => {
const userId = ctx.req.accessToken.userId;
let query = `CALL hedera.order_confirmWithUser(?, ?)`;
return await Self.rawSql(query, [orderFk, userId]);
const query = `CALL hedera.order_confirmWithUser(?, ?)`;
const response = await Self.rawSql(query, [orderFk, userId]);
return response;
};
};

View File

@ -9,60 +9,60 @@ module.exports = Self => {
accepts: [
{
arg: 'ctx',
type: 'Object',
type: 'object',
http: {source: 'context'}
}, {
arg: 'filter',
type: 'Object',
description: `Filter defining where, order, offset, and limit - must be a JSON-encoded string`
type: 'object',
description: 'Filter defining where, order, offset, and limit - must be a JSON-encoded string'
}, {
arg: 'search',
type: 'String',
type: 'string',
description: `If it's and integer searchs by id, otherwise it searchs by nickname`
}, {
arg: 'from',
type: 'Date',
description: `The from date`
type: 'date',
description: 'The from date'
}, {
arg: 'to',
type: 'Date',
description: `The to date`
type: 'date',
description: 'The to date'
}, {
arg: 'id',
type: 'Integer',
description: `The ticket id`
type: 'integer',
description: 'The ticket id'
}, {
arg: 'clientFk',
type: 'Integer',
description: `The client id`
type: 'integer',
description: 'The client id'
}, {
arg: 'ticketFk',
type: 'Integer',
description: `The ticket id`
type: 'integer',
description: 'The ticket id'
}, {
arg: 'agencyModeFk',
type: 'Integer',
description: `The agency mode id`
type: 'integer',
description: 'The agency mode id'
}, {
arg: 'workerFk',
type: 'Integer',
description: `The salesperson id`
type: 'integer',
description: 'The salesperson id'
}, {
arg: 'myTeam',
type: 'Boolean',
description: `Whether to show only tickets for the current logged user team (For now it shows only the current user tickets)`
type: 'boolean',
description: 'Whether to show only tickets for the current logged user team (currently user tickets)'
}, {
arg: 'isConfirmed',
type: 'Boolean',
description: `Order is confirmed`
type: 'boolean',
description: 'Order is confirmed'
}, {
arg: 'showEmpty',
type: 'boolean',
description: `Show empty orders`
description: 'Show empty orders'
}
],
returns: {
type: ['Object'],
type: ['object'],
root: true
},
http: {
@ -71,34 +71,35 @@ module.exports = Self => {
}
});
Self.filter = async(ctx, filter) => {
let conn = Self.dataSource.connector;
let worker = await Self.app.models.Worker.findOne({
where: {userFk: ctx.req.accessToken.userId},
include: [
{relation: 'collegues'}
]
});
Self.filter = async(ctx, filter, options) => {
const conn = Self.dataSource.connector;
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
const args = ctx.args;
let teamIds = [];
if (worker.collegues().length && args.myTeam) {
worker.collegues().forEach(collegue => {
teamIds.push(collegue.collegueFk);
});
}
// Apply filter by team
const teamMembersId = [];
if (args.myTeam != null) {
const worker = await models.Worker.findById(userId, {
include: {
relation: 'collegues'
}
}, myOptions);
const collegues = worker.collegues() || [];
for (let collegue of collegues)
teamMembersId.push(collegue.collegueFk);
if (worker.collegues().length === 0 && args.myTeam) {
worker = await Self.app.models.Worker.findOne({
fields: ['id'],
where: {userFk: ctx.req.accessToken.userId}
});
teamIds = [worker && worker.id];
if (teamMembersId.length == 0)
teamMembersId.push(userId);
}
if (args && args.myTeam)
args.teamIds = teamIds;
let where = buildFilter(args, (param, value) => {
const where = buildFilter(args, (param, value) => {
switch (param) {
case 'search':
return /^\d+$/.test(value)
@ -123,7 +124,10 @@ module.exports = Self => {
case 'isConfirmed':
return {'o.confirmed': value ? 1 : 0};
case 'myTeam':
return {'c.salesPersonFk': {inq: teamIds}};
if (value)
return {'c.salesPersonFk': {inq: teamMembersId}};
else
return {'c.salesPersonFk': {nin: teamMembersId}};
case 'showEmpty':
return {'o.total': {neq: value}};
case 'id':
@ -133,7 +137,7 @@ module.exports = Self => {
});
filter = mergeFilters(filter, {where});
let stmts = [];
const stmts = [];
let stmt;
stmt = new ParameterizedSQL(
@ -183,7 +187,7 @@ module.exports = Self => {
stmts.push(`DROP TEMPORARY TABLE tmp.filter`);
const sql = ParameterizedSQL.join(stmts, ';');
const result = await conn.executeStmt(sql);
const result = await conn.executeStmt(sql, myOptions);
return result[ordersIndex];
};

View File

@ -3,7 +3,7 @@ const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
module.exports = Self => {
Self.remoteMethod('getItemTypeAvailable', {
description: 'Gets the item types available for an rder and item category ',
description: 'Gets the item types available for an order and item category',
accessType: 'READ',
accepts: [{
arg: 'id',
@ -27,11 +27,16 @@ module.exports = Self => {
}
});
Self.getItemTypeAvailable = async(orderId, itemCategoryId) => {
Self.getItemTypeAvailable = async(orderId, itemCategoryId, options) => {
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
const stmts = [];
let stmt;
const order = await app.models.Order.findById(orderId);
const order = await app.models.Order.findById(orderId, null, myOptions);
stmt = new ParameterizedSQL('call vn.available_calc(?, ?, ?)', [
order.landed,
order.addressFk,
@ -78,7 +83,7 @@ module.exports = Self => {
stmts.push('DROP TEMPORARY TABLE tmp.item');
const sql = ParameterizedSQL.join(stmts, ';');
const result = await Self.rawStmt(sql);
const result = await Self.rawStmt(sql, myOptions);
return result[categoriesIndex];
};

View File

@ -3,7 +3,7 @@ module.exports = Self => {
description: 'Gets the sourceApp type set',
accessType: 'READ',
returns: {
type: ['String'],
type: ['string'],
root: true
},
http: {

View File

@ -21,10 +21,14 @@ module.exports = Self => {
}
});
Self.getTaxes = async orderFk => {
let conn = Self.dataSource.connector;
let stmts = [];
Self.getTaxes = async(orderFk, options) => {
const conn = Self.dataSource.connector;
const stmts = [];
let stmt;
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
stmts.push('DROP TEMPORARY TABLE IF EXISTS tmp.order');
@ -37,15 +41,15 @@ module.exports = Self => {
stmts.push('CALL hedera.order_getTax()');
let orderTaxIndex = stmts.push('SELECT * FROM tmp.orderAmount') - 1;
const orderTaxIndex = stmts.push('SELECT * FROM tmp.orderAmount') - 1;
stmts.push(`
DROP TEMPORARY TABLE
tmp.order,
tmp.orderTax`);
let sql = ParameterizedSQL.join(stmts, ';');
let result = await conn.executeStmt(sql);
const sql = ParameterizedSQL.join(stmts, ';');
const result = await conn.executeStmt(sql, myOptions);
return result[orderTaxIndex];
};

View File

@ -19,9 +19,14 @@ module.exports = Self => {
}
});
Self.getTotal = async orderFk => {
let query = `SELECT hedera.order_getTotal(?) total;`;
let [total] = await Self.rawSql(query, [orderFk]);
Self.getTotal = async(orderFk, options) => {
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
const query = `SELECT hedera.order_getTotal(?) total;`;
const [total] = await Self.rawSql(query, [orderFk], myOptions);
return total.total;
};

View File

@ -19,9 +19,14 @@ module.exports = Self => {
}
});
Self.getTotalVolume = async orderFk => {
let query = `SELECT vn.orderTotalVolume(?) totalVolume, vn.orderTotalVolumeBoxes(?) totalBoxes`;
let [res] = await Self.rawSql(query, [orderFk, orderFk]);
Self.getTotalVolume = async(orderFk, options) => {
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
const query = `SELECT vn.orderTotalVolume(?) totalVolume, vn.orderTotalVolumeBoxes(?) totalBoxes`;
const [res] = await Self.rawSql(query, [orderFk, orderFk], myOptions);
return res;
};
};

View File

@ -19,9 +19,14 @@ module.exports = Self => {
}
});
Self.getVAT = async orderId => {
Self.getVAT = async(orderId, options) => {
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
let totalTax = 0.00;
let taxes = await Self.app.models.Order.getTaxes(orderId);
const taxes = await Self.app.models.Order.getTaxes(orderId, myOptions);
taxes.forEach(tax => {
totalTax += tax.tax;
});

View File

@ -18,8 +18,13 @@ module.exports = Self => {
}
});
Self.getVolumes = async orderFk => {
let [volume] = await Self.rawSql(`CALL vn.orderListVolume(?)`, [orderFk]);
Self.getVolumes = async(orderFk, options) => {
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
const [volume] = await Self.rawSql(`CALL vn.orderListVolume(?)`, [orderFk], myOptions);
return volume;
};
};

View File

@ -19,8 +19,13 @@ module.exports = Self => {
}
});
Self.isEditable = async orderId => {
let exists = await Self.app.models.Order.findOne({
Self.isEditable = async(orderId, options) => {
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
const exists = await Self.app.models.Order.findOne({
where: {id: orderId},
fields: ['isConfirmed', 'clientFk'],
include: [
@ -32,7 +37,7 @@ module.exports = Self => {
}
}
]
});
}, myOptions);
if (exists && exists.client().type().code !== 'normal')
return true;

View File

@ -32,34 +32,52 @@ module.exports = Self => {
}
});
Self.new = async(landed, addressId, agencyModeId) => {
let address = await Self.app.models.Address.findOne({
where: {id: addressId},
fields: ['clientFk'],
include: [
{relation: 'client',
scope: {
include: {
relation: 'type'
}
}
}
]
});
Self.new = async(landed, addressId, agencyModeId, options) => {
const myOptions = {};
let tx;
if (address.client().type().code === 'normal') {
if (!address.client().isActive)
throw new UserError(`You can't create an order for a inactive client`);
if (typeof options == 'object')
Object.assign(myOptions, options);
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
query = `CALL vn.orderListCreate(?, ?, ?, ?);`;
[result] = await Self.rawSql(query, [
landed,
agencyModeId,
addressId,
'SALIX'
]);
try {
const address = await Self.app.models.Address.findOne({
where: {id: addressId},
fields: ['clientFk'],
include: [
{relation: 'client',
scope: {
include: {
relation: 'type'
}
}
}
]
}, myOptions);
return result[0].vOrderId;
if (address.client().type().code === 'normal') {
if (!address.client().isActive)
throw new UserError(`You can't create an order for an inactive client`);
}
query = `CALL vn.orderListCreate(?, ?, ?, ?);`;
[result] = await Self.rawSql(query, [
landed,
agencyModeId,
addressId,
'SALIX'
], myOptions);
if (tx) await tx.commit();
return result[0].vOrderId;
} catch (e) {
if (tx) await tx.rollback();
throw e;
}
};
};

View File

@ -18,17 +18,35 @@ module.exports = Self => {
}
});
Self.newFromTicket = async ticketFk => {
let ticket = await Self.app.models.Ticket.findOne({
where: {id: ticketFk}
});
Self.newFromTicket = async(ticketFk, options) => {
const myOptions = {};
let tx;
let landed = ticket.landed;
let addressFk = ticket.addressFk;
let agencyModeFk = ticket.agencyModeFk;
if (typeof options == 'object')
Object.assign(myOptions, options);
let orderID = await Self.app.models.Order.new(landed, addressFk, agencyModeFk);
if (!myOptions.transaction) {
tx = await Self.beginTransaction({});
myOptions.transaction = tx;
}
return orderID;
try {
const ticket = await Self.app.models.Ticket.findOne({
where: {id: ticketFk}
}, myOptions);
const landed = ticket.landed;
const addressFk = ticket.addressFk;
const agencyModeFk = ticket.agencyModeFk;
const orderID = await Self.app.models.Order.new(landed, addressFk, agencyModeFk, myOptions);
if (tx) await tx.commit();
return orderID;
} catch (e) {
if (tx) await tx.rollback();
throw e;
}
};
};

View File

@ -1,51 +1,73 @@
const app = require('vn-loopback/server/server');
const models = require('vn-loopback/server/server').models;
describe('order catalogFilter()', () => {
const colorTagId = 1;
const categoryTagId = 67;
it('should return an array of items', async() => {
let filter = {
where: {
categoryFk: 1,
typeFk: 2
}
};
let tags = [];
let orderFk = 11;
let orderBy = {field: 'relevancy DESC, name', way: 'DESC'};
let result = await app.models.Order.catalogFilter(orderFk, orderBy, filter, tags);
let firstItemId = result[0].id;
const tx = await models.Order.beginTransaction({});
expect(result.length).toEqual(4);
expect(firstItemId).toEqual(1);
try {
const options = {transaction: tx};
const filter = {
where: {
categoryFk: 1,
typeFk: 2
}
};
const tags = [];
const orderFk = 11;
const orderBy = {field: 'relevancy DESC, name', way: 'DESC'};
const result = await models.Order.catalogFilter(orderFk, orderBy, filter, tags, options);
const firstItemId = result[0].id;
expect(result.length).toEqual(4);
expect(firstItemId).toEqual(1);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should now return an array of items based on tag filter', async() => {
const filter = {
where: {
categoryFk: 1,
typeFk: 2
}
};
const tx = await models.Order.beginTransaction({});
const tagGroups = [
{tagFk: colorTagId, values: [{value: 'Silver'}, {value: 'Brown'}]},
{tagFk: categoryTagId, values: [{value: 'Concussion'}]}
];
const orderFk = 11;
const orderBy = {field: 'relevancy DESC, name', way: 'DESC'};
const result = await app.models.Order.catalogFilter(orderFk, orderBy, filter, tagGroups);
try {
const options = {transaction: tx};
const randomIndex = Math.round(Math.random());
const item = result[randomIndex];
const itemTags = item.tags;
const filter = {
where: {
categoryFk: 1,
typeFk: 2
}
};
const colorTag = itemTags.find(tag => tag.tagFk == colorTagId);
const categoryTag = itemTags.find(tag => tag.tagFk == categoryTagId);
const tagGroups = [
{tagFk: colorTagId, values: [{value: 'Silver'}, {value: 'Brown'}]},
{tagFk: categoryTagId, values: [{value: 'Concussion'}]}
];
const orderFk = 11;
const orderBy = {field: 'relevancy DESC, name', way: 'DESC'};
const result = await models.Order.catalogFilter(orderFk, orderBy, filter, tagGroups, options);
expect(result.length).toEqual(2);
expect(colorTag.value).toEqual('Silver');
expect(categoryTag.value).toEqual('Concussion');
const randomIndex = Math.round(Math.random());
const item = result[randomIndex];
const itemTags = item.tags;
const colorTag = itemTags.find(tag => tag.tagFk == colorTagId);
const categoryTag = itemTags.find(tag => tag.tagFk == categoryTagId);
expect(result.length).toEqual(2);
expect(colorTag.value).toEqual('Silver');
expect(categoryTag.value).toEqual('Concussion');
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});

View File

@ -1,4 +1,4 @@
const app = require('vn-loopback/server/server');
const models = require('vn-loopback/server/server').models;
describe('order filter()', () => {
const ctx = {
@ -8,51 +8,107 @@ describe('order filter()', () => {
};
it('should call the filter method with a basic search', async() => {
const filter = {where: {'o.id': 2}};
const result = await app.models.Order.filter(ctx, filter);
const orderId = result[0].id;
const myCtx = Object.assign({}, ctx);
const tx = await models.Order.beginTransaction({});
expect(orderId).toEqual(2);
try {
const options = {transaction: tx};
const filter = {where: {'o.id': 2}};
const result = await models.Order.filter(myCtx, filter, options);
const orderId = result[0].id;
expect(orderId).toEqual(2);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should call the filter method with a single advanced search', async() => {
const filter = {where: {'o.confirmed': false}};
const result = await app.models.Order.filter(ctx, filter);
const myCtx = Object.assign({}, ctx);
const tx = await models.Order.beginTransaction({});
expect(result.length).toEqual(16);
try {
const options = {transaction: tx};
const filter = {where: {'o.confirmed': false}};
const result = await models.Order.filter(myCtx, filter, options);
expect(result.length).toEqual(16);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should call the filter method with a complex advanced search', async() => {
const filter = {where: {'o.confirmed': false, 'c.salesPersonFk': 18}};
const result = await app.models.Order.filter(ctx, filter);
const myCtx = Object.assign({}, ctx);
const tx = await models.Order.beginTransaction({});
expect(result.length).toEqual(9);
expect(result[0].id).toEqual(7);
try {
const options = {transaction: tx};
const filter = {where: {'o.confirmed': false, 'c.salesPersonFk': 18}};
const result = await models.Order.filter(myCtx, filter, options);
expect(result.length).toEqual(9);
expect(result[0].id).toEqual(7);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should return the orders matching the showEmpty on false', async() => {
const filter = {};
ctx.args = {showEmpty: false};
const result = await app.models.Order.filter(ctx, filter);
const hasEmptyLines = result.some(order => {
return order.total === 0;
});
const myCtx = Object.assign({}, ctx);
const tx = await models.Order.beginTransaction({});
expect(hasEmptyLines).toBeFalsy();
try {
const options = {transaction: tx};
ctx.args = {showEmpty: null};
const filter = {};
myCtx.args = {showEmpty: false};
const result = await models.Order.filter(myCtx, filter, options);
const hasEmptyLines = result.some(order => {
return order.total === 0;
});
expect(hasEmptyLines).toBeFalsy();
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should return the orders matching the showEmpty on true', async() => {
const filter = {};
ctx.args = {showEmpty: true};
const result = await app.models.Order.filter(ctx, filter);
const hasEmptyLines = result.some(order => {
return order.total === 0;
});
const myCtx = Object.assign({}, ctx);
const tx = await models.Order.beginTransaction({});
expect(hasEmptyLines).toBeTruthy();
try {
const options = {transaction: tx};
ctx.args = {showEmpty: null};
const filter = {};
myCtx.args = {showEmpty: true};
const result = await models.Order.filter(myCtx, filter, options);
const hasEmptyLines = result.some(order => {
return order.total === 0;
});
expect(hasEmptyLines).toBeTruthy();
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});

View File

@ -1,19 +1,41 @@
const app = require('vn-loopback/server/server');
const models = require('vn-loopback/server/server').models;
describe('order getItemTypeAvailable()', () => {
it('should call the getItemTypeAvailable method with a valid order and item category', async() => {
let orderId = 11;
let itemCategoryId = 1;
let result = await app.models.Order.getItemTypeAvailable(orderId, itemCategoryId);
const tx = await models.Order.beginTransaction({});
expect(result.length).toEqual(1);
try {
const options = {transaction: tx};
const orderId = 11;
const itemCategoryId = 1;
const result = await models.Order.getItemTypeAvailable(orderId, itemCategoryId, options);
expect(result.length).toEqual(1);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should call the getItemTypeAvailable method with the same order and different item category', async() => {
let orderId = 11;
let itemCategoryId = 4;//
let result = await app.models.Order.getItemTypeAvailable(orderId, itemCategoryId);
const tx = await models.Order.beginTransaction({});
expect(result.length).toEqual(0);
try {
const options = {transaction: tx};
const orderId = 11;
const itemCategoryId = 4;
const result = await models.Order.getItemTypeAvailable(orderId, itemCategoryId, options);
expect(result.length).toEqual(0);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});

View File

@ -1,31 +1,75 @@
const app = require('vn-loopback/server/server');
const models = require('vn-loopback/server/server').models;
describe('order getTaxes()', () => {
it('should call the getTaxes method and return undefined if its called with a string', async() => {
let result = await app.models.Order.getTaxes('string');
const tx = await models.Order.beginTransaction({});
expect(result.length).toEqual(0);
try {
const options = {transaction: tx};
const result = await models.Order.getTaxes('string', options);
expect(result.length).toEqual(0);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should call the getTaxes method and return undefined if its called with unknown id', async() => {
let result = await app.models.Order.getTaxes(99999999999999999999999);
const tx = await models.Order.beginTransaction({});
expect(result.length).toEqual(0);
try {
const options = {transaction: tx};
const result = await models.Order.getTaxes(9999, options);
expect(result.length).toEqual(0);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should call the getTaxes method and return the taxes splited if different type of taxes', async() => {
let result = await app.models.Order.getTaxes(1);
const tx = await models.Order.beginTransaction({});
const expectedResult = result[0].tax + result[1].tax;
try {
const options = {transaction: tx};
expect(expectedResult).toEqual(20.29);
expect(result.length).toEqual(2);
const result = await models.Order.getTaxes(1, options);
const expectedResult = result[0].tax + result[1].tax;
expect(expectedResult).toEqual(20.29);
expect(result.length).toEqual(2);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should call the getTaxes method and return the taxes for them same type', async() => {
let result = await app.models.Order.getTaxes(2);
const tx = await models.Order.beginTransaction({});
expect(result[0].tax).toEqual(9.1);
expect(result.length).toEqual(1);
try {
const options = {transaction: tx};
const result = await models.Order.getTaxes(2, options);
expect(result[0].tax).toEqual(9.1);
expect(result.length).toEqual(1);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});

View File

@ -1,9 +1,19 @@
const app = require('vn-loopback/server/server');
const models = require('vn-loopback/server/server').models;
describe('order getTotal()', () => {
it('should return the order total', async() => {
let result = await app.models.Order.getTotal(1);
const tx = await models.Order.beginTransaction({});
expect(result).toEqual(155.89);
try {
const options = {transaction: tx};
const result = await models.Order.getTotal(1, options);
expect(result).toEqual(155.89);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});

View File

@ -1,10 +1,21 @@
const app = require('vn-loopback/server/server');
const models = require('vn-loopback/server/server').models;
describe('order getTotalVolume()', () => {
it('should return the total', async() => {
let result = await app.models.Order.getTotalVolume(1);
const tx = await models.Order.beginTransaction({});
expect(result.totalVolume).toEqual(1.568);
expect(result.totalBoxes).toEqual(11.1);
try {
const options = {transaction: tx};
const result = await models.Order.getTotalVolume(1, options);
expect(result.totalVolume).toEqual(1.568);
expect(result.totalBoxes).toEqual(11.1);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});

View File

@ -1,9 +1,20 @@
const app = require('vn-loopback/server/server');
const models = require('vn-loopback/server/server').models;
describe('order getVAT()', () => {
it('should return the order VAT', async() => {
const result = await app.models.Order.getVAT(1);
const tx = await models.Order.beginTransaction({});
expect(result).toEqual(20.29);
try {
const options = {transaction: tx};
const result = await models.Order.getVAT(1, options);
expect(result).toEqual(20.29);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});

View File

@ -1,9 +1,20 @@
const app = require('vn-loopback/server/server');
const models = require('vn-loopback/server/server').models;
describe('order getVolumes()', () => {
it('should return the volumes of a given order id', async() => {
let [result] = await app.models.Order.getVolumes(1);
const tx = await models.Order.beginTransaction({});
expect(result.volume).toEqual(1.09);
try {
const options = {transaction: tx};
const [result] = await models.Order.getVolumes(1, options);
expect(result.volume).toEqual(1.09);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});

View File

@ -1,21 +1,54 @@
const app = require('vn-loopback/server/server');
const models = require('vn-loopback/server/server').models;
describe('order isEditable()', () => {
it('should return false when the given order is not editable', async() => {
let isEditable = await app.models.Order.isEditable(2);
const tx = await models.Order.beginTransaction({});
expect(isEditable).toBeFalsy();
try {
const options = {transaction: tx};
const isEditable = await models.Order.isEditable(2, options);
expect(isEditable).toBeFalsy();
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should return false when the given order doesnt exists', async() => {
let isEditable = await app.models.Order.isEditable(99999);
const tx = await models.Order.beginTransaction({});
expect(isEditable).toBeFalsy();
try {
const options = {transaction: tx};
const isEditable = await models.Order.isEditable(999, options);
expect(isEditable).toBeFalsy();
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should return true when the given order is editable', async() => {
let isEditable = await app.models.Order.isEditable(16);
const tx = await models.Order.beginTransaction({});
expect(isEditable).toBeTruthy();
try {
const options = {transaction: tx};
const isEditable = await models.Order.isEditable(16, options);
expect(isEditable).toBeTruthy();
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});

Some files were not shown because too many files have changed in this diff Show More