3347-worker_basic-data #925

Merged
carlosjr merged 8 commits from 3347-worker_basic-data into dev 2022-04-11 11:02:17 +00:00
79 changed files with 1198 additions and 146 deletions
Showing only changes of commit 018047b6be - Show all commits

View File

@ -30,8 +30,13 @@ module.exports = Self => {
const sender = await models.Account.findById(accessToken.userId); const sender = await models.Account.findById(accessToken.userId);
const recipient = to.replace('@', ''); const recipient = to.replace('@', '');
if (sender.name != recipient) if (sender.name != recipient) {
return sendMessage(sender, to, message); await sendMessage(sender, to, message);
return true;
}
return false;
}; };
async function sendMessage(sender, channel, message) { async function sendMessage(sender, channel, message) {

View File

@ -5,7 +5,7 @@ module.exports = Self => {
description: 'Sends a RocketChat message to a connected user or department channel', description: 'Sends a RocketChat message to a connected user or department channel',
accessType: 'WRITE', accessType: 'WRITE',
accepts: [{ accepts: [{
arg: 'recipientId', arg: 'workerId',
type: 'number', type: 'number',
required: true, required: true,
description: 'The recipient user id' description: 'The recipient user id'

View File

@ -1,2 +1,2 @@
DELETE FROM salix.ACL DELETE FROM `salix`.`ACL`
WHERE model = 'ClaimEnd' AND property = 'importTicketSales'; WHERE model = 'ClaimEnd' AND property = 'importTicketSales';

View File

@ -1,3 +1,3 @@
INSERT INTO salix.ACL INSERT INTO `salix`.`ACL`
(model, property, accessType, permission, principalType, principalId) (model, property, accessType, permission, principalType, principalId)
VALUES('Collection', 'setSaleQuantity', '*', 'ALLOW', 'ROLE', 'employee'); VALUES('Collection', 'setSaleQuantity', '*', 'ALLOW', 'ROLE', 'employee');

View File

@ -1,3 +1,3 @@
INSERT INTO salix.ACL INSERT INTO `salix`.`ACL`
(model, property, accessType, permission, principalType, principalId) (model, property, accessType, permission, principalType, principalId)
VALUES('Docuware', '*', '*', 'ALLOW', 'ROLE', 'employee'); VALUES('Docuware', '*', '*', 'ALLOW', 'ROLE', 'employee');

View File

@ -1,3 +1,3 @@
UPDATE salix.defaultViewConfig UPDATE `salix`.`defaultViewConfig`
SET `columns`='{"intrastat":false,"stemMultiplier":false,"landed":false,"producer":false}' SET `columns`='{"intrastat":false,"stemMultiplier":false,"landed":false,"producer":false}'
WHERE tableCode ='itemsIndex'; WHERE tableCode ='itemsIndex';

View File

@ -1,2 +1,2 @@
INSERT INTO salix.ACL (model,property,accessType,principalId) INSERT INTO `salix`.`ACL` (model,property,accessType,principalId)
VALUES ('AgencyTerm','*','*','administrative'); VALUES ('AgencyTerm','*','*','administrative');

View File

@ -1,3 +1 @@
UPDATE `account`.`user` UPDATE `account`.`user` SET `role` = 57 WHERE id IN (2294, 4365, 7294);
SET `role` = 57
WHERE id IN (2294, 4365, 7294);

View File

@ -0,0 +1,3 @@
INSERT INTO `salix`.`ACL`
(`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
VALUES('InvoiceInIntrastat', '*', '*', 'ALLOW', 'ROLE', 'employee');

View File

@ -0,0 +1,2 @@
INSERT INTO `vn`.`component` (`name`,`typeFk`,`classRate`,`isRenewable`,`code`,`isRequired`)
VALUES ('maná reclamacion',7,4,0,'manaClaim',0);

View File

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

View File

@ -0,0 +1,106 @@
DROP PROCEDURE IF EXISTS `bs`.`manaCustomerUpdate`;
DELIMITER $$
$$
CREATE DEFINER=`root`@`localhost` PROCEDURE `bs`.`manaCustomerUpdate`()
BEGIN
DECLARE vToDated DATE;
DECLARE vFromDated DATE;
DECLARE vForDeleteDated DATE;
DECLARE vManaId INT;
DECLARE vManaAutoId INT;
DECLARE vClaimManaId INT;
DECLARE vManaBankId INT;
DECLARE vManaGreugeTypeId INT;
SELECT id INTO vManaId
FROM `component` WHERE code = 'mana';
SELECT id INTO vManaAutoId
FROM `component` WHERE code = 'autoMana';
SELECT id INTO vClaimManaId
FROM `component` WHERE code = 'manaClaim';
SELECT id INTO vManaBankId
FROM `bank` WHERE code = 'mana';
SELECT id INTO vManaGreugeTypeId
FROM `greugeType` WHERE code = 'mana';
SELECT IFNULL(max(dated), '2016-01-01')
INTO vFromDated
FROM bs.manaCustomer;
DELETE
FROM bs.manaCustomer
WHERE dated = vFromDated;
SELECT IFNULL(max(dated), '2016-01-01')
INTO vFromDated
FROM bs.manaCustomer;
WHILE timestampadd(DAY,30,vFromDated) < CURDATE() DO
SELECT
timestampadd(DAY,30,vFromDated),
timestampadd(DAY,-90,vFromDated)
INTO
vToDated,
vForDeleteDated;
DELETE FROM bs.manaCustomer
WHERE dated <= vForDeleteDated;
INSERT INTO bs.manaCustomer(Id_Cliente, Mana, dated)
SELECT
Id_Cliente,
cast(sum(mana) as decimal(10,2)) as mana,
vToDated as dated
FROM
(
SELECT cs.Id_Cliente, Cantidad * Valor as mana
FROM vn2008.Tickets t
JOIN vn2008.Consignatarios cs using(Id_Consigna)
JOIN vn2008.Movimientos m on m.Id_Ticket = t.Id_Ticket
JOIN vn2008.Movimientos_componentes mc on mc.Id_Movimiento = m.Id_Movimiento
WHERE Id_Componente IN (vManaAutoId, vManaId, vClaimManaId)
AND t.Fecha > vFromDated
AND date(t.Fecha) <= vToDated
UNION ALL
SELECT r.Id_Cliente, - Entregado
FROM vn2008.Recibos r
WHERE Id_Banco = vManaBankId
AND Fechacobro > vFromDated
AND Fechacobro <= vToDated
UNION ALL
SELECT g.Id_Cliente, g.Importe
FROM vn2008.Greuges g
WHERE Greuges_type_id = vManaGreugeTypeId
AND Fecha > vFromDated
AND Fecha <= vToDated
UNION ALL
SELECT Id_Cliente, mana
FROM bs.manaCustomer
WHERE dated = vFromDated
) sub
GROUP BY Id_Cliente
HAVING Id_Cliente;
SET vFromDated = vToDated;
END WHILE;
END$$
DELIMITER ;

View File

@ -0,0 +1,75 @@
DROP PROCEDURE IF EXISTS `vn`.`manaSpellersRequery`;
DELIMITER $$
$$
CREATE DEFINER=`root`@`localhost` PROCEDURE `vn`.`manaSpellersRequery`(vWorkerFk INTEGER)
BEGIN
/**
* Recalcula el mana consumido por un trabajador
*
* @param vWorkerFk Id Trabajador
*/
DECLARE vWorkerIsExcluded BOOLEAN;
DECLARE vFromDated DATE;
DECLARE vToDated DATE DEFAULT TIMESTAMPADD(DAY,1,CURDATE());
DECLARE vMana INT;
DECLARE vAutoMana INT;
DECLARE vClaimMana INT;
DECLARE vManaBank INT;
DECLARE vManaGreugeType INT;
SELECT COUNT(*) INTO vWorkerIsExcluded
FROM workerManaExcluded
WHERE workerFk = vWorkerFk;
IF NOT vWorkerIsExcluded THEN
SELECT id INTO vMana
FROM `component` WHERE code = 'mana';
SELECT id INTO vAutoMana
FROM `component` WHERE code = 'autoMana';
SELECT id INTO vClaimMana
FROM `component` WHERE code = 'manaClaim';
SELECT id INTO vManaBank
FROM `bank` WHERE code = 'mana';
SELECT id INTO vManaGreugeType
FROM `greugeType` WHERE code = 'mana';
SELECT max(dated) INTO vFromDated
FROM clientManaCache;
REPLACE workerMana (workerFk, amount)
SELECT vWorkerFk, sum(mana) FROM
(
SELECT s.quantity * sc.value as mana
FROM ticket t
JOIN address a ON a.id = t.addressFk
JOIN client c ON c.id = a.clientFk
JOIN sale s ON s.ticketFk = t.id
JOIN saleComponent sc ON sc.saleFk = s.id
WHERE c.salesPersonFk = vWorkerFk AND sc.componentFk IN (vMana, vAutoMana, vClaimMana)
AND t.shipped > vFromDated AND t.shipped < vToDated
UNION ALL
SELECT - r.amountPaid
FROM receipt r
JOIN client c ON c.id = r.clientFk
WHERE c.salesPersonFk = vWorkerFk AND bankFk = vManaBank
AND payed > vFromDated
UNION ALL
SELECT g.amount
FROM greuge g
JOIN client c ON c.id = g.clientFk
WHERE c.salesPersonFk = vWorkerFk AND g.greugeTypeFk = vManaGreugeType
AND g.shipped > vFromDated and g.shipped < CURDATE()
UNION ALL
SELECT cc.mana
FROM clientManaCache cc
JOIN client c ON c.id = cc.clientFk
WHERE c.salesPersonFk = vWorkerFk AND cc.dated = vFromDated
) sub;
END IF;
END$$
DELIMITER ;

View File

@ -0,0 +1,149 @@
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;
INSERT INTO vn.ticketRefund(refundTicketFk, originalTicketFk)
VALUES(vNewTicket, vOriginTicket);
END$$
DELIMITER ;
CREATE TABLE `vn`.`ticketRefund` (
`id` INT auto_increment NULL,
`refundTicketFk` INT NOT NULL,
`originalTicketFk` INT NOT NULL,
CONSTRAINT `ticketRefund_PK` PRIMARY KEY (id)
)
ENGINE=InnoDB
DEFAULT CHARSET=utf8
COLLATE=utf8_unicode_ci;
ALTER TABLE `vn`.`ticketRefund` ADD CONSTRAINT `ticketRefund_FK` FOREIGN KEY (`refundTicketFk`) REFERENCES `vn`.`ticket`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
ALTER TABLE `vn`.`ticketRefund` ADD CONSTRAINT `ticketRefund_FK_1` FOREIGN KEY (`originalTicketFk`) REFERENCES `vn`.`ticket`(`id`) ON DELETE RESTRICT ON UPDATE CASCADE;
DELIMITER $$
$$
CREATE DEFINER=`root`@`localhost` TRIGGER `vn`.`ticketRefund_beforeInsert`
BEFORE INSERT ON `ticketRefund`
FOR EACH ROW
BEGIN
DECLARE vAlreadyExists BOOLEAN DEFAULT FALSE;
IF NEW.refundTicketFk = NEW.originalTicketFk THEN
CALL util.throw('Original ticket and refund ticket has same id');
END IF;
SELECT COUNT(*) INTO vAlreadyExists
FROM ticketRefund
WHERE refundTicketFk = NEW.originalTicketFk;
IF vAlreadyExists > 0 THEN
CALL util.throw('This ticket is already a refund');
END IF;
END$$
DELIMITER ;
DELIMITER $$
$$
CREATE DEFINER=`root`@`localhost` TRIGGER `vn`.`ticketRefund_beforeUpdate`
BEFORE UPDATE ON `ticketRefund`
FOR EACH ROW
BEGIN
DECLARE vAlreadyExists BOOLEAN DEFAULT FALSE;
IF NEW.refundTicketFk = NEW.originalTicketFk THEN
CALL util.throw('Original ticket and refund ticket has same id');
END IF;
SELECT COUNT(*) INTO vAlreadyExists
FROM ticketRefund
WHERE refundTicketFk = NEW.originalTicketFk;
IF vAlreadyExists > 0 THEN
CALL util.throw('This ticket is already a refund');
END IF;
END$$
DELIMITER ;

View File

@ -0,0 +1,16 @@
DROP TRIGGER `vn`.`travelThermograph_beforeInsert`;
ALTER TABLE `vn`.`travelThermograph` CHANGE `temperature` `temperature__` enum('COOL','WARM','DRY') CHARACTER SET utf8 COLLATE utf8_unicode_ci DEFAULT NULL NULL;
CREATE OR REPLACE
ALGORITHM = UNDEFINED VIEW `vn2008`.`travel_thermograph` AS
select
`tt`.`thermographFk` AS `thermograph_id`,
`tt`.`created` AS `odbc_date`,
`tt`.`warehouseFk` AS `warehouse_id`,
`tt`.`travelFk` AS `travel_id`,
`tt`.`temperatureFk` AS `temperature`,
`tt`.`result` AS `result`,
`tt`.`dmsFk` AS `gestdoc_id`
from
`vn`.`travelThermograph` `tt`;

View File

@ -0,0 +1,73 @@
DROP PROCEDURE IF EXISTS vn.timeControl_getError;
DELIMITER $$
$$
CREATE DEFINER=`root`@`localhost` PROCEDURE `vn`.`timeControl_getError`(vDatedFrom DATETIME, vDatedTo DATETIME)
BEGIN
/*
* @param vDatedFrom
* @param vDatedTo
* @table tmp.`user`(userFk)
* Fichadas incorrectas de las cuales no se puede calcular horas trabajadas
* @return tmp.timeControlError (id)
*/
DECLARE vDayMaxTime INTEGER;
SET @journeyCounter := 0;
SET @lastUserFk := NULL;
SELECT dayMaxTime INTO vDayMaxTime
FROM workerTimeControlConfig LIMIT 1;
DROP TEMPORARY TABLE IF EXISTS tmp.timeControl;
CREATE TEMPORARY TABLE tmp.timeControl
(INDEX(id), INDEX(journeyCounter))
ENGINE = MEMORY
SELECT sub.id,
sub.direction,
sub.timed,
IF(sub.direction = 'in' OR @hasOut OR sub.userFk <> @lastUserFk, @journeyCounter := @journeyCounter + 1, @journeyCounter) journeyCounter,
@lastUserFk := sub.userFk workerFk,
IF(sub.direction = 'out', @hasOut:= TRUE, @hasOut:= FALSE)
FROM (
SELECT DISTINCT wtc.id,
wtc.direction,
wtc.timed,
wtc.userFk
FROM workerTimeControl wtc
JOIN tmp.`user` w ON w.userFk = wtc.userFk
WHERE wtc.timed BETWEEN DATE_SUB(vDatedFrom, INTERVAL 1 DAY) AND DATE_ADD(vDatedTo, INTERVAL 1 DAY)
ORDER BY wtc.userFk, wtc.timed
) sub;
DROP TEMPORARY TABLE IF EXISTS tmp.timeControlAux;
CREATE TEMPORARY TABLE tmp.timeControlAux
(INDEX(id), INDEX(journeyCounter))
ENGINE = MEMORY
SELECT * FROM tmp.timeControl;
DROP TEMPORARY TABLE IF EXISTS tmp.timeControlError;
CREATE TEMPORARY TABLE tmp.timeControlError
(INDEX(id))
ENGINE = MEMORY
SELECT id
FROM tmp.timeControlAux tca
JOIN (SELECT journeyCounter,
UNIX_TIMESTAMP(MAX(timed)) - UNIX_TIMESTAMP(MIN(timed)) timeWork,
SUM(direction = 'in') totalIn,
SUM(direction = 'out') totalOut,
timed
FROM tmp.timeControl
GROUP BY journeyCounter
HAVING COUNT(*) MOD 2 = 1
OR totalIn <> 1
OR totalOut <> 1
OR timeWork >= vDayMaxTime
)sub ON sub.journeyCounter = tca.journeyCounter
WHERE sub.timed BETWEEN vDatedFrom AND vDatedTo;
DROP TEMPORARY TABLE IF EXISTS tmp.timeControl;
DROP TEMPORARY TABLE IF EXISTS tmp.timeControlAux;
END$$
DELIMITER ;

View File

View File

@ -318,10 +318,10 @@ INSERT INTO `vn`.`contactChannel`(`id`, `name`)
INSERT INTO `vn`.`client`(`id`,`name`,`fi`,`socialName`,`contact`,`street`,`city`,`postcode`,`phone`,`mobile`,`isRelevant`,`email`,`iban`,`dueDay`,`accountingAccount`,`isEqualizated`,`provinceFk`,`hasToInvoice`,`credit`,`countryFk`,`isActive`,`gestdocFk`,`quality`,`payMethodFk`,`created`,`isToBeMailed`,`contactChannelFk`,`hasSepaVnl`,`hasCoreVnl`,`hasCoreVnh`,`riskCalculated`,`clientTypeFk`,`mailAddress`,`hasToInvoiceByAddress`,`isTaxDataChecked`,`isFreezed`,`creditInsurance`,`isCreatedAsServed`,`hasInvoiceSimplified`,`salesPersonFk`,`isVies`,`eypbc`, `businessTypeFk`) INSERT INTO `vn`.`client`(`id`,`name`,`fi`,`socialName`,`contact`,`street`,`city`,`postcode`,`phone`,`mobile`,`isRelevant`,`email`,`iban`,`dueDay`,`accountingAccount`,`isEqualizated`,`provinceFk`,`hasToInvoice`,`credit`,`countryFk`,`isActive`,`gestdocFk`,`quality`,`payMethodFk`,`created`,`isToBeMailed`,`contactChannelFk`,`hasSepaVnl`,`hasCoreVnl`,`hasCoreVnh`,`riskCalculated`,`clientTypeFk`,`mailAddress`,`hasToInvoiceByAddress`,`isTaxDataChecked`,`isFreezed`,`creditInsurance`,`isCreatedAsServed`,`hasInvoiceSimplified`,`salesPersonFk`,`isVies`,`eypbc`, `businessTypeFk`)
VALUES VALUES
(1101, 'Bruce Wayne', '84612325V', 'Batman', 'Alfred', '1007 Mountain Drive, Gotham', 'Silla', 46460, 1111111111, 222222222, 1, 'BruceWayne@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist'), (1101, 'Bruce Wayne', '84612325V', 'Batman', 'Alfred', '1007 Mountain Drive, Gotham', 'Silla', 46460, 1111111111, 222222222, 1, 'BruceWayne@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist'),
(1102, 'Petter Parker', '87945234L', 'Spider man', 'Aunt May', '20 Ingram Street, Queens, USA', 'Silla', 46460, 1111111111, 222222222, 1, 'PetterParker@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist'), (1102, 'Petter Parker', '87945234L', 'Spider man', 'Aunt May', '20 Ingram Street, Queens, USA', 'Silla', 46460, 1111111111, 222222222, 1, 'PetterParker@mydomain.com', NULL, 0, 1234567890, 0, 2, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist'),
(1103, 'Clark Kent', '06815934E', 'Super man', 'lois lane', '344 Clinton Street, Apartament 3-D', 'Silla', 46460, 1111111111, 222222222, 1, 'ClarkKent@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 0, 19, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist'), (1103, 'Clark Kent', '06815934E', 'Super man', 'lois lane', '344 Clinton Street, Apartament 3-D', 'Silla', 46460, 1111111111, 222222222, 1, 'ClarkKent@mydomain.com', NULL, 0, 1234567890, 0, 3, 1, 0, 19, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist'),
(1104, 'Tony Stark', '06089160W', 'Iron man', 'Pepper Potts', '10880 Malibu Point, 90265', 'Silla', 46460, 1111111111, 222222222, 1, 'TonyStark@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist'), (1104, 'Tony Stark', '06089160W', 'Iron man', 'Pepper Potts', '10880 Malibu Point, 90265', 'Silla', 46460, 1111111111, 222222222, 1, 'TonyStark@mydomain.com', NULL, 0, 1234567890, 0, 2, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 1, 0, NULL, 0, 0, 18, 0, 1, 'florist'),
(1105, 'Max Eisenhardt', '251628698', 'Magneto', 'Rogue', 'Unknown Whereabouts', 'Silla', 46460, 1111111111, 222222222, 1, 'MaxEisenhardt@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 8, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 1, 1, NULL, 0, 0, 18, 0, 1, 'florist'), (1105, 'Max Eisenhardt', '251628698', 'Magneto', 'Rogue', 'Unknown Whereabouts', 'Silla', 46460, 1111111111, 222222222, 1, 'MaxEisenhardt@mydomain.com', NULL, 0, 1234567890, 0, 3, 1, 300, 8, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 1, 1, NULL, 0, 0, 18, 0, 1, 'florist'),
(1106, 'DavidCharlesHaller', '53136686Q', 'Legion', 'Charles Xavier', 'City of New York, New York, USA', 'Silla', 46460, 1111111111, 222222222, 1, 'DavidCharlesHaller@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 0, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 1, 0, NULL, 0, 0, 19, 0, 1, 'florist'), (1106, 'DavidCharlesHaller', '53136686Q', 'Legion', 'Charles Xavier', 'City of New York, New York, USA', 'Silla', 46460, 1111111111, 222222222, 1, 'DavidCharlesHaller@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 0, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 1, 0, NULL, 0, 0, 19, 0, 1, 'florist'),
(1107, 'Hank Pym', '09854837G', 'Ant man', 'Hawk', 'Anthill, San Francisco, California', 'Silla', 46460, 1111111111, 222222222, 1, 'HankPym@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 0, 0, NULL, 0, 0, 19, 0, 1, 'florist'), (1107, 'Hank Pym', '09854837G', 'Ant man', 'Hawk', 'Anthill, San Francisco, California', 'Silla', 46460, 1111111111, 222222222, 1, 'HankPym@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 0, 0, NULL, 0, 0, 19, 0, 1, 'florist'),
(1108, 'Charles Xavier', '22641921P', 'Professor X', 'Beast', '3800 Victory Pkwy, Cincinnati, OH 45207, USA', 'Silla', 46460, 1111111111, 222222222, 1, 'CharlesXavier@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 1, 1, NULL, 0, 0, 19, 0, 1, 'florist'), (1108, 'Charles Xavier', '22641921P', 'Professor X', 'Beast', '3800 Victory Pkwy, Cincinnati, OH 45207, USA', 'Silla', 46460, 1111111111, 222222222, 1, 'CharlesXavier@mydomain.com', NULL, 0, 1234567890, 0, 1, 1, 300, 1, 1, NULL, 10, 5,CURDATE(), 1, 5, 1, 1, 1, '0000-00-00', 1, 1, 1, 1, 1, NULL, 0, 0, 19, 0, 1, 'florist'),
@ -2454,6 +2454,13 @@ INSERT INTO `vn`.`invoiceInTax` (`invoiceInFk`, `taxableBase`, `expenceFk`, `for
(6, 29.95, '7001000000', NULL, 7, 20), (6, 29.95, '7001000000', NULL, 7, 20),
(7, 58.64, '6210000567', NULL, 8, 20); (7, 58.64, '6210000567', NULL, 8, 20);
INSERT INTO `vn`.`invoiceInIntrastat` (`invoiceInFk`, `net`, `intrastatFk`, `amount`, `stems`, `countryFk`)
VALUES
(1, 30.50, 5080000, 10.00, 162, 5),
(1, 10, 6021010, 20.00, 205, 5),
(2, 13.20, 5080000, 15.00, 580, 5),
(2, 16.10, 6021010, 25.00, 80, 5);
INSERT INTO `vn`.`ticketRecalc`(`ticketFk`) INSERT INTO `vn`.`ticketRecalc`(`ticketFk`)
SELECT `id` SELECT `id`
FROM `vn`.`ticket` t FROM `vn`.`ticket` t
@ -2503,18 +2510,6 @@ INSERT INTO `bs`.`defaulter` (`clientFk`, `amount`, `created`, `defaulterSinced`
(1107, 500, CURDATE(), CURDATE()), (1107, 500, CURDATE(), CURDATE()),
(1109, 500, CURDATE(), CURDATE()); (1109, 500, CURDATE(), CURDATE());
UPDATE `vn`.`agency`
SET `supplierFk`=1
WHERE `id`=1;
UPDATE `vn`.`agency`
SET `supplierFk`=1
WHERE `id`=2;
UPDATE `vn`.`agency`
SET `supplierFk`=2
WHERE `id`=3;
UPDATE `vn`.`route` UPDATE `vn`.`route`
SET `invoiceInFk`=1 SET `invoiceInFk`=1
WHERE `id`=1; WHERE `id`=1;

View File

@ -392,7 +392,6 @@ export default {
name: 'vn-item-basic-data vn-textfield[ng-model="$ctrl.item.name"]', name: 'vn-item-basic-data vn-textfield[ng-model="$ctrl.item.name"]',
relevancy: 'vn-item-basic-data vn-input-number[ng-model="$ctrl.item.relevancy"]', relevancy: 'vn-item-basic-data vn-input-number[ng-model="$ctrl.item.relevancy"]',
origin: 'vn-autocomplete[ng-model="$ctrl.item.originFk"]', origin: 'vn-autocomplete[ng-model="$ctrl.item.originFk"]',
compression: 'vn-item-basic-data vn-input-number[ng-model="$ctrl.item.compression"]',
generic: 'vn-autocomplete[ng-model="$ctrl.item.genericFk"]', generic: 'vn-autocomplete[ng-model="$ctrl.item.genericFk"]',
isFragile: 'vn-check[ng-model="$ctrl.item.isFragile"]', isFragile: 'vn-check[ng-model="$ctrl.item.isFragile"]',
longName: 'vn-textfield[ng-model="$ctrl.item.longName"]', longName: 'vn-textfield[ng-model="$ctrl.item.longName"]',
@ -586,6 +585,7 @@ export default {
firstSalePriceInput: '.vn-popover.shown input[ng-model="$ctrl.field"]', firstSalePriceInput: '.vn-popover.shown input[ng-model="$ctrl.field"]',
firstSaleDiscount: 'vn-ticket-sale vn-table vn-tr:nth-child(1) > vn-td:nth-child(10) > span', firstSaleDiscount: 'vn-ticket-sale vn-table vn-tr:nth-child(1) > vn-td:nth-child(10) > span',
firstSaleDiscountInput: '.vn-popover.shown [ng-model="$ctrl.field"]', firstSaleDiscountInput: '.vn-popover.shown [ng-model="$ctrl.field"]',
saveSaleDiscountButton: '.vn-popover.shown vn-button[label="Save"]',
firstSaleImport: 'vn-ticket-sale:nth-child(1) vn-td:nth-child(11)', firstSaleImport: 'vn-ticket-sale:nth-child(1) vn-td:nth-child(11)',
firstSaleReservedIcon: 'vn-ticket-sale vn-tr:nth-child(1) > vn-td:nth-child(2) > vn-icon:nth-child(3)', firstSaleReservedIcon: 'vn-ticket-sale vn-tr:nth-child(1) > vn-td:nth-child(2) > vn-icon:nth-child(3)',
firstSaleColour: 'vn-ticket-sale vn-tr:nth-child(1) vn-fetched-tags section', firstSaleColour: 'vn-ticket-sale vn-tr:nth-child(1) vn-fetched-tags section',

View File

@ -28,7 +28,7 @@ describe('Client defaulter path', () => {
const salesPersonName = const salesPersonName =
await page.waitToGetProperty(selectors.clientDefaulter.firstSalesPersonName, 'innerText'); await page.waitToGetProperty(selectors.clientDefaulter.firstSalesPersonName, 'innerText');
expect(clientName).toEqual('Batman'); expect(clientName).toEqual('Ororo Munroe');
expect(salesPersonName).toEqual('salesPersonNick'); expect(salesPersonName).toEqual('salesPersonNick');
}); });

View File

@ -99,8 +99,8 @@ describe('Worker time control path', () => {
expect(result).toEqual(scanTime); expect(result).toEqual(scanTime);
}); });
// 3736 check proc vn.timeControl_calculate
xit(`should check Hank Pym worked 6:40 hours`, async() => { it(`should check Hank Pym worked 6:40 hours`, async() => {
await page.waitForTextInElement(selectors.workerTimeControl.mondayWorkedHours, '06:40 h.'); await page.waitForTextInElement(selectors.workerTimeControl.mondayWorkedHours, '06:40 h.');
}); });
}); });

View File

@ -30,8 +30,6 @@ describe('Item Edit basic data path', () => {
await page.autocompleteSearch(selectors.itemBasicData.origin, 'Spain'); await page.autocompleteSearch(selectors.itemBasicData.origin, 'Spain');
await page.clearInput(selectors.itemBasicData.relevancy); await page.clearInput(selectors.itemBasicData.relevancy);
await page.write(selectors.itemBasicData.relevancy, '1'); await page.write(selectors.itemBasicData.relevancy, '1');
await page.clearInput(selectors.itemBasicData.compression);
await page.write(selectors.itemBasicData.compression, '2');
await page.clearInput(selectors.itemBasicData.generic); await page.clearInput(selectors.itemBasicData.generic);
await page.autocompleteSearch(selectors.itemBasicData.generic, '16'); await page.autocompleteSearch(selectors.itemBasicData.generic, '16');
await page.waitToClick(selectors.itemBasicData.isActiveCheckbox); await page.waitToClick(selectors.itemBasicData.isActiveCheckbox);
@ -96,13 +94,6 @@ describe('Item Edit basic data path', () => {
expect(result).toEqual('Spain'); expect(result).toEqual('Spain');
}); });
it(`should confirm the item compression was edited`, async() => {
const result = await page
.waitToGetProperty(selectors.itemBasicData.compression, 'value');
expect(result).toEqual('2');
});
it(`should confirm the item generic was edited`, async() => { it(`should confirm the item generic was edited`, async() => {
const result = await page const result = await page
.waitToGetProperty(selectors.itemBasicData.generic, 'value'); .waitToGetProperty(selectors.itemBasicData.generic, 'value');

View File

@ -175,7 +175,8 @@ describe('Ticket Edit sale path', () => {
it('should update the discount', async() => { it('should update the discount', async() => {
await page.waitToClick(selectors.ticketSales.firstSaleDiscount); await page.waitToClick(selectors.ticketSales.firstSaleDiscount);
await page.waitForSelector(selectors.ticketSales.firstSaleDiscountInput); await page.waitForSelector(selectors.ticketSales.firstSaleDiscountInput);
await page.type(selectors.ticketSales.firstSaleDiscountInput, '50\u000d'); await page.type(selectors.ticketSales.firstSaleDiscountInput, '50');
await page.waitToClick(selectors.ticketSales.saveSaleDiscountButton);
const message = await page.waitForSnackbar(); const message = await page.waitForSnackbar();
expect(message.text).toContain('Data saved!'); expect(message.text).toContain('Data saved!');

View File

@ -223,5 +223,6 @@
"The item is required": "El artículo es requerido", "The item is required": "El artículo es requerido",
"The agency is already assigned to another autonomous": "La agencia ya está asignada a otro autónomo", "The agency is already assigned to another autonomous": "La agencia ya está asignada a otro autónomo",
"date in the future": "Fecha en el futuro", "date in the future": "Fecha en el futuro",
"reference duplicated": "Referencia duplicada" "reference duplicated": "Referencia duplicada",
"This ticket is already a refund": "Este ticket ya es un abono"
} }

View File

@ -27,7 +27,7 @@ module.exports = Self => {
http: {source: 'query'} http: {source: 'query'}
}, },
{ {
arg: 'client', arg: 'clientName',
type: 'string', type: 'string',
description: 'The worker name', description: 'The worker name',
http: {source: 'query'} http: {source: 'query'}
@ -94,14 +94,19 @@ module.exports = Self => {
? {'cl.id': value} ? {'cl.id': value}
: { : {
or: [ or: [
{'cl.socialName': {like: `%${value}%`}} {'cl.clientName': {like: `%${value}%`}}
] ]
}; };
case 'clientName':
return {'cl.clientName': {like: `%${value}%`}};
case 'clientFk':
return {'cl.clientFk': value};
case 'id': case 'id':
case 'claimStateFk': case 'claimStateFk':
case 'priority': case 'priority':
return {[`cl.${param}`]: value}; return {[`cl.${param}`]: value};
case 'salesPersonFk': case 'salesPersonFk':
return {'cl.salesPersonFk': value};
case 'attenderFk': case 'attenderFk':
return {'cl.workerFk': value}; return {'cl.workerFk': value};
case 'created': case 'created':
@ -123,13 +128,14 @@ module.exports = Self => {
SELECT SELECT
cl.id, cl.id,
cl.clientFk, cl.clientFk,
c.socialName, c.name AS clientName,
cl.workerFk, cl.workerFk,
u.name AS workerName, u.name AS workerName,
cs.description, cs.description,
cl.created, cl.created,
cs.priority, cs.priority,
cl.claimStateFk cl.claimStateFk,
c.salesPersonFk
FROM claim cl FROM claim cl
LEFT JOIN client c ON c.id = cl.clientFk LEFT JOIN client c ON c.id = cl.clientFk
LEFT JOIN worker w ON w.id = cl.workerFk LEFT JOIN worker w ON w.id = cl.workerFk

View File

@ -25,7 +25,7 @@ describe('claim filter()', () => {
try { try {
const options = {transaction: tx}; const options = {transaction: tx};
const result = await app.models.Claim.filter({args: {filter: {}, search: 'Iron man'}}, null, options); const result = await app.models.Claim.filter({args: {filter: {}, search: 'Tony Stark'}}, null, options);
expect(result.length).toEqual(1); expect(result.length).toEqual(1);
expect(result[0].id).toEqual(4); expect(result[0].id).toEqual(4);

View File

@ -10,16 +10,16 @@
<table> <table>
<thead> <thead>
<tr> <tr>
<th field="id" shrink> <th field="clientFk" shrink>
<span translate>Id</span> <span translate>Id</span>
</th> </th>
<th field="clientFk"> <th field="clientName">
<span translate>Client</span> <span translate>Client</span>
</th> </th>
<th field="created" center shrink-date> <th field="created" center shrink-date>
<span translate>Created</span> <span translate>Created</span>
</th> </th>
<th field="salesPersonFk"> <th field="workerFk">
<span translate>Worker</span> <span translate>Worker</span>
</th> </th>
<th field="claimStateFk"> <th field="claimStateFk">
@ -40,7 +40,7 @@
<span <span
vn-click-stop="clientDescriptor.show($event, claim.clientFk)" vn-click-stop="clientDescriptor.show($event, claim.clientFk)"
class="link"> class="link">
{{::claim.socialName}} {{::claim.clientName}}
</span> </span>
</td> </td>
<td center shrink-date>{{::claim.created | date:'dd/MM/yyyy'}}</td> <td center shrink-date>{{::claim.created | date:'dd/MM/yyyy'}}</td>

View File

@ -11,11 +11,11 @@ class Controller extends Section {
}, },
columns: [ columns: [
{ {
field: 'clientFk', field: 'clientName',
autocomplete: { autocomplete: {
url: 'Clients', url: 'Clients',
showField: 'socialName', showField: 'name',
valueField: 'socialName' valueField: 'name'
} }
}, },
{ {
@ -46,21 +46,12 @@ class Controller extends Section {
exprBuilder(param, value) { exprBuilder(param, value) {
switch (param) { switch (param) {
case 'clientName':
return {'cl.clientName': {like: `%${value}%`}};
case 'clientFk': case 'clientFk':
return {['cl.socialName']: value};
case 'id':
case 'claimStateFk': case 'claimStateFk':
case 'priority': case 'workerFk':
return {[`cl.${param}`]: value}; return {[`cl.${param}`]: value};
case 'salesPersonFk':
case 'attenderFk':
return {'cl.workerFk': value};
case 'created':
value.setHours(0, 0, 0, 0);
to = new Date(value);
to.setHours(23, 59, 59, 999);
return {'cl.created': {between: [value, to]}};
} }
} }

View File

@ -18,7 +18,7 @@
<vn-textfield <vn-textfield
vn-one vn-one
label="Client" label="Client"
ng-model="filter.client"> ng-model="filter.clientName">
</vn-textfield> </vn-textfield>
</vn-horizontal> </vn-horizontal>
<vn-horizontal> <vn-horizontal>

View File

@ -0,0 +1,64 @@
module.exports = Self => {
Self.remoteMethod('checkDuplicatedData', {
description: 'Checks if a client has same email, mobile or phone than other client and send an email',
accepts: [{
arg: 'id',
type: 'number',
required: true,
description: 'The client id'
}],
returns: {
type: 'object',
root: true
},
http: {
verb: 'GET',
path: '/:id/checkDuplicatedData'
}
});
Self.checkDuplicatedData = async function(id, options) {
const myOptions = {};
if (typeof options == 'object')
Object.assign(myOptions, options);
const client = await Self.app.models.Client.findById(id, myOptions);
const emails = client.email ? client.email.split(',') : null;
const findParams = [];
if (emails.length) {
for (let email of emails)
findParams.push({email: email});
}
if (client.phone)
findParams.push({phone: client.phone});
if (client.mobile)
findParams.push({mobile: client.mobile});
const filterObj = {
where: {
and: [
{or: findParams},
{id: {neq: client.id}}
]
}
};
const clientSameData = await Self.findOne(filterObj, myOptions);
if (clientSameData) {
await Self.app.models.Mail.create({
receiver: 'direccioncomercial@verdnatura.es',
subject: `Cliente con email/teléfono/móvil duplicados`,
body: 'El cliente ' + client.id + ' comparte alguno de estos datos con el cliente ' + clientSameData.id +
'\n- Email: ' + client.email +
'\n- Teléfono: ' + client.phone +
'\n- Móvil: ' + client.mobile
}, myOptions);
}
};
};

View File

@ -0,0 +1,24 @@
const models = require('vn-loopback/server/server').models;
describe('client checkDuplicated()', () => {
it('should send an mail if mobile/phone/email is duplicated', async() => {
const tx = await models.Client.beginTransaction({});
try {
const options = {transaction: tx};
const id = 1110;
const mailModel = models.Mail;
spyOn(mailModel, 'create');
await models.Client.checkDuplicatedData(id, options);
expect(mailModel.create).toHaveBeenCalled();
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});

View File

@ -1,9 +1,7 @@
const models = require('vn-loopback/server/server').models; const models = require('vn-loopback/server/server').models;
const soap = require('soap');
describe('client sendSms()', () => { describe('client sendSms()', () => {
it('should now send a message and log it', async() => { it('should now send a message and log it', async() => {
spyOn(soap, 'createClientAsync').and.returnValue('a so fake client');
const tx = await models.Client.beginTransaction({}); const tx = await models.Client.beginTransaction({});
try { try {

View File

@ -6,6 +6,12 @@ describe('Address updateAddress', () => {
const provinceId = 5; const provinceId = 5;
const incotermsId = 'FAS'; const incotermsId = 'FAS';
const customAgentOneId = 1; const customAgentOneId = 1;
const employeeId = 1;
const ctx = {
req: {
accessToken: {userId: employeeId}
}
};
it('should throw the non uee member error if no incoterms is defined', async() => { it('should throw the non uee member error if no incoterms is defined', async() => {
const tx = await models.Client.beginTransaction({}); const tx = await models.Client.beginTransaction({});
@ -14,11 +20,9 @@ describe('Address updateAddress', () => {
try { try {
const options = {transaction: tx}; const options = {transaction: tx};
const ctx = { ctx.args = {
args: {
provinceFk: provinceId, provinceFk: provinceId,
customsAgentFk: customAgentOneId customsAgentFk: customAgentOneId
}
}; };
await models.Client.updateAddress(ctx, clientId, addressId, options); await models.Client.updateAddress(ctx, clientId, addressId, options);
@ -40,11 +44,9 @@ describe('Address updateAddress', () => {
try { try {
const options = {transaction: tx}; const options = {transaction: tx};
const ctx = { ctx.args = {
args: {
provinceFk: provinceId, provinceFk: provinceId,
incotermsFk: incotermsId incotermsFk: incotermsId
}
}; };
await models.Client.updateAddress(ctx, clientId, addressId, options); await models.Client.updateAddress(ctx, clientId, addressId, options);
@ -66,13 +68,11 @@ describe('Address updateAddress', () => {
const options = {transaction: tx}; const options = {transaction: tx};
const expectedResult = 'My edited address'; const expectedResult = 'My edited address';
const ctx = { ctx.args = {
args: {
provinceFk: provinceId, provinceFk: provinceId,
nickname: expectedResult, nickname: expectedResult,
incotermsFk: incotermsId, incotermsFk: incotermsId,
customsAgentFk: customAgentOneId customsAgentFk: customAgentOneId
}
}; };
await models.Client.updateAddress(ctx, clientId, addressId, options); await models.Client.updateAddress(ctx, clientId, addressId, options);
@ -88,6 +88,48 @@ describe('Address updateAddress', () => {
} }
}); });
it('should return an error for a user without enough privileges', async() => {
const tx = await models.Client.beginTransaction({});
try {
const options = {transaction: tx};
ctx.args = {
isLogifloraAllowed: true
};
await models.Client.updateAddress(ctx, clientId, addressId, options);
await tx.rollback();
} catch (e) {
await tx.rollback();
error = e;
}
expect(error.message).toEqual(`You don't have enough privileges`);
});
it('should update isLogifloraAllowed', async() => {
const tx = await models.Client.beginTransaction({});
const salesAssistantId = 21;
try {
const options = {transaction: tx};
ctx.req.accessToken.userId = salesAssistantId;
ctx.args = {
isLogifloraAllowed: true
};
await models.Client.updateAddress(ctx, clientId, addressId, options);
const address = await models.Address.findById(addressId, null, options);
expect(address.isLogifloraAllowed).toEqual(true);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should update the address', async() => { it('should update the address', async() => {
const tx = await models.Client.beginTransaction({}); const tx = await models.Client.beginTransaction({});
@ -95,10 +137,8 @@ describe('Address updateAddress', () => {
const options = {transaction: tx}; const options = {transaction: tx};
const expectedResult = 'My second time edited address'; const expectedResult = 'My second time edited address';
const ctx = { ctx.args = {
args: {
nickname: expectedResult nickname: expectedResult
}
}; };
await models.Client.updateAddress(ctx, clientId, addressId, options); await models.Client.updateAddress(ctx, clientId, addressId, options);

View File

@ -26,10 +26,9 @@ describe('Client updatePortfolio', () => {
throw e; throw e;
} }
}); });
// 3742 first have to migrate vn2008.Clientes_cedidos to vn // task 3817
xit('should keep the same portfolioWeight when a salesperson is unassigned of a client', async() => { xit('should keep the same portfolioWeight when a salesperson is unassigned of a client', async() => {
const salesPersonId = 19; const salesPersonId = 19;
const tx = await models.Client.beginTransaction({}); const tx = await models.Client.beginTransaction({});
try { try {

View File

@ -68,6 +68,10 @@ module.exports = function(Self) {
{ {
arg: 'isEqualizated', arg: 'isEqualizated',
type: 'boolean' type: 'boolean'
},
{
arg: 'isLogifloraAllowed',
type: 'boolean'
} }
], ],
returns: { returns: {
@ -83,11 +87,16 @@ module.exports = function(Self) {
Self.updateAddress = async(ctx, clientId, addressId, options) => { Self.updateAddress = async(ctx, clientId, addressId, options) => {
const models = Self.app.models; const models = Self.app.models;
const args = ctx.args; const args = ctx.args;
const userId = ctx.req.accessToken.userId;
const myOptions = {}; const myOptions = {};
const isSalesAssistant = await models.Account.hasRole(userId, 'salesAssistant', myOptions);
if (typeof options == 'object') if (typeof options == 'object')
Object.assign(myOptions, options); Object.assign(myOptions, options);
if (args.isLogifloraAllowed && !isSalesAssistant)
throw new UserError(`You don't have enough privileges`);
const address = await models.Address.findOne({ const address = await models.Address.findOne({
where: { where: {
id: addressId, id: addressId,

View File

@ -56,7 +56,7 @@ module.exports = Self => {
FROM ( FROM (
SELECT SELECT
DISTINCT c.id clientFk, DISTINCT c.id clientFk,
c.socialName clientName, c.name clientName,
c.salesPersonFk, c.salesPersonFk,
u.nickname salesPersonName, u.nickname salesPersonName,
d.amount, d.amount,
@ -80,6 +80,7 @@ module.exports = Self => {
stmt.merge(conn.makeWhere(filter.where)); stmt.merge(conn.makeWhere(filter.where));
stmt.merge(`GROUP BY d.clientFk`); stmt.merge(`GROUP BY d.clientFk`);
stmt.merge(conn.makeOrderBy(filter.order)); stmt.merge(conn.makeOrderBy(filter.order));
stmt.merge(conn.makeLimit(filter));
const itemsIndex = stmts.push(stmt) - 1; const itemsIndex = stmts.push(stmt) - 1;
const sql = ParameterizedSQL.join(stmts, ';'); const sql = ParameterizedSQL.join(stmts, ';');

View File

@ -47,12 +47,12 @@ describe('defaulter filter()', () => {
try { try {
const options = {transaction: tx}; const options = {transaction: tx};
const ctx = {req: {accessToken: {userId: authUserId}}, args: {search: 'spider'}}; const ctx = {req: {accessToken: {userId: authUserId}}, args: {search: 'Petter Parker'}};
const result = await models.Defaulter.filter(ctx, null, options); const result = await models.Defaulter.filter(ctx, null, options);
const firstRow = result[0]; const firstRow = result[0];
expect(firstRow.clientName).toEqual('Spider man'); expect(firstRow.clientName).toEqual('Petter Parker');
await tx.rollback(); await tx.rollback();
} catch (e) { } catch (e) {

View File

@ -50,6 +50,9 @@
}, },
"isEqualizated": { "isEqualizated": {
"type": "boolean" "type": "boolean"
},
"isLogifloraAllowed": {
"type": "boolean"
} }
}, },
"validations": [], "validations": [],

View File

@ -30,6 +30,7 @@ module.exports = Self => {
require('../methods/client/consumption')(Self); require('../methods/client/consumption')(Self);
require('../methods/client/createReceipt')(Self); require('../methods/client/createReceipt')(Self);
require('../methods/client/updatePortfolio')(Self); require('../methods/client/updatePortfolio')(Self);
require('../methods/client/checkDuplicated')(Self);
// Validations // Validations

View File

@ -39,6 +39,12 @@
ng-model="$ctrl.address.isEqualizated" ng-model="$ctrl.address.isEqualizated"
vn-acl="administrative, salesAssistant"> vn-acl="administrative, salesAssistant">
</vn-check> </vn-check>
<vn-check
vn-one
label="Is Logiflora allowed"
ng-model="$ctrl.address.isLogifloraAllowed"
vn-acl="salesAssistant">
</vn-check>
</vn-horizontal> </vn-horizontal>
<vn-horizontal> <vn-horizontal>
<vn-textfield <vn-textfield

View File

@ -60,6 +60,11 @@
ng-model="address.isEqualizated" ng-model="address.isEqualizated"
disabled="true"> disabled="true">
</vn-check> </vn-check>
<vn-check
vn-one label="Is Logiflora allowed"
ng-model="address.isLogifloraAllowed"
disabled="true">
</vn-check>
</vn-one> </vn-one>
<vn-vertical <vn-vertical
vn-one vn-one

View File

@ -17,6 +17,7 @@ class Controller extends Section {
'phone', 'phone',
'mobile', 'mobile',
'isEqualizated', 'isEqualizated',
'isLogifloraAllowed',
'postalCode' 'postalCode'
], ],
order: [ order: [

View File

@ -27,3 +27,4 @@ Mobile: Móvil
# Common # Common
Fiscal name: Nombre fiscal Fiscal name: Nombre fiscal
Street: Dirección fiscal Street: Dirección fiscal
Is Logiflora allowed: Compra directa en Holanda

View File

@ -6,8 +6,11 @@ class Controller extends Dialog {
super($element, $, $transclude); super($element, $, $transclude);
this.vnReport = vnReport; this.vnReport = vnReport;
const tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);
this.receipt = { this.receipt = {
payed: new Date() payed: tomorrow
}; };
} }

View File

@ -12,6 +12,7 @@ export default class Controller extends Section {
return this.$.watcher.submit().then(() => { return this.$.watcher.submit().then(() => {
const query = `Clients/updatePortfolio`; const query = `Clients/updatePortfolio`;
this.$http.get(query); this.$http.get(query);
this.$http.get(`Clients/${this.$params.id}/checkDuplicatedData`);
}); });
} }
} }

View File

@ -10,9 +10,10 @@ export default class Controller extends Section {
} }
onSubmit() { onSubmit() {
return this.$.watcher.submit().then( return this.$.watcher.submit().then(json => {
json => this.$state.go('client.card.basicData', {id: json.data.id}) this.$state.go('client.card.basicData', {id: json.data.id});
); this.$http.get(`Clients/${this.client.id}/checkDuplicatedData`);
});
} }
get province() { get province() {

View File

@ -49,7 +49,7 @@
model="model"> model="model">
</vn-multi-check> </vn-multi-check>
</th> </th>
<th field="clientName"> <th field="clientFk">
<span translate>Client</span> <span translate>Client</span>
</th> </th>
<th field="salesPersonFk"> <th field="salesPersonFk">

View File

@ -13,11 +13,11 @@ export default class Controller extends Section {
}, },
columns: [ columns: [
{ {
field: 'clientName', field: 'clientFk',
autocomplete: { autocomplete: {
url: 'Clients', url: 'Clients',
showField: 'socialName', showField: 'name',
valueField: 'socialName' valueField: 'id'
} }
}, },
{ {
@ -114,7 +114,7 @@ export default class Controller extends Section {
switch (param) { switch (param) {
case 'creditInsurance': case 'creditInsurance':
case 'amount': case 'amount':
case 'clientName': case 'clientFk':
case 'workerFk': case 'workerFk':
case 'salesPersonFk': case 'salesPersonFk':
return {[`d.${param}`]: value}; return {[`d.${param}`]: value};

View File

@ -104,15 +104,15 @@ describe('client defaulter', () => {
describe('exprBuilder()', () => { describe('exprBuilder()', () => {
it('should search by sales person', () => { it('should search by sales person', () => {
let expr = controller.exprBuilder('salesPersonFk', '5'); const expr = controller.exprBuilder('salesPersonFk', '5');
expect(expr).toEqual({'d.salesPersonFk': '5'}); expect(expr).toEqual({'d.salesPersonFk': '5'});
}); });
it('should search by client name', () => { it('should search by client', () => {
let expr = controller.exprBuilder('clientName', '1foo'); const expr = controller.exprBuilder('clientFk', '5');
expect(expr).toEqual({'d.clientName': '1foo'}); expect(expr).toEqual({'d.clientFk': '5'});
}); });
}); });
}); });

View File

@ -23,6 +23,7 @@ export default class Client extends ModuleMain {
case 'id': case 'id':
case 'fi': case 'fi':
case 'postcode': case 'postcode':
case 'provinceFk':
case 'salesPersonFk': case 'salesPersonFk':
return {[param]: value}; return {[param]: value};
} }

View File

@ -67,7 +67,7 @@
</td> </td>
<td> <td>
<span <span
vn-click-stop="itemDescriptor.show($event, item.id)" vn-click-stop="clientDescriptor.show($event, client.id)"
class="link"> class="link">
{{::client.id}} {{::client.id}}
</span> </span>
@ -83,7 +83,9 @@
</smart-table> </smart-table>
</vn-card> </vn-card>
<vn-client-descriptor-popover
vn-id="clientDescriptor">
</vn-client-descriptor-popover>
<vn-popover vn-id="filters"> <vn-popover vn-id="filters">
<div class="vn-pa-lg"> <div class="vn-pa-lg">
<form ng-submit="$ctrl.onSendClientConsumption()"> <form ng-submit="$ctrl.onSendClientConsumption()">
@ -153,3 +155,6 @@
</vn-item> </vn-item>
</slot-menu> </slot-menu>
</vn-contextmenu> </vn-contextmenu>
<vn-client-descriptor-popover
vn-id="clientDescriptor">
</vn-client-descriptor-popover>

View File

@ -50,6 +50,15 @@
ng-model="filter.postcode"> ng-model="filter.postcode">
</vn-textfield> </vn-textfield>
</vn-horizontal> </vn-horizontal>
<vn-horizontal>
<vn-autocomplete
ng-model="filter.provinceFk"
url="Provinces"
show-field="name"
value-field="id"
label="Province">
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal> <vn-horizontal>
<vn-textfield <vn-textfield
vn-one vn-one

View File

@ -64,6 +64,34 @@ module.exports = Self => {
}] }]
} }
}, },
{
relation: 'invoiceInIntrastat',
scope: {
fields: [
'id',
'invoiceInFk',
'net',
'intrastatFk',
'amount',
'stems',
'countryFk',
'statisticalValue'],
include: [{
relation: 'intrastat',
scope: {
fields: [
'id',
'description']
}
},
{
relation: 'country',
scope: {
fields: ['code']
}
}]
}
},
{ {
relation: 'invoiceInTax', relation: 'invoiceInTax',
scope: { scope: {

View File

@ -8,6 +8,9 @@
"InvoiceInDueDay": { "InvoiceInDueDay": {
"dataSource": "vn" "dataSource": "vn"
}, },
"InvoiceInIntrastat": {
"dataSource": "vn"
},
"InvoiceInLog": { "InvoiceInLog": {
"dataSource": "vn" "dataSource": "vn"
} }

View File

@ -0,0 +1,50 @@
{
"name": "InvoiceInIntrastat",
"base": "VnModel",
"options": {
"mysql": {
"table": "invoiceInIntrastat"
}
},
"properties": {
"id": {
"id": true,
"type": "number",
"description": "Identifier"
},
"invoiceInFk": {
"type": "number"
},
"net": {
"type": "number"
},
"intrastatFk": {
"type": "number"
},
"amount": {
"type": "number"
},
"stems": {
"type": "number"
},
"countryFk": {
"type": "number"
},
"statisticalValue": {
"type": "number"
}
},
"relations": {
"intrastat": {
"type": "belongsTo",
"model": "Intrastat",
"foreignKey": "intrastatFk"
},
"country": {
"type": "belongsTo",
"model": "Country",
"foreignKey": "countryFk"
}
}
}

View File

@ -64,6 +64,11 @@
"model": "InvoiceInDueDay", "model": "InvoiceInDueDay",
"foreignKey": "invoiceInFk" "foreignKey": "invoiceInFk"
}, },
"invoiceInIntrastat": {
"type": "hasMany",
"model": "InvoiceInIntrastat",
"foreignKey": "invoiceInFk"
},
"invoiceInTax": { "invoiceInTax": {
"type": "hasMany", "type": "hasMany",
"model": "InvoiceInTax", "model": "InvoiceInTax",

View File

@ -10,5 +10,6 @@ import './summary';
import './basic-data'; import './basic-data';
import './tax'; import './tax';
import './dueDay'; import './dueDay';
import './intrastat';
import './create'; import './create';
import './log'; import './log';

View File

@ -0,0 +1,100 @@
<vn-crud-model
vn-id="model"
url="InvoiceInIntrastats"
data="$ctrl.invoceInIntrastat"
link="{invoiceInFk: $ctrl.$params.id}"
auto-load="true"
on-data-change="$ctrl.calculateTotals()">
</vn-crud-model>
<vn-crud-model
auto-load="true"
url="Countries"
data="countries"
order="country">
</vn-crud-model>
<vn-crud-model
auto-load="true"
url="Intrastats"
data="intrastats"
order="id">
</vn-crud-model>
<vn-watcher
vn-id="watcher"
data="$ctrl.invoceInIntrastat"
form="form">
</vn-watcher>
<vn-card
class="vn-mb-md vn-pa-lg vn-w-lg"
style="text-align: right"
ng-if="$ctrl.invoceInIntrastat.length > 0">
<vn-label-value label="Total amount"
value="{{$ctrl.amountTotal | currency: 'EUR':2}}">
</vn-label-value>
<vn-label-value label="Total net"
value="{{$ctrl.netTotal}}">
</vn-label-value>
<vn-label-value label="Total stems"
value="{{$ctrl.stemsTotal}}">
</vn-label-value>
</vn-card>
<form name="form" ng-submit="$ctrl.onSubmit()">
<vn-card class="vn-pa-lg">
<vn-horizontal ng-repeat="intrastat in $ctrl.invoceInIntrastat">
<vn-autocomplete vn-three
label="Code"
data="intrastats"
ng-model="intrastat.intrastatFk"
show-field="description"
rule
vn-focus>
<tpl-item>{{id | zeroFill:8}}: {{description}}</tpl-item>
</vn-autocomplete>
<vn-input-number
label="Amount"
ng-model="intrastat.amount"
step="0.01"
rule>
</vn-input-number>
<vn-input-number
label="Net"
ng-model="intrastat.net"
step="0.01"
rule>
</vn-input-number>
<vn-input-number
label="Stems"
ng-model="intrastat.stems"
rule>
</vn-input-number>
<vn-autocomplete
label="Country"
data="countries"
ng-model="intrastat.countryFk"
show-field="code"
rule>
</vn-autocomplete>
<vn-none>
<vn-icon-button
vn-tooltip="Remove due day"
icon="delete"
ng-click="$ctrl.deleteIntrastat($index)"
tabindex="-1">
</vn-icon-button>
</vn-none>
</vn-horizontal>
<vn-one>
<vn-icon-button
vn-bind="+"
vn-tooltip="Add due day"
icon="add_circle"
ng-click="$ctrl.add()">
</vn-icon-button>
</vn-one>
</vn-card>
<vn-button-bar>
<vn-submit
disabled="!watcher.dataChanged()"
label="Save">
</vn-submit>
</vn-button-bar>
</form>

View File

@ -0,0 +1,60 @@
import ngModule from '../module';
import Section from 'salix/components/section';
class Controller extends Section {
set invoceInIntrastat(value) {
this._invoceInIntrastat = value;
if (value) this.calculateTotals();
}
get invoceInIntrastat() {
return this._invoceInIntrastat;
}
calculateTotals() {
this.amountTotal = 0.0;
this.netTotal = 0.0;
this.stemsTotal = 0.0;
if (!this.invoceInIntrastat) return;
this.invoceInIntrastat.forEach(intrastat => {
this.amountTotal += intrastat.amount;
this.netTotal += intrastat.net;
this.stemsTotal += intrastat.stems;
});
}
add() {
this.$.model.insert({});
}
deleteIntrastat($index) {
this.$.model.remove($index);
this.$.model.save().then(() => {
this.vnApp.showSuccess(this.$t('Data saved!'));
this.calculateTotals();
});
}
onSubmit() {
this.$.watcher.check();
this.$.model.save().then(() => {
this.$.watcher.notifySaved();
this.$.watcher.updateOriginalData();
this.calculateTotals();
this.card.reload();
});
}
}
ngModule.vnComponent('vnInvoiceInIntrastat', {
template: require('./index.html'),
controller: Controller,
require: {
card: '^vnInvoiceInCard'
},
bindings: {
invoiceIn: '<'
}
});

View File

@ -0,0 +1,85 @@
import './index.js';
import watcher from 'core/mocks/watcher';
import crudModel from 'core/mocks/crud-model';
describe('InvoiceIn', () => {
describe('Component intrastat', () => {
let controller;
let $scope;
let vnApp;
beforeEach(ngModule('invoiceIn'));
beforeEach(inject(($componentController, $rootScope, _vnApp_) => {
vnApp = _vnApp_;
jest.spyOn(vnApp, 'showError');
$scope = $rootScope.$new();
$scope.model = crudModel;
$scope.watcher = watcher;
const $element = angular.element('<vn-invoice-in-intrastat></vn-invoice-in-intrastat>');
controller = $componentController('vnInvoiceInIntrastat', {$element, $scope});
controller.invoiceIn = {id: 1};
}));
describe('calculateTotals()', () => {
it('should set amountTotal, netTotal and stemsTotal to 0 if salesClaimed has no data', () => {
controller.invoceInIntrastat = [];
controller.calculateTotals();
expect(controller.amountTotal).toEqual(0);
expect(controller.netTotal).toEqual(0);
expect(controller.stemsTotal).toEqual(0);
});
it('should set amountTotal, netTotal and stemsTotal', () => {
controller.invoceInIntrastat = [
{
id: 1,
invoiceInFk: 1,
net: 30.5,
intrastatFk: 5080000,
amount: 10,
stems: 162,
countryFk: 5,
statisticalValue: 0
},
{
id: 2,
invoiceInFk: 1,
net: 10,
intrastatFk: 6021010,
amount: 20,
stems: 205,
countryFk: 5,
statisticalValue: 0
}
];
controller.calculateTotals();
expect(controller.amountTotal).toEqual(30);
expect(controller.netTotal).toEqual(40.5);
expect(controller.stemsTotal).toEqual(367);
});
});
describe('onSubmit()', () => {
it('should make HTTP POST request to save intrastat values', () => {
controller.card = {reload: () => {}};
jest.spyOn($scope.watcher, 'check');
jest.spyOn($scope.watcher, 'notifySaved');
jest.spyOn($scope.watcher, 'updateOriginalData');
jest.spyOn(controller.card, 'reload');
jest.spyOn($scope.model, 'save');
controller.onSubmit();
expect($scope.model.save).toHaveBeenCalledWith();
expect($scope.watcher.updateOriginalData).toHaveBeenCalledWith();
expect($scope.watcher.check).toHaveBeenCalledWith();
expect($scope.watcher.notifySaved).toHaveBeenCalledWith();
expect(controller.card.reload).toHaveBeenCalledWith();
});
});
});
});

View File

@ -9,10 +9,13 @@ InvoiceIn cloned: Factura clonada
InvoiceIn deleted: Factura eliminada InvoiceIn deleted: Factura eliminada
Invoice list: Listado de facturas recibidas Invoice list: Listado de facturas recibidas
InvoiceIn booked: Factura contabilizada InvoiceIn booked: Factura contabilizada
Net: Neto
Remove tax: Quitar iva Remove tax: Quitar iva
Remove due day: Quitar vencimiento Remove due day: Quitar vencimiento
Sage tax: Sage iva Sage tax: Sage iva
Sage transaction: Sage transaccion Sage transaction: Sage transaccion
Search invoices in by reference: Buscar facturas recibidas por referencia Search invoices in by reference: Buscar facturas recibidas por referencia
To book: Contabilizar To book: Contabilizar
Total amount: Total importe
Total net: Total neto
Total stems: Total tallos

View File

@ -27,6 +27,10 @@
"state": "invoiceIn.card.dueDay", "state": "invoiceIn.card.dueDay",
"icon": "icon-calendar" "icon": "icon-calendar"
}, },
{
"state": "invoiceIn.card.intrastat",
"icon": "icon-lines"
},
{ {
"state": "invoiceIn.card.log", "state": "invoiceIn.card.log",
"icon": "history" "icon": "history"
@ -109,6 +113,16 @@
}, },
"acl": ["administrative"] "acl": ["administrative"]
}, },
{
"url": "/intrastat",
"state": "invoiceIn.card.intrastat",
"component": "vn-invoice-in-intrastat",
"description": "Intrastat",
"params": {
"invoice-in": "$ctrl.invoiceIn"
},
"acl": ["administrative"]
},
{ {
"url": "/log", "url": "/log",
"state": "invoiceIn.card.log", "state": "invoiceIn.card.log",

View File

@ -120,6 +120,37 @@
</vn-table> </vn-table>
</vn-one> </vn-one>
</vn-horizontal> </vn-horizontal>
<vn-horizontal>
<vn-one ng-if="$ctrl.summary.invoiceInIntrastat.length != 0">
<h4>
<a
ui-sref="invoiceIn.card.intrastat({id:$ctrl.invoiceIn.id})"
target="_self">
<span translate vn-tooltip="Go to">Intrastat</span>
</a>
</h4>
<vn-table model="model">
<vn-thead>
<vn-tr>
<vn-th>Code</vn-th>
<vn-th>Amount</vn-th>
<vn-th>Net</vn-th>
<vn-th>Stems</vn-th>
<vn-th>Country</vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>
<vn-tr ng-repeat="intrastat in $ctrl.summary.invoiceInIntrastat">
<vn-td>{{::intrastat.intrastatFk | zeroFill:8}}: {{::intrastat.intrastat.description}}</vn-td>
<vn-td>{{::intrastat.amount | currency: 'EUR':2}}</vn-td>
<vn-td>{{::intrastat.net}}</vn-td>
<vn-td>{{::intrastat.stems}}</vn-td>
<vn-td>{{::intrastat.country.code}}</vn-td>
</vn-tr>
</vn-tbody>
</vn-table>
</vn-one>
</vn-horizontal>
</vn-card> </vn-card>
<vn-supplier-descriptor-popover <vn-supplier-descriptor-popover
vn-id="supplierDescriptor"> vn-id="supplierDescriptor">

View File

@ -112,9 +112,6 @@
"itemPackingTypeFk": { "itemPackingTypeFk": {
"type": "string" "type": "string"
}, },
"compression": {
"type": "number"
},
"hasKgPrice": { "hasKgPrice": {
"type": "boolean", "type": "boolean",
"description": "Price per Kg" "description": "Price per Kg"

View File

@ -129,14 +129,6 @@
ng-model="$ctrl.item.density" ng-model="$ctrl.item.density"
rule> rule>
</vn-input-number> </vn-input-number>
<vn-input-number
vn-one
min="0"
step="0.01"
label="Compression"
ng-model="$ctrl.item.compression"
rule>
</vn-input-number>
<vn-autocomplete <vn-autocomplete
vn-one vn-one
label="Generic" label="Generic"

View File

@ -40,7 +40,6 @@ Create: Crear
Client card: Ficha del cliente Client card: Ficha del cliente
Shipped: F. envío Shipped: F. envío
stems: Tallos stems: Tallos
Compression: Compresión
Density: Densidad Density: Densidad
Search items by id, name or barcode: Buscar articulos por identificador, nombre o codigo de barras Search items by id, name or barcode: Buscar articulos por identificador, nombre o codigo de barras
SalesPerson: Comercial SalesPerson: Comercial

View File

@ -94,9 +94,6 @@
<vn-label-value label="Density" <vn-label-value label="Density"
value="{{$ctrl.summary.item.density}}"> value="{{$ctrl.summary.item.density}}">
</vn-label-value> </vn-label-value>
<vn-label-value label="Compression"
value="{{$ctrl.summary.item.compression}}">
</vn-label-value>
<vn-label-value label="Expense" <vn-label-value label="Expense"
value="{{$ctrl.summary.item.expense.name}}"> value="{{$ctrl.summary.item.expense.name}}">
</vn-label-value> </vn-label-value>

View File

@ -1,5 +1,4 @@
const models = require('vn-loopback/server/server').models; const models = require('vn-loopback/server/server').models;
const soap = require('soap');
describe('ticket sendSms()', () => { describe('ticket sendSms()', () => {
it('should send a message and log it', async() => { it('should send a message and log it', async() => {
@ -8,7 +7,6 @@ describe('ticket sendSms()', () => {
try { try {
const options = {transaction: tx}; const options = {transaction: tx};
spyOn(soap, 'createClientAsync').and.returnValue('a so fake client');
const ctx = {req: {accessToken: {userId: 9}}}; const ctx = {req: {accessToken: {userId: 9}}};
const id = 11; const id = 11;
const destination = 222222222; const destination = 222222222;

View File

@ -90,7 +90,7 @@ describe('sale updateDiscount()', () => {
expect(error.message).toEqual(`The sales of this ticket can't be modified`); expect(error.message).toEqual(`The sales of this ticket can't be modified`);
}); });
it('should update the discount if the salesPerson has mana', async() => { it('should update the discount if the salesPerson has mana and manaCode = "mana"', async() => {
const tx = await models.Ticket.beginTransaction({}); const tx = await models.Ticket.beginTransaction({});
try { try {
@ -108,8 +108,49 @@ describe('sale updateDiscount()', () => {
const newDiscount = 100; const newDiscount = 100;
const manaDiscount = await models.Component.findOne({where: {code: 'mana'}}, options); const manaDiscount = await models.Component.findOne({where: {code: 'mana'}}, options);
const componentId = manaDiscount.id; const componentId = manaDiscount.id;
const manaCode = 'mana';
await models.Ticket.updateDiscount(ctx, ticketId, sales, newDiscount, options); await models.Ticket.updateDiscount(ctx, ticketId, sales, newDiscount, manaCode, options);
const updatedSale = await models.Sale.findById(originalSaleId, null, options);
const createdSaleComponent = await models.SaleComponent.findOne({
where: {
componentFk: componentId,
saleFk: originalSaleId
}
}, options);
expect(createdSaleComponent.componentFk).toEqual(componentId);
expect(updatedSale.discount).toEqual(100);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should update the discount if the salesPerson has mana and manaCode = "manaClaim"', async() => {
const tx = await models.Ticket.beginTransaction({});
try {
const options = {transaction: tx};
const ctx = {
req: {
accessToken: {userId: 18},
headers: {origin: 'localhost:5000'},
__: () => {}
}
};
const ticketId = 11;
const sales = [originalSaleId];
const newDiscount = 100;
const manaDiscount = await models.Component.findOne({where: {code: 'manaClaim'}}, options);
const componentId = manaDiscount.id;
const manaCode = 'manaClaim';
await models.Ticket.updateDiscount(ctx, ticketId, sales, newDiscount, manaCode, options);
const updatedSale = await models.Sale.findById(originalSaleId, null, options); const updatedSale = await models.Sale.findById(originalSaleId, null, options);
const createdSaleComponent = await models.SaleComponent.findOne({ const createdSaleComponent = await models.SaleComponent.findOne({

View File

@ -23,6 +23,12 @@ module.exports = Self => {
description: 'The new discount', description: 'The new discount',
type: 'number', type: 'number',
required: true required: true
},
{
arg: 'manaCode',
description: 'The type of mana',
type: 'string',
required: false
} }
], ],
returns: { returns: {
@ -35,7 +41,7 @@ module.exports = Self => {
} }
}); });
Self.updateDiscount = async(ctx, id, salesIds, newDiscount, options) => { Self.updateDiscount = async(ctx, id, salesIds, newDiscount, manaCode, options) => {
const $t = ctx.req.__; // $translate const $t = ctx.req.__; // $translate
const models = Self.app.models; const models = Self.app.models;
const myOptions = {}; const myOptions = {};
@ -98,7 +104,7 @@ module.exports = Self => {
}, },
fields: 'amount'}, myOptions); fields: 'amount'}, myOptions);
const componentCode = usesMana ? 'mana' : 'buyerDiscount'; const componentCode = usesMana ? manaCode : 'buyerDiscount';
const discountComponent = await models.Component.findOne({ const discountComponent = await models.Component.findOne({
where: {code: componentCode}}, myOptions); where: {code: componentCode}}, myOptions);

View File

@ -285,10 +285,21 @@
vn-focus vn-focus
label="Discount" label="Discount"
ng-model="$ctrl.edit.discount" ng-model="$ctrl.edit.discount"
on-change="$ctrl.changeDiscount()"
clear-disabled="true" clear-disabled="true"
suffix="%"> suffix="%">
</vn-input-number> </vn-input-number>
<vn-vertical ng-if="$ctrl.currentWorkerMana != 0">
<vn-radio
label="Promotion mana"
val="mana"
ng-model="$ctrl.manaCode">
</vn-radio>
<vn-radio
label="Claim mana"
val="manaClaim"
ng-model="$ctrl.manaCode">
</vn-radio>
</vn-vertical>
<div class="simulator"> <div class="simulator">
<p class="simulatorTitle" translate>New price</p> <p class="simulatorTitle" translate>New price</p>
<p> <p>
@ -297,6 +308,16 @@
</div> </div>
</div> </div>
</div> </div>
<vn-horizontal >
<vn-button
label="Cancel"
ng-click="$ctrl.cancel()">
</vn-button>
<vn-button
label="Save"
ng-click="$ctrl.save()">
</vn-button>
</vn-horizontal>
</div> </div>
</vn-popover> </vn-popover>

View File

@ -6,6 +6,15 @@ class Controller extends Section {
constructor($element, $) { constructor($element, $) {
super($element, $); super($element, $);
this._sales = []; this._sales = [];
this.manaCode = 'mana';
}
get manaCode() {
return this._manaCode;
}
set manaCode(value) {
this._manaCode = value;
} }
get ticket() { get ticket() {
@ -66,6 +75,14 @@ class Controller extends Section {
this.$.editPricePopover.relocate(); this.$.editPricePopover.relocate();
}); });
}); });
this.getCurrentWorkerMana();
}
getCurrentWorkerMana() {
this.$http.get(`WorkerManas/getCurrentWorkerMana`)
.then(res => {
this.currentWorkerMana = res.data;
});
} }
/** /**
@ -273,7 +290,7 @@ class Controller extends Section {
return sale.id; return sale.id;
}); });
const params = {salesIds: saleIds, newDiscount: this.edit.discount}; const params = {salesIds: saleIds, newDiscount: this.edit.discount, manaCode: this.manaCode};
const query = `Tickets/${this.$params.id}/updateDiscount`; const query = `Tickets/${this.$params.id}/updateDiscount`;
this.$http.post(query, params).then(() => { this.$http.post(query, params).then(() => {
this.vnApp.showSuccess(this.$t('Data saved!')); this.vnApp.showSuccess(this.$t('Data saved!'));
@ -479,6 +496,14 @@ class Controller extends Section {
? {id: $search} ? {id: $search}
: {name: {like: '%' + $search + '%'}}; : {name: {like: '%' + $search + '%'}};
} }
save() {
this.changeDiscount();
}
cancel() {
this.$.editDiscount.hide();
}
} }
ngModule.vnComponent('vnTicketSale', { ngModule.vnComponent('vnTicketSale', {

View File

@ -43,7 +43,7 @@ describe('Ticket', () => {
$scope.sms = {open: () => {}}; $scope.sms = {open: () => {}};
$scope.ticket = ticket; $scope.ticket = ticket;
$scope.model = crudModel; $scope.model = crudModel;
$scope.editDiscount = {relocate: () => {}}; $scope.editDiscount = {relocate: () => {}, hide: () => {}};
$scope.editPricePopover = {relocate: () => {}}; $scope.editPricePopover = {relocate: () => {}};
$httpBackend = _$httpBackend_; $httpBackend = _$httpBackend_;
Object.defineProperties($state.params, { Object.defineProperties($state.params, {
@ -115,10 +115,12 @@ describe('Ticket', () => {
const expectedAmount = 250; const expectedAmount = 250;
$httpBackend.expect('GET', 'Tickets/1/getSalesPersonMana').respond(200, expectedAmount); $httpBackend.expect('GET', 'Tickets/1/getSalesPersonMana').respond(200, expectedAmount);
$httpBackend.expect('GET', 'WorkerManas/getCurrentWorkerMana').respond(200, expectedAmount);
controller.getMana(); controller.getMana();
$httpBackend.flush(); $httpBackend.flush();
expect(controller.edit.mana).toEqual(expectedAmount); expect(controller.edit.mana).toEqual(expectedAmount);
expect(controller.currentWorkerMana).toEqual(expectedAmount);
}); });
}); });
@ -446,7 +448,7 @@ describe('Ticket', () => {
const expectedSales = [firstSelectedSale, secondSelectedSale]; const expectedSales = [firstSelectedSale, secondSelectedSale];
const expectedSaleIds = [firstSelectedSale.id, secondSelectedSale.id]; const expectedSaleIds = [firstSelectedSale.id, secondSelectedSale.id];
const expectedParams = {salesIds: expectedSaleIds, newDiscount: expectedDiscount}; const expectedParams = {salesIds: expectedSaleIds, newDiscount: expectedDiscount, manaCode: 'mana'};
$httpBackend.expect('POST', `Tickets/1/updateDiscount`, expectedParams).respond(200, {discount: 10}); $httpBackend.expect('POST', `Tickets/1/updateDiscount`, expectedParams).respond(200, {discount: 10});
controller.updateDiscount(expectedSales); controller.updateDiscount(expectedSales);
$httpBackend.flush(); $httpBackend.flush();
@ -732,5 +734,14 @@ describe('Ticket', () => {
expect(result).toEqual({name: {like: '%' + itemName + '%'}}); expect(result).toEqual({name: {like: '%' + itemName + '%'}});
}); });
}); });
describe('cancel()', () => {
it('should call hide()', () => {
jest.spyOn(controller.$.editDiscount, 'hide').mockReturnThis();
controller.cancel();
expect(controller.$.editDiscount.hide).toHaveBeenCalledWith();
});
});
}); });
}); });

View File

@ -37,3 +37,5 @@ Agency: Agencia
Shipped: F. envio Shipped: F. envio
Packaging: Encajado Packaging: Encajado
Pay Back: Abono Pay Back: Abono
Promotion mana: Maná promoción
Claim mana: Maná reclamación

View File

@ -20,9 +20,6 @@
"created": { "created": {
"type": "date" "type": "date"
}, },
"temperature": {
"type": "string"
},
"temperatureFk": { "temperatureFk": {
"type": "string", "type": "string",
"required": true "required": true

View File

@ -158,7 +158,7 @@
<vn-tbody> <vn-tbody>
<vn-tr ng-repeat="thermograph in $ctrl.travelThermographs"> <vn-tr ng-repeat="thermograph in $ctrl.travelThermographs">
<vn-td>{{thermograph.thermographFk}} </vn-td> <vn-td>{{thermograph.thermographFk}} </vn-td>
<vn-td>{{thermograph.temperature}}</vn-td> <vn-td>{{thermograph.temperatureFk}}</vn-td>
<vn-td>{{thermograph.result}}</vn-td> <vn-td>{{thermograph.result}}</vn-td>
<vn-td>{{thermograph.warehouse.name}}</vn-td> <vn-td>{{thermograph.warehouse.name}}</vn-td>
<vn-td expand>{{thermograph.created | date: 'dd/MM/yyyy'}}</vn-td> <vn-td expand>{{thermograph.created | date: 'dd/MM/yyyy'}}</vn-td>

View File

@ -78,7 +78,7 @@
class="clickable search-result"> class="clickable search-result">
<vn-td number>{{::zone.id}}</vn-td> <vn-td number>{{::zone.id}}</vn-td>
<vn-td expand>{{::zone.name}}</vn-td> <vn-td expand>{{::zone.name}}</vn-td>
<vn-td>{{::zone.agencyMode.name}}</vn-td> <vn-td>{{::zone.agencyModeName}}</vn-td>
<vn-td shrink>{{::zone.hour | date: 'HH:mm'}}</vn-td> <vn-td shrink>{{::zone.hour | date: 'HH:mm'}}</vn-td>
<vn-td number>{{::zone.price | currency: 'EUR':2}}</vn-td> <vn-td number>{{::zone.price | currency: 'EUR':2}}</vn-td>
<vn-td shrink> <vn-td shrink>

View File

@ -104,7 +104,7 @@
"test": "jest --watch", "test": "jest --watch",
"back": "nodemon --inspect -w modules ./node_modules/gulp/bin/gulp.js back", "back": "nodemon --inspect -w modules ./node_modules/gulp/bin/gulp.js back",
"lint": "eslint ./ --cache --ignore-pattern .gitignore", "lint": "eslint ./ --cache --ignore-pattern .gitignore",
"docker": "docker build -t salix-db ./db" "docker": "docker build --progress=plain -t salix-db ./db"
}, },
"jest": { "jest": {
"projects": [ "projects": [