merge
gitea/salix/test This commit looks good Details

This commit is contained in:
Joan Sanchez 2019-07-29 08:35:58 +02:00
commit 2c6ba0089b
126 changed files with 3954 additions and 1950 deletions

4
.gitignore vendored
View File

@ -1,7 +1,9 @@
node_modules
dist/*
e2e/dms/*/
!e2e/dms/temp/
!e2e/dms/c4c
!e2e/dms/c81
!e2e/dms/ecc
npm-debug.log
.eslintcache
datasources.*.json

View File

@ -30,11 +30,7 @@ module.exports = Self => {
arg: 'description',
type: 'String'
}, {
arg: 'hasFile',
type: 'Boolean',
description: 'True if has original file'
}, {
arg: 'hasAttachedFile',
arg: 'hasFileAttached',
type: 'Boolean',
description: 'True if has an attached file'
}],
@ -49,7 +45,7 @@ module.exports = Self => {
});
Self.updateFile = async(ctx, id, warehouseId, companyId,
dmsTypeId, reference, description, hasFile, hasAttachedFile, options) => {
dmsTypeId, reference, description, hasFileAttached, options) => {
const models = Self.app.models;
let tx;
@ -74,11 +70,10 @@ module.exports = Self => {
companyFk: companyId,
warehouseFk: warehouseId,
reference: reference,
description: description,
hasFile: hasFile
description: description
}, myOptions);
if (hasAttachedFile)
if (hasFileAttached)
await uploadNewFile(ctx, dms, myOptions);
if (tx) await tx.commit();

View File

@ -21,6 +21,7 @@ WORKDIR /docker-entrypoint-initdb.d
ARG STAMP=unknown
COPY import-changes.sh config.ini /docker-entrypoint-initdb.d/import/
COPY docker.cnf /etc/mysql/mysql.conf.d/
COPY changes /docker-entrypoint-initdb.d/import/changes
COPY docker-boot.sh /docker-entrypoint-initdb.d/

View File

@ -1,16 +0,0 @@
UPDATE `salix`.`ACL` SET principalId ='employee' WHERE id = 122;
INSERT INTO `salix`.`ACL` (`id`, `model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
VALUES
(167, 'Worker', 'isSubordinate', 'READ', 'ALLOW', 'ROLE', 'employee'),
(168, 'Worker', 'mySubordinates', 'READ', 'ALLOW', 'ROLE', 'employee'),
(169, 'WorkerTimeControl', 'filter', 'READ', 'ALLOW', 'ROLE', 'employee'),
(170, 'WorkerTimeControl', 'addTime', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
(171, 'TicketServiceType', '*', 'WRITE', 'ALLOW', 'ROLE', 'administrative');
-- ONLY FOR ACL ALREADY ON PRODUCTION
INSERT IGNORE INTO `salix`.`ACL` (`id`, `model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
VALUES
(172, 'Sms', '*', 'READ', 'ALLOW', 'ROLE', 'employee'),
(173, 'Sms', 'send', 'WRITE', 'ALLOW', 'ROLE', 'employee');

View File

@ -1,12 +0,0 @@
ALTER TABLE `vn2008`.`cl_est`
ADD COLUMN `roleFk` INT(10) UNSIGNED NOT NULL DEFAULT '1' AFTER `estado`;
ALTER TABLE `vn2008`.`cl_est`
ADD INDEX `roleFgn_idx` (`roleFk` ASC);
ALTER TABLE `vn2008`.`cl_est`
ADD CONSTRAINT `roleFgn`
FOREIGN KEY (`roleFk`)
REFERENCES `account`.`role` (`id`)
ON DELETE RESTRICT
ON UPDATE CASCADE;

View File

@ -1,10 +0,0 @@
CREATE
ALGORITHM = UNDEFINED
DEFINER = `root`@`%`
SQL SECURITY DEFINER
VIEW `vn`.`clientDms` AS
SELECT
`g`.`Id_Cliente` AS `clientFk`,
`g`.`gest_doc_id` AS `dmsFk`
FROM
`vn2008`.`clientes_gestdoc` `g`

View File

@ -1,19 +0,0 @@
CREATE
OR REPLACE ALGORITHM = UNDEFINED
DEFINER = `root`@`%`
SQL SECURITY DEFINER
VIEW `vn`.`dms` AS
SELECT
`g`.`id` AS `id`,
`g`.`gesttip_id` AS `dmsTypeFk`,
`g`.`file` AS `file`,
`g`.`trabajador_id` AS `workerFk`,
`g`.`warehouse_id` AS `warehouseFk`,
`g`.`emp_id` AS `companyFk`,
`g`.`orden` AS `hardCopyNumber`,
`g`.`original` AS `hasFile`,
`g`.`sref` AS `reference`,
`g`.`brief` AS `description`,
`g`.`odbc_date` AS `created`
FROM
`vn2008`.`gestdoc` `g`

View File

@ -1 +0,0 @@
UPDATE `vn2008`.`mandato_tipo` SET `Nombre`='LCR' WHERE `idmandato_tipo`='3';

View File

@ -1,4 +0,0 @@
INSERT INTO `vn`.`sample`(`code`, `description`, `isVisible`, `hasCompany`)
VALUES
('client-lcr', 'Email de solicitud de datos bancarios LCR', 1, 1);

View File

@ -1,2 +0,0 @@
ALTER TABLE `bi`.`tarifa_componentes`
ADD COLUMN `code` VARCHAR(45) NULL DEFAULT NULL AFTER `is_renewable`;

View File

@ -1,11 +0,0 @@
CREATE
OR REPLACE ALGORITHM = UNDEFINED
DEFINER = `root`@`%`
SQL SECURITY DEFINER
VIEW `vn`.`claimState` AS
SELECT
`c`.`id` AS `id`,
`c`.`estado` AS `description`,
`c`.`roleFk` AS `roleFk`
FROM
`vn2008`.`cl_est` `c`;

View File

@ -1,16 +0,0 @@
CREATE
OR REPLACE ALGORITHM = UNDEFINED
DEFINER = `root`@`%`
SQL SECURITY DEFINER
VIEW `vn`.`componentRate` AS
SELECT
`t`.`Id_Componente` AS `id`,
`t`.`Componente` AS `name`,
`t`.`tarifa_componentes_series_id` AS `componentTypeRate`,
`t`.`tarifa_class` AS `classRate`,
`t`.`tax` AS `tax`,
`t`.`is_renewable` AS `isRenewable`,
`t`.`code` AS `code`
FROM
`bi`.`tarifa_componentes` `t`;

View File

@ -1,26 +0,0 @@
CREATE OR REPLACE
ALGORITHM = UNDEFINED
DEFINER = `root`@`%`
SQL SECURITY DEFINER
VIEW `vn`.`ticket` AS
SELECT
`t`.`Id_Ticket` AS `id`,
`t`.`Id_Cliente` AS `clientFk`,
`t`.`warehouse_id` AS `warehouseFk`,
`t`.`Fecha` AS `shipped`,
`t`.`landing` AS `landed`,
`t`.`Alias` AS `nickname`,
`t`.`Factura` AS `refFk`,
`t`.`Id_Consigna` AS `addressFk`,
`t`.`Localizacion` AS `location`,
`t`.`Solucion` AS `solution`,
`t`.`Id_Ruta` AS `routeFk`,
`t`.`empresa_id` AS `companyFk`,
`t`.`Id_Agencia` AS `agencyModeFk`,
`t`.`Prioridad` AS `priority`,
`t`.`Bultos` AS `packages`,
`t`.`isDeleted` AS `isDeleted`,
`t`.`odbc_date` AS `created`,
`t`.`zoneFk` AS `zoneFk`
FROM
`vn2008`.`Tickets` `t`;

View File

@ -1,17 +0,0 @@
INSERT INTO `salix`.`ACL` ( `model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
VALUES
('Dms', 'removeFile', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
('Dms', 'uploadFile', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
('Dms', 'downloadFile', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Client', 'uploadFile', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
('ClientDms', 'removeFile', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
('ClientDms', '*', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'uploadFile', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
('TicketDms', 'removeFile', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
('TicketDms', '*', 'READ', 'ALLOW', 'ROLE', 'employee'),
('Route', 'updateVolume', 'WRITE', 'ALLOW', 'ROLE', 'deliveryBoss');
INSERT INTO `salix`.`ACL` (`id`, `model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('', 'Agency', 'getLanded', 'READ', 'ALLOW', 'ROLE', 'employee');
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`) VALUES ('Agency', 'getShipped', 'READ', 'ALLOW', 'ROLE', 'employee');

View File

@ -1,15 +0,0 @@
ALTER TABLE `vn2008`.`clientes_gestdoc`
DROP FOREIGN KEY `clientes_gestdoc_ibfk_3`;
ALTER TABLE `vn2008`.`clientes_gestdoc`
DROP PRIMARY KEY,
ADD PRIMARY KEY (`gest_doc_id`);
ALTER TABLE `vn2008`.`clientes_gestdoc`
ADD INDEX `fk_clientes_gestdoc_1_idx` (`Id_Cliente` ASC);
ALTER TABLE `vn2008`.`clientes_gestdoc`
ADD CONSTRAINT `fk_clientes_gestdoc_3`
FOREIGN KEY (`Id_Cliente`)
REFERENCES `vn2008`.`Clientes` (`id_cliente`)
ON DELETE RESTRICT
ON UPDATE CASCADE;

View File

@ -1,28 +0,0 @@
DROP TRIGGER IF EXISTS `vn2008`.`expeditionsBeforeInsert`;
DELIMITER $$
CREATE DEFINER=`root`@`%` TRIGGER `vn2008`.`expeditionsBeforeInsert`
BEFORE INSERT ON `expeditions` FOR EACH ROW
-- Edit trigger body code below this line. Do not edit lines above this one
BEGIN
DECLARE intcounter INT;
DECLARE vShipFk INT;
IF NEW.EsBulto > 0 THEN
UPDATE Tickets SET Bultos = nz(Bultos) + 1 WHERE Id_Ticket = NEW.ticket_id;
SELECT IFNULL(MAX(counter),0) +1 INTO intcounter FROM expeditions e
INNER JOIN Tickets t1 ON e.ticket_id = t1.Id_Ticket
LEFT JOIN vn.ticketState ts ON ts.ticket = t1.Id_Ticket
INNER JOIN Tickets t2 ON t2.Id_Consigna = t1.Id_Consigna AND DATE(t2.Fecha) = DATE(t1.Fecha) AND t1.warehouse_id = t2.warehouse_id
WHERE t2.Id_Ticket = NEW.ticket_id AND ts.alertLevel < 3 AND t1.empresa_id = t2.empresa_id AND t1.Id_Agencia = t2.Id_Agencia;
SET NEW.`counter` = intcounter;
END IF;
-- JGF 14/01/19 si existe un polizon queda anulado
SELECT shipFk INTO vShipFk FROM vn.stowaway WHERE id = NEW.ticket_id;
IF vShipFk THEN
CALL vn.stowawayUnBoarding(vShipFk, NEW.ticket_id);
END IF;
END$$
DELIMITER ;

View File

@ -1,21 +0,0 @@
-- adds column to table
ALTER TABLE `vn2008`.`gesttip`
ADD COLUMN `code` VARCHAR(45) NOT NULL AFTER `readRoleFk`;
-- adds column to view
CREATE
OR REPLACE ALGORITHM = UNDEFINED
DEFINER = `root`@`%`
SQL SECURITY DEFINER
VIEW `vn`.`dmsType` AS
SELECT
`g`.`id` AS `id`,
`g`.`tipo` AS `name`,
`g`.`path` AS `path`,
`g`.`readRoleFk` AS `readRoleFk`,
`g`.`writeRoleFk` AS `writeRoleFk`,
`g`.`code` AS `code`
FROM
`vn2008`.`gesttip` `g`;

View File

@ -1,17 +0,0 @@
DROP procedure IF EXISTS `vn`.`routeUpdateM3`;
DELIMITER $$
CREATE DEFINER=`root`@`%` PROCEDURE `vn`.`routeUpdateM3`(vRoute INT)
BEGIN
UPDATE vn.route r
JOIN (SELECT routeFk, SUM(volume) AS m3
FROM ticketGetVolume
WHERE routeFk = vRoute
) v ON v.routeFk = r.id
SET r.m3 = v.m3;
END$$
DELIMITER ;

View File

@ -1,17 +0,0 @@
UPDATE `bi`.`tarifa_componentes` SET `code`='specialPrices' WHERE `Id_Componente`='10';
UPDATE `bi`.`tarifa_componentes` SET `code`='extraCostPerWeekDay' WHERE `Id_Componente`='14';
UPDATE `bi`.`tarifa_componentes` SET `code`='delivery' WHERE `Id_Componente`='15';
UPDATE `bi`.`tarifa_componentes` SET `code`='debtCollection' WHERE `Id_Componente`='17';
UPDATE `bi`.`tarifa_componentes` SET `code`='adjustment' WHERE `Id_Componente`='21';
UPDATE `bi`.`tarifa_componentes` SET `code`='salePerPackage' WHERE `Id_Componente`='22';
UPDATE `bi`.`tarifa_componentes` SET `code`='salePerBox' WHERE `Id_Componente`='23';
UPDATE `bi`.`tarifa_componentes` SET `code`='purchaseValue' WHERE `Id_Componente`='28';
UPDATE `bi`.`tarifa_componentes` SET `code`='margin' WHERE `Id_Componente`='29';
UPDATE `bi`.`tarifa_componentes` SET `code`='lastUnitsDiscount' WHERE `Id_Componente`='32';
UPDATE `bi`.`tarifa_componentes` SET `code`='salePerBox' WHERE `Id_Componente`='33';
UPDATE `bi`.`tarifa_componentes` SET `code`='buyerDiscount' WHERE `Id_Componente`='34';
UPDATE `bi`.`tarifa_componentes` SET `code`='mismatch' WHERE `Id_Componente`='36';
UPDATE `bi`.`tarifa_componentes` SET `code`='mana' WHERE `Id_Componente`='37';
UPDATE `bi`.`tarifa_componentes` SET `code`='bagged' WHERE `Id_Componente`='38';
UPDATE `bi`.`tarifa_componentes` SET `code`='autoMana' WHERE `Id_Componente`='39';
UPDATE `bi`.`tarifa_componentes` SET `code`='freightCharge' WHERE `Id_Componente`='41';

View File

@ -1,49 +0,0 @@
DROP procedure IF EXISTS `vn`.`zoneGetWarehouse`;
DELIMITER $$
CREATE DEFINER=`root`@`%` PROCEDURE `vn`.`zoneGetWarehouse`(vAddress INT, vLanded DATE, vWarehouse INT)
BEGIN
/**
* Devuelve el listado de agencias disponibles para la fecha,
* dirección y warehouse pasadas
*
* @param vAddress
* @param vWarehouse warehouse
* @param vLanded Fecha de recogida
* @select Listado de agencias disponibles
*/
DECLARE vPostalCode varchar(10);
SELECT postalCode INTO vPostalCode
FROM address WHERE id = vAddress;
SELECT * FROM (
SELECT * FROM (
SELECT am.id agencyModeFk,
am.name agencyMode,
am.description,
am.deliveryMethodFk,
TIMESTAMPADD(DAY,-z.travelingDays, vLanded) shipped,
z.warehouseFk,
zi.isIncluded,
z.id zoneFk
FROM zoneGeo zgSon
JOIN zoneGeo zgFather ON zgSon.lft BETWEEN zgFather.lft AND zgFather.rgt
JOIN zoneIncluded zi ON zi.geoFk = zgFather.id
JOIN zone z ON z.id = zi.zoneFk
JOIN zoneCalendar zc ON zc.zoneFk = z.id
JOIN agencyMode am ON am.id = z.agencyModeFk
WHERE zgSon.`name` LIKE vPostalCode
AND delivered = vLanded
AND z.warehouseFk = vWarehouse
AND IF(TIMESTAMPADD(DAY,-z.travelingDays, vLanded) = CURDATE(), hour(now()) < hour(z.`hour`),TRUE)
ORDER BY z.id, zgFather.depth DESC) t
GROUP BY zoneFk
HAVING isIncluded > 0) t
GROUP BY agencyModeFk;
END$$
DELIMITER ;

View File

@ -1,24 +0,0 @@
UPDATE `vn2008`.`gesttip` SET `writeRoleFk`='1', `readRoleFk`='1' WHERE `id`='5';
UPDATE `vn2008`.`gesttip` SET `writeRoleFk`='1', `readRoleFk`='1' WHERE `id`='12';
UPDATE `vn2008`.`gesttip` SET `writeRoleFk`='1', `readRoleFk`='1' WHERE `id`='14';
UPDATE `vn2008`.`gesttip` SET `writeRoleFk`='1', `readRoleFk`='1' WHERE `id`='13';
UPDATE `vn2008`.`gesttip` SET `code`='invoiceIn' WHERE `id`='1';
UPDATE `vn2008`.`gesttip` SET `code`='officialDoc' WHERE `id`='2';
UPDATE `vn2008`.`gesttip` SET `code`='hhrrData' WHERE `id`='3';
UPDATE `vn2008`.`gesttip` SET `code`='deliveryNote' WHERE `id`='4';
UPDATE `vn2008`.`gesttip` SET `code`='miscellaneous' WHERE `id`='5';
UPDATE `vn2008`.`gesttip` SET `code`='tests' WHERE `id`='6';
UPDATE `vn2008`.`gesttip` SET `code`='economicActivitiesTax' WHERE `id`='7';
UPDATE `vn2008`.`gesttip` SET `code`='fiscal' WHERE `id`='8';
UPDATE `vn2008`.`gesttip` SET `code`='vehicles' WHERE `id`='9';
UPDATE `vn2008`.`gesttip` SET `code`='templates' WHERE `id`='10';
UPDATE `vn2008`.`gesttip` SET `code`='contracts' WHERE `id`='11';
UPDATE `vn2008`.`gesttip` SET `code`='paymentsLaw' WHERE `id`='12';
UPDATE `vn2008`.`gesttip` SET `code`='trash' WHERE `id`='13';
UPDATE `vn2008`.`gesttip` SET `code`='ticket' WHERE `id`='14';
UPDATE `vn2008`.`gesttip` SET `code`='budgets' WHERE `id`='15';
UPDATE `vn2008`.`gesttip` SET `code`='logistics' WHERE `id`='16';
UPDATE `vn2008`.`gesttip` SET `code`='cmr' WHERE `id`='17';
UPDATE `vn2008`.`gesttip` SET `code`='dua' WHERE `id`='18';
UPDATE `vn2008`.`gesttip` SET `code`='fixedAssets' WHERE `id`='19';

View File

@ -1,28 +0,0 @@
ALTER TABLE `vn2008`.`Paises`
ADD COLUMN `ibanLength` TINYINT(4) NULL DEFAULT NULL AFTER `isUeeMember`;
CREATE
OR REPLACE ALGORITHM = UNDEFINED
DEFINER = `root`@`%`
SQL SECURITY DEFINER
VIEW `vn`.`country` AS
SELECT
`p`.`Id` AS `id`,
`p`.`Pais` AS `country`,
`p`.`CEE` AS `CEE`,
`p`.`isUeeMember` AS `isUeeMember`,
`p`.`Codigo` AS `code`,
`p`.`Id_Moneda` AS `currencyFk`,
`p`.`Id_Paisreal` AS `politicalCountryFk`,
`p`.`geoFk` AS `geoFk`,
`p`.`ibanLength` AS `ibanLength`
FROM
`vn2008`.`Paises` `p`;
UPDATE `vn2008`.`Paises` SET `ibanLength`=22 WHERE `Id`=1;
UPDATE `vn2008`.`Paises` SET `ibanLength`=25 WHERE `Id`=2;
UPDATE `vn2008`.`Paises` SET `ibanLength`=20 WHERE `Id`=3;
UPDATE `vn2008`.`Paises` SET `ibanLength`=22 WHERE `Id`=4;
UPDATE `vn2008`.`Paises` SET `ibanLength`=16 WHERE `Id`=5;
UPDATE `vn2008`.`Paises` SET `ibanLength`=25 WHERE `Id`=19;
UPDATE `vn2008`.`Paises` SET `ibanLength`=22 WHERE `Id`=30;

View File

@ -1,5 +0,0 @@
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
VALUES
('Zone', 'editPrices', 'WRITE', 'ALLOW', 'ROLE', 'deliveryBoss'),
('Postcode', '*', 'WRITE', 'ALLOW', 'ROLE', 'employee'),
('Ticket', 'addSale', 'WRITE', 'ALLOW', 'ROLE', 'employee');

View File

@ -1,3 +0,0 @@
ALTER TABLE `vn`.`zoneCalendar`
ADD COLUMN `price` DOUBLE NOT NULL AFTER `delivered`,
ADD COLUMN `bonus` DOUBLE NOT NULL AFTER `price`;

View File

@ -1,139 +0,0 @@
DROP procedure IF EXISTS `vn`.`ticketGetProblems`;
DELIMITER $$
CREATE DEFINER=`root`@`%` PROCEDURE `vn`.`ticketGetProblems`()
BEGIN
DECLARE vWarehouse INT;
DECLARE vDate DATE;
DECLARE vAvailableCache INT;
DECLARE vVisibleCache INT;
DECLARE vDone INT DEFAULT 0;
DECLARE vCursor CURSOR FOR
SELECT DISTINCT tt.warehouseFk, date(tt.shipped)
FROM tmp.ticketGetProblems tt
WHERE DATE(tt.shipped) BETWEEN CURDATE()
AND TIMESTAMPADD(DAY, 1.9, CURDATE());
DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = 1;
DROP TEMPORARY TABLE IF EXISTS tmp.ticketProblems;
CREATE TEMPORARY TABLE tmp.ticketProblems (
ticketFk INT(11) PRIMARY KEY,
isFreezed INTEGER(1) DEFAULT 0,
risk DECIMAL(10,2) DEFAULT 0,
hasTicketRequest INTEGER(1) DEFAULT 0,
isAvailable INTEGER(1) DEFAULT 1
) ENGINE = MEMORY;
DROP TEMPORARY TABLE IF EXISTS tmp.ticketList;
CREATE TEMPORARY TABLE tmp.ticketList
(PRIMARY KEY (ticketFk))
ENGINE = MEMORY
SELECT tp.ticketFk, c.id clientFk
FROM tmp.ticketGetProblems tp
JOIN vn.client c ON c.id = tp.clientFk;
INSERT INTO tmp.ticketProblems(ticketFk, isFreezed)
SELECT DISTINCT tl.ticketFk, 1
FROM tmp.ticketList tl
JOIN vn.client c ON c.id = tl.clientFk
WHERE c.isFreezed;
DROP TEMPORARY TABLE IF EXISTS tmp.clientGetDebt;
CREATE TEMPORARY TABLE tmp.clientGetDebt
(PRIMARY KEY (clientFk))
ENGINE = MEMORY
SELECT DISTINCT clientFk
FROM tmp.ticketList;
CALL clientGetDebt(CURDATE());
INSERT INTO tmp.ticketProblems(ticketFk, risk)
SELECT DISTINCT tl.ticketFk, r.risk
FROM tmp.ticketList 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
WHERE r.risk > c.credit + 10
AND a.deliveryMethodFk != 3
ON DUPLICATE KEY UPDATE
risk = r.risk;
INSERT INTO tmp.ticketProblems(ticketFk, hasTicketRequest)
SELECT DISTINCT tl.ticketFk, 1
FROM tmp.ticketList tl
JOIN vn.ticketRequest tr ON tr.ticketFk = tl.ticketFk
WHERE tr.isOK IS NULL
ON DUPLICATE KEY UPDATE
hasTicketRequest = 1;
OPEN vCursor;
WHILE NOT vDone
DO
FETCH vCursor INTO vWarehouse, vDate;
CALL cache.visible_refresh(vVisibleCache, FALSE, vWarehouse);
CALL cache.available_refresh(vAvailableCache, FALSE, vWarehouse, vDate);
INSERT INTO tmp.ticketProblems(ticketFk, isAvailable)
SELECT tl.ticketFk, 0
FROM tmp.ticketList tl
JOIN vn.ticket t ON t.id = tl.ticketFk
LEFT 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 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 = 0;
INSERT INTO tmp.ticketProblems(ticketFk, isAvailable)
SELECT tl.ticketFk, 0
FROM tmp.ticketList tl
JOIN vn.ticket t ON t.id = tl.ticketFk
LEFT 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.visible v ON i.id = v.item_id AND v.calc_id = vVisibleCache
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(v.visible, 0)
AND s.isPicked = FALSE
AND s.reserved = FALSE
AND it.categoryFk != 6
AND date(t.shipped) = vDate
AND NOT i.generic
AND CURDATE() = vDate
AND t.warehouseFk = vWarehouse
GROUP BY tl.ticketFk
ON DUPLICATE KEY UPDATE
isAvailable = 0;
END WHILE;
CLOSE vCursor;
SELECT * FROM tmp.ticketProblems;
DROP TEMPORARY TABLE
tmp.clientGetDebt,
tmp.ticketList;
END$$
DELIMITER ;

View File

@ -0,0 +1,24 @@
CREATE
OR REPLACE ALGORITHM = UNDEFINED
DEFINER = `root`@`%`
SQL SECURITY DEFINER
VIEW `vn`.`invoiceOut` AS
SELECT
`f`.`factura_id` AS `id`,
`f`.`Id_Factura` AS `ref`,
`f`.`Serie` AS `serial`,
`f`.`Fecha` AS `issued`,
`f`.`Importe` AS `amount`,
`f`.`Id_Cliente` AS `clientFk`,
`f`.`odbc_date` AS `created`,
`f`.`empresa_id` AS `companyFk`,
`f`.`Vencimiento` AS `dued`,
`f`.`booked` AS `booked`,
`f`.`Id_Banco` AS `bankFk`,
`f`.`cplusInvoiceType477Fk` AS `cplusInvoiceType477Fk`,
`f`.`cplusTaxBreakFk` AS `cplusTaxBreakFk`,
`f`.`cplusSubjectOpFk` AS `cplusSubjectOpFk`,
`f`.`cplusTrascendency477Fk` AS `cplusTrascendency477Fk`,
`f`.`pdf` AS `hasPdf`
FROM
`vn2008`.`Facturas` `f`;

View File

@ -0,0 +1,60 @@
DROP procedure IF EXISTS `vn`.`invoiceOutAgain`;
DELIMITER $$
CREATE DEFINER=`root`@`%` PROCEDURE `vn`.`invoiceOutAgain`(IN vInvoiceRef VARCHAR(15), vTaxArea VARCHAR(25))
BEGIN
/* Para tickets ya facturados, vuelve a repetir el proceso de facturación.
*
* @param vInvoiceFk Numero de factura
* @param vTaxArea Numero de factura
*/
DECLARE vInvoiceFk INT;
DECLARE vCountry INT;
DECLARE vTaxArea VARCHAR(15);
DECLARE vSpainCountryCode INT DEFAULT 1;
SELECT id INTO vInvoiceFk
FROM invoiceOut
WHERE ref = vInvoiceRef;
UPDATE invoiceOut
SET hasPdf = 0
WHERE id = vInvoiceFk;
SELECT s.countryFk INTO vCountry
FROM supplier s
JOIN invoiceOut io ON io.companyFk = s.id
WHERE io.id = vInvoiceFk;
DROP TEMPORARY TABLE IF EXISTS ticketToInvoice;
CREATE TEMPORARY TABLE ticketToInvoice
SELECT id
FROM ticket
WHERE refFk = vInvoiceRef;
CALL invoiceExpenceMake(vInvoiceFk);
CALL invoiceTaxMake(vInvoiceFk,vTaxArea);
UPDATE invoiceOut io
JOIN (
SELECT SUM(amount) AS total
FROM invoiceOutExpence
WHERE invoiceOutFk = vInvoiceFk
) base
JOIN (
SELECT SUM(vat) AS total
FROM invoiceOutTax
WHERE invoiceOutFk = vInvoiceFk
) vat
SET io.amount = base.total + vat.total
WHERE io.id = vInvoiceFk;
CALL vn.invoiceOutBooking(vInvoiceFk);
END$$
DELIMITER ;

View File

@ -0,0 +1,38 @@
DELIMITER $$
CREATE DEFINER=`root`@`%` PROCEDURE `vn`.`ticket_componentMakeUpdate`(
vTicketFk INT,
vClientFk INT,
vAgencyModeFk INT,
vAddressFk INT,
vZoneFk INT,
vWarehouseFk TINYINT,
vCompanyFk SMALLINT,
vShipped DATETIME,
vLanded DATE,
vIsDeleted BOOLEAN,
vHasToBeUnrouted BOOLEAN,
vOption INT)
BEGIN
CALL vn.ticket_componentPreview (vTicketFk, vLanded, vAddressFk, vZoneFk, vWarehouseFk);
CALL vn.ticket_componentUpdate (
vTicketFk,
vClientFk,
vAgencyModeFk,
vAddressFk,
vZoneFk,
vWarehouseFk,
vCompanyFk,
vShipped,
vLanded,
vIsDeleted,
vHasToBeUnrouted,
vOption
);
DROP TEMPORARY TABLE
tmp.ticketComponent,
tmp.ticketComponentPrice;
END$$
DELIMITER ;

View File

@ -0,0 +1,111 @@
USE `vn`;
DROP procedure IF EXISTS `ticket_componentPreview`;
DELIMITER $$
USE `vn`$$
CREATE DEFINER=`root`@`%` PROCEDURE `ticket_componentPreview`(
vTicketFk INT,
vLanded DATE,
vAddressFk INT,
vZoneFk INT,
vWarehouseFk SMALLINT)
BEGIN
/**
* Calcula los componentes de los articulos de un ticket
*
* @param vTicketFk id del ticket
* @param vLanded nueva fecha de entrega
* @param vAddressFk nuevo consignatario
* @param vZoneFk nueva zona
* @param vWarehouseFk nuevo warehouse
*
* @return tmp.ticketComponent (warehouseFk, itemFk, componentFk, cost)
*/
DECLARE vShipped DATE;
DECLARE vBuyOrderItem INT DEFAULT 100;
DECLARE vHasDataChanged BOOL DEFAULT FALSE;
DECLARE vHasAddressChanged BOOL;
DECLARE vHasZoneChanged BOOL DEFAULT FALSE;
DECLARE vHasWarehouseChanged BOOL DEFAULT FALSE;
DECLARE vAddressTypeRateFk INT DEFAULT NULL;
DECLARE vAgencyModeTypeRateFk INT DEFAULT NULL;
DECLARE vHasChangeAll BOOL DEFAULT FALSE;
SELECT DATE(landed) <> vLanded,
addressFk <> vAddressFk,
zoneFk <> vZoneFk,
warehouseFk <> vWarehouseFk
INTO
vHasDataChanged,
vHasAddressChanged,
vHasZoneChanged,
vHasWarehouseChanged
FROM vn.ticket t
WHERE t.id = vTicketFk;
IF vHasDataChanged OR vHasWarehouseChanged THEN
SET vHasChangeAll = TRUE;
END IF;
IF vHasAddressChanged THEN
SET vAddressTypeRateFk = 5;
END IF;
IF vHasZoneChanged THEN
SET vAgencyModeTypeRateFk = 6;
END IF;
SELECT TIMESTAMPADD(DAY, -travelingDays, vLanded) INTO vShipped
FROM zone
WHERE id = vZoneFk;
CALL buyUltimate(vWarehouseFk, vShipped);
DROP TEMPORARY TABLE IF EXISTS tmp.ticketLot;
CREATE TEMPORARY TABLE tmp.ticketLot ENGINE = MEMORY (
SELECT
vWarehouseFk AS warehouseFk,
NULL AS available,
s.itemFk,
bu.buyFk
FROM sale s
LEFT JOIN tmp.buyUltimate bu ON bu.itemFk = s.itemFk
WHERE s.ticketFk = vTicketFk
AND s.itemFk != vBuyOrderItem
GROUP BY bu.warehouseFk, bu.itemFk);
CALL catalog_componentCalculate(vZoneFk, vAddressFk, vShipped);
REPLACE INTO tmp.ticketComponent (warehouseFk, itemFk, componentFk, cost)
SELECT t.warehouseFk, s.itemFk, sc.componentFk, sc.value
FROM saleComponent sc
JOIN sale s ON s.id = sc.saleFk
JOIN ticket t ON t.id = s.ticketFk
JOIN componentRate cr ON cr.id = sc.componentFk
WHERE s.ticketFk = vTicketFk
AND (cr.isRenewable = FALSE
OR
(NOT vHasChangeAll
AND (NOT (cr.componentTypeRate <=> vAddressTypeRateFk
OR cr.componentTypeRate <=> vAgencyModeTypeRateFk))));
SET @shipped = vShipped;
DROP TEMPORARY TABLE
tmp.buyUltimate,
tmp.ticketLot;
IF vShipped IS NULL THEN
CALL util.throw('NO_ZONE_AVAILABLE');
END IF;
IF vShipped < CURDATE() THEN
CALL util.throw('ERROR_PAST_SHIPMENT');
END IF;
END$$
DELIMITER ;

View File

@ -0,0 +1,52 @@
DROP procedure IF EXISTS `vn`.`ticket_priceDifference`;
DELIMITER $$
CREATE DEFINER=`root`@`%` PROCEDURE `vn`.`ticket_priceDifference`(
vTicketFk INT,
vLanded DATE,
vAddressFk INT,
vZoneFk INT,
vWarehouseFk INT)
BEGIN
/**
* Devuelve las diferencias de precio
* de los movimientos de un ticket.
*
* @param vTicketFk Id del ticket
* @param vLanded Fecha de recepcion
* @param vAddressFk Id del consignatario
* @param vZoneFk Id de la zona
* @param vWarehouseFk Id del almacén
*/
CALL vn.ticket_componentPreview(vTicketFk, vLanded, vAddressFk, vZoneFk, vWarehouseFk);
SELECT s.itemFk,
i.name,
i.size,
i.category,
IFNULL(s.quantity, 0) AS quantity,
IFNULL(s.price, 0) AS price,
ROUND(SUM(tc.cost), 2) AS newPrice,
s.quantity * (s.price - ROUND(SUM(tc.cost), 2)) difference,
s.id AS saleFk
FROM sale s
JOIN item i ON i.id = s.itemFk
JOIN ticket t ON t.id = s.ticketFk
LEFT JOIN tmp.ticketComponent tc ON tc.itemFk = s.itemFk
AND tc.warehouseFk = t.warehouseFk
LEFT JOIN saleComponent sc ON sc.saleFk = s.id
AND sc.componentFk = tc.componentFk
LEFT JOIN componentRate cr ON cr.id = tc.componentFk
WHERE
t.id = vTicketFk
AND IF(sc.componentFk IS NULL
AND cr.classRate IS NOT NULL, FALSE, TRUE)
GROUP BY s.id ORDER BY s.id;
DROP TEMPORARY TABLE
tmp.ticketComponent,
tmp.ticketComponentPrice;
END$$
DELIMITER ;

View File

@ -0,0 +1,147 @@
DROP procedure IF EXISTS `cache`.`available_refresh`;
DELIMITER $$
CREATE DEFINER=`root`@`%` PROCEDURE `cache`.`available_refresh`(OUT `vCalc` INT, IN `vRefresh` INT, IN `vWarehouse` INT, IN `vDate` DATE)
proc: BEGIN
DECLARE vStartDate DATE;
DECLARE vEndDate DATETIME;
DECLARE vReserveDate DATETIME;
DECLARE vParams CHAR(100);
DECLARE vInventoryDate DATE;
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
CALL cache_calc_unlock (vCalc);
RESIGNAL;
END;
IF vDate < CURDATE() THEN
LEAVE proc;
END IF;
CALL vn2008.item_stock (vWarehouse, vDate, NULL);
SET vParams = CONCAT_WS('/', vWarehouse, vDate);
CALL cache_calc_start (vCalc, vRefresh, 'available', vParams);
IF !vRefresh THEN
LEAVE proc;
END IF;
-- Calcula algunos parámetros necesarios
SET vStartDate = TIMESTAMP(vDate, '00:00:00');
SET vEndDate = TIMESTAMP(TIMESTAMPADD(DAY, 4, vDate), '23:59:59');
SELECT FechaInventario INTO vInventoryDate FROM vn2008.tblContadores;
SELECT SUBTIME(NOW(), reserveTime) INTO vReserveDate
FROM hedera.orderConfig;
-- Calcula el ultimo dia de vida para cada producto
DROP TEMPORARY TABLE IF EXISTS item_range;
CREATE TEMPORARY TABLE item_range
(PRIMARY KEY (item_id))
ENGINE = MEMORY
SELECT c.item_id, IF(t.life IS NULL, NULL,
TIMESTAMP(TIMESTAMPADD(DAY, t.life, c.landing), '23:59:59')) AS date_end
FROM (
SELECT c.Id_Article item_id, MAX(landing) landing
FROM vn2008.Compres c
JOIN vn2008.Entradas e ON c.Id_Entrada = e.Id_Entrada
JOIN vn2008.travel t ON t.id = e.travel_id
JOIN vn2008.warehouse w ON w.id = t.warehouse_id
WHERE t.landing BETWEEN vInventoryDate AND vStartDate
AND t.warehouse_id = vWarehouse
AND NOT e.Inventario
AND NOT e.Redada
GROUP BY Id_Article
) c
JOIN vn2008.Articles a ON a.Id_Article = c.item_id
JOIN vn2008.Tipos t ON t.tipo_id = a.tipo_id
HAVING date_end >= vStartDate OR date_end IS NULL;
-- Replica la tabla item_range para poder usarla varias veces en la misma consulta
DROP TEMPORARY TABLE IF EXISTS item_range_copy1;
CREATE TEMPORARY TABLE item_range_copy1 LIKE item_range;
INSERT INTO item_range_copy1
SELECT * FROM item_range;
DROP TEMPORARY TABLE IF EXISTS item_range_copy2;
CREATE TEMPORARY TABLE item_range_copy2 LIKE item_range;
INSERT INTO item_range_copy2
SELECT * FROM item_range;
DROP TEMPORARY TABLE IF EXISTS item_range_copy3;
CREATE TEMPORARY TABLE item_range_copy3 LIKE item_range;
INSERT INTO item_range_copy3
SELECT * FROM item_range;
DROP TEMPORARY TABLE IF EXISTS item_range_copy4;
CREATE TEMPORARY TABLE item_range_copy4 LIKE item_range;
INSERT INTO item_range_copy4
SELECT * FROM item_range;
-- Calcula el ATP
DELETE FROM available WHERE calc_id = vCalc;
INSERT INTO available (calc_id, item_id, available)
SELECT vCalc, t.item_id, SUM(stock) amount FROM (
SELECT ti.item_id, stock
FROM vn2008.tmp_item ti
JOIN item_range ir ON ir.item_id = ti.item_id
UNION ALL
SELECT t.item_id, minacum(dt, amount, vDate) AS available FROM (
SELECT item_id, DATE(dat) dt, SUM(amount) amount FROM (
SELECT i.item_id, i.dat, i.amount
FROM vn2008.item_out i
JOIN item_range_copy1 ir ON ir.item_id = i.item_id
WHERE i.dat >= vStartDate
AND (ir.date_end IS NULL OR i.dat <= ir.date_end)
AND i.warehouse_id = vWarehouse
UNION ALL
SELECT i.item_id, i.dat, i.amount
FROM vn2008.item_entry_in i
JOIN item_range_copy2 ir ON ir.item_id = i.item_id
WHERE i.dat >= vStartDate
AND (ir.date_end IS NULL OR i.dat <= ir.date_end)
AND i.warehouse_id = vWarehouse
UNION ALL
SELECT i.item_id, i.dat, i.amount
FROM vn2008.item_entry_out i
JOIN item_range_copy3 ir ON ir.item_id = i.item_id
WHERE i.dat >= vStartDate
AND (ir.date_end IS NULL OR i.dat <= ir.date_end)
AND i.warehouse_id = vWarehouse
UNION ALL
SELECT r.item_id, r.shipment, -r.amount
FROM hedera.order_row r
JOIN hedera.`order` o ON o.id = r.order_id
JOIN item_range_copy4 ir ON ir.item_id = r.item_id
WHERE r.shipment >= vStartDate
AND (ir.date_end IS NULL OR r.shipment <= ir.date_end)
AND r.warehouse_id = vWarehouse
AND r.created >= vReserveDate
AND NOT o.confirmed
) t
GROUP BY item_id, dt
) t
GROUP BY t.item_id
) t GROUP BY t.item_id;
DROP TEMPORARY TABLE
vn2008.tmp_item
,item_range
,item_range_copy1
,item_range_copy2
,item_range_copy3
,item_range_copy4;
CALL cache_calc_end (vCalc);
END$$
DELIMITER ;

View File

@ -0,0 +1,12 @@
DROP VIEW IF EXISTS `vn`.`queuePriority` ;
CREATE
OR REPLACE ALGORITHM = UNDEFINED
DEFINER = `root`@`%`
SQL SECURITY DEFINER
VIEW `vn`.`queuePriority` AS
SELECT
`p`.`Id_Prioridad` AS `id`,
`p`.`Prioridad` AS `priority`
FROM
`vn2008`.`Prioridades` `p`;

View File

@ -4,7 +4,7 @@ export MYSQL_PWD=root
mysql_import() {
FILE=$1
echo "[INFO] -> Imported $FILE"
echo "[INFO] -> Importing $FILE"
mysql -u root --default-character-set=utf8 --comments -f < "$FILE"
}

3
db/docker.cnf Normal file
View File

@ -0,0 +1,3 @@
[mysqld]
innodb_log_file_size = 4M
innodb_autoextend_increment = 4

File diff suppressed because one or more lines are too long

View File

@ -381,7 +381,7 @@ INSERT INTO `vn`.`company`(`id`, `code`, `supplierAccountFk`, `workerManagerFk`,
(791 , 'FTH', NULL, 30, NULL, 3, '2015-11-30'),
(1381, 'ORN', NULL, 30, NULL, 7, NULL);
INSERT INTO `vn`.`invoiceOut`(`id`, `serial`, `amount`, `issued`,`clientFk`, `created`, `companyFk`, `dued`, `booked`, `bankFk`, `pdf`)
INSERT INTO `vn`.`invoiceOut`(`id`, `serial`, `amount`, `issued`,`clientFk`, `created`, `companyFk`, `dued`, `booked`, `bankFk`, `hasPdf`)
VALUES
(1, 'T', 1014.24, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 101, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 442, DATE_ADD(CURDATE(), INTERVAL -1 MONTH), DATE_ADD(CURDATE(), INTERVAL -1 MONTH), 1, 1),
(2, 'T', 121.36, CURDATE(), 102, CURDATE(), 442, CURDATE(), CURDATE(), 1, 1),
@ -1448,6 +1448,14 @@ INSERT INTO `vn`.`ticketRequest`(`id`, `description`, `requesterFk`, `atenderFk`
(3, 'Melee weapon heavy shield 1x0.5m', 18, 35, 20, 4, 3.06, 0, NULL, 1, DATE_ADD(CURDATE(), INTERVAL -15 DAY)),
(4, 'Melee weapon combat first 15cm', 18, 35, 15, NULL, 1.30, NULL, NULL, 11, CURDATE());
INSERT INTO `vn`.`ticketServiceType`(`id`, `name`)
VALUES
(1, 'Porte Agencia'),
(2, 'Portes Retorno'),
(3, 'Porte Carry'),
(4, 'Cargo FITOSANITARIO'),
(5, 'Documentos');
INSERT INTO `vn`.`ticketService`(`id`, `description`, `quantity`, `price`, `taxClassFk`, `ticketFk`)
VALUES
(1, 'Documentos', 1, 2.00, 1, 1),
@ -1820,11 +1828,11 @@ INSERT INTO `vn`.`dmsType`(`id`, `name`, `path`, `readRoleFk`, `writeRoleFk`, `c
(18, 'dua', 'dua', NULL, NULL, 'dua'),
(19, 'inmovilizado', 'inmovilizado', NULL, NULL, 'fixedAssets');
INSERT INTO `vn`.`dms`(`id`, `dmsTypeFk`, `file`, `workerFk`, `warehouseFk`, `companyFk`, `hardCopyNumber`, `hasFile`, `reference`, `description`, `created`)
INSERT INTO `vn`.`dms`(`id`, `dmsTypeFk`, `file`, `contentType`, `workerFk`, `warehouseFk`, `companyFk`, `hardCopyNumber`, `hasFile`, `reference`, `description`, `created`)
VALUES
(1, 14, '1.pdf', 5, 1, 442, NULL, FALSE, 'Ticket:11', 'Ticket:11 dms for the ticket', CURDATE()),
(2, 5, '2.pdf', 5, 1, 442, 1, TRUE, 'Client:101', 'Client:101 dms for the client', CURDATE()),
(3, 5, '3.pdf', 5, 1, 442, NULL, TRUE, 'Client: 101', 'Client:101 readme', CURDATE());
(1, 14, '1.txt', 'text/plain', 5, 1, 442, NULL, FALSE, 'Ticket:11', 'Ticket:11 dms for the ticket', CURDATE()),
(2, 5, '2.txt', 'text/plain', 5, 1, 442, 1, TRUE, 'Client:101', 'Client:101 dms for the client', CURDATE()),
(3, 5, '3.txt', 'text/plain', 5, 1, 442, NULL, TRUE, 'Client: 101', 'Client:101 readme', CURDATE());
INSERT INTO `vn`.`ticketDms`(`ticketFk`, `dmsFk`)
VALUES
@ -1835,4 +1843,12 @@ INSERT INTO `vn`.`clientDms`(`clientFk`, `dmsFk`)
(101, 2),
(101, 3);
INSERT INTO `vn`.`device` (`sn`, `model`, `userFk`) VALUES ('aaa', 'android', '9');
INSERT INTO `vn`.`device` (`sn`, `model`, `userFk`)
VALUES
('aaa', 'android', '9');
INSERT INTO `vn`.`queuePriority`(`id`, `priority`)
VALUES
(1, 'Alta'),
(2, 'Normal'),
(3, 'Baja');

File diff suppressed because it is too large Load Diff

View File

@ -100,4 +100,3 @@ TABLES=(
workcenter
)
dump_tables ${TABLES[@]}

View File

@ -26,4 +26,3 @@ mysqldump \
--databases \
${SCHEMAS[@]} \
> dump/structure.sql

View File

@ -20,27 +20,27 @@ describe('last_buy_refresh()', () => {
let lastBuyTable = result[lastBuyTableIndex];
expect(lastBuyTable.length).toEqual(6);
expect(lastBuyTable.length).toEqual(12);
expect(lastBuyTable[0].item_id).toEqual(1);
expect(lastBuyTable[1].item_id).toEqual(2);
expect(lastBuyTable[2].item_id).toEqual(3);
expect(lastBuyTable[3].item_id).toEqual(4);
expect(lastBuyTable[4].item_id).toEqual(8);
expect(lastBuyTable[5].item_id).toEqual(9);
expect(lastBuyTable[1].item_id).toEqual(1);
expect(lastBuyTable[2].item_id).toEqual(1);
expect(lastBuyTable[3].item_id).toEqual(2);
expect(lastBuyTable[4].item_id).toEqual(2);
expect(lastBuyTable[5].item_id).toEqual(3);
expect(lastBuyTable[0].warehouse_id).toEqual(1);
expect(lastBuyTable[1].warehouse_id).toEqual(1);
expect(lastBuyTable[2].warehouse_id).toEqual(1);
expect(lastBuyTable[1].warehouse_id).toEqual(3);
expect(lastBuyTable[2].warehouse_id).toEqual(5);
expect(lastBuyTable[3].warehouse_id).toEqual(1);
expect(lastBuyTable[4].warehouse_id).toEqual(1);
expect(lastBuyTable[4].warehouse_id).toEqual(5);
expect(lastBuyTable[5].warehouse_id).toEqual(1);
expect(lastBuyTable[1].buy_id).toEqual(4);
expect(lastBuyTable[1].buy_id).toEqual(10);
expect(lastBuyTable[0].buy_id).toEqual(3);
expect(lastBuyTable[2].buy_id).toEqual(5);
expect(lastBuyTable[3].buy_id).toEqual(8);
expect(lastBuyTable[4].buy_id).toEqual(6);
expect(lastBuyTable[5].buy_id).toEqual(7);
expect(lastBuyTable[2].buy_id).toEqual(13);
expect(lastBuyTable[3].buy_id).toEqual(4);
expect(lastBuyTable[4].buy_id).toEqual(14);
expect(lastBuyTable[5].buy_id).toEqual(5);
});
});

View File

@ -8,7 +8,7 @@ describe('ticketComponentUpdateSale()', () => {
let params = {
warehouseFk: 1,
ticketFk: 1
ticketFk: 13
};
stmts.push('START TRANSACTION');
@ -48,26 +48,29 @@ describe('ticketComponentUpdateSale()', () => {
let insertTicketComponentTable = `
INSERT INTO tmp.ticketComponent (warehouseFk, itemFk, componentFk, cost)
VALUES
(1 , 2 , 23 , 999.00),
(1 , 2 , 28 , 2.00),
(1 , 4 , 23 , 999.00),
(1 , 4 , 28 , 1.00)
(1 , 4 , 15 , 999.00),
(1 , 4 , 17 , 2.00),
(1 , 4 , 22 , 999.00),
(1 , 4 , 28 , 1.00),
(1 , 4 , 29 , 2.00),
(1 , 4 , 32 , 999.00),
(1 , 4 , 39 , 1.00)
`;
stmts.push(insertTicketComponentTable);
let updateComponentTwentyThree = `
let updateComponentTwentyNine = `
UPDATE vn.saleComponent
SET value = '5'
WHERE saleFk = 1 AND componentFk = 23
WHERE saleFk = 26 AND componentFk = 29
`;
stmts.push(updateComponentTwentyThree);
stmts.push(updateComponentTwentyNine);
let updateComponentTwentyEight = `
UPDATE vn.saleComponent
SET value = '5'
WHERE saleFk = 1 AND componentFk = 28
WHERE saleFk = 26 AND componentFk = 28
`;
stmts.push(updateComponentTwentyEight);
@ -75,24 +78,24 @@ describe('ticketComponentUpdateSale()', () => {
let priceFixtedToZero = `
UPDATE vn.sale
SET priceFixed = 0
WHERE id = 1
WHERE id = 26
`;
stmts.push(priceFixtedToZero);
let firstSalePriceIndexBefore = stmts.push('SELECT price FROM vn.sale WHERE id = 1') - 1;
let firstSalePriceIndexBefore = stmts.push('SELECT price FROM vn.sale WHERE id = 26') - 1;
stmts.push('CALL vn.ticketComponentUpdateSale(1)');
let firstSalePriceIndexAfter = stmts.push('SELECT price FROM vn.sale WHERE id = 1') - 1;
let firstSalePriceIndexAfter = stmts.push('SELECT price FROM vn.sale WHERE id = 26') - 1;
stmts.push('ROLLBACK');
let sql = ParameterizedSQL.join(stmts, ';');
let result = await app.models.Ticket.rawStmt(sql);
expect(result[firstSalePriceIndexBefore][0].price).toEqual(9.1);
expect(result[firstSalePriceIndexAfter][0].price).toEqual(5);
expect(result[firstSalePriceIndexBefore][0].price).toEqual(1.72);
expect(result[firstSalePriceIndexAfter][0].price).toEqual(1005);
});
it(`should keep the sale price when option TWO using the base components and save the difference in a new component`, async() => {
@ -101,7 +104,7 @@ describe('ticketComponentUpdateSale()', () => {
let params = {
warehouseFk: 1,
ticketFk: 1
ticketFk: 13
};
stmts.push('START TRANSACTION');
@ -139,28 +142,31 @@ describe('ticketComponentUpdateSale()', () => {
stmts.push(createTicketComponentTable);
let insertTicketComponentTable = `
INSERT INTO tmp.ticketComponent (warehouseFk, itemFk, componentFk, cost)
VALUES
(1 , 2 , 23 , 999.00),
(1 , 2 , 28 , 2.00),
(1 , 4 , 23 , 999.00),
(1 , 4 , 28 , 1.00)
INSERT INTO tmp.ticketComponent (warehouseFk, itemFk, componentFk, cost)
VALUES
(1 , 4 , 15 , 999.00),
(1 , 4 , 17 , 2.00),
(1 , 4 , 22 , 999.00),
(1 , 4 , 28 , 1.00),
(1 , 4 , 29 , 2.00),
(1 , 4 , 32 , 999.00),
(1 , 4 , 39 , 1.00)
`;
stmts.push(insertTicketComponentTable);
let updateComponentTwentyThree = `
let updateComponentTwentyNine = `
UPDATE vn.saleComponent
SET value = '5'
WHERE saleFk = 1 AND componentFk = 23
WHERE saleFk = 26 AND componentFk = 29
`;
stmts.push(updateComponentTwentyThree);
stmts.push(updateComponentTwentyNine);
let updateComponentTwentyEight = `
UPDATE vn.saleComponent
SET value = '5'
WHERE saleFk = 1 AND componentFk = 28
WHERE saleFk = 26 AND componentFk = 28
`;
stmts.push(updateComponentTwentyEight);
@ -168,24 +174,24 @@ describe('ticketComponentUpdateSale()', () => {
let priceFixtedToZero = `
UPDATE vn.sale
SET priceFixed = 0
WHERE id = 1
WHERE id = 26
`;
stmts.push(priceFixtedToZero);
let firstSalePriceIndexBefore = stmts.push('SELECT price FROM vn.sale WHERE id = 1') - 1;
let firstSalePriceIndexBefore = stmts.push('SELECT price FROM vn.sale WHERE id = 26') - 1;
stmts.push('CALL vn.ticketComponentUpdateSale(2)');
let addedComponentIndex = stmts.push('SELECT * FROM vn.saleComponent WHERE saleFk = 1 AND componentFk = 17') - 1;
let firstSalePriceIndexAfter = stmts.push('SELECT price FROM vn.sale WHERE id = 1') - 1;
let addedComponentIndex = stmts.push('SELECT * FROM vn.saleComponent WHERE saleFk = 26 AND componentFk = 17') - 1;
let firstSalePriceIndexAfter = stmts.push('SELECT price FROM vn.sale WHERE id = 26') - 1;
stmts.push('ROLLBACK');
let sql = ParameterizedSQL.join(stmts, ';');
let result = await app.models.Ticket.rawStmt(sql);
expect(result[addedComponentIndex][0].value).toEqual(4.1);
expect(result[addedComponentIndex][0].value).toEqual(-1003.28);
expect(result[firstSalePriceIndexBefore][0].price).toEqual(result[firstSalePriceIndexAfter][0].price);
});
@ -280,8 +286,8 @@ describe('ticketComponentUpdateSale()', () => {
let sql = ParameterizedSQL.join(stmts, ';');
let result = await app.models.Ticket.rawStmt(sql);
expect(result[componentTwentyEightIndex][0].value).toEqual(1.6);
expect(result[componentTwentyNineIndex][0].value).toEqual(0.4);
expect(result[componentTwentyEightIndex][0].value).toEqual(79.517);
expect(result[componentTwentyNineIndex][0].value).toEqual(19.879);
expect(result[firstSalePriceIndexBefore][0].price).toEqual(result[firstSalePriceIndexAfter][0].price);
});
});

1
e2e/dms/c81/2.txt Normal file
View File

@ -0,0 +1 @@
It works!

1
e2e/dms/ecc/3.txt Normal file
View File

@ -0,0 +1 @@
It works!

View File

@ -441,7 +441,8 @@ export default {
basicDataButton: 'vn-left-menu a[ui-sref="ticket.card.basicData.stepOne"]',
clientAutocomplete: 'vn-autocomplete[field="$ctrl.clientFk"]',
addressAutocomplete: 'vn-autocomplete[field="$ctrl.ticket.addressFk"]',
agencyAutocomplete: 'vn-autocomplete[field="$ctrl.ticket.agencyModeFk"]',
agencyAutocomplete: 'vn-autocomplete[field="$ctrl.agencyModeId"]',
zoneAutocomplete: 'vn-autocomplete[field="$ctrl.zoneId"]',
nextStepButton: 'vn-step-control > section > section.buttons > section:nth-child(2) > vn-button',
finalizeButton: 'vn-step-control > section > section.buttons > section:nth-child(2) > vn-submit',
stepTwoTotalPriceDif: 'vn-ticket-basic-data-step-two > form > vn-card > div > vn-horizontal > table > tfoot > tr > td:nth-child(4)',

View File

@ -14,6 +14,7 @@ describe('Ticket Edit basic data path', () => {
it(`should edit the ticket agency then click next`, async() => {
let url = await nightmare
.autocompleteSearch(selectors.ticketBasicData.agencyAutocomplete, 'Silla247Expensive')
.waitToGetProperty(`${selectors.ticketBasicData.zoneAutocomplete} input`, 'value')
.waitToClick(selectors.ticketBasicData.nextStepButton)
.waitForURL('data/step-two')
.parsedUrl();

View File

@ -92,8 +92,6 @@ export default class Autocomplete extends Input {
set field(value) {
this._field = value;
if (!value) return;
this.refreshSelection();
this.emit('change', {value});
}

View File

@ -1,5 +1,5 @@
Local warehouse: Almacén local
Local bank: Banco local
Local company: Compañia local
Local company: Empresa local
User warehouse: Almacén del usuario
User company: Compañia del usuario
User company: Empresa del usuario

View File

@ -198,7 +198,9 @@ async function backendStatus() {
timer = setInterval(() => {
const url = `${e2eConfig.url}/api/Applications/status`;
request.get(url, (err, res) => {
if (res.body == 'true') {
if (err || attempts > 100) // 250ms * 100 => 25s timeout
throw new Error('Could not connect to backend');
else if (res && res.body == 'true') {
clearInterval(timer);
resolve(attempts);
} else

View File

@ -21,7 +21,6 @@
"Cannot check Equalization Tax in this NIF/CIF": "Cannot check Equalization Tax in this NIF/CIF",
"You can't create an order for a frozen client": "You can't create an order for a frozen client",
"This address doesn't exist": "This address doesn't exist",
"NO_AGENCY_AVAILABLE": "NO_AGENCY_AVAILABLE",
"Warehouse cannot be blank": "Warehouse cannot be blank",
"Agency cannot be blank": "Agency cannot be blank",
"The IBAN does not have the correct format": "The IBAN does not have the correct format",

View File

@ -82,7 +82,8 @@
"INFINITE_LOOP": "Existe una dependencia entre dos Jefes",
"The sales of the current ticket can't be modified": "Las lineas de este ticket no pueden ser modificadas",
"The sales of the receiver ticket can't be modified": "Las lineas del ticket al que envias no pueden ser modificadas",
"NO_AGENCY_AVAILABLE": "No hay agencias disponibles",
"NO_AGENCY_AVAILABLE": "No hay una zona de reparto disponible con estos parámetros",
"ERROR_PAST_SHIPMENT": "No puedes seleccionar una fecha de envío en pasado",
"The current ticket can't be modified": "El ticket actual no puede ser modificado",
"The sales of this ticket can't be modified": "Las lineas de este ticket no pueden ser modificadas",
"Please select at least one sale": "Por favor selecciona al menos una linea",
@ -95,5 +96,6 @@
"This item is not available": "Este artículo no está disponible",
"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"
"File doesn't exists": "El archivo no existe",
"You don't have privileges to change the zone": "No tienes permisos para cambiar la zona"
}

View File

@ -1,14 +1,10 @@
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
module.exports = Self => {
Self.remoteMethodCtx('getLanded', {
Self.remoteMethod('getLanded', {
description: 'Returns the first shipped and landed possible for params',
accessType: 'READ',
accepts: [{
arg: 'params',
type: 'Object',
description: `shipped, addressFk, agencyModeFk, warehouseFk`
}, {
arg: 'shipped',
type: 'date',
required: true
@ -38,15 +34,14 @@ module.exports = Self => {
}
});
Self.getLanded = async(ctx, params) => {
Self.getLanded = async(shipped, addressFk, agencyModeFk, warehouseFk) => {
let stmts = [];
params = params || ctx.args;
stmts.push(new ParameterizedSQL(
`CALL vn.zoneGetLanded(?, ?, ?, ?)`, [
params.shipped,
params.addressFk,
params.agencyModeFk,
params.warehouseFk
shipped,
addressFk,
agencyModeFk,
warehouseFk
]
));

View File

@ -1,12 +1,8 @@
module.exports = Self => {
Self.remoteMethodCtx('getShipped', {
Self.remoteMethod('getShipped', {
description: 'Returns the first shipped possible for params',
accessType: 'READ',
accepts: [{
arg: 'params',
type: 'Object',
description: `landed, addressFk, agencyModeFk, warehouseFk`
}, {
arg: 'landed',
type: 'date',
required: true
@ -36,15 +32,14 @@ module.exports = Self => {
}
});
Self.getShipped = async(ctx, params)=> {
params = params || ctx.args;
Self.getShipped = async(landed, addressFk, agencyModeFk, warehouseFk)=> {
let query = `CALL vn.zoneGetShipped(?, ?, ?, ?)`;
let [response] = await Self.rawSql(query, [
params.landed,
params.addressFk,
params.agencyModeFk,
params.warehouseFk
let [[response]] = await Self.rawSql(query, [
landed,
addressFk,
agencyModeFk,
warehouseFk
]);
return (response[0] && response[0].shipped && response[0].shipped.toJSON()) || null;
return response;
};
};

View File

@ -2,13 +2,11 @@ const app = require('vn-loopback/server/server');
describe('agency getLanded()', () => {
it('should return a landing date', async() => {
let data = {
shipped: new Date(),
addressFk: 121,
agencyModeFk: 7,
warehouseFk: 1
};
let result = await app.models.Agency.getLanded({}, data);
const shipped = new Date();
const addressFk = 121;
const agencyModeFk = 7;
const warehouseFk = 1;
let result = await app.models.Agency.getLanded(shipped, addressFk, agencyModeFk, warehouseFk);
expect(result.landed).toBeDefined();
});

View File

@ -2,13 +2,12 @@ const app = require('vn-loopback/server/server');
describe('agency getShipped()', () => {
it('should return a shipment date', async() => {
let data = {
landed: new Date(),
addressFk: 121,
agencyModeFk: 7,
warehouseFk: 1
};
let result = await app.models.Agency.getShipped({}, data);
const landed = new Date();
const addressFk = 121;
const agencyModeFk = 7;
const warehouseFk = 1;
let result = await app.models.Agency.getShipped(landed, addressFk, agencyModeFk, warehouseFk);
expect(result).toBeDefined();
});
@ -17,14 +16,13 @@ describe('agency getShipped()', () => {
let newDate = new Date();
newDate.setMonth(newDate.getMonth() - 1);
let data = {
landed: newDate,
addressFk: 121,
agencyModeFk: 7,
warehouseFk: 1
};
let result = await app.models.Agency.getShipped({}, data);
const landed = newDate;
const addressFk = 121;
const agencyModeFk = 7;
const warehouseFk = 1;
expect(result).toBeNull();
let result = await app.models.Agency.getShipped(landed, addressFk, agencyModeFk, warehouseFk);
expect(result).toBeUndefined();
});
});

View File

@ -43,7 +43,7 @@ module.exports = Self => {
r.bankFk,
u.nickname userNickname,
r.clientFk,
FALSE pdf,
FALSE hasPdf,
FALSE isInvoice
FROM vn.receipt r
LEFT JOIN vn.worker w ON w.id = r.workerFk
@ -64,7 +64,7 @@ module.exports = Self => {
NULL,
NULL,
i.clientFk,
i.pdf,
i.hasPdf,
TRUE isInvoice
FROM vn.invoiceOut i
JOIN vn.company c ON c.id = i.companyFk

View File

@ -24,12 +24,30 @@
<vn-textfield vn-one label="Street address" field="$ctrl.address.street"></vn-textfield>
</vn-horizontal>
<vn-horizontal>
<vn-autocomplete vn-id="province" vn-one
field="$ctrl.address.provinceFk"
url="/api/Provinces"
show-field="name"
value-field="id"
label="Province">
</vn-autocomplete>
<vn-autocomplete vn-id="town" vn-one
label="City"
url="/api/Towns"
fields="['id', 'name']"
where="{provinceFk: province.selection.id}"
show-field="name"
value-field="name"
field="$ctrl.address.city">
</vn-autocomplete>
<vn-autocomplete vn-one
url="/api/Postcodes/location"
fields="['code', 'townFk']"
field="$ctrl.address.postalCode"
selection="$ctrl.postcodeSelection"
search-function="{code: $search}"
url="/api/Postcodes/location"
fields="['code', 'townFk']"
where="{townFk: town.selection.id}"
order="code, townFk"
show-field="code"
value-field="code"
label="Postcode">
@ -43,21 +61,7 @@
vn-tooltip="New postcode"
ng-click="postcode.open()">
</vn-icon-button>
<vn-autocomplete vn-one
label="City"
url="/api/Towns"
show-field="name"
value-field="name"
field="$ctrl.address.city">
</vn-autocomplete>
<vn-autocomplete vn-one
disabled="true"
field="$ctrl.address.provinceFk"
url="/api/Provinces"
show-field="name"
value-field="id"
label="Province">
</vn-horizontal>
</vn-horizontal>
<vn-horizontal>
<vn-autocomplete
vn-one

View File

@ -40,12 +40,30 @@
<vn-textfield vn-one label="Street" field="$ctrl.address.street"></vn-textfield>
</vn-horizontal>
<vn-horizontal>
<vn-autocomplete vn-id="province" vn-one
field="$ctrl.address.provinceFk"
url="/api/Provinces"
show-field="name"
value-field="id"
label="Province">
</vn-autocomplete>
<vn-autocomplete vn-id="town" vn-one
label="City"
url="/api/Towns"
fields="['id', 'name']"
where="{provinceFk: province.selection.id}"
show-field="name"
value-field="name"
field="$ctrl.address.city">
</vn-autocomplete>
<vn-autocomplete vn-one
url="/api/Postcodes/location"
fields="['code', 'townFk']"
field="$ctrl.address.postalCode"
selection="$ctrl.postcodeSelection"
search-function="{code: $search}"
url="/api/Postcodes/location"
fields="['code', 'townFk']"
where="{townFk: town.selection.id}"
order="code, townFk"
show-field="code"
value-field="code"
label="Postcode">
@ -59,21 +77,6 @@
vn-tooltip="New postcode"
ng-click="postcode.open()">
</vn-icon-button>
<vn-autocomplete vn-one
label="City"
url="/api/Towns"
show-field="name"
value-field="name"
field="$ctrl.address.city">
</vn-autocomplete>
<vn-autocomplete vn-one
disabled="true"
field="$ctrl.address.provinceFk"
url="/api/Provinces"
show-field="name"
value-field="id"
label="Province">
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal>
<vn-autocomplete vn-one

View File

@ -25,9 +25,10 @@ export default class Controller {
}
set postcodeSelection(selection) {
const hasValue = this._postcodeSelection;
this._postcodeSelection = selection;
if (!selection) return;
if (!selection || !hasValue) return;
const town = selection.town;
const province = town.province;

View File

@ -59,6 +59,7 @@ describe('Client', () => {
describe('postcodeSelection() setter', () => {
it(`should set the town, province and contry properties`, () => {
controller.address = {};
controller._postcodeSelection = {townFk: 2};
controller.postcodeSelection = {
townFk: 1,
code: 46001,

View File

@ -83,7 +83,7 @@
</vn-check>
</vn-td>
<vn-td center>
<a ng-show="balance.pdf"
<a ng-show="balance.hasPdf"
target="_blank"
href="api/InvoiceOuts/{{::balance.id}}/download?access_token={{::$ctrl.accessToken}}">
<vn-icon-button

View File

@ -33,19 +33,31 @@
</vn-textfield>
</vn-horizontal>
<vn-horizontal>
<vn-autocomplete vn-one
field="$ctrl.client.postcode"
selection="$ctrl.postcodeSelection"
search-function="{code: $search}"
url="/api/Postcodes/location"
fields="['code', 'townFk']"
show-field="code"
value-field="code"
label="Postcode">
<tpl-item>
{{code}}, {{town.name}} - {{town.province.name}}
({{town.province.country.country}})
</tpl-item>
<vn-autocomplete vn-id="country" vn-one
field="$ctrl.client.countryFk"
url="/api/Countries"
show-field="country"
value-field="id"
label="Country">
</vn-autocomplete>
<vn-autocomplete vn-id="province" vn-one
url="/api/Provinces"
field="$ctrl.client.provinceFk"
where="{countryFk: country.selection.id}"
show-field="name"
value-field="id"
label="Province">
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal>
<vn-autocomplete vn-id="town" vn-one
label="City"
url="/api/Towns"
fields="['id', 'name']"
where="{provinceFk: province.selection.id}"
show-field="name"
value-field="name"
field="$ctrl.client.city">
</vn-autocomplete>
<vn-icon-button vn-auto margin-medium-v
icon="add_circle"
@ -53,29 +65,20 @@
ng-click="postcode.open()">
</vn-icon-button>
<vn-autocomplete vn-one
label="City"
url="/api/Towns"
show-field="name"
value-field="name"
field="$ctrl.client.city">
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal>
<vn-autocomplete vn-one
disabled="true"
field="$ctrl.client.provinceFk"
url="/api/Provinces"
show-field="name"
value-field="id"
label="Province">
</vn-autocomplete>
<vn-autocomplete vn-one
disabled="true"
field="$ctrl.client.countryFk"
url="/api/Countries"
show-field="country"
value-field="id"
label="Country">
url="/api/Postcodes/location"
fields="['code', 'townFk']"
field="$ctrl.client.postcode"
selection="$ctrl.postcodeSelection"
search-function="{code: $search}"
where="{townFk: town.selection.id}"
order="code, townFk"
show-field="code"
value-field="code"
label="Postcode">
<tpl-item>
{{code}}, {{town.name}} - {{town.province.name}}
({{town.province.country.country}})
</tpl-item>
</vn-autocomplete>
</vn-horizontal>
<vn-horizontal>

View File

@ -11,7 +11,7 @@ class Controller {
this.dms = {
files: [],
hasFile: false,
hasAttachedFile: false
hasFileAttached: false
};
}
@ -79,12 +79,12 @@ class Controller {
}
onFileChange(files) {
let hasAttachedFile = false;
let hasFileAttached = false;
if (files.length > 0)
hasAttachedFile = true;
hasFileAttached = true;
this.$.$applyAsync(() => {
this.dms.hasAttachedFile = hasAttachedFile;
this.dms.hasFileAttached = hasFileAttached;
});
}
}

View File

@ -48,12 +48,12 @@ describe('Client', () => {
});
describe('onFileChange()', () => {
it('should set dms hasFile property to true if has any files', () => {
it('should set dms hasFileAttached property to true if has any files', () => {
const files = [{id: 1, name: 'MyFile'}];
controller.onFileChange(files);
$scope.$apply();
expect(controller.dms.hasFile).toBeTruthy();
expect(controller.dms.hasFileAttached).toBeTruthy();
});
});
});

View File

@ -49,7 +49,7 @@
</vn-input-file>
</vn-horizontal>
<vn-vertical>
<vn-check
<vn-check disabled="true"
label="Generate identifier for original file"
field="$ctrl.dms.hasFile">
</vn-check>

View File

@ -33,7 +33,7 @@ class Controller {
dmsTypeId: dms.dmsTypeFk,
description: dms.description,
hasFile: dms.hasFile,
hasAttachedFile: false,
hasFileAttached: false,
files: []
};
});
@ -68,12 +68,12 @@ class Controller {
}
onFileChange(files) {
let hasAttachedFile = false;
let hasFileAttached = false;
if (files.length > 0)
hasAttachedFile = true;
hasFileAttached = true;
this.$.$applyAsync(() => {
this.dms.hasAttachedFile = hasAttachedFile;
this.dms.hasFileAttached = hasFileAttached;
});
}
}

View File

@ -48,12 +48,12 @@ describe('Client', () => {
});
describe('onFileChange()', () => {
it('should set dms hasFile property to true if has any files', () => {
it('should set dms hasFileAttached property to true if has any files', () => {
const files = [{id: 1, name: 'MyFile'}];
controller.onFileChange(files);
$scope.$apply();
expect(controller.dms.hasFile).toBeTruthy();
expect(controller.dms.hasFileAttached).toBeTruthy();
});
});
});

View File

@ -14,7 +14,8 @@
<vn-tr>
<vn-th field="dmsFk" default-order="DESC" shrink>Id</vn-th>
<vn-th field="dmsTypeFk" shrink>Type</vn-th>
<vn-th field="reference">Reference</vn-th>
<vn-th field="hardCopyNumber" shrink number>Order</vn-th>
<vn-th field="reference" shrink>Reference</vn-th>
<vn-th>Description</vn-th>
<vn-th field="hasFile" shrink>Original</vn-th>
<vn-th>File</vn-th>
@ -31,7 +32,12 @@
{{::document.dms.dmsType.name}}
</span>
</vn-td>
<vn-td>
<vn-td shrink number>
<span title="{{::document.dms.hardCopyNumber}}">
{{::document.dms.hardCopyNumber}}
</span>
</vn-td>
<vn-td shrink>
<span title="{{::document.dms.reference}}">
{{::document.dms.reference}}
</span>

View File

@ -15,8 +15,9 @@ class Controller {
scope: {
fields: [
'dmsTypeFk',
'workerFk',
'reference',
'hardCopyNumber',
'workerFk',
'description',
'hasFile',
'file',

View File

@ -83,7 +83,7 @@ module.exports = Self => {
case 'max':
return {amount: {lte: value}};
case 'hasPdf':
return {'i.pdf': value};
return {'i.hasPdf': value};
case 'created':
return {'i.created': value};
case 'amount':
@ -109,7 +109,7 @@ module.exports = Self => {
i.created,
i.dued,
i.clientFk,
i.pdf AS hasPdf,
i.hasPdf,
c.socialName AS clientSocialName,
co.code AS companyCode
FROM invoiceOut i

View File

@ -35,10 +35,7 @@
"type": "date"
},
"hasPdf": {
"type": "Boolean",
"mysql": {
"columnName": "pdf"
}
"type": "Boolean"
}
},
"relations": {

View File

@ -3,26 +3,29 @@
url="/ticket/api/TicketRequests/filter"
limit="20"
data="requests"
order="isOk ASC"
auto-load="false">
</vn-crud-model>
<form name="form">
<div margin-medium>
<vn-card pad-medium-h class="vn-list">
<vn-horizontal>
<vn-searchbar
<vn-searchbar
auto-load="false"
panel="vn-request-search-panel"
on-search="$ctrl.onSearch($params)"
info="Search request by id or alias"
vn-one
vn-focus>
</vn-searchbar>
</vn-horizontal>
</vn-card>
<vn-card margin-medium-v>
<vn-table model="model">
<vn-table model="model" auto-load="false">
<vn-thead>
<vn-tr>
<vn-th number field="ticketFk">Ticket ID</vn-th>
<vn-th field="shipped" default-order="DESC">Shipped</vn-th>
<vn-th field="shipped">Shipped</vn-th>
<vn-th field="warehouse">Warehouse</vn-th>
<vn-th field="salesPersonNickname">SalesPerson</vn-th>
<vn-th field="description">Description</vn-th>
@ -31,8 +34,8 @@
<vn-th field="atenderNickname">Atender</vn-th>
<vn-th field="itemFk">Item</vn-th>
<vn-th field="description">Concept</vn-th>
<vn-th number>Quantity</vn-th>
<vn-th>State</vn-th>
<vn-th field="saleQuantity" number>Sale quantity</vn-th>
<vn-th field="isOk">State</vn-th>
</vn-tr>
</vn-thead>
<vn-tbody>
@ -56,14 +59,8 @@
ng-click="$ctrl.showWorkerDescriptor($event, request.salesPersonFk)">
{{::request.salesPersonNickname}}
</span>
</vn-td>
<vn-td>
<span
class="link"
ng-click="$ctrl.showItemDescriptor($event, request.itemFk)">
{{::request.description}}
</span>
</vn-td>
<vn-td title="{{::request.description}}">{{::request.description}}</vn-td>
<vn-td number>{{::request.quantity}}</vn-td>
<vn-td number>{{::request.price | currency: 'EUR':2}}</vn-td>
<vn-td>
@ -73,7 +70,7 @@
{{::request.atenderNickname}}
</span>
</vn-td>
<vn-td-editable number>
<vn-td-editable disabled="request.isOk === 0" number>
<text>{{request.itemFk}}</text>
<field>
<vn-input-number vn-focus
@ -82,8 +79,15 @@
</vn-input-number>
</field>
</vn-td-editable>
<vn-td>{{::request.itemDescription}}</vn-td>
<vn-td-editable disabled="!request.saleFk && request.itemFk" number>
<vn-td>
<span
class="link"
ng-click="$ctrl.showItemDescriptor($event, request.itemFk)"
title="{{::request.itemDescription}}">
{{::request.itemDescription}}
</span>
</vn-td>
<vn-td-editable disabled="request.isOk === 0" number>
<text number>{{request.saleQuantity}}</text>
<field>
<vn-input-number vn-focus
@ -94,8 +98,13 @@
</vn-td-editable>
<vn-td>{{::$ctrl.getState(request.isOk)}}</vn-td>
<vn-td>
<vn-icon
ng-if="request.response.length"
vn-tooltip="{{request.response}}"
icon="insert_drive_file">
</vn-icon>
<vn-icon-button
disabled="request.isOk === 0"
ng-if="request.isOk != 0"
number
icon="thumb_down"
ng-click="$ctrl.showDenyReason($event, request.id)"

View File

@ -28,16 +28,17 @@ export default class Controller {
}
confirmRequest(request) {
if (request.itemFk && request.quantity) {
if (request.itemFk && request.saleQuantity) {
let params = {
itemFk: request.itemFk,
quantity: request.quantity || request.saleQuantity
quantity: request.saleQuantity
};
let endpoint = `/api/TicketRequests/${request.id}/confirm`;
this.$http.post(endpoint, params).then(() => {
this.vnApp.showSuccess(this._.instant('Data saved!'));
this.$.model.refresh();
}).catch( e => {
this.$.model.refresh();
throw e;
@ -59,7 +60,8 @@ export default class Controller {
this.$.model.refresh();
throw e;
});
}
} else
this.confirmRequest(request);
}
compareDate(date) {
@ -87,6 +89,7 @@ export default class Controller {
this.denyRequestId = requestId;
this.$.denyReason.parent = event.target;
this.$.denyReason.show();
document.querySelector('vn-item-request vn-textarea textArea').focus();
}
clear() {

View File

@ -0,0 +1,129 @@
import './index.js';
import crudModel from 'core/mocks/crud-model';
describe('Item', () => {
describe('Component vnItemRequest', () => {
let $scope;
let controller;
let $httpBackend;
beforeEach(ngModule('item'));
beforeEach(angular.mock.inject(($componentController, $rootScope, _$httpBackend_) => {
$httpBackend = _$httpBackend_;
$scope = $rootScope.$new();
$scope.model = crudModel;
$scope.denyReason = {hide: () => {}};
controller = $componentController('vnItemRequest', {$scope: $scope});
}));
describe('getState()', () => {
it(`should return an string depending to the isOK value`, () => {
let isOk = null;
let result = controller.getState(isOk);
expect(result).toEqual('Nueva');
isOk = 1;
result = controller.getState(isOk);
expect(result).toEqual('Aceptada');
isOk = 0;
result = controller.getState(isOk);
expect(result).toEqual('Denegada');
});
});
describe('confirmRequest()', () => {
it(`should do nothing if the request does't have itemFk or saleQuantity`, () => {
let request = {};
spyOn(controller.vnApp, 'showSuccess');
controller.confirmRequest(request);
expect(controller.vnApp.showSuccess).not.toHaveBeenCalledWith();
});
it('should perform a query and call vnApp.showSuccess() and refresh if the conditions are met', () => {
spyOn(controller.vnApp, 'showSuccess');
let model = controller.$.model;
spyOn(model, 'refresh');
let request = {itemFk: 1, saleQuantity: 1, id: 1};
$httpBackend.when('POST', `/api/TicketRequests/${request.id}/confirm`).respond();
$httpBackend.expect('POST', `/api/TicketRequests/${request.id}/confirm`).respond();
controller.confirmRequest(request);
$httpBackend.flush();
expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Data saved!');
expect($scope.model.refresh).toHaveBeenCalledWith();
});
});
describe('changeQuantity()', () => {
it(`should call confirmRequest() if there's no sale id in the request`, () => {
let request = {};
spyOn(controller, 'confirmRequest');
controller.changeQuantity(request);
expect(controller.confirmRequest).toHaveBeenCalledWith(jasmine.any(Object));
});
it(`should perform a query and call vnApp.showSuccess() if the conditions are met`, () => {
let request = {saleFk: 1, saleQuantity: 1};
spyOn(controller.vnApp, 'showSuccess');
$httpBackend.when('PATCH', `/api/Sales/${request.saleFk}/`).respond();
$httpBackend.expect('PATCH', `/api/Sales/${request.saleFk}/`).respond();
controller.changeQuantity(request);
$httpBackend.flush();
expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Data saved!');
});
});
describe('compareDate()', () => {
it(`should return "success" if receives a future date`, () => {
let date = '3019-02-18T11:00:00.000Z';
let result = controller.compareDate(date);
expect(result).toEqual('success');
});
it(`should return "warning" if date is today`, () => {
let date = new Date();
let result = controller.compareDate(date);
expect(result).toEqual('warning');
});
});
describe('denyRequest()', () => {
it(`should perform a query and call vnApp.showSuccess(), refresh(), hide() and set denyObservation to null in the controller`, () => {
spyOn(controller.vnApp, 'showSuccess');
let model = controller.$.model;
spyOn(model, 'refresh');
spyOn(controller.$.denyReason, 'hide');
controller.denyRequestId = 1;
$httpBackend.when('POST', `/api/TicketRequests/${controller.denyRequestId}/deny`).respond();
$httpBackend.expect('POST', `/api/TicketRequests/${controller.denyRequestId}/deny`).respond();
controller.denyRequest();
$httpBackend.flush();
expect(controller.vnApp.showSuccess).toHaveBeenCalledWith('Data saved!');
expect($scope.model.refresh).toHaveBeenCalledWith();
expect($scope.denyReason.hide).toHaveBeenCalledWith();
});
});
});
});

View File

@ -1,3 +1,5 @@
Discard: Descartar
Indicate the reasons to deny this request: Indique las razones para descartar esta peticion
Buy requests: Peticiones de compra
Buy requests: Peticiones de compra
Search request by id or alias: Buscar peticiones por identificador o alias
Sale quantity: C. conseguida

View File

@ -1,12 +1,20 @@
vn-dialog[vn-id="denyReason"] {
button.close {
display: none
}
& vn-button {
margin: 0 auto
@import "variables";
vn-item-request {
vn-dialog[vn-id="denyReason"] {
button.close {
display: none
}
& vn-button {
margin: 0 auto
}
vn-textarea {
width: 100%
}
}
vn-textarea {
width: 100%
vn-icon[icon=insert_drive_file]{
color: $color-font-secondary;
}
}

View File

@ -111,7 +111,7 @@ module.exports = Self => {
FROM tmp.ticketCalculateItem tci
JOIN vn.item i ON i.id = tci.itemFk
JOIN vn.itemType it ON it.id = i.typeFk
JOIN vn.ink ON ink.id = i.inkFk
LEFT JOIN vn.ink ON ink.id = i.inkFk
JOIN vn.worker w on w.id = it.workerFk`);
// Apply order by tag

View File

@ -1,2 +1,3 @@
Routes: Rutas
Search routes by id: Buscar rutas por identificador
Search routes by id: Buscar rutas por identificador
New route: Nueva ruta

View File

@ -27,12 +27,12 @@ module.exports = Self => {
let newTicketData = {};
let receiverTicket = params.receiverTicket;
let isCurrentTicketEditable = await models.Ticket.isEditable(params.currentTicket.currentTicketId);
let isCurrentTicketEditable = await models.Ticket.isEditable(ctx, params.currentTicket.currentTicketId);
if (!isCurrentTicketEditable)
throw new UserError(`The sales of the current ticket can't be modified`);
if (params.receiverTicket.id) {
let isReceiverTicketEditable = await models.Ticket.isEditable(params.receiverTicket.id);
let isReceiverTicketEditable = await models.Ticket.isEditable(ctx, params.receiverTicket.id);
if (!isReceiverTicketEditable)
throw new UserError(`The sales of the receiver ticket can't be modified`);
}

View File

@ -1,75 +0,0 @@
const UserError = require('vn-loopback/util/user-error');
module.exports = Self => {
Self.remoteMethod('priceDifference', {
description: 'Returns sales with price difference if the ticket is editable',
accessType: 'READ',
accepts: [{
arg: 'ticketFk',
type: 'number',
required: true,
description: 'ticket id',
http: {source: 'path'}
}, {
arg: 'data',
type: 'Object',
required: true,
description: 'landed, addressFk, agencyModeFk',
http: {source: 'body'}
}],
returns: {
type: ['Object'],
root: true
},
http: {
path: `/:ticketFk/priceDifference`,
verb: 'post'
}
});
Self.priceDifference = async(ticketFk, data) => {
let thisTicketIsEditable = await Self.app.models.Ticket.isEditable(ticketFk);
if (!thisTicketIsEditable)
throw new UserError(`The sales of this ticket can't be modified`);
let filter = {
where: {
ticketFk: ticketFk
},
order: 'concept ASC',
include: [{
relation: 'item'
}]
};
let salesObj = {};
salesObj.items = await Self.find(filter);
salesObj.totalUnitPrice = 0.00;
salesObj.totalNewPrice = 0.00;
salesObj.totalDifference = 0.00;
let query = `CALL vn.ticketComponentPriceDifference(?, ?, ?, ?, ?)`;
let [differences] = await Self.rawSql(query, [
ticketFk,
data.landed,
data.addressFk,
data.agencyModeFk,
data.warehouseFk
]);
salesObj.items.forEach(sale => {
differences.forEach(difference => {
if (sale.id == difference.saleFk)
sale.component = difference;
});
salesObj.totalUnitPrice += sale.price;
salesObj.totalNewPrice += sale.component.newPrice;
salesObj.totalDifference += sale.component.difference;
salesObj.totalUnitPrice = Math.round(salesObj.totalUnitPrice * 100) / 100;
salesObj.totalNewPrice = Math.round(salesObj.totalNewPrice * 100) / 100;
salesObj.totalDifference = Math.round(salesObj.totalDifference * 100) / 100;
});
return salesObj;
};
};

View File

@ -1,7 +1,7 @@
let UserError = require('vn-loopback/util/user-error');
module.exports = Self => {
Self.remoteMethod('removes', {
Self.remoteMethodCtx('removes', {
description: 'Change the state of a ticket',
accessType: 'WRITE',
accepts: [{
@ -21,8 +21,8 @@ module.exports = Self => {
}
});
Self.removes = async params => {
let thisTicketIsEditable = await Self.app.models.Ticket.isEditable(params.actualTicketFk);
Self.removes = async(ctx, params) => {
let thisTicketIsEditable = await Self.app.models.Ticket.isEditable(ctx, params.actualTicketFk);
if (!thisTicketIsEditable)
throw new UserError(`The sales of this ticket can't be modified`);

View File

@ -2,7 +2,7 @@
let UserError = require('vn-loopback/util/user-error');
module.exports = Self => {
Self.remoteMethod('reserve', {
Self.remoteMethodCtx('reserve', {
description: 'Change the state of a ticket',
accessType: 'WRITE',
accepts: [{
@ -22,8 +22,8 @@ module.exports = Self => {
}
});
Self.reserve = async params => {
let thisTicketIsEditable = await Self.app.models.Ticket.isEditable(params.ticketFk);
Self.reserve = async(ctx, params) => {
let thisTicketIsEditable = await Self.app.models.Ticket.isEditable(ctx, params.ticketFk);
if (!thisTicketIsEditable)
throw new UserError(`The sales of this ticket can't be modified`);

View File

@ -13,6 +13,7 @@ describe('sale removes()', () => {
});
it('should throw an error if the ticket of the given sales is not editable', async() => {
let ctx = {req: {accessToken: {userId: 9}}};
let error;
let params = {
@ -21,7 +22,7 @@ describe('sale removes()', () => {
};
try {
await app.models.Sale.removes(params);
await app.models.Sale.removes(ctx, params);
} catch (e) {
error = e;
}
@ -30,12 +31,13 @@ describe('sale removes()', () => {
});
it('should delete the sales', async() => {
let ctx = {req: {accessToken: {userId: 9}}};
let params = {
sales: [{id: newsale.id, instance: 0}],
actualTicketFk: 16
};
let res = await app.models.Sale.removes(params);
let res = await app.models.Sale.removes(ctx, params);
expect(res).toEqual([{count: 1}]);
});

View File

@ -2,6 +2,7 @@ const app = require('vn-loopback/server/server');
describe('sale reserve()', () => {
afterAll(async done => {
let ctx = {req: {accessToken: {userId: 9}}};
let params = {
sales: [
{id: 7},
@ -10,18 +11,19 @@ describe('sale reserve()', () => {
reserved: false
};
await app.models.Sale.reserve(params);
await app.models.Sale.reserve(ctx, params);
done();
});
it('should throw an error if the ticket can not be modified', async() => {
let ctx = {req: {accessToken: {userId: 9}}};
let error;
let params = {ticketFk: 2,
sales: [{id: 5}],
reserved: false};
await app.models.Sale.reserve(params)
await app.models.Sale.reserve(ctx, params)
.catch(response => {
expect(response).toEqual(new Error(`The sales of this ticket can't be modified`));
error = response;
@ -36,6 +38,7 @@ describe('sale reserve()', () => {
expect(originalTicketSales[0].reserved).toEqual(0);
expect(originalTicketSales[1].reserved).toEqual(0);
let ctx = {req: {accessToken: {userId: 9}}};
let params = {
sales: [
{id: 7},
@ -44,7 +47,7 @@ describe('sale reserve()', () => {
reserved: true
};
await app.models.Sale.reserve(params);
await app.models.Sale.reserve(ctx, params);
let reservedTicketSales = await app.models.Ticket.getSales(11);

View File

@ -26,10 +26,11 @@ describe('sale updatePrice()', () => {
it('should throw an error if the ticket is not editable', async() => {
let ctx = {req: {accessToken: {userId: 9}}};
let immutableSaleId = 1;
let price = 5;
await app.models.Sale.updatePrice(immutableSaleId, price)
await app.models.Sale.updatePrice(ctx, immutableSaleId, price)
.catch(response => {
expect(response).toEqual(new Error(`The sales of this ticket can't be modified`));
error = response;
@ -39,27 +40,30 @@ describe('sale updatePrice()', () => {
});
it('should return 0 if the price is an empty string', async() => {
let ctx = {req: {accessToken: {userId: 9}}};
let price = '';
await app.models.Sale.updatePrice(saleId, price);
await app.models.Sale.updatePrice(ctx, saleId, price);
let saleUpdated = await app.models.Sale.findById(saleId);
expect(saleUpdated.price).toEqual(0);
});
it('should now set price as a decimal number in a string', async() => {
let ctx = {req: {accessToken: {userId: 9}}};
let price = '8';
await app.models.Sale.updatePrice(saleId, price);
await app.models.Sale.updatePrice(ctx, saleId, price);
let saleUpdated = await app.models.Sale.findById(saleId);
expect(saleUpdated.price).toEqual(8);
});
it('should set price as a decimal number and check the sale has the mana component', async() => {
let ctx = {req: {accessToken: {userId: 9}}};
let price = 5.3;
await app.models.Sale.updatePrice(saleId, price);
await app.models.Sale.updatePrice(ctx, saleId, price);
let saleUpdated = await app.models.Sale.findById(saleId);
createdSaleComponent = await app.models.SaleComponent.findOne({where: {saleFk: saleId, componentFk: manaComponentId}});

View File

@ -1,7 +1,7 @@
let UserError = require('vn-loopback/util/user-error');
module.exports = Self => {
Self.remoteMethod('updatePrice', {
Self.remoteMethodCtx('updatePrice', {
description: 'Changes the price of a sale',
accessType: 'WRITE',
accepts: [
@ -28,7 +28,7 @@ module.exports = Self => {
}
});
Self.updatePrice = async(id, newPrice) => {
Self.updatePrice = async(ctx, id, newPrice) => {
let models = Self.app.models;
let tx = await Self.beginTransaction({});
@ -51,7 +51,7 @@ module.exports = Self => {
};
let sale = await models.Sale.findById(id, filter, options);
let isEditable = await models.Ticket.isEditable(sale.ticketFk);
let isEditable = await models.Ticket.isEditable(ctx, sale.ticketFk);
if (!isEditable)
throw new UserError(`The sales of this ticket can't be modified`);

View File

@ -13,12 +13,12 @@ module.exports = Self => {
arg: 'itemFk',
type: 'Integer',
required: true,
description: 'The request observation',
description: 'The requested item ID',
}, {
arg: 'quantity',
type: 'Integer',
required: true,
description: 'The request observation',
description: 'The requested item quantity',
}],
returns: {
type: 'Object',
@ -32,6 +32,7 @@ module.exports = Self => {
Self.confirm = async ctx => {
const models = Self.app.models;
let sale;
let tx = await Self.beginTransaction({});
try {
@ -52,32 +53,32 @@ module.exports = Self => {
false
]);
if (stock.available < quantity)
if (stock.available < ctx.args.quantity)
throw new UserError(`This item is not available`);
if (request.saleFk) {
let sale = await models.Sale.findById(request.saleFk);
sale = await models.Sale.findById(request.saleFk);
sale.updateAttributes({
itemFk: ctx.args.itemFk,
quantity: ctx.args.quantity,
description: item.description
concept: item.name,
}, options);
} else {
params = {
sale = await models.Sale.create({
ticketFk: request.ticketFk,
itemFk: ctx.args.itemFk,
quantity: ctx.args.quantity
};
sale = await models.Sale.create(params, options);
request.updateAttributes({saleFk: sale.id, itemFk: sale.itemFk}, options);
quantity: ctx.args.quantity,
concept: item.name
}, options);
request.updateAttributes({saleFk: sale.id, itemFk: sale.itemFk, isOk: true}, options);
}
query = `CALL vn.ticketCalculateSale(?)`;
params = [sale.id];
await Self.rawSql(query, params, options);
await Self.rawSql(query, [sale.id], options);
const message = `Se ha comprado ${params.quantity} unidades de "${item.description}" (#${params.itemFk}) `
+ `para el ticket #${params.ticketFk}`;
const message = `Se ha comprado ${sale.quantity} unidades de "${sale.concept}" (#${sale.itemFk}) `
+ `para el ticket #${sale.ticketFk}`;
await models.Message.send(ctx, {
recipientFk: request.requesterFk,

View File

@ -1,6 +1,6 @@
module.exports = Self => {
Self.remoteMethodCtx('deny', {
description: 'Create a newticket and returns the new ID',
description: 'sets a ticket request to denied and returns the changes',
accessType: 'WRITE',
accepts: [{
arg: 'id',
@ -30,7 +30,7 @@ module.exports = Self => {
let params = {
isOk: false,
atenderFk: worker.id,
observation: ctx.args.observation,
response: ctx.args.observation,
};
let request = await Self.app.models.TicketRequest.findById(ctx.args.id);

View File

@ -71,7 +71,7 @@ module.exports = Self => {
switch (param) {
case 'search':
return /^\d+$/.test(value)
? {'t.ticketFk': {inq: value}}
? {'tr.ticketFk': {inq: value}}
: {'t.nickname': {like: `%${value}%`}};
case 'ticketFk':
return {'t.id': value};
@ -92,41 +92,47 @@ module.exports = Self => {
}
});
if (!where)
where = {};
where['tw.ticketFk'] = null;
filter = mergeFilters(filter, {where});
let stmt;
stmt = new ParameterizedSQL(
`SELECT
tr.id,
tr.ticketFk,
tr.quantity,
tr.price,
tr.atenderFk,
tr.description,
tr.itemFk,
tr.saleFk,
tr.isOk,
s.quantity AS saleQuantity,
i.description AS itemDescription,
t.shipped,
t.nickname,
t.warehouseFk,
t.clientFk,
w.name AS warehouse,
u.nickname AS salesPersonNickname,
ua.nickname AS atenderNickname,
c.salesPersonFk
FROM ticketRequest tr
LEFT JOIN ticket t ON t.id = tr.ticketFk
LEFT JOIN warehouse w ON w.id = t.warehouseFk
LEFT JOIN client c ON c.id = t.clientFk
LEFT JOIN item i ON i.id = tr.itemFk
LEFT JOIN sale s ON s.id = tr.saleFk
LEFT JOIN worker wk ON wk.id = c.salesPersonFk
LEFT JOIN account.user u ON u.id = wk.userFk
LEFT JOIN worker wka ON wka.id = tr.atenderFk
LEFT JOIN account.user ua ON ua.id = wka.userFk`);
tr.id,
tr.ticketFk,
tr.quantity,
tr.price,
tr.atenderFk,
tr.description,
tr.response,
tr.saleFk,
tr.isOk,
s.quantity AS saleQuantity,
s.itemFK,
i.name AS itemDescription,
t.shipped,
t.nickname,
t.warehouseFk,
t.clientFk,
w.name AS warehouse,
u.nickname AS salesPersonNickname,
ua.nickname AS atenderNickname,
c.salesPersonFk
FROM ticketRequest tr
LEFT JOIN ticketWeekly tw on tw.ticketFk = tr.ticketFk
LEFT JOIN ticket t ON t.id = tr.ticketFk
LEFT JOIN warehouse w ON w.id = t.warehouseFk
LEFT JOIN client c ON c.id = t.clientFk
LEFT JOIN item i ON i.id = tr.itemFk
LEFT JOIN sale s ON s.id = tr.saleFk
LEFT JOIN worker wk ON wk.id = c.salesPersonFk
LEFT JOIN account.user u ON u.id = wk.userFk
LEFT JOIN worker wka ON wka.id = tr.atenderFk
LEFT JOIN account.user ua ON ua.id = wka.userFk`);
stmt.merge(conn.makeSuffix(filter));
let result = await conn.executeStmt(stmt);

View File

@ -0,0 +1,110 @@
const app = require('vn-loopback/server/server');
describe('ticket-request confirm()', () => {
let request;
let sale;
let createdSaleId;
afterAll(async done => {
const paramsForRequest = {
saleFk: request.saleFk,
isOk: request.isOk,
itemFk: request.itemFk,
ticketFk: request.ticketFk
};
const paramsForSale = {
itemFk: sale.itemFk,
quantity: sale.quantity,
concept: sale.concept,
};
await request.updateAttributes(paramsForRequest);
await sale.updateAttributes(paramsForSale);
app.models.Sale.destroyById(createdSaleId);
done();
});
it(`should throw an error if the item doesn't exist`, async() => {
let ctx = {req: {accessToken: {userId: 9}}, args: {itemFk: 999}};
let error;
try {
await app.models.TicketRequest.confirm(ctx);
} catch (err) {
error = err;
}
expect(error.message).toEqual(`That item doesn't exists`);
});
it(`should throw an error if the item is not available`, async() => {
const requestId = 4;
const itemId = 1;
const quantity = 99999;
let ctx = {req: {accessToken: {userId: 9}}, args: {
itemFk: itemId,
id: requestId,
quantity: quantity
}};
let error;
try {
await app.models.TicketRequest.confirm(ctx);
} catch (err) {
error = err;
}
expect(error.message).toEqual(`This item is not available`);
});
it(`should update the sale details if the request already contains a sale id`, async() => {
const requestId = 4;
const saleId = 11;
const itemId = 1;
const quantity = 10;
request = await app.models.TicketRequest.findById(requestId);
sale = await app.models.Sale.findById(saleId);
request.updateAttributes({saleFk: saleId});
let ctx = {req: {accessToken: {userId: 9}}, args: {
itemFk: itemId,
id: requestId,
quantity: quantity
}};
await app.models.TicketRequest.confirm(ctx);
let updatedSale = await app.models.Sale.findById(saleId);
expect(updatedSale.itemFk).toEqual(itemId);
expect(updatedSale.quantity).toEqual(quantity);
});
it(`should create a new sale for the the request if there's no sale id`, async() => {
const requestId = 4;
const itemId = 1;
const quantity = 10;
request.updateAttributes({saleFk: null});
let ctx = {req: {accessToken: {userId: 9}}, args: {
itemFk: itemId,
id: requestId,
quantity: quantity,
ticketFk: 1
}};
await app.models.TicketRequest.confirm(ctx);
let updatedRequest = await app.models.TicketRequest.findById(requestId);
createdSaleId = updatedRequest.saleFk;
expect(updatedRequest.saleFk).toEqual(createdSaleId);
expect(updatedRequest.isOk).toEqual(true);
expect(updatedRequest.itemFk).toEqual(itemId);
});
});

View File

@ -0,0 +1,25 @@
const app = require('vn-loopback/server/server');
describe('ticket-request deny()', () => {
let request;
afterAll(async done => {
let params = {
isOk: null,
atenderFk: request.atenderFk,
response: null,
};
await request.updateAttributes(params);
done();
});
it('should return all ticket requests', async() => {
let ctx = {req: {accessToken: {userId: 9}}, args: {id: 4, observation: 'my observation'}};
request = await app.models.TicketRequest.findById(ctx.args.id);
let result = await app.models.TicketRequest.deny(ctx);
expect(result.id).toEqual(4);
});
});

View File

@ -0,0 +1,83 @@
const app = require('vn-loopback/server/server');
describe('ticket-request filter()', () => {
it('should return all ticket requests', async() => {
let ctx = {req: {accessToken: {userId: 9}}, args: {}};
let result = await app.models.TicketRequest.filter(ctx);
expect(result.length).toEqual(1);
});
it('should return the ticket request matching a generic search value which is the ticket ID', async() => {
let ctx = {req: {accessToken: {userId: 9}}, args: {search: 11}};
let result = await app.models.TicketRequest.filter(ctx);
let requestId = result[0].id;
expect(requestId).toEqual(4);
});
it('should return the ticket request matching a generic search value which is the client address alias', async() => {
let ctx = {req: {accessToken: {userId: 9}}, args: {search: 'NY roofs'}};
let result = await app.models.TicketRequest.filter(ctx);
let requestId = result[0].id;
expect(requestId).toEqual(4);
});
it('should return the ticket request matching the ticket ID', async() => {
let ctx = {req: {accessToken: {userId: 9}}, args: {ticketFk: 11}};
let result = await app.models.TicketRequest.filter(ctx);
let requestId = result[0].id;
expect(requestId).toEqual(4);
});
it('should return the ticket request matching the atender ID', async() => {
let ctx = {req: {accessToken: {userId: 9}}, args: {atenderFk: 35}};
let result = await app.models.TicketRequest.filter(ctx);
let requestId = result[0].id;
expect(requestId).toEqual(4);
});
it('should return the ticket request matching the isOk triple-state', async() => {
let ctx = {req: {accessToken: {userId: 9}}, args: {isOk: null}};
let result = await app.models.TicketRequest.filter(ctx);
let requestId = result[0].id;
expect(requestId).toEqual(4);
});
it('should return the ticket request matching the client ID', async() => {
let ctx = {req: {accessToken: {userId: 9}}, args: {clientFk: 102}};
let result = await app.models.TicketRequest.filter(ctx);
let requestId = result[0].id;
expect(requestId).toEqual(4);
});
it('should return the ticket request matching the warehouse ID', async() => {
let ctx = {req: {accessToken: {userId: 9}}, args: {warehouse: 1}};
let result = await app.models.TicketRequest.filter(ctx);
let requestId = result[0].id;
expect(requestId).toEqual(4);
});
it('should return the ticket request matching the salesPerson ID', async() => {
let ctx = {req: {accessToken: {userId: 9}}, args: {salesPersonFk: 18}};
let result = await app.models.TicketRequest.filter(ctx);
let requestId = result[0].id;
expect(requestId).toEqual(4);
});
});

View File

@ -2,7 +2,7 @@
const UserError = require('vn-loopback/util/user-error');
module.exports = Self => {
Self.remoteMethod('addSale', {
Self.remoteMethodCtx('addSale', {
description: 'Inserts a new sale for the current ticket',
accessType: 'WRITE',
accepts: [{
@ -32,10 +32,10 @@ module.exports = Self => {
}
});
Self.addSale = async(id, itemId, quantity) => {
Self.addSale = async(ctx, id, itemId, quantity) => {
const models = Self.app.models;
const isEditable = await models.Ticket.isEditable(id);
const isEditable = await models.Ticket.isEditable(ctx, id);
if (!isEditable)
throw new UserError(`The sales of this ticket can't be modified`);

View File

@ -1,56 +1,116 @@
const UserError = require('vn-loopback/util/user-error');
module.exports = Self => {
Self.remoteMethod('componentUpdate', {
Self.remoteMethodCtx('componentUpdate', {
description: 'Save ticket sale components',
accessType: 'WRITE',
accepts: [{
arg: 'ticketFk',
type: 'number',
arg: 'id',
type: 'Number',
required: true,
description: 'ticket id',
description: 'The ticket id',
http: {source: 'path'}
}, {
arg: 'data',
type: 'Object',
required: true,
description: 'landed, addressFk, agencyModeFk, warehouseFk',
http: {source: 'body'}
arg: 'clientId',
type: 'Number',
description: 'The client id',
required: true
}, {
arg: 'context',
type: 'object',
http: function(ctx) {
return ctx;
}
arg: 'agencyModeId',
type: 'Number',
description: 'The agencyMode id',
required: true
}, {
arg: 'addressId',
type: 'Number',
description: 'The address id',
required: true
}, {
arg: 'zoneId',
type: 'Number',
description: 'The zone id',
required: true
}, {
arg: 'warehouseId',
type: 'Number',
description: 'The warehouse id',
required: true
}, {
arg: 'companyId',
type: 'Number',
description: 'The company id',
required: true
}, {
arg: 'shipped',
type: 'Date',
description: 'The shipped date',
required: true
}, {
arg: 'landed',
type: 'Date',
description: 'The landing date',
required: true
}, {
arg: 'isDeleted',
type: 'Boolean',
description: 'Ticket is deleted',
required: true
}, {
arg: 'hasToBeUnrouted',
type: 'Boolean',
description: 'Ticket should be removed from ticket',
required: true
}, {
arg: 'option',
type: 'Number',
description: 'Action id',
required: true
}],
returns: {
type: ['Object'],
root: true
},
http: {
path: `/:ticketFk/componentUpdate`,
path: `/:id/componentUpdate`,
verb: 'post'
}
});
Self.componentUpdate = async(ticketFk, data, ctx) => {
let userId = ctx.req.accessToken.userId;
let hasDeliveryRole = await Self.app.models.Account.hasRole(userId, 'delivery');
Self.componentUpdate = async(ctx, id, clientId, agencyModeId, addressId, zoneId, warehouseId,
companyId, shipped, landed, isDeleted, hasToBeUnrouted, option) => {
const userId = ctx.req.accessToken.userId;
const models = Self.app.models;
const isEditable = await models.Ticket.isEditable(ctx, id);
if (!isEditable)
throw new UserError(`The sales of this ticket can't be modified`);
const hasDeliveryRole = await models.Account.hasRole(userId, 'delivery');
if (!hasDeliveryRole)
data.hasToBeUnrouted = true;
hasToBeUnrouted = true;
let query = 'CALL vn.ticketComponentMakeUpdate(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
const isProductionBoss = await models.Account.hasRole(userId, 'productionBoss');
if (!isProductionBoss) {
const zone = await models.Agency.getShipped(landed, addressId, agencyModeId, warehouseId);
if (zone.id != zoneId)
throw new UserError(`You don't have privileges to change the zone`);
}
let query = 'CALL vn.ticket_componentMakeUpdate(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
let res = await Self.rawSql(query, [
ticketFk,
data.clientFk,
data.agencyModeFk,
data.addressFk,
data.warehouseFk,
data.companyFk,
data.shipped,
data.landed,
data.isDeleted,
data.hasToBeUnrouted,
data.option
id,
clientId,
agencyModeId,
addressId,
zoneId,
warehouseId,
companyId,
shipped,
landed,
isDeleted,
hasToBeUnrouted,
option
]);
return res;
};

View File

@ -1,5 +1,5 @@
module.exports = Self => {
Self.remoteMethod('isEditable', {
Self.remoteMethodCtx('isEditable', {
description: 'Check if a ticket is editable',
accessType: 'READ',
accepts: [{
@ -19,10 +19,13 @@ module.exports = Self => {
}
});
Self.isEditable = async ticketFk => {
Self.isEditable = async(ctx, ticketFk) => {
const accessToken = ctx.req.accessToken;
const userId = accessToken.userId;
let state = await Self.app.models.TicketState.findOne({
where: {ticketFk: ticketFk}
});
let isProductionBoss = await Self.app.models.Account.hasRole(userId, 'productionBoss');
let alertLevel = state ? state.alertLevel : null;
let ticket = await Self.app.models.Ticket.findById(ticketFk, {
fields: ['isDeleted', 'clientFk', 'refFk'],
@ -41,7 +44,7 @@ module.exports = Self => {
const isNotNormalClient = ticket && ticket.client().type().code == 'normal';
const isInvoiced = ticket && ticket.refFk;
if (!ticket || ((isDeleted || isOnDelivery) && isNotNormalClient) || isInvoiced)
if (!ticket || (isOnDelivery && isNotNormalClient && !isProductionBoss) || isInvoiced || isDeleted)
return false;
return true;

View File

@ -1,4 +1,5 @@
const UserError = require('vn-loopback/util/user-error');
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
module.exports = function(Self) {
Self.remoteMethodCtx('makeInvoice', {
@ -25,6 +26,7 @@ module.exports = function(Self) {
});
Self.makeInvoice = async(ctx, id) => {
const conn = Self.dataSource.connector;
let userId = ctx.req.accessToken.userId;
let models = Self.app.models;
let tx = await Self.beginTransaction({});
@ -48,29 +50,32 @@ module.exports = function(Self) {
let [result] = await Self.rawSql(query, [ticket.clientFk, ticket.companyFk, 'R'], options);
let serial = result.serial;
query = `CALL vn.invoiceFromTicket(?)`;
await Self.rawSql(query, [ticket.id], options);
let stmts = [];
result = await Self.rawSql(
`CALL vn.invoiceOutMake(?, ?, @invoiceId);
SELECT @invoiceId AS invoiceId;`,
[serial, null],
options
);
let invoice = result[1][0].invoiceId;
stmt = new ParameterizedSQL('CALL vn.invoiceOut_newFromTicket(?, ?, ?, @invoiceId)', [
ticket.id,
serial,
null
]);
stmts.push(stmt);
if (serial != 'R' && invoice) {
let invoiceIndex = stmts.push(`SELECT @invoiceId AS invoiceId`) - 1;
let sql = ParameterizedSQL.join(stmts, ';');
result = await conn.executeStmt(sql);
let invoiceId = result[invoiceIndex][0].invoiceId;
if (serial != 'R' && invoiceId) {
query = `CALL vn.invoiceOutBooking(?)`;
await Self.rawSql(query, [invoice], options);
await Self.rawSql(query, [invoiceId], options);
}
let user = await models.Worker.findOne({where: {userFk: userId}}, options);
query = `INSERT INTO printServerQueue(reportFk, param1, workerFk) VALUES (?, ?, ?)`;
await Self.rawSql(query, [3, invoice, user.id], options);
await Self.rawSql(query, [3, invoiceId, user.id], options);
await tx.commit();
return {invoiceFk: invoice, serial};
return {invoiceFk: invoiceId, serial};
} catch (e) {
await tx.rollback();
throw e;

View File

@ -61,21 +61,14 @@ module.exports = Self => {
try {
if (!params.shipped && params.landed) {
params.shipped = await models.Agency.getShipped(ctx, {
landed: params.landed,
addressFk: address.id,
agencyModeFk: params.agencyModeFk,
warehouseFk: params.warehouseFk
});
const shippedResult = await models.Agency.getShipped(params.landed,
address.id, params.agencyModeFk, params.warehouseFk);
params.shipped = shippedResult.shipped;
}
if (params.shipped && !params.landed) {
const landedResult = await models.Agency.getLanded(ctx, {
shipped: params.shipped,
addressFk: address.id,
agencyModeFk: params.agencyModeFk,
warehouseFk: params.warehouseFk
});
const landedResult = await models.Agency.getLanded(params.shipped,
address.id, params.agencyModeFk, params.warehouseFk);
params.landed = landedResult.landed;
}

View File

@ -0,0 +1,110 @@
const UserError = require('vn-loopback/util/user-error');
module.exports = Self => {
Self.remoteMethodCtx('priceDifference', {
description: 'Returns sales with price difference if the ticket is editable',
accessType: 'READ',
accepts: [{
arg: 'id',
type: 'Number',
required: true,
description: 'The ticket id',
http: {source: 'path'}
},
{
arg: 'landed',
type: 'Date',
description: 'The landing date',
required: true
},
{
arg: 'addressId',
type: 'Number',
description: 'The address id',
required: true
},
{
arg: 'agencyModeId',
type: 'Number',
description: 'The agencyMode id',
required: true
},
{
arg: 'zoneId',
type: 'Number',
description: 'The zone id',
required: true
},
{
arg: 'warehouseId',
type: 'Number',
description: 'The warehouse id',
required: true
}],
returns: {
type: ['Object'],
root: true
},
http: {
path: `/:id/priceDifference`,
verb: 'POST'
}
});
Self.priceDifference = async(ctx, id, landed, addressId, agencyModeId, zoneId, warehouseId) => {
const models = Self.app.models;
const isEditable = await models.Ticket.isEditable(ctx, id);
const userId = ctx.req.accessToken.userId;
if (!isEditable)
throw new UserError(`The sales of this ticket can't be modified`);
const isProductionBoss = await models.Account.hasRole(userId, 'productionBoss');
if (!isProductionBoss) {
const zone = await models.Agency.getShipped(landed, addressId, agencyModeId, warehouseId);
if (zone.id != zoneId)
throw new UserError(`You don't have privileges to change the zone`);
}
let salesObj = {};
salesObj.items = await models.Sale.find({
where: {
ticketFk: id
},
order: 'concept ASC',
include: [{
relation: 'item'
}]
});
salesObj.totalUnitPrice = 0.00;
salesObj.totalNewPrice = 0.00;
salesObj.totalDifference = 0.00;
const query = `CALL vn.ticket_priceDifference(?, ?, ?, ?, ?)`;
const args = [id, landed, addressId, zoneId, warehouseId];
const [difComponents] = await Self.rawSql(query, args);
const map = new Map();
difComponents.forEach(difComponent => {
map.set(difComponent.saleFk, difComponent);
});
salesObj.items.forEach(sale => {
const difComponent = map.get(sale.id);
if (difComponent)
sale.component = difComponent;
salesObj.totalUnitPrice += sale.price;
salesObj.totalNewPrice += sale.component.newPrice;
salesObj.totalDifference += sale.component.difference;
salesObj.totalUnitPrice = Math.round(salesObj.totalUnitPrice * 100) / 100;
salesObj.totalNewPrice = Math.round(salesObj.totalNewPrice * 100) / 100;
salesObj.totalDifference = Math.round(salesObj.totalDifference * 100) / 100;
});
return salesObj;
};
};

View File

@ -12,19 +12,21 @@ describe('ticket addSale()', () => {
});
it('should create a new sale for the ticket with id 13', async() => {
let ctx = {req: {accessToken: {userId: 9}}};
const itemId = 4;
const quantity = 10;
newSale = await app.models.Ticket.addSale(ticketId, itemId, quantity);
newSale = await app.models.Ticket.addSale(ctx, ticketId, itemId, quantity);
expect(newSale.itemFk).toEqual(4);
});
it('should not be able to add a sale if the item quantity is not available', async() => {
let ctx = {req: {accessToken: {userId: 9}}};
const itemId = 11;
const quantity = 10;
let error;
await app.models.Ticket.addSale(ticketId, itemId, quantity).catch(e => {
await app.models.Ticket.addSale(ctx, ticketId, itemId, quantity).catch(e => {
error = e;
}).finally(() => {
expect(error.message).toEqual(`This item is not available`);
@ -34,11 +36,12 @@ describe('ticket addSale()', () => {
});
it('should not be able to add a sale if the ticket is not editable', async() => {
let ctx = {req: {accessToken: {userId: 9}}};
const notEditableTicketId = 1;
const itemId = 4;
const quantity = 10;
let error;
await app.models.Ticket.addSale(notEditableTicketId, itemId, quantity).catch(e => {
await app.models.Ticket.addSale(ctx, notEditableTicketId, itemId, quantity).catch(e => {
error = e;
}).finally(() => {
expect(error.message).toEqual(`The sales of this ticket can't be modified`);

View File

@ -28,22 +28,22 @@ describe('ticket componentUpdate()', () => {
});
it('should change the agencyMode to modify the sale components value', async() => {
let data = {
clientFk: 102,
agencyModeFk: 8,
addressFk: 122,
warehouseFk: 1,
companyFk: 442,
shipped: today,
landed: tomorrow,
isDeleted: false,
hasToBeUnrouted: false,
option: 1
};
const clientId = 102;
const addressId = 122;
const agencyModeId = 8;
const warehouseId = 1;
const zoneId = 5;
const shipped = today;
const companyId = 442;
const isDeleted = false;
const landed = tomorrow;
const hasToBeUnrouted = false;
const option = 1;
let ctx = {req: {accessToken: {userId: 101}}};
await app.models.Ticket.componentUpdate(ticketId, data, ctx);
await app.models.Ticket.componentUpdate(ctx, ticketId, clientId, agencyModeId, addressId,
zoneId, warehouseId, companyId, shipped, landed, isDeleted, hasToBeUnrouted, option);
[componentValue] = await app.models.SaleComponent.rawSql(componentOfSaleSeven);
let firstvalueAfterChange = componentValue.value;
@ -56,21 +56,21 @@ describe('ticket componentUpdate()', () => {
});
it('should change the agencyMode to go back to the originals sale components value', async() => {
let data = {
clientFk: 102,
agencyModeFk: 7,
addressFk: 122,
warehouseFk: 1,
companyFk: 442,
shipped: today,
landed: tomorrow,
isDeleted: false,
hasToBeUnrouted: false,
option: 1
};
const clientId = 102;
const addressId = 122;
const agencyModeId = 7;
const warehouseId = 1;
const zoneId = 3;
const shipped = today;
const companyId = 442;
const isDeleted = false;
const landed = tomorrow;
const hasToBeUnrouted = false;
const option = 1;
let ctx = {req: {accessToken: {userId: 101}}};
await app.models.Ticket.componentUpdate(ticketId, data, ctx);
await app.models.Ticket.componentUpdate(ctx, ticketId, clientId, agencyModeId, addressId,
zoneId, warehouseId, companyId, shipped, landed, isDeleted, hasToBeUnrouted, option);
[componentValue] = await app.models.SaleComponent.rawSql(componentOfSaleSeven);
let firstvalueAfterChange = componentValue.value;

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