Merge branch 'dev' into 5063-item-module-doPhoto
gitea/salix/pipeline/head This commit looks good
Details
gitea/salix/pipeline/head This commit looks good
Details
This commit is contained in:
commit
08476fe2a6
13
CHANGELOG.md
13
CHANGELOG.md
|
@ -5,10 +5,22 @@ All notable changes to this project will be documented in this file.
|
||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [2308.01] - 2023-03-09
|
||||||
|
|
||||||
|
### Added
|
||||||
|
-
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
-
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
-
|
||||||
|
|
||||||
## [2306.01] - 2023-02-23
|
## [2306.01] - 2023-02-23
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
- (Tickets -> Datos Básicos) Mensaje de confirmación al intentar generar tickets con negativos
|
- (Tickets -> Datos Básicos) Mensaje de confirmación al intentar generar tickets con negativos
|
||||||
|
- (Artículos) El visible y disponible se calcula a partir de un almacén diferente dependiendo de la sección en la que te encuentres. Se ha añadido un icono que informa sobre a partir de que almacén se esta calculando.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- (General -> Inicio) Ahora permite recuperar la contraseña tanto con el correo de recuperación como el usuario
|
- (General -> Inicio) Ahora permite recuperar la contraseña tanto con el correo de recuperación como el usuario
|
||||||
|
@ -16,6 +28,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
### Fixed
|
### Fixed
|
||||||
- (Monitor de tickets) Cuando ordenas por columna, ya no se queda deshabilitado el botón de 'Actualizar'
|
- (Monitor de tickets) Cuando ordenas por columna, ya no se queda deshabilitado el botón de 'Actualizar'
|
||||||
- (Zone -> Días de entrega) Al hacer click en un día, muestra correctamente las zonas
|
- (Zone -> Días de entrega) Al hacer click en un día, muestra correctamente las zonas
|
||||||
|
- (Artículos) El disponible en la vista previa se muestra correctamente
|
||||||
|
|
||||||
## [2304.01] - 2023-02-09
|
## [2304.01] - 2023-02-09
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
"type": "date"
|
"type": "date"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
"scope": {
|
"scope": {
|
||||||
"where" :{
|
"where" :{
|
||||||
"expired": null
|
"expired": null
|
||||||
|
|
|
@ -3,7 +3,3 @@ ALTER TABLE `vn`.`itemConfig` ADD CONSTRAINT itemConfig_FK FOREIGN KEY (defaultT
|
||||||
ALTER TABLE `vn`.`itemConfig` ADD validPriorities varchar(50) DEFAULT '[1,2,3]' NOT NULL;
|
ALTER TABLE `vn`.`itemConfig` ADD validPriorities varchar(50) DEFAULT '[1,2,3]' NOT NULL;
|
||||||
ALTER TABLE `vn`.`itemConfig` ADD defaultPriority INT DEFAULT 2 NOT NULL;
|
ALTER TABLE `vn`.`itemConfig` ADD defaultPriority INT DEFAULT 2 NOT NULL;
|
||||||
ALTER TABLE `vn`.`item` MODIFY COLUMN relevancy tinyint(1) DEFAULT 0 NOT NULL COMMENT 'La web ordena de forma descendiente por este campo para mostrar los artículos';
|
ALTER TABLE `vn`.`item` MODIFY COLUMN relevancy tinyint(1) DEFAULT 0 NOT NULL COMMENT 'La web ordena de forma descendiente por este campo para mostrar los artículos';
|
||||||
|
|
||||||
INSERT INTO `salix`.`ACL`
|
|
||||||
(model, property, accessType, permission, principalType, principalId)
|
|
||||||
VALUES('ItemConfig', '*', 'READ', 'ALLOW', 'ROLE', 'buyer');
|
|
||||||
|
|
|
@ -3,7 +3,3 @@ ALTER TABLE `vn`.`itemConfig` ADD CONSTRAINT itemConfig_FK FOREIGN KEY (defaultT
|
||||||
ALTER TABLE `vn`.`itemConfig` ADD validPriorities varchar(50) DEFAULT '[1,2,3]' NOT NULL;
|
ALTER TABLE `vn`.`itemConfig` ADD validPriorities varchar(50) DEFAULT '[1,2,3]' NOT NULL;
|
||||||
ALTER TABLE `vn`.`itemConfig` ADD defaultPriority INT DEFAULT 2 NOT NULL;
|
ALTER TABLE `vn`.`itemConfig` ADD defaultPriority INT DEFAULT 2 NOT NULL;
|
||||||
ALTER TABLE `vn`.`item` MODIFY COLUMN relevancy tinyint(1) DEFAULT 0 NOT NULL COMMENT 'La web ordena de forma descendiente por este campo para mostrar los artículos';
|
ALTER TABLE `vn`.`item` MODIFY COLUMN relevancy tinyint(1) DEFAULT 0 NOT NULL COMMENT 'La web ordena de forma descendiente por este campo para mostrar los artículos';
|
||||||
|
|
||||||
INSERT INTO `salix`.`ACL`
|
|
||||||
(model, property, accessType, permission, principalType, principalId)
|
|
||||||
VALUES('ItemConfig', '*', 'READ', 'ALLOW', 'ROLE', 'buyer');
|
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
DROP FUNCTION IF EXISTS `vn`.`invoiceOut_getWeight`;
|
||||||
|
|
||||||
|
DELIMITER $$
|
||||||
|
$$
|
||||||
|
CREATE DEFINER=`root`@`localhost` FUNCTION `vn`.`invoiceOut_getWeight`(vInvoice VARCHAR(15)) RETURNS decimal(10,2)
|
||||||
|
READS SQL DATA
|
||||||
|
BEGIN
|
||||||
|
/**
|
||||||
|
* Calcula el peso de una factura emitida
|
||||||
|
*
|
||||||
|
* @param vInvoice Id de la factura
|
||||||
|
* @return vTotalWeight peso de la factura
|
||||||
|
*/
|
||||||
|
DECLARE vTotalWeight DECIMAL(10,2);
|
||||||
|
|
||||||
|
SELECT SUM(CAST(IFNULL(i.stems, 1)
|
||||||
|
* s.quantity
|
||||||
|
* IF(ic.grams, ic.grams, IFNULL(i.weightByPiece, 0)) / 1000 AS DECIMAL(10,2)))
|
||||||
|
INTO vTotalWeight
|
||||||
|
FROM ticket t
|
||||||
|
JOIN sale s ON s.ticketFk = t.id
|
||||||
|
JOIN item i ON i.id = s.itemFk
|
||||||
|
JOIN itemCost ic ON ic.itemFk = i.id
|
||||||
|
AND ic.warehouseFk = t.warehouseFk
|
||||||
|
WHERE t.refFk = vInvoice
|
||||||
|
AND i.intrastatFk;
|
||||||
|
|
||||||
|
RETURN vTotalWeight;
|
||||||
|
END$$
|
||||||
|
DELIMITER ;
|
|
@ -0,0 +1,3 @@
|
||||||
|
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
|
||||||
|
VALUES
|
||||||
|
('Client', 'getClientOrSupplierReference', 'READ', 'ALLOW', 'ROLE', 'employee');
|
|
@ -0,0 +1,127 @@
|
||||||
|
DROP PROCEDURE IF EXISTS `vn`.`ticket_canAdvance`;
|
||||||
|
|
||||||
|
DELIMITER $$
|
||||||
|
$$
|
||||||
|
CREATE DEFINER=`root`@`localhost` PROCEDURE `vn`.`ticket_canAdvance`(vDateFuture DATE, vDateToAdvance DATE, vWarehouseFk INT)
|
||||||
|
BEGIN
|
||||||
|
/**
|
||||||
|
* Devuelve los tickets y la cantidad de lineas de venta que se pueden adelantar.
|
||||||
|
*
|
||||||
|
* @param vDateFuture Fecha de los tickets que se quieren adelantar.
|
||||||
|
* @param vDateToAdvance Fecha a cuando se quiere adelantar.
|
||||||
|
* @param vWarehouseFk Almacén
|
||||||
|
*/
|
||||||
|
|
||||||
|
DECLARE vDateInventory DATE;
|
||||||
|
|
||||||
|
SELECT inventoried INTO vDateInventory FROM config;
|
||||||
|
|
||||||
|
DROP TEMPORARY TABLE IF EXISTS tmp.stock;
|
||||||
|
CREATE TEMPORARY TABLE tmp.stock
|
||||||
|
(itemFk INT PRIMARY KEY,
|
||||||
|
amount INT)
|
||||||
|
ENGINE = MEMORY;
|
||||||
|
|
||||||
|
INSERT INTO tmp.stock(itemFk, amount)
|
||||||
|
SELECT itemFk, SUM(quantity) amount FROM
|
||||||
|
(
|
||||||
|
SELECT itemFk, quantity
|
||||||
|
FROM itemTicketOut
|
||||||
|
WHERE shipped >= vDateInventory
|
||||||
|
AND shipped < vDateFuture
|
||||||
|
AND warehouseFk = vWarehouseFk
|
||||||
|
UNION ALL
|
||||||
|
SELECT itemFk, quantity
|
||||||
|
FROM itemEntryIn
|
||||||
|
WHERE landed >= vDateInventory
|
||||||
|
AND landed < vDateFuture
|
||||||
|
AND isVirtualStock = FALSE
|
||||||
|
AND warehouseInFk = vWarehouseFk
|
||||||
|
UNION ALL
|
||||||
|
SELECT itemFk, quantity
|
||||||
|
FROM itemEntryOut
|
||||||
|
WHERE shipped >= vDateInventory
|
||||||
|
AND shipped < vDateFuture
|
||||||
|
AND warehouseOutFk = vWarehouseFk
|
||||||
|
) t
|
||||||
|
GROUP BY itemFk HAVING amount != 0;
|
||||||
|
|
||||||
|
DROP TEMPORARY TABLE IF EXISTS tmp.filter;
|
||||||
|
CREATE TEMPORARY TABLE tmp.filter
|
||||||
|
(INDEX (id))
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
origin.ticketFk futureId,
|
||||||
|
dest.ticketFk id,
|
||||||
|
dest.state,
|
||||||
|
origin.futureState,
|
||||||
|
origin.futureIpt,
|
||||||
|
dest.ipt,
|
||||||
|
origin.workerFk,
|
||||||
|
origin.futureLiters,
|
||||||
|
origin.futureLines,
|
||||||
|
dest.shipped,
|
||||||
|
origin.shipped futureShipped,
|
||||||
|
dest.totalWithVat,
|
||||||
|
origin.totalWithVat futureTotalWithVat,
|
||||||
|
dest.agency,
|
||||||
|
origin.futureAgency,
|
||||||
|
dest.lines,
|
||||||
|
dest.liters,
|
||||||
|
origin.futureLines - origin.hasStock AS notMovableLines,
|
||||||
|
(origin.futureLines = origin.hasStock) AS isFullMovable
|
||||||
|
FROM (
|
||||||
|
SELECT
|
||||||
|
s.ticketFk,
|
||||||
|
t.workerFk,
|
||||||
|
t.shipped,
|
||||||
|
t.totalWithVat,
|
||||||
|
st.name futureState,
|
||||||
|
t.addressFk,
|
||||||
|
am.name futureAgency,
|
||||||
|
count(s.id) futureLines,
|
||||||
|
GROUP_CONCAT(DISTINCT ipt.code ORDER BY ipt.code) futureIpt,
|
||||||
|
CAST(SUM(litros) AS DECIMAL(10,0)) futureLiters,
|
||||||
|
SUM((s.quantity <= IFNULL(st.amount,0))) hasStock
|
||||||
|
FROM ticket t
|
||||||
|
JOIN sale s ON s.ticketFk = t.id
|
||||||
|
JOIN saleVolume sv ON sv.saleFk = s.id
|
||||||
|
JOIN item i ON i.id = s.itemFk
|
||||||
|
JOIN ticketState ts ON ts.ticketFk = t.id
|
||||||
|
JOIN state st ON st.id = ts.stateFk
|
||||||
|
JOIN agencyMode am ON t.agencyModeFk = am.id
|
||||||
|
LEFT JOIN itemPackingType ipt ON ipt.code = i.itemPackingTypeFk
|
||||||
|
LEFT JOIN tmp.stock st ON st.itemFk = i.id
|
||||||
|
WHERE t.shipped BETWEEN vDateFuture AND util.dayend(vDateFuture)
|
||||||
|
AND t.warehouseFk = vWarehouseFk
|
||||||
|
GROUP BY t.id
|
||||||
|
) origin
|
||||||
|
JOIN (
|
||||||
|
SELECT
|
||||||
|
t.id ticketFk,
|
||||||
|
t.addressFk,
|
||||||
|
st.name state,
|
||||||
|
GROUP_CONCAT(DISTINCT ipt.code ORDER BY ipt.code) ipt,
|
||||||
|
t.shipped,
|
||||||
|
t.totalWithVat,
|
||||||
|
am.name agency,
|
||||||
|
CAST(SUM(litros) AS DECIMAL(10,0)) liters,
|
||||||
|
CAST(COUNT(*) AS DECIMAL(10,0)) `lines`
|
||||||
|
FROM ticket t
|
||||||
|
JOIN sale s ON s.ticketFk = t.id
|
||||||
|
JOIN saleVolume sv ON sv.saleFk = s.id
|
||||||
|
JOIN item i ON i.id = s.itemFk
|
||||||
|
JOIN ticketState ts ON ts.ticketFk = t.id
|
||||||
|
JOIN state st ON st.id = ts.stateFk
|
||||||
|
JOIN agencyMode am ON t.agencyModeFk = am.id
|
||||||
|
LEFT JOIN itemPackingType ipt ON ipt.code = i.itemPackingTypeFk
|
||||||
|
WHERE t.shipped BETWEEN vDateToAdvance AND util.dayend(vDateToAdvance)
|
||||||
|
AND t.warehouseFk = vWarehouseFk
|
||||||
|
AND st.order <= 5
|
||||||
|
GROUP BY t.id
|
||||||
|
) dest ON dest.addressFk = origin.addressFk
|
||||||
|
WHERE origin.hasStock != 0;
|
||||||
|
|
||||||
|
DROP TEMPORARY TABLE tmp.stock;
|
||||||
|
END$$
|
||||||
|
DELIMITER ;
|
|
@ -0,0 +1,4 @@
|
||||||
|
ALTER TABLE `vn`.`itemConfig` ADD warehouseFk smallint(6) unsigned NULL;
|
||||||
|
UPDATE `vn`.`itemConfig`
|
||||||
|
SET warehouseFk=60
|
||||||
|
WHERE id=0;
|
|
@ -717,7 +717,8 @@ INSERT INTO `vn`.`ticket`(`id`, `priority`, `agencyModeFk`,`warehouseFk`,`routeF
|
||||||
(28, 1, 8, 1, 1, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1103, 'Phone Box', 123, NULL, 0, 1, 5, 1, util.VN_CURDATE()),
|
(28, 1, 8, 1, 1, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1103, 'Phone Box', 123, NULL, 0, 1, 5, 1, util.VN_CURDATE()),
|
||||||
(29, 1, 8, 1, 1, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1103, 'Phone Box', 123, NULL, 0, 1, 5, 1, util.VN_CURDATE()),
|
(29, 1, 8, 1, 1, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1103, 'Phone Box', 123, NULL, 0, 1, 5, 1, util.VN_CURDATE()),
|
||||||
(30, 1, 8, 1, 1, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1103, 'Phone Box', 123, NULL, 0, 1, 5, 1, util.VN_CURDATE()),
|
(30, 1, 8, 1, 1, util.VN_CURDATE(), DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), 1103, 'Phone Box', 123, NULL, 0, 1, 5, 1, util.VN_CURDATE()),
|
||||||
(31, 1, 8, 1, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), DATE_ADD(util.VN_CURDATE(), INTERVAL + 2 DAY), 1103, 'Phone Box', 123, NULL, 0, 1, 5, 1, util.VN_CURDATE());
|
(31, 1, 8, 1, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), DATE_ADD(util.VN_CURDATE(), INTERVAL + 2 DAY), 1103, 'Phone Box', 123, NULL, 0, 1, 5, 1, util.VN_CURDATE()),
|
||||||
|
(32, 1, 8, 1, 1, DATE_ADD(util.VN_CURDATE(), INTERVAL + 1 DAY), DATE_ADD(util.VN_CURDATE(), INTERVAL + 2 DAY), 1103, 'Phone Box', 123, NULL, 0, 1, 5, 1, util.VN_CURDATE());
|
||||||
|
|
||||||
INSERT INTO `vn`.`ticketObservation`(`id`, `ticketFk`, `observationTypeFk`, `description`)
|
INSERT INTO `vn`.`ticketObservation`(`id`, `ticketFk`, `observationTypeFk`, `description`)
|
||||||
VALUES
|
VALUES
|
||||||
|
@ -1019,7 +1020,9 @@ INSERT INTO `vn`.`sale`(`id`, `itemFk`, `ticketFk`, `concept`, `quantity`, `pric
|
||||||
(34, 4, 28, 'Melee weapon heavy shield 1x0.5m', 20, 1.72, 0, 0, 0, util.VN_CURDATE()),
|
(34, 4, 28, 'Melee weapon heavy shield 1x0.5m', 20, 1.72, 0, 0, 0, util.VN_CURDATE()),
|
||||||
(35, 4, 29, 'Melee weapon heavy shield 1x0.5m', 20, 1.72, 0, 0, 0, util.VN_CURDATE()),
|
(35, 4, 29, 'Melee weapon heavy shield 1x0.5m', 20, 1.72, 0, 0, 0, util.VN_CURDATE()),
|
||||||
(36, 4, 30, 'Melee weapon heavy shield 1x0.5m', 20, 1.72, 0, 0, 0, util.VN_CURDATE()),
|
(36, 4, 30, 'Melee weapon heavy shield 1x0.5m', 20, 1.72, 0, 0, 0, util.VN_CURDATE()),
|
||||||
(37, 4, 31, 'Melee weapon heavy shield 1x0.5m', 20, 1.72, 0, 0, 0, util.VN_CURDATE());
|
(37, 4, 31, 'Melee weapon heavy shield 1x0.5m', 20, 1.72, 0, 0, 0, util.VN_CURDATE()),
|
||||||
|
(38, 2, 32, 'Melee weapon combat fist 15cm', 30, 7.07, 0, 0, 0, DATE_ADD(util.VN_CURDATE(), INTERVAL +1 MONTH)),
|
||||||
|
(39, 1, 32, 'Ranged weapon longbow 2m', 2, 103.49, 0, 0, 0, util.VN_CURDATE());
|
||||||
|
|
||||||
INSERT INTO `vn`.`saleChecked`(`saleFk`, `isChecked`)
|
INSERT INTO `vn`.`saleChecked`(`saleFk`, `isChecked`)
|
||||||
VALUES
|
VALUES
|
||||||
|
@ -2744,9 +2747,9 @@ INSERT INTO `vn`.`collection` (`id`, `created`, `workerFk`, `stateFk`, `itemPack
|
||||||
VALUES
|
VALUES
|
||||||
(3, util.VN_NOW(), 1107, 5, NULL, 0, 0, 1, NULL, NULL);
|
(3, util.VN_NOW(), 1107, 5, NULL, 0, 0, 1, NULL, NULL);
|
||||||
|
|
||||||
INSERT INTO `vn`.`itemConfig` (`id`, `isItemTagTriggerDisabled`, `monthToDeactivate`, `wasteRecipients`, `validPriorities`, `defaultPriority`, `defaultTag`)
|
INSERT INTO `vn`.`itemConfig` (`id`, `isItemTagTriggerDisabled`, `monthToDeactivate`, `wasteRecipients`, `validPriorities`, `defaultPriority`, `defaultTag`, `warehouseFk`)
|
||||||
VALUES
|
VALUES
|
||||||
(0, 0, 24, '', '[1,2,3]', 2, 56);
|
(0, 0, 24, '', '[1,2,3]', 2, 56, 60);
|
||||||
|
|
||||||
INSERT INTO `vn`.`ticketCollection` (`ticketFk`, `collectionFk`, `created`, `level`, `wagon`, `smartTagFk`, `usedShelves`, `itemCount`, `liters`)
|
INSERT INTO `vn`.`ticketCollection` (`ticketFk`, `collectionFk`, `created`, `level`, `wagon`, `smartTagFk`, `usedShelves`, `itemCount`, `liters`)
|
||||||
VALUES
|
VALUES
|
||||||
|
|
|
@ -26286,6 +26286,7 @@ CREATE TABLE `entry` (
|
||||||
`typeFk` varchar(100) COLLATE utf8mb3_unicode_ci DEFAULT NULL COMMENT 'Tipo de entrada',
|
`typeFk` varchar(100) COLLATE utf8mb3_unicode_ci DEFAULT NULL COMMENT 'Tipo de entrada',
|
||||||
`reference` varchar(50) COLLATE utf8mb3_unicode_ci DEFAULT NULL COMMENT 'Referencia para eti',
|
`reference` varchar(50) COLLATE utf8mb3_unicode_ci DEFAULT NULL COMMENT 'Referencia para eti',
|
||||||
`ref` varchar(50) GENERATED ALWAYS AS (`invoiceNumber`) VIRTUAL COMMENT 'Columna virtual provisional para Salix',
|
`ref` varchar(50) GENERATED ALWAYS AS (`invoiceNumber`) VIRTUAL COMMENT 'Columna virtual provisional para Salix',
|
||||||
|
`observationEditorFk` INT(10) unsigned NULL COMMENT 'Último usuario que ha modificado el campo evaNotes',
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
KEY `Id_Proveedor` (`supplierFk`),
|
KEY `Id_Proveedor` (`supplierFk`),
|
||||||
KEY `Fecha` (`dated`),
|
KEY `Fecha` (`dated`),
|
||||||
|
@ -26300,7 +26301,8 @@ CREATE TABLE `entry` (
|
||||||
CONSTRAINT `entry_FK_1` FOREIGN KEY (`typeFk`) REFERENCES `entryType` (`code`) ON UPDATE CASCADE,
|
CONSTRAINT `entry_FK_1` FOREIGN KEY (`typeFk`) REFERENCES `entryType` (`code`) ON UPDATE CASCADE,
|
||||||
CONSTRAINT `entry_ibfk_1` FOREIGN KEY (`supplierFk`) REFERENCES `supplier` (`id`) ON UPDATE CASCADE,
|
CONSTRAINT `entry_ibfk_1` FOREIGN KEY (`supplierFk`) REFERENCES `supplier` (`id`) ON UPDATE CASCADE,
|
||||||
CONSTRAINT `entry_ibfk_6` FOREIGN KEY (`travelFk`) REFERENCES `travel` (`id`) ON UPDATE CASCADE,
|
CONSTRAINT `entry_ibfk_6` FOREIGN KEY (`travelFk`) REFERENCES `travel` (`id`) ON UPDATE CASCADE,
|
||||||
CONSTRAINT `entry_ibfk_7` FOREIGN KEY (`companyFk`) REFERENCES `company` (`id`) ON UPDATE CASCADE
|
CONSTRAINT `entry_ibfk_7` FOREIGN KEY (`companyFk`) REFERENCES `company` (`id`) ON UPDATE CASCADE,
|
||||||
|
CONSTRAINT `entry_observationEditorFk` FOREIGN KEY (`observationEditorFk`) REFERENCES `account`.`user`(`id`) ON UPDATE CASCADE
|
||||||
) ENGINE=InnoDBDEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci COMMENT='InnoDB free: 88064 kB; (`Id_Proveedor`) REFER `vn2008/Provee';
|
) ENGINE=InnoDBDEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci COMMENT='InnoDB free: 88064 kB; (`Id_Proveedor`) REFER `vn2008/Provee';
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
/*!50003 SET @saved_cs_client = @@character_set_client */ ;
|
/*!50003 SET @saved_cs_client = @@character_set_client */ ;
|
||||||
|
|
|
@ -778,18 +778,16 @@ export default {
|
||||||
ipt: 'vn-autocomplete[label="Destination IPT"]',
|
ipt: 'vn-autocomplete[label="Destination IPT"]',
|
||||||
tableIpt: 'vn-autocomplete[name="ipt"]',
|
tableIpt: 'vn-autocomplete[name="ipt"]',
|
||||||
tableFutureIpt: 'vn-autocomplete[name="futureIpt"]',
|
tableFutureIpt: 'vn-autocomplete[name="futureIpt"]',
|
||||||
futureState: 'vn-check[label="Pending Origin"]',
|
isFullMovable: 'vn-check[ng-model="filter.isFullMovable"]',
|
||||||
state: 'vn-check[label="Pending Destination"]',
|
|
||||||
warehouseFk: 'vn-autocomplete[label="Warehouse"]',
|
warehouseFk: 'vn-autocomplete[label="Warehouse"]',
|
||||||
tableButtonSearch: 'vn-button[vn-tooltip="Search"]',
|
tableButtonSearch: 'vn-button[vn-tooltip="Search"]',
|
||||||
moveButton: 'vn-button[vn-tooltip="Advance tickets"]',
|
moveButton: 'vn-button[vn-tooltip="Advance tickets"]',
|
||||||
acceptButton: '.vn-confirm.shown button[response="accept"]',
|
acceptButton: '.vn-confirm.shown button[response="accept"]',
|
||||||
multiCheck: 'vn-multi-check',
|
firstCheck: 'tbody > tr:nth-child(1) > td > vn-check',
|
||||||
tableId: 'vn-textfield[name="id"]',
|
tableId: 'vn-textfield[name="id"]',
|
||||||
tableFutureId: 'vn-textfield[name="futureId"]',
|
tableFutureId: 'vn-textfield[name="futureId"]',
|
||||||
tableLiters: 'vn-textfield[name="liters"]',
|
tableLiters: 'vn-textfield[name="liters"]',
|
||||||
tableLines: 'vn-textfield[name="lines"]',
|
tableLines: 'vn-textfield[name="lines"]',
|
||||||
tableStock: 'vn-textfield[name="hasStock"]',
|
|
||||||
submit: 'vn-submit[label="Search"]',
|
submit: 'vn-submit[label="Search"]',
|
||||||
table: 'tbody > tr:not(.empty-rows)'
|
table: 'tbody > tr:not(.empty-rows)'
|
||||||
},
|
},
|
||||||
|
|
|
@ -55,7 +55,7 @@ describe('Ticket Summary path', () => {
|
||||||
let result = await page
|
let result = await page
|
||||||
.waitToGetProperty(selectors.ticketSummary.firstSaleItemId, 'innerText');
|
.waitToGetProperty(selectors.ticketSummary.firstSaleItemId, 'innerText');
|
||||||
|
|
||||||
expect(result).toContain('000002');
|
expect(result).toContain('2');
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`should click on the first sale ID to make the item descriptor visible`, async() => {
|
it(`should click on the first sale ID to make the item descriptor visible`, async() => {
|
||||||
|
|
|
@ -4,12 +4,17 @@ import getBrowser from '../../helpers/puppeteer';
|
||||||
describe('Ticket Advance path', () => {
|
describe('Ticket Advance path', () => {
|
||||||
let browser;
|
let browser;
|
||||||
let page;
|
let page;
|
||||||
|
const httpRequests = [];
|
||||||
|
|
||||||
beforeAll(async() => {
|
beforeAll(async() => {
|
||||||
browser = await getBrowser();
|
browser = await getBrowser();
|
||||||
page = browser.page;
|
page = browser.page;
|
||||||
await page.loginAndModule('employee', 'ticket');
|
await page.loginAndModule('employee', 'ticket');
|
||||||
await page.accessToSection('ticket.advance');
|
await page.accessToSection('ticket.advance');
|
||||||
|
page.on('request', req => {
|
||||||
|
if (req.url().includes(`Tickets/getTicketsAdvance`))
|
||||||
|
httpRequests.push(req.url());
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async() => {
|
afterAll(async() => {
|
||||||
|
@ -43,91 +48,74 @@ describe('Ticket Advance path', () => {
|
||||||
it('should search with the required data', async() => {
|
it('should search with the required data', async() => {
|
||||||
await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
|
await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
|
||||||
await page.waitToClick(selectors.ticketAdvance.submit);
|
await page.waitToClick(selectors.ticketAdvance.submit);
|
||||||
await page.waitForNumberOfElements(selectors.ticketAdvance.table, 1);
|
|
||||||
|
expect(httpRequests.length).toBeGreaterThan(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should search with the origin IPT', async() => {
|
it('should search with the origin IPT', async() => {
|
||||||
await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
|
|
||||||
await page.autocompleteSearch(selectors.ticketAdvance.ipt, 'Horizontal');
|
|
||||||
await page.waitToClick(selectors.ticketAdvance.submit);
|
|
||||||
await page.waitForNumberOfElements(selectors.ticketAdvance.table, 1);
|
|
||||||
|
|
||||||
await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
|
|
||||||
await page.clearInput(selectors.ticketAdvance.ipt);
|
|
||||||
await page.waitToClick(selectors.ticketAdvance.submit);
|
|
||||||
await page.waitForNumberOfElements(selectors.ticketAdvance.table, 1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should search with the destination IPT', async() => {
|
|
||||||
await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
|
await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
|
||||||
await page.autocompleteSearch(selectors.ticketAdvance.futureIpt, 'Horizontal');
|
await page.autocompleteSearch(selectors.ticketAdvance.futureIpt, 'Horizontal');
|
||||||
await page.waitToClick(selectors.ticketAdvance.submit);
|
await page.waitToClick(selectors.ticketAdvance.submit);
|
||||||
await page.waitForNumberOfElements(selectors.ticketAdvance.table, 1);
|
|
||||||
|
const request = httpRequests.find(req => req.includes(('futureIpt=H')));
|
||||||
|
|
||||||
|
expect(request).toBeDefined();
|
||||||
|
|
||||||
|
httpRequests.splice(httpRequests.indexOf(request), 1);
|
||||||
|
|
||||||
await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
|
await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
|
||||||
await page.clearInput(selectors.ticketAdvance.futureIpt);
|
await page.clearInput(selectors.ticketAdvance.futureIpt);
|
||||||
await page.waitToClick(selectors.ticketAdvance.submit);
|
await page.waitToClick(selectors.ticketAdvance.submit);
|
||||||
await page.waitForNumberOfElements(selectors.ticketAdvance.table, 1);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should search with the origin pending state', async() => {
|
it('should search with the destination IPT', async() => {
|
||||||
await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
|
await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
|
||||||
await page.waitToClick(selectors.ticketAdvance.futureState);
|
await page.autocompleteSearch(selectors.ticketAdvance.ipt, 'Horizontal');
|
||||||
await page.waitToClick(selectors.ticketAdvance.submit);
|
await page.waitToClick(selectors.ticketAdvance.submit);
|
||||||
await page.waitForNumberOfElements(selectors.ticketAdvance.table, 1);
|
|
||||||
|
const request = httpRequests.find(req => req.includes(('ipt=H')));
|
||||||
|
|
||||||
|
expect(request).toBeDefined();
|
||||||
|
|
||||||
|
httpRequests.splice(httpRequests.indexOf(request), 1);
|
||||||
|
|
||||||
await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
|
await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
|
||||||
await page.waitToClick(selectors.ticketAdvance.futureState);
|
await page.clearInput(selectors.ticketAdvance.ipt);
|
||||||
await page.waitToClick(selectors.ticketAdvance.submit);
|
await page.waitToClick(selectors.ticketAdvance.submit);
|
||||||
await page.waitForNumberOfElements(selectors.ticketAdvance.table, 0);
|
|
||||||
|
|
||||||
await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
|
|
||||||
await page.waitToClick(selectors.ticketAdvance.futureState);
|
|
||||||
await page.waitToClick(selectors.ticketAdvance.submit);
|
|
||||||
await page.waitForNumberOfElements(selectors.ticketAdvance.table, 1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should search with the destination grouped state', async() => {
|
|
||||||
await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
|
|
||||||
await page.waitToClick(selectors.ticketAdvance.state);
|
|
||||||
await page.waitToClick(selectors.ticketAdvance.submit);
|
|
||||||
await page.waitForNumberOfElements(selectors.ticketAdvance.table, 0);
|
|
||||||
|
|
||||||
await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
|
|
||||||
await page.waitToClick(selectors.ticketAdvance.state);
|
|
||||||
await page.waitToClick(selectors.ticketAdvance.submit);
|
|
||||||
await page.waitForNumberOfElements(selectors.ticketAdvance.table, 1);
|
|
||||||
|
|
||||||
await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
|
|
||||||
await page.waitToClick(selectors.ticketAdvance.state);
|
|
||||||
await page.waitToClick(selectors.ticketAdvance.submit);
|
|
||||||
await page.waitForNumberOfElements(selectors.ticketAdvance.table, 1);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should search in smart-table with an IPT Origin', async() => {
|
it('should search in smart-table with an IPT Origin', async() => {
|
||||||
await page.waitToClick(selectors.ticketAdvance.tableButtonSearch);
|
await page.waitToClick(selectors.ticketAdvance.tableButtonSearch);
|
||||||
await page.autocompleteSearch(selectors.ticketAdvance.tableFutureIpt, 'Vertical');
|
await page.autocompleteSearch(selectors.ticketAdvance.tableFutureIpt, 'Vertical');
|
||||||
await page.waitForNumberOfElements(selectors.ticketAdvance.table, 1);
|
|
||||||
|
const request = httpRequests.find(req => req.includes(('futureIpt')));
|
||||||
|
|
||||||
|
expect(request).toBeDefined();
|
||||||
|
|
||||||
|
httpRequests.splice(httpRequests.indexOf(request), 1);
|
||||||
|
|
||||||
await page.waitToClick(selectors.ticketAdvance.tableButtonSearch);
|
await page.waitToClick(selectors.ticketAdvance.tableButtonSearch);
|
||||||
await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
|
await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
|
||||||
await page.waitToClick(selectors.ticketAdvance.submit);
|
await page.waitToClick(selectors.ticketAdvance.submit);
|
||||||
await page.waitForNumberOfElements(selectors.ticketAdvance.table, 1);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should search in smart-table with an IPT Destination', async() => {
|
it('should search in smart-table with an IPT Destination', async() => {
|
||||||
await page.waitToClick(selectors.ticketAdvance.tableButtonSearch);
|
await page.waitToClick(selectors.ticketAdvance.tableButtonSearch);
|
||||||
await page.autocompleteSearch(selectors.ticketAdvance.tableIpt, 'Vertical');
|
await page.autocompleteSearch(selectors.ticketAdvance.tableIpt, 'Vertical');
|
||||||
await page.waitForNumberOfElements(selectors.ticketAdvance.table, 1);
|
|
||||||
|
const request = httpRequests.find(req => req.includes(('ipt')));
|
||||||
|
|
||||||
|
expect(request).toBeDefined();
|
||||||
|
|
||||||
|
httpRequests.splice(httpRequests.indexOf(request), 1);
|
||||||
|
|
||||||
await page.waitToClick(selectors.ticketAdvance.tableButtonSearch);
|
await page.waitToClick(selectors.ticketAdvance.tableButtonSearch);
|
||||||
await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
|
await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
|
||||||
await page.waitToClick(selectors.ticketAdvance.submit);
|
await page.waitToClick(selectors.ticketAdvance.submit);
|
||||||
await page.waitForNumberOfElements(selectors.ticketAdvance.table, 1);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should check the one ticket and move to the present', async() => {
|
it('should check the first ticket and move to the present', async() => {
|
||||||
await page.waitToClick(selectors.ticketAdvance.multiCheck);
|
await page.waitToClick(selectors.ticketAdvance.firstCheck);
|
||||||
await page.waitToClick(selectors.ticketAdvance.moveButton);
|
await page.waitToClick(selectors.ticketAdvance.moveButton);
|
||||||
await page.waitToClick(selectors.ticketAdvance.acceptButton);
|
await page.waitToClick(selectors.ticketAdvance.acceptButton);
|
||||||
const message = await page.waitForSnackbar();
|
const message = await page.waitForSnackbar();
|
||||||
|
|
|
@ -45,7 +45,7 @@ describe('Claim summary path', () => {
|
||||||
it('should display the claimed line(s)', async() => {
|
it('should display the claimed line(s)', async() => {
|
||||||
const result = await page.waitToGetProperty(selectors.claimSummary.firstSaleItemId, 'innerText');
|
const result = await page.waitToGetProperty(selectors.claimSummary.firstSaleItemId, 'innerText');
|
||||||
|
|
||||||
expect(result).toContain('000002');
|
expect(result).toContain('2');
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`should click on the first sale ID making the item descriptor visible`, async() => {
|
it(`should click on the first sale ID making the item descriptor visible`, async() => {
|
||||||
|
|
|
@ -3,5 +3,4 @@ import './ucwords';
|
||||||
import './dash-if-empty';
|
import './dash-if-empty';
|
||||||
import './percentage';
|
import './percentage';
|
||||||
import './currency';
|
import './currency';
|
||||||
import './zero-fill';
|
|
||||||
import './id';
|
import './id';
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
describe('ZeroFill filter', () => {
|
|
||||||
let zeroFillFilter;
|
|
||||||
|
|
||||||
beforeEach(ngModule('vnCore'));
|
|
||||||
|
|
||||||
beforeEach(inject(_zeroFillFilter_ => {
|
|
||||||
zeroFillFilter = _zeroFillFilter_;
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should return null for a input null', () => {
|
|
||||||
expect(zeroFillFilter(null, null)).toBeNull();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return a positive number pads a number with five zeros', () => {
|
|
||||||
expect(zeroFillFilter(1, 5)).toBe('00001');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return negative number pads a number with five zeros', () => {
|
|
||||||
expect(zeroFillFilter(-1, 5)).toBe('-00001');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return zero number with zero zeros', () => {
|
|
||||||
expect(zeroFillFilter(0, 1)).toBe('0');
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,17 +0,0 @@
|
||||||
import ngModule from '../module';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pads a number with zeros.
|
|
||||||
*
|
|
||||||
* @param {Number} input The number to pad
|
|
||||||
* @param {Number} padLength The resulting number of digits
|
|
||||||
* @return {String} The zero-filled number
|
|
||||||
*/
|
|
||||||
export default function zeroFill() {
|
|
||||||
return function(input, padLength) {
|
|
||||||
if (input == null) return input;
|
|
||||||
let sign = Math.sign(input) === -1 ? '-' : '';
|
|
||||||
return sign + new Array(padLength).concat([Math.abs(input)]).join('0').slice(-padLength);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
ngModule.filter('zeroFill', zeroFill);
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
module.exports = Self => {
|
||||||
|
Self.remoteMethodCtx('post', {
|
||||||
|
description: 'Returns the sent parameters',
|
||||||
|
returns: {
|
||||||
|
type: 'object',
|
||||||
|
root: true
|
||||||
|
},
|
||||||
|
http: {
|
||||||
|
path: `/post`,
|
||||||
|
verb: 'POST'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Self.post = async ctx => {
|
||||||
|
return ctx.req.body;
|
||||||
|
};
|
||||||
|
};
|
|
@ -1,4 +1,5 @@
|
||||||
|
|
||||||
module.exports = function(Self) {
|
module.exports = function(Self) {
|
||||||
require('../methods/application/status')(Self);
|
require('../methods/application/status')(Self);
|
||||||
|
require('../methods/application/post')(Self);
|
||||||
};
|
};
|
||||||
|
|
|
@ -7,6 +7,12 @@
|
||||||
"principalType": "ROLE",
|
"principalType": "ROLE",
|
||||||
"principalId": "$everyone",
|
"principalId": "$everyone",
|
||||||
"permission": "ALLOW"
|
"permission": "ALLOW"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"property": "post",
|
||||||
|
"principalType": "ROLE",
|
||||||
|
"principalId": "$everyone",
|
||||||
|
"permission": "ALLOW"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -101,7 +101,7 @@
|
||||||
<vn-span
|
<vn-span
|
||||||
ng-click="itemDescriptor.show($event, saleClaimed.itemFk)"
|
ng-click="itemDescriptor.show($event, saleClaimed.itemFk)"
|
||||||
class="link">
|
class="link">
|
||||||
{{::saleClaimed.itemFk | zeroFill:6}}
|
{{::saleClaimed.itemFk}}
|
||||||
</vn-span>
|
</vn-span>
|
||||||
</td>
|
</td>
|
||||||
<td number>
|
<td number>
|
||||||
|
|
|
@ -115,7 +115,7 @@
|
||||||
<span
|
<span
|
||||||
ng-click="itemDescriptor.show($event, saleClaimed.sale.itemFk, saleClaimed.sale.id)"
|
ng-click="itemDescriptor.show($event, saleClaimed.sale.itemFk, saleClaimed.sale.id)"
|
||||||
class="link">
|
class="link">
|
||||||
{{::saleClaimed.sale.itemFk | zeroFill:6}}
|
{{::saleClaimed.sale.itemFk}}
|
||||||
</span>
|
</span>
|
||||||
</vn-td>
|
</vn-td>
|
||||||
<vn-td expand>{{::saleClaimed.sale.ticket.landed | date: 'dd/MM/yyyy'}}</vn-td>
|
<vn-td expand>{{::saleClaimed.sale.ticket.landed | date: 'dd/MM/yyyy'}}</vn-td>
|
||||||
|
@ -241,7 +241,7 @@
|
||||||
<span
|
<span
|
||||||
ng-click="itemDescriptor.show($event, action.sale.itemFk, action.sale.id)"
|
ng-click="itemDescriptor.show($event, action.sale.itemFk, action.sale.id)"
|
||||||
class="link">
|
class="link">
|
||||||
{{::action.sale.itemFk | zeroFill:6}}
|
{{::action.sale.itemFk}}
|
||||||
</span>
|
</span>
|
||||||
</vn-td>
|
</vn-td>
|
||||||
<vn-td number>
|
<vn-td number>
|
||||||
|
|
|
@ -67,7 +67,7 @@ module.exports = function(Self) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
delete args.ctx; // Remove unwanted properties
|
delete args.ctx; // Remove unwanted properties
|
||||||
const newReceipt = await models.Receipt.create(args, myOptions);
|
|
||||||
const originalClient = await models.Client.findById(args.clientFk, null, myOptions);
|
const originalClient = await models.Client.findById(args.clientFk, null, myOptions);
|
||||||
const bank = await models.Bank.findById(args.bankFk, null, myOptions);
|
const bank = await models.Bank.findById(args.bankFk, null, myOptions);
|
||||||
const accountingType = await models.AccountingType.findById(bank.accountingTypeFk, null, myOptions);
|
const accountingType = await models.AccountingType.findById(bank.accountingTypeFk, null, myOptions);
|
||||||
|
@ -76,23 +76,8 @@ module.exports = function(Self) {
|
||||||
if (!args.compensationAccount)
|
if (!args.compensationAccount)
|
||||||
throw new UserError('Compensation account is empty');
|
throw new UserError('Compensation account is empty');
|
||||||
|
|
||||||
const supplierCompensation = await models.Supplier.findOne({
|
// Check compensation account exists
|
||||||
where: {
|
await models.Client.getClientOrSupplierReference(args.compensationAccount, myOptions);
|
||||||
account: args.compensationAccount
|
|
||||||
}
|
|
||||||
}, myOptions);
|
|
||||||
|
|
||||||
let clientCompensation = {};
|
|
||||||
|
|
||||||
if (!supplierCompensation) {
|
|
||||||
clientCompensation = await models.Client.findOne({
|
|
||||||
where: {
|
|
||||||
accountingAccount: args.compensationAccount
|
|
||||||
}
|
|
||||||
}, myOptions);
|
|
||||||
}
|
|
||||||
if (!supplierCompensation && !clientCompensation)
|
|
||||||
throw new UserError('Invalid account');
|
|
||||||
|
|
||||||
await Self.rawSql(
|
await Self.rawSql(
|
||||||
`CALL vn.ledger_doCompensation(?, ?, ?, ?, ?, ?, ?)`,
|
`CALL vn.ledger_doCompensation(?, ?, ?, ?, ?, ?, ?)`,
|
||||||
|
@ -151,7 +136,7 @@ module.exports = function(Self) {
|
||||||
myOptions
|
myOptions
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
const newReceipt = await models.Receipt.create(args, myOptions);
|
||||||
if (tx) await tx.commit();
|
if (tx) await tx.commit();
|
||||||
|
|
||||||
return newReceipt;
|
return newReceipt;
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
const UserError = require('vn-loopback/util/user-error');
|
||||||
|
|
||||||
|
module.exports = Self => {
|
||||||
|
Self.remoteMethod('getClientOrSupplierReference', {
|
||||||
|
description: 'Returns the reference of a compensation providing a bank account',
|
||||||
|
accessType: 'READ',
|
||||||
|
accepts: {
|
||||||
|
arg: 'bankAccount',
|
||||||
|
type: 'number',
|
||||||
|
required: true,
|
||||||
|
description: 'The bank account of a client or a supplier'
|
||||||
|
},
|
||||||
|
returns: {
|
||||||
|
type: 'string',
|
||||||
|
root: true
|
||||||
|
},
|
||||||
|
http: {
|
||||||
|
path: `/getClientOrSupplierReference`,
|
||||||
|
verb: 'GET'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Self.getClientOrSupplierReference = async(bankAccount, options) => {
|
||||||
|
const models = Self.app.models;
|
||||||
|
const myOptions = {};
|
||||||
|
let reference = {};
|
||||||
|
|
||||||
|
if (typeof options == 'object')
|
||||||
|
Object.assign(myOptions, options);
|
||||||
|
|
||||||
|
const supplierCompensation = await models.Supplier.findOne({
|
||||||
|
where: {
|
||||||
|
account: bankAccount
|
||||||
|
}
|
||||||
|
}, myOptions);
|
||||||
|
|
||||||
|
reference.supplierId = supplierCompensation?.id;
|
||||||
|
reference.supplierName = supplierCompensation?.name;
|
||||||
|
|
||||||
|
let clientCompensation = {};
|
||||||
|
|
||||||
|
if (!supplierCompensation) {
|
||||||
|
clientCompensation = await models.Client.findOne({
|
||||||
|
where: {
|
||||||
|
accountingAccount: bankAccount
|
||||||
|
}
|
||||||
|
}, myOptions);
|
||||||
|
reference.clientId = clientCompensation?.id;
|
||||||
|
reference.clientName = clientCompensation?.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!supplierCompensation && !clientCompensation)
|
||||||
|
throw new UserError('Invalid account');
|
||||||
|
|
||||||
|
return reference;
|
||||||
|
};
|
||||||
|
};
|
|
@ -47,4 +47,5 @@ module.exports = Self => {
|
||||||
require('../methods/client/incotermsAuthorizationEmail')(Self);
|
require('../methods/client/incotermsAuthorizationEmail')(Self);
|
||||||
require('../methods/client/consumptionSendQueued')(Self);
|
require('../methods/client/consumptionSendQueued')(Self);
|
||||||
require('../methods/client/filter')(Self);
|
require('../methods/client/filter')(Self);
|
||||||
|
require('../methods/client/getClientOrSupplierReference')(Self);
|
||||||
};
|
};
|
||||||
|
|
|
@ -48,6 +48,14 @@
|
||||||
max="$ctrl.maxAmount">
|
max="$ctrl.maxAmount">
|
||||||
</vn-input-number>
|
</vn-input-number>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
|
<vn-vertical ng-show="$ctrl.bankSelection.accountingType.code == 'compensation'">
|
||||||
|
<h6 translate>Compensation</h6>
|
||||||
|
<vn-textfield
|
||||||
|
ng-model="$ctrl.receipt.compensationAccount"
|
||||||
|
label="Compensation Account"
|
||||||
|
on-change="$ctrl.accountShortToStandard(value)">
|
||||||
|
</vn-textfield>
|
||||||
|
</vn-vertical>
|
||||||
<vn-horizontal>
|
<vn-horizontal>
|
||||||
<vn-textfield
|
<vn-textfield
|
||||||
label="Reference"
|
label="Reference"
|
||||||
|
@ -71,14 +79,6 @@
|
||||||
</vn-input-number>
|
</vn-input-number>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
</vn-vertical>
|
</vn-vertical>
|
||||||
<vn-vertical ng-show="$ctrl.bankSelection.accountingType.code == 'compensation'">
|
|
||||||
<h6 translate>Compensation</h6>
|
|
||||||
<vn-textfield
|
|
||||||
ng-model="$ctrl.receipt.compensationAccount"
|
|
||||||
label="Compensation Account"
|
|
||||||
on-change="$ctrl.accountShortToStandard(value)">
|
|
||||||
</vn-textfield>
|
|
||||||
</vn-vertical>
|
|
||||||
<vn-horizontal ng-show="$ctrl.bankSelection.accountingType.code == 'cash'">
|
<vn-horizontal ng-show="$ctrl.bankSelection.accountingType.code == 'cash'">
|
||||||
<vn-check
|
<vn-check
|
||||||
label="View receipt"
|
label="View receipt"
|
||||||
|
|
|
@ -61,12 +61,15 @@ class Controller extends Dialog {
|
||||||
|
|
||||||
this.receipt.description = [];
|
this.receipt.description = [];
|
||||||
this.viewReceipt = accountingType.code == 'cash';
|
this.viewReceipt = accountingType.code == 'cash';
|
||||||
|
if (accountingType.code == 'compensation')
|
||||||
|
this.receipt.description = '';
|
||||||
|
else {
|
||||||
if (accountingType.receiptDescription != null && accountingType.receiptDescription != '')
|
if (accountingType.receiptDescription != null && accountingType.receiptDescription != '')
|
||||||
this.receipt.description.push(accountingType.receiptDescription);
|
this.receipt.description.push(accountingType.receiptDescription);
|
||||||
if (this.originalDescription)
|
if (this.originalDescription)
|
||||||
this.receipt.description.push(this.originalDescription);
|
this.receipt.description.push(this.originalDescription);
|
||||||
this.receipt.description.join(', ');
|
this.receipt.description.join(', ');
|
||||||
|
}
|
||||||
this.maxAmount = accountingType && accountingType.maxAmount;
|
this.maxAmount = accountingType && accountingType.maxAmount;
|
||||||
|
|
||||||
this.receipt.payed = Date.vnNew();
|
this.receipt.payed = Date.vnNew();
|
||||||
|
@ -112,7 +115,25 @@ class Controller extends Dialog {
|
||||||
}
|
}
|
||||||
|
|
||||||
accountShortToStandard(value) {
|
accountShortToStandard(value) {
|
||||||
|
if (value) {
|
||||||
this.receipt.compensationAccount = value.replace('.', '0'.repeat(11 - value.length));
|
this.receipt.compensationAccount = value.replace('.', '0'.repeat(11 - value.length));
|
||||||
|
const params = {bankAccount: this.receipt.compensationAccount};
|
||||||
|
this.$http.get(`Clients/getClientOrSupplierReference`, {params})
|
||||||
|
.then(res => {
|
||||||
|
if (res.data.clientId) {
|
||||||
|
this.receipt.description = this.$t('Client Compensation Reference', {
|
||||||
|
clientId: res.data.clientId,
|
||||||
|
clientName: res.data.clientName
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.receipt.description = this.$t('Supplier Compensation Reference', {
|
||||||
|
supplierId: res.data.supplierId,
|
||||||
|
supplierName: res.data.supplierName
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else
|
||||||
|
this.receipt.description = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
getAmountPaid() {
|
getAmountPaid() {
|
||||||
|
|
|
@ -1,2 +1,4 @@
|
||||||
View receipt: Ver recibo
|
View receipt: Ver recibo
|
||||||
Amount exceeded: Según ley contra el fraude no se puede recibir cobros por importe igual o superior a {{maxAmount}}
|
Amount exceeded: Según ley contra el fraude no se puede recibir cobros por importe igual o superior a {{maxAmount}}
|
||||||
|
Client Compensation Reference: "({{clientId}}) Ntro Cliente: {{clientName}}"
|
||||||
|
Supplier Compensation Reference: "({{supplierId}}) Ntro Proveedor: {{supplierName}}"
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
const LoopBackContext = require('loopback-context');
|
||||||
module.exports = Self => {
|
module.exports = Self => {
|
||||||
require('../methods/entry/filter')(Self);
|
require('../methods/entry/filter')(Self);
|
||||||
require('../methods/entry/getEntry')(Self);
|
require('../methods/entry/getEntry')(Self);
|
||||||
|
@ -7,4 +8,41 @@ module.exports = Self => {
|
||||||
require('../methods/entry/importBuysPreview')(Self);
|
require('../methods/entry/importBuysPreview')(Self);
|
||||||
require('../methods/entry/lastItemBuys')(Self);
|
require('../methods/entry/lastItemBuys')(Self);
|
||||||
require('../methods/entry/entryOrderPdf')(Self);
|
require('../methods/entry/entryOrderPdf')(Self);
|
||||||
|
|
||||||
|
Self.observe('before save', async function(ctx, options) {
|
||||||
|
if (ctx.isNewInstance) return;
|
||||||
|
|
||||||
|
const changes = ctx.data || ctx.instance;
|
||||||
|
const orgData = ctx.currentInstance;
|
||||||
|
|
||||||
|
const observation = changes.observation || orgData.observation;
|
||||||
|
const hasChanges = orgData && changes;
|
||||||
|
const observationChanged = hasChanges
|
||||||
|
&& orgData.observation != observation;
|
||||||
|
|
||||||
|
if (observationChanged) {
|
||||||
|
let tx;
|
||||||
|
const myOptions = {};
|
||||||
|
|
||||||
|
if (typeof options == 'object')
|
||||||
|
Object.assign(myOptions, options);
|
||||||
|
|
||||||
|
if (!myOptions.transaction) {
|
||||||
|
tx = await Self.beginTransaction({});
|
||||||
|
myOptions.transaction = tx;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const loopbackContext = LoopBackContext.getCurrentContext();
|
||||||
|
const userId = loopbackContext.active.accessToken.userId;
|
||||||
|
const id = changes.id || orgData.id;
|
||||||
|
const entry = await Self.app.models.Entry.findById(id, null, myOptions);
|
||||||
|
await entry.updateAttribute('observationEditorFk', userId, myOptions);
|
||||||
|
if (tx) await tx.commit();
|
||||||
|
} catch (e) {
|
||||||
|
if (tx) await tx.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -77,6 +77,9 @@
|
||||||
"companyFk": {
|
"companyFk": {
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"required": true
|
"required": true
|
||||||
|
},
|
||||||
|
"observationEditorFk": {
|
||||||
|
"type": "number"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"relations": {
|
"relations": {
|
||||||
|
@ -99,6 +102,11 @@
|
||||||
"type": "belongsTo",
|
"type": "belongsTo",
|
||||||
"model": "Currency",
|
"model": "Currency",
|
||||||
"foreignKey": "currencyFk"
|
"foreignKey": "currencyFk"
|
||||||
|
},
|
||||||
|
"observationEditor": {
|
||||||
|
"type": "belongsTo",
|
||||||
|
"model": "Account",
|
||||||
|
"foreignKey": "observationEditorFk"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,7 @@
|
||||||
ng-if="buy.id"
|
ng-if="buy.id"
|
||||||
ng-click="itemDescriptor.show($event, buy.item.id)"
|
ng-click="itemDescriptor.show($event, buy.item.id)"
|
||||||
class="link">
|
class="link">
|
||||||
{{::buy.item.id | zeroFill:6}}
|
{{::buy.item.id}}
|
||||||
</span>
|
</span>
|
||||||
<vn-autocomplete ng-if="!buy.id" class="dense"
|
<vn-autocomplete ng-if="!buy.id" class="dense"
|
||||||
vn-focus
|
vn-focus
|
||||||
|
|
|
@ -148,7 +148,7 @@
|
||||||
<span
|
<span
|
||||||
ng-click="itemDescriptor.show($event, line.item.id)"
|
ng-click="itemDescriptor.show($event, line.item.id)"
|
||||||
class="link">
|
class="link">
|
||||||
{{::line.item.id | zeroFill:6}}
|
{{::line.item.id}}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td number shrink>
|
<td number shrink>
|
||||||
|
|
|
@ -47,7 +47,7 @@
|
||||||
show-field="description"
|
show-field="description"
|
||||||
rule
|
rule
|
||||||
vn-focus>
|
vn-focus>
|
||||||
<tpl-item>{{id | zeroFill:8}}: {{description}}</tpl-item>
|
<tpl-item>{{id}}: {{description}}</tpl-item>
|
||||||
</vn-autocomplete>
|
</vn-autocomplete>
|
||||||
<vn-input-number
|
<vn-input-number
|
||||||
label="Amount"
|
label="Amount"
|
||||||
|
|
|
@ -141,7 +141,7 @@
|
||||||
</vn-thead>
|
</vn-thead>
|
||||||
<vn-tbody>
|
<vn-tbody>
|
||||||
<vn-tr ng-repeat="intrastat in $ctrl.summary.invoiceInIntrastat">
|
<vn-tr ng-repeat="intrastat in $ctrl.summary.invoiceInIntrastat">
|
||||||
<vn-td>{{::intrastat.intrastatFk | zeroFill:8}}: {{::intrastat.intrastat.description}}</vn-td>
|
<vn-td>{{::intrastat.intrastatFk}}: {{::intrastat.intrastat.description}}</vn-td>
|
||||||
<vn-td>{{::intrastat.amount | currency: 'EUR':2}}</vn-td>
|
<vn-td>{{::intrastat.amount | currency: 'EUR':2}}</vn-td>
|
||||||
<vn-td>{{::intrastat.net}}</vn-td>
|
<vn-td>{{::intrastat.net}}</vn-td>
|
||||||
<vn-td>{{::intrastat.stems}}</vn-td>
|
<vn-td>{{::intrastat.stems}}</vn-td>
|
||||||
|
|
|
@ -98,9 +98,8 @@ module.exports = Self => {
|
||||||
summary.tags = res[1];
|
summary.tags = res[1];
|
||||||
[summary.botanical] = res[2];
|
[summary.botanical] = res[2];
|
||||||
|
|
||||||
const userConfig = await models.UserConfig.getUserConfig(ctx, myOptions);
|
const itemConfig = await models.ItemConfig.findOne(null, myOptions);
|
||||||
|
res = await models.Item.getVisibleAvailable(summary.item.id, itemConfig.warehouseFk, undefined, myOptions);
|
||||||
res = await models.Item.getVisibleAvailable(summary.item.id, userConfig.warehouseFk, null, myOptions);
|
|
||||||
|
|
||||||
summary.available = res.available;
|
summary.available = res.available;
|
||||||
summary.visible = res.visible;
|
summary.visible = res.visible;
|
||||||
|
|
|
@ -12,7 +12,7 @@ describe('item getVisibleAvailable()', () => {
|
||||||
|
|
||||||
const result = await models.Item.getVisibleAvailable(itemFk, warehouseFk, dated, options);
|
const result = await models.Item.getVisibleAvailable(itemFk, warehouseFk, dated, options);
|
||||||
|
|
||||||
expect(result.available).toEqual(187);
|
expect(result.available).toEqual(185);
|
||||||
expect(result.visible).toEqual(92);
|
expect(result.visible).toEqual(92);
|
||||||
|
|
||||||
await tx.rollback();
|
await tx.rollback();
|
||||||
|
|
|
@ -25,6 +25,9 @@
|
||||||
},
|
},
|
||||||
"defaultTag": {
|
"defaultTag": {
|
||||||
"type": "int"
|
"type": "int"
|
||||||
|
},
|
||||||
|
"warehouseFk": {
|
||||||
|
"type": "int"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"relations": {
|
"relations": {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<vn-portal slot="menu">
|
<vn-portal slot="menu">
|
||||||
<vn-item-descriptor
|
<vn-item-descriptor
|
||||||
warehouse-fk="$ctrl.vnConfig.warehouseFk"
|
warehouse-fk="$ctrl.warehouseFk"
|
||||||
item="$ctrl.item"
|
item="$ctrl.item"
|
||||||
card-reload="$ctrl.reload()"></vn-item-descriptor>
|
card-reload="$ctrl.reload()"></vn-item-descriptor>
|
||||||
<vn-left-menu source="card"></vn-left-menu>
|
<vn-left-menu source="card"></vn-left-menu>
|
||||||
|
|
|
@ -36,6 +36,16 @@
|
||||||
<p translate>Available</p>
|
<p translate>Available</p>
|
||||||
<p>{{$ctrl.available | dashIfEmpty}}</p>
|
<p>{{$ctrl.available | dashIfEmpty}}</p>
|
||||||
</vn-one>
|
</vn-one>
|
||||||
|
<vn-one>
|
||||||
|
<p>
|
||||||
|
<vn-icon
|
||||||
|
ng-if="$ctrl.showIcon"
|
||||||
|
icon="info_outline"
|
||||||
|
vn-tooltip="{{$ctrl.warehouseText}}"
|
||||||
|
pointer>
|
||||||
|
</vn-icon>
|
||||||
|
</p>
|
||||||
|
</vn-one>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
</slot-before>
|
</slot-before>
|
||||||
<slot-body>
|
<slot-body>
|
||||||
|
|
|
@ -30,7 +30,10 @@ class Controller extends Descriptor {
|
||||||
|
|
||||||
set warehouseFk(value) {
|
set warehouseFk(value) {
|
||||||
this._warehouseFk = value;
|
this._warehouseFk = value;
|
||||||
if (value) this.updateStock();
|
if (value) {
|
||||||
|
this.updateStock();
|
||||||
|
this.getWarehouseName(value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loadData() {
|
loadData() {
|
||||||
|
@ -89,6 +92,22 @@ class Controller extends Descriptor {
|
||||||
this.$.photo.setAttribute('src', newSrc);
|
this.$.photo.setAttribute('src', newSrc);
|
||||||
this.$.photo.setAttribute('zoom-image', newZoomSrc);
|
this.$.photo.setAttribute('zoom-image', newZoomSrc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getWarehouseName(warehouseFk) {
|
||||||
|
this.showIcon = false;
|
||||||
|
|
||||||
|
const filter = {
|
||||||
|
where: {id: warehouseFk}
|
||||||
|
};
|
||||||
|
this.$http.get('Warehouses/findOne', {filter})
|
||||||
|
.then(res => {
|
||||||
|
this.warehouseText = this.$t('WarehouseFk', {
|
||||||
|
warehouseName: res.data.name
|
||||||
|
});
|
||||||
|
|
||||||
|
this.showIcon = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Controller.$inject = ['$element', '$scope', '$rootScope'];
|
Controller.$inject = ['$element', '$scope', '$rootScope'];
|
||||||
|
@ -100,6 +119,6 @@ ngModule.vnComponent('vnItemDescriptor', {
|
||||||
item: '<',
|
item: '<',
|
||||||
dated: '<',
|
dated: '<',
|
||||||
cardReload: '&',
|
cardReload: '&',
|
||||||
warehouseFk: '<?'
|
warehouseFk: '<'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -37,6 +37,7 @@ class Controller extends Section {
|
||||||
set warehouseFk(value) {
|
set warehouseFk(value) {
|
||||||
if (value && value != this._warehouseFk) {
|
if (value && value != this._warehouseFk) {
|
||||||
this._warehouseFk = value;
|
this._warehouseFk = value;
|
||||||
|
this.card.warehouseFk = value;
|
||||||
|
|
||||||
this.$state.go(this.$state.current.name, {
|
this.$state.go(this.$state.current.name, {
|
||||||
warehouseFk: value
|
warehouseFk: value
|
||||||
|
@ -76,5 +77,8 @@ ngModule.vnComponent('vnItemDiary', {
|
||||||
controller: Controller,
|
controller: Controller,
|
||||||
bindings: {
|
bindings: {
|
||||||
item: '<'
|
item: '<'
|
||||||
|
},
|
||||||
|
require: {
|
||||||
|
card: '?^vnItemCard'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -14,6 +14,7 @@ describe('Item', () => {
|
||||||
controller = $componentController('vnItemDiary', {$element, $scope});
|
controller = $componentController('vnItemDiary', {$element, $scope});
|
||||||
controller.$.model = crudModel;
|
controller.$.model = crudModel;
|
||||||
controller.$params = {id: 1};
|
controller.$params = {id: 1};
|
||||||
|
controller.card = {};
|
||||||
}));
|
}));
|
||||||
|
|
||||||
describe('set item()', () => {
|
describe('set item()', () => {
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
<vn-card class="vn-w-md vn-pa-md">
|
<vn-card class="vn-w-md vn-pa-md">
|
||||||
<vn-horizontal>
|
<vn-horizontal>
|
||||||
<vn-date-picker class="vn-pa-xs"
|
<vn-date-picker class="vn-pa-xs"
|
||||||
|
vn-one
|
||||||
|
label="Since"
|
||||||
vn-one
|
vn-one
|
||||||
label="Since"
|
label="Since"
|
||||||
ng-model="$ctrl.dateFrom">
|
ng-model="$ctrl.dateFrom">
|
||||||
|
@ -35,7 +37,7 @@
|
||||||
<vn-th field="warehouseFk">Warehouse</vn-th>
|
<vn-th field="warehouseFk">Warehouse</vn-th>
|
||||||
<vn-th field="landed">Landed</vn-th>
|
<vn-th field="landed">Landed</vn-th>
|
||||||
<vn-th number>Entry</vn-th>
|
<vn-th number>Entry</vn-th>
|
||||||
<vn-th vn-tooltip="Grouping / Packing">PVP</vn-th>
|
<vn-th vn-tooltip="Grouping / Packing" expand>PVP</vn-th>
|
||||||
<vn-th number class="expendable">Label</vn-th>
|
<vn-th number class="expendable">Label</vn-th>
|
||||||
<vn-th number>Packing</vn-th>
|
<vn-th number>Packing</vn-th>
|
||||||
<vn-th number>Grouping</vn-th>
|
<vn-th number>Grouping</vn-th>
|
||||||
|
@ -64,7 +66,7 @@
|
||||||
{{::entry.entryFk | dashIfEmpty}}
|
{{::entry.entryFk | dashIfEmpty}}
|
||||||
</span>
|
</span>
|
||||||
</vn-td>
|
</vn-td>
|
||||||
<vn-td title="{{::entry.price2 | currency: 'EUR':2 | dashIfEmpty}} / {{::entry.price3 | currency: 'EUR':2 | dashIfEmpty}}">
|
<vn-td title="Grouping / Packing">
|
||||||
{{::entry.price2 | currency: 'EUR':2 | dashIfEmpty}} / {{::entry.price3 | currency: 'EUR':2 | dashIfEmpty}}
|
{{::entry.price2 | currency: 'EUR':2 | dashIfEmpty}} / {{::entry.price3 | currency: 'EUR':2 | dashIfEmpty}}
|
||||||
</vn-td>
|
</vn-td>
|
||||||
<vn-td number class="expendable">{{entry.stickers | dashIfEmpty}}</vn-td>
|
<vn-td number class="expendable">{{entry.stickers | dashIfEmpty}}</vn-td>
|
||||||
|
|
|
@ -22,6 +22,16 @@
|
||||||
<p translate>Available</p>
|
<p translate>Available</p>
|
||||||
<p>{{$ctrl.summary.available}}</p>
|
<p>{{$ctrl.summary.available}}</p>
|
||||||
</vn-one>
|
</vn-one>
|
||||||
|
<vn-one>
|
||||||
|
<p>
|
||||||
|
<vn-icon
|
||||||
|
ng-if="$ctrl.warehouseText != null"
|
||||||
|
icon="info_outline"
|
||||||
|
vn-tooltip="{{$ctrl.warehouseText}}"
|
||||||
|
pointer>
|
||||||
|
</vn-icon>
|
||||||
|
</p>
|
||||||
|
</vn-one>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
</vn-one>
|
</vn-one>
|
||||||
<vn-one name="basicData">
|
<vn-one name="basicData">
|
||||||
|
|
|
@ -7,6 +7,24 @@ class Controller extends Summary {
|
||||||
this.$http.get(`Items/${this.item.id}/getSummary`).then(response => {
|
this.$http.get(`Items/${this.item.id}/getSummary`).then(response => {
|
||||||
this.summary = response.data;
|
this.summary = response.data;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.$http.get('ItemConfigs/findOne')
|
||||||
|
.then(res => {
|
||||||
|
if (this.card) this.card.warehouseFk = res.data.warehouseFk;
|
||||||
|
this.getWarehouseName(res.data.warehouseFk);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getWarehouseName(warehouseFk) {
|
||||||
|
const filter = {
|
||||||
|
where: {id: warehouseFk}
|
||||||
|
};
|
||||||
|
this.$http.get('Warehouses/findOne', {filter})
|
||||||
|
.then(res => {
|
||||||
|
this.warehouseText = this.$t('WarehouseFk', {
|
||||||
|
warehouseName: res.data.name
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$onChanges() {
|
$onChanges() {
|
||||||
|
@ -37,4 +55,7 @@ ngModule.vnComponent('vnItemSummary', {
|
||||||
bindings: {
|
bindings: {
|
||||||
item: '<',
|
item: '<',
|
||||||
},
|
},
|
||||||
|
require: {
|
||||||
|
card: '?^vnItemCard'
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -14,12 +14,15 @@ describe('Item', () => {
|
||||||
const $element = angular.element('<vn-item-summary></vn-item-summary>');
|
const $element = angular.element('<vn-item-summary></vn-item-summary>');
|
||||||
controller = $componentController('vnItemSummary', {$element, $scope});
|
controller = $componentController('vnItemSummary', {$element, $scope});
|
||||||
controller.item = {id: 1};
|
controller.item = {id: 1};
|
||||||
|
controller.card = {};
|
||||||
}));
|
}));
|
||||||
|
|
||||||
describe('getSummary()', () => {
|
describe('getSummary()', () => {
|
||||||
it('should perform a query to set summary', () => {
|
it('should perform a query to set summary', () => {
|
||||||
let data = {id: 1, name: 'Gem of mind'};
|
let data = {id: 1, name: 'Gem of mind'};
|
||||||
$httpBackend.expect('GET', `Items/1/getSummary`).respond(200, data);
|
$httpBackend.expect('GET', `Items/1/getSummary`).respond(200, data);
|
||||||
|
$httpBackend.expect('GET', `ItemConfigs/findOne`).respond({});
|
||||||
|
$httpBackend.expect('GET', `Warehouses/findOne`).respond({});
|
||||||
controller.getSummary();
|
controller.getSummary();
|
||||||
$httpBackend.flush();
|
$httpBackend.flush();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
WarehouseFk: Calculated on the warehouse of {{ warehouseName }}
|
|
@ -1,3 +1,4 @@
|
||||||
Barcode: Códigos de barras
|
Barcode: Códigos de barras
|
||||||
Other data: Otros datos
|
Other data: Otros datos
|
||||||
Go to the item: Ir al artículo
|
Go to the item: Ir al artículo
|
||||||
|
WarehouseFk: Calculado sobre el almacén de {{ warehouseName }}
|
||||||
|
|
|
@ -31,5 +31,9 @@ vn-item-summary {
|
||||||
&:nth-child(1) {
|
&:nth-child(1) {
|
||||||
border-right: 1px solid white;
|
border-right: 1px solid white;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:nth-child(2) {
|
||||||
|
border-right: 1px solid white;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -40,6 +40,7 @@ class Controller extends Section {
|
||||||
this.$.model.refresh();
|
this.$.model.refresh();
|
||||||
this.$.watcher.notifySaved();
|
this.$.watcher.notifySaved();
|
||||||
this.$.watcher.updateOriginalData();
|
this.$.watcher.updateOriginalData();
|
||||||
|
this.card.reload();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@
|
||||||
<vn-td number>
|
<vn-td number>
|
||||||
<span ng-click="itemDescriptor.show($event, row.itemFk)"
|
<span ng-click="itemDescriptor.show($event, row.itemFk)"
|
||||||
class="link">
|
class="link">
|
||||||
{{::row.itemFk | zeroFill:6}}
|
{{::row.itemFk}}
|
||||||
</span>
|
</span>
|
||||||
</vn-td>
|
</vn-td>
|
||||||
<vn-td vn-fetched-tags>
|
<vn-td vn-fetched-tags>
|
||||||
|
|
|
@ -95,7 +95,7 @@
|
||||||
<span
|
<span
|
||||||
ng-click="itemDescriptor.show($event, row.itemFk)"
|
ng-click="itemDescriptor.show($event, row.itemFk)"
|
||||||
class="link">
|
class="link">
|
||||||
{{::row.itemFk | zeroFill:6}}
|
{{::row.itemFk}}
|
||||||
</span>
|
</span>
|
||||||
</vn-td>
|
</vn-td>
|
||||||
<vn-td vn-fetched-tags>
|
<vn-td vn-fetched-tags>
|
||||||
|
|
|
@ -50,15 +50,9 @@ module.exports = Self => {
|
||||||
required: false
|
required: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
arg: 'isNotValidated',
|
arg: 'isFullMovable',
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
description: 'Origin state',
|
description: 'True when lines and stock of origin are equal',
|
||||||
required: false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
arg: 'futureIsNotValidated',
|
|
||||||
type: 'boolean',
|
|
||||||
description: 'Destination state',
|
|
||||||
required: false
|
required: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -105,10 +99,8 @@ module.exports = Self => {
|
||||||
{'f.futureIpt': null}
|
{'f.futureIpt': null}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
case 'isNotValidated':
|
case 'isFullMovable':
|
||||||
return {'f.isNotValidated': value};
|
return {'f.isFullMovable': value};
|
||||||
case 'futureIsNotValidated':
|
|
||||||
return {'f.futureIsNotValidated': value};
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ describe('TicketFuture getTicketsAdvance()', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return the tickets matching the origin pending state', async() => {
|
it('should return the tickets matching the fullMovable true', async() => {
|
||||||
const tx = await models.Ticket.beginTransaction({});
|
const tx = await models.Ticket.beginTransaction({});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -39,7 +39,7 @@ describe('TicketFuture getTicketsAdvance()', () => {
|
||||||
dateFuture: tomorrow,
|
dateFuture: tomorrow,
|
||||||
dateToAdvance: today,
|
dateToAdvance: today,
|
||||||
warehouseFk: 1,
|
warehouseFk: 1,
|
||||||
futureIsNotValidated: true
|
isFullMovable: true
|
||||||
};
|
};
|
||||||
|
|
||||||
const ctx = {req: {accessToken: {userId: 9}}, args};
|
const ctx = {req: {accessToken: {userId: 9}}, args};
|
||||||
|
@ -54,7 +54,7 @@ describe('TicketFuture getTicketsAdvance()', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return the tickets matching the destination pending state', async() => {
|
it('should return the tickets matching the fullMovable false', async() => {
|
||||||
const tx = await models.Ticket.beginTransaction({});
|
const tx = await models.Ticket.beginTransaction({});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -64,7 +64,7 @@ describe('TicketFuture getTicketsAdvance()', () => {
|
||||||
dateFuture: tomorrow,
|
dateFuture: tomorrow,
|
||||||
dateToAdvance: today,
|
dateToAdvance: today,
|
||||||
warehouseFk: 1,
|
warehouseFk: 1,
|
||||||
isNotValidated: true
|
isFullMovable: false
|
||||||
};
|
};
|
||||||
|
|
||||||
const ctx = {req: {accessToken: {userId: 9}}, args};
|
const ctx = {req: {accessToken: {userId: 9}}, args};
|
||||||
|
@ -95,7 +95,7 @@ describe('TicketFuture getTicketsAdvance()', () => {
|
||||||
const ctx = {req: {accessToken: {userId: 9}}, args};
|
const ctx = {req: {accessToken: {userId: 9}}, args};
|
||||||
const result = await models.Ticket.getTicketsAdvance(ctx, options);
|
const result = await models.Ticket.getTicketsAdvance(ctx, options);
|
||||||
|
|
||||||
expect(result.length).toBeLessThan(5);
|
expect(result.length).toBeGreaterThan(5);
|
||||||
|
|
||||||
await tx.rollback();
|
await tx.rollback();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -120,7 +120,7 @@ describe('TicketFuture getTicketsAdvance()', () => {
|
||||||
const ctx = {req: {accessToken: {userId: 9}}, args};
|
const ctx = {req: {accessToken: {userId: 9}}, args};
|
||||||
const result = await models.Ticket.getTicketsAdvance(ctx, options);
|
const result = await models.Ticket.getTicketsAdvance(ctx, options);
|
||||||
|
|
||||||
expect(result.length).toBeLessThan(5);
|
expect(result.length).toBeGreaterThan(5);
|
||||||
|
|
||||||
await tx.rollback();
|
await tx.rollback();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
@ -86,7 +86,7 @@ describe('sale priceDifference()', () => {
|
||||||
const firstItem = result.items[0];
|
const firstItem = result.items[0];
|
||||||
const secondtItem = result.items[1];
|
const secondtItem = result.items[1];
|
||||||
|
|
||||||
expect(firstItem.movable).toEqual(410);
|
expect(firstItem.movable).toEqual(380);
|
||||||
expect(secondtItem.movable).toEqual(1790);
|
expect(secondtItem.movable).toEqual(1790);
|
||||||
|
|
||||||
await tx.rollback();
|
await tx.rollback();
|
||||||
|
|
|
@ -41,18 +41,10 @@
|
||||||
<vn-horizontal class="vn-px-lg">
|
<vn-horizontal class="vn-px-lg">
|
||||||
<vn-check
|
<vn-check
|
||||||
vn-one
|
vn-one
|
||||||
label="Pending Origin"
|
label="100% movable"
|
||||||
ng-model="filter.futureIsNotValidated"
|
ng-model="filter.isFullMovable"
|
||||||
triple-state="true">
|
triple-state="true">
|
||||||
</vn-check>
|
</vn-check>
|
||||||
<vn-check
|
|
||||||
vn-one
|
|
||||||
label="Pending Destination"
|
|
||||||
ng-model="filter.isNotValidated"
|
|
||||||
triple-state="true">
|
|
||||||
</vn-check>
|
|
||||||
</vn-horizontal>
|
|
||||||
<vn-horizontal class="vn-px-lg">
|
|
||||||
<vn-autocomplete
|
<vn-autocomplete
|
||||||
vn-one
|
vn-one
|
||||||
label="Warehouse"
|
label="Warehouse"
|
||||||
|
|
|
@ -1,3 +1,2 @@
|
||||||
Advance tickets: Adelantar tickets
|
Advance tickets: Adelantar tickets
|
||||||
Pending Origin: Pendiente origen
|
100% movable: 100% movible
|
||||||
Pending Destination: Pendiente destino
|
|
||||||
|
|
|
@ -32,8 +32,8 @@
|
||||||
<thead>
|
<thead>
|
||||||
<tr second-header>
|
<tr second-header>
|
||||||
<td></td>
|
<td></td>
|
||||||
<th colspan="9" translate>Origin</th>
|
|
||||||
<th colspan="7" translate>Destination</th>
|
<th colspan="7" translate>Destination</th>
|
||||||
|
<th colspan="9" translate>Origin</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th shrink>
|
<th shrink>
|
||||||
|
@ -45,31 +45,7 @@
|
||||||
</th>
|
</th>
|
||||||
<th shrink>
|
<th shrink>
|
||||||
</th>
|
</th>
|
||||||
<th field="futureId">
|
<th field="id">
|
||||||
<span translate>ID</span>
|
|
||||||
</th>
|
|
||||||
<th field="futureShipped">
|
|
||||||
<span translate>Date</span>
|
|
||||||
</th>
|
|
||||||
<th field="futureIpt" title="{{'Item Packing Type' | translate}}">
|
|
||||||
<span>IPT</span>
|
|
||||||
</th>
|
|
||||||
<th field="futureState">
|
|
||||||
<span translate>State</span>
|
|
||||||
</th>
|
|
||||||
<th field="futureLiters">
|
|
||||||
<span translate>Liters</span>
|
|
||||||
</th>
|
|
||||||
<th field="hasStock">
|
|
||||||
<span>Stock</span>
|
|
||||||
</th>
|
|
||||||
<th field="futureLines">
|
|
||||||
<span translate>Lines</span>
|
|
||||||
</th>
|
|
||||||
<th field="futureTotalWithVat">
|
|
||||||
<span translate>Import</span>
|
|
||||||
</th>
|
|
||||||
<th separator field="id">
|
|
||||||
<span translate>ID</span>
|
<span translate>ID</span>
|
||||||
</th>
|
</th>
|
||||||
<th field="shipped">
|
<th field="shipped">
|
||||||
|
@ -90,6 +66,30 @@
|
||||||
<th field="totalWithVat">
|
<th field="totalWithVat">
|
||||||
<span translate>Import</span>
|
<span translate>Import</span>
|
||||||
</th>
|
</th>
|
||||||
|
<th separator field="futureId">
|
||||||
|
<span translate>ID</span>
|
||||||
|
</th>
|
||||||
|
<th field="futureShipped">
|
||||||
|
<span translate>Date</span>
|
||||||
|
</th>
|
||||||
|
<th field="futureIpt" title="{{'Item Packing Type' | translate}}">
|
||||||
|
<span>IPT</span>
|
||||||
|
</th>
|
||||||
|
<th field="futureState">
|
||||||
|
<span translate>State</span>
|
||||||
|
</th>
|
||||||
|
<th field="futureLiters">
|
||||||
|
<span translate>Liters</span>
|
||||||
|
</th>
|
||||||
|
<th field="notMovableLines">
|
||||||
|
<span translate>Not Movable</span>
|
||||||
|
</th>
|
||||||
|
<th field="futureLines">
|
||||||
|
<span translate>Lines</span>
|
||||||
|
</th>
|
||||||
|
<th field="futureTotalWithVat">
|
||||||
|
<span translate>Import</span>
|
||||||
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
@ -104,36 +104,9 @@
|
||||||
<vn-icon
|
<vn-icon
|
||||||
ng-show="ticket.futureAgency !== ticket.agency"
|
ng-show="ticket.futureAgency !== ticket.agency"
|
||||||
icon="icon-agency-term"
|
icon="icon-agency-term"
|
||||||
vn-tooltip="{{$ctrl.agencies(ticket.futureAgency, ticket.agency)}}">
|
title="{{$ctrl.agencies(ticket.futureAgency, ticket.agency)}}">
|
||||||
</vn-icon>
|
</vn-icon>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
|
||||||
<span
|
|
||||||
ng-click="ticketDescriptor.show($event, ticket.futureId)"
|
|
||||||
class="link">
|
|
||||||
{{::ticket.futureId | dashIfEmpty}}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td shrink-date>
|
|
||||||
<span class="chip {{$ctrl.compareDate(ticket.futureShipped)}}">
|
|
||||||
{{::ticket.futureShipped | date: 'dd/MM/yyyy'}}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td>{{::ticket.futureIpt | dashIfEmpty}}</td>
|
|
||||||
<td>
|
|
||||||
<span
|
|
||||||
class="chip {{$ctrl.stateColor(ticket.futureState)}}">
|
|
||||||
{{::ticket.futureState | dashIfEmpty}}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td>{{::ticket.futureLiters | dashIfEmpty}}</td>
|
|
||||||
<td>{{::ticket.hasStock | dashIfEmpty}}</td>
|
|
||||||
<td>{{::ticket.futureLines | dashIfEmpty}}</td>
|
|
||||||
<td>
|
|
||||||
<span class="chip {{$ctrl.totalPriceColor(ticket.futureTotalWithVat)}}">
|
|
||||||
{{::(ticket.futureTotalWithVat ? ticket.futureTotalWithVat : 0) | currency: 'EUR': 2}}
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td>
|
<td>
|
||||||
<span
|
<span
|
||||||
ng-click="ticketDescriptor.show($event, ticket.id)"
|
ng-click="ticketDescriptor.show($event, ticket.id)"
|
||||||
|
@ -156,10 +129,42 @@
|
||||||
<td>{{::ticket.liters | dashIfEmpty}}</td>
|
<td>{{::ticket.liters | dashIfEmpty}}</td>
|
||||||
<td>{{::ticket.lines | dashIfEmpty}}</td>
|
<td>{{::ticket.lines | dashIfEmpty}}</td>
|
||||||
<td>
|
<td>
|
||||||
<span class="chip {{$ctrl.totalPriceColor(ticket.totalWithVat)}}">
|
<span
|
||||||
|
class="chip {{$ctrl.totalPriceColor(ticket.totalWithVat)}}"
|
||||||
|
title="{{$ctrl.totalPriceTitle(ticket.totalWithVat) | translate}}">
|
||||||
{{::(ticket.totalWithVat ? ticket.totalWithVat : 0) | currency: 'EUR': 2}}
|
{{::(ticket.totalWithVat ? ticket.totalWithVat : 0) | currency: 'EUR': 2}}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
|
<td separator>
|
||||||
|
<span
|
||||||
|
ng-click="ticketDescriptor.show($event, ticket.futureId)"
|
||||||
|
class="link">
|
||||||
|
{{::ticket.futureId | dashIfEmpty}}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td shrink-date>
|
||||||
|
<span class="chip {{$ctrl.compareDate(ticket.futureShipped)}}">
|
||||||
|
{{::ticket.futureShipped | date: 'dd/MM/yyyy'}}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>{{::ticket.futureIpt | dashIfEmpty}}</td>
|
||||||
|
<td>
|
||||||
|
<span
|
||||||
|
class="chip {{$ctrl.stateColor(ticket.futureState)}}">
|
||||||
|
{{::ticket.futureState | dashIfEmpty}}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>{{::ticket.futureLiters | dashIfEmpty}}</td>
|
||||||
|
<td>{{::ticket.notMovableLines | dashIfEmpty}}</td>
|
||||||
|
<td>{{::ticket.futureLines | dashIfEmpty}}</td>
|
||||||
|
<td>
|
||||||
|
<span
|
||||||
|
class="chip {{$ctrl.totalPriceColor(ticket.futureTotalWithVat)}}"
|
||||||
|
title="{{$ctrl.totalPriceTitle(ticket.futureTotalWithVat) | translate}}">
|
||||||
|
{{::(ticket.futureTotalWithVat ? ticket.futureTotalWithVat : 0) | currency: 'EUR': 2}}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
|
@ -119,9 +119,15 @@ export default class Controller extends Section {
|
||||||
}
|
}
|
||||||
|
|
||||||
totalPriceColor(totalWithVat) {
|
totalPriceColor(totalWithVat) {
|
||||||
const total = parseInt(totalWithVat);
|
return this.isLessThan50(totalWithVat) ? 'warning' : '';
|
||||||
if (total > 0 && total < 50)
|
}
|
||||||
return 'warning';
|
|
||||||
|
totalPriceTitle(totalWithVat) {
|
||||||
|
return this.isLessThan50(totalWithVat) ? 'Less than 50€' : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
isLessThan50(totalWithVat) {
|
||||||
|
return (parseInt(totalWithVat) > 0 && parseInt(totalWithVat) < 50);
|
||||||
}
|
}
|
||||||
|
|
||||||
get confirmationMessage() {
|
get confirmationMessage() {
|
||||||
|
@ -134,7 +140,7 @@ export default class Controller extends Section {
|
||||||
|
|
||||||
agencies(futureAgency, agency) {
|
agencies(futureAgency, agency) {
|
||||||
return this.$t(`Origin agency`, {agency: futureAgency}) +
|
return this.$t(`Origin agency`, {agency: futureAgency}) +
|
||||||
'<br/>' + this.$t(`Destination agency`, {agency: agency});
|
'\n' + this.$t(`Destination agency`, {agency: agency});
|
||||||
}
|
}
|
||||||
|
|
||||||
moveTicketsAdvance() {
|
moveTicketsAdvance() {
|
||||||
|
@ -171,15 +177,25 @@ export default class Controller extends Section {
|
||||||
case 'futureLines':
|
case 'futureLines':
|
||||||
return {'futureLines': value};
|
return {'futureLines': value};
|
||||||
case 'ipt':
|
case 'ipt':
|
||||||
return {'ipt': value};
|
return {or:
|
||||||
|
[
|
||||||
|
{'ipt': {like: `%${value}%`}},
|
||||||
|
{'ipt': null}
|
||||||
|
]
|
||||||
|
};
|
||||||
case 'futureIpt':
|
case 'futureIpt':
|
||||||
return {'futureIpt': value};
|
return {or:
|
||||||
|
[
|
||||||
|
{'futureIpt': {like: `%${value}%`}},
|
||||||
|
{'futureIpt': null}
|
||||||
|
]
|
||||||
|
};
|
||||||
case 'totalWithVat':
|
case 'totalWithVat':
|
||||||
return {'totalWithVat': value};
|
return {'totalWithVat': value};
|
||||||
case 'futureTotalWithVat':
|
case 'futureTotalWithVat':
|
||||||
return {'futureTotalWithVat': value};
|
return {'futureTotalWithVat': value};
|
||||||
case 'hasStock':
|
case 'notMovableLines':
|
||||||
return {'hasStock': value};
|
return {'notMovableLines': value};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,3 +7,5 @@ Liters: Litros
|
||||||
Item Packing Type: Encajado
|
Item Packing Type: Encajado
|
||||||
Origin agency: "Agencia origen: {{agency}}"
|
Origin agency: "Agencia origen: {{agency}}"
|
||||||
Destination agency: "Agencia destino: {{agency}}"
|
Destination agency: "Agencia destino: {{agency}}"
|
||||||
|
Less than 50€: Menor a 50€
|
||||||
|
Not Movable: No movibles
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
title="{{::sale.item.name}}"
|
title="{{::sale.item.name}}"
|
||||||
vn-click-stop="itemDescriptor.show($event, sale.itemFk, sale.id)"
|
vn-click-stop="itemDescriptor.show($event, sale.itemFk, sale.id)"
|
||||||
class="link">
|
class="link">
|
||||||
{{::sale.itemFk | zeroFill:6}}
|
{{::sale.itemFk}}
|
||||||
</span>
|
</span>
|
||||||
</vn-td>
|
</vn-td>
|
||||||
<vn-td vn-fetched-tags>
|
<vn-td vn-fetched-tags>
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
<span
|
<span
|
||||||
ng-click="itemDescriptor.show($event, sale.itemFk, sale.id)"
|
ng-click="itemDescriptor.show($event, sale.itemFk, sale.id)"
|
||||||
class="link">
|
class="link">
|
||||||
{{sale.itemFk | zeroFill:6}}
|
{{sale.itemFk}}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td rowspan="{{::sale.components.length + 1}}" vn-fetched-tags>
|
<td rowspan="{{::sale.components.length + 1}}" vn-fetched-tags>
|
||||||
|
|
|
@ -55,7 +55,7 @@
|
||||||
ng-model="expedition.checked">
|
ng-model="expedition.checked">
|
||||||
</vn-check>
|
</vn-check>
|
||||||
</vn-td>
|
</vn-td>
|
||||||
<vn-td number expand>{{expedition.id | zeroFill:6}}</vn-td>
|
<vn-td number expand>{{expedition.id}}</vn-td>
|
||||||
<vn-td number>
|
<vn-td number>
|
||||||
<span
|
<span
|
||||||
ng-class="{link: expedition.packagingItemFk}"
|
ng-class="{link: expedition.packagingItemFk}"
|
||||||
|
|
|
@ -143,7 +143,7 @@
|
||||||
</td>
|
</td>
|
||||||
<td>{{::ticket.liters}}</td>
|
<td>{{::ticket.liters}}</td>
|
||||||
<td>{{::ticket.lines}}</td>
|
<td>{{::ticket.lines}}</td>
|
||||||
<td>
|
<td separator>
|
||||||
<span
|
<span
|
||||||
ng-click="ticketDescriptor.show($event, ticket.futureId)"
|
ng-click="ticketDescriptor.show($event, ticket.futureId)"
|
||||||
class="link">
|
class="link">
|
||||||
|
|
|
@ -149,9 +149,19 @@ export default class Controller extends Section {
|
||||||
case 'lines':
|
case 'lines':
|
||||||
return {'lines': value};
|
return {'lines': value};
|
||||||
case 'ipt':
|
case 'ipt':
|
||||||
return {'ipt': value};
|
return {or:
|
||||||
|
[
|
||||||
|
{'ipt': {like: `%${value}%`}},
|
||||||
|
{'ipt': null}
|
||||||
|
]
|
||||||
|
};
|
||||||
case 'futureIpt':
|
case 'futureIpt':
|
||||||
return {'futureIpt': value};
|
return {or:
|
||||||
|
[
|
||||||
|
{'futureIpt': {like: `%${value}%`}},
|
||||||
|
{'futureIpt': null}
|
||||||
|
]
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,7 +75,7 @@
|
||||||
ng-show="::request.saleFk"
|
ng-show="::request.saleFk"
|
||||||
ng-click="itemDescriptor.show($event, request.sale.itemFk, request.sale.id)"
|
ng-click="itemDescriptor.show($event, request.sale.itemFk, request.sale.id)"
|
||||||
class="link">
|
class="link">
|
||||||
{{::request.saleFk | zeroFill:6}}
|
{{::request.saleFk}}
|
||||||
</span>
|
</span>
|
||||||
</vn-td>
|
</vn-td>
|
||||||
<vn-td number
|
<vn-td number
|
||||||
|
|
|
@ -131,7 +131,7 @@
|
||||||
</vn-td>
|
</vn-td>
|
||||||
<vn-td>
|
<vn-td>
|
||||||
<span class="link" ng-if="sale.id"
|
<span class="link" ng-if="sale.id"
|
||||||
ng-click="itemDescriptor.show($event, sale.itemFk, sale.id)">
|
ng-click="itemDescriptor.show($event, sale.itemFk, sale.id, $ctrl.ticket.shipped)">
|
||||||
{{sale.itemFk}}
|
{{sale.itemFk}}
|
||||||
</span>
|
</span>
|
||||||
<vn-autocomplete ng-if="!sale.id" class="dense"
|
<vn-autocomplete ng-if="!sale.id" class="dense"
|
||||||
|
@ -365,7 +365,7 @@
|
||||||
</vn-thead>
|
</vn-thead>
|
||||||
<vn-tbody>
|
<vn-tbody>
|
||||||
<vn-tr ng-repeat="sale in $ctrl.transfer.sales">
|
<vn-tr ng-repeat="sale in $ctrl.transfer.sales">
|
||||||
<vn-td number shrink>{{::sale.itemFk | zeroFill:6}}</vn-td>
|
<vn-td number shrink>{{::sale.itemFk}}</vn-td>
|
||||||
<vn-td>
|
<vn-td>
|
||||||
<span title="{{::sale.concept}}">{{::sale.concept}}</span>
|
<span title="{{::sale.concept}}">{{::sale.concept}}</span>
|
||||||
</vn-td>
|
</vn-td>
|
||||||
|
|
|
@ -177,7 +177,7 @@
|
||||||
<span
|
<span
|
||||||
ng-click="itemDescriptor.show($event, sale.itemFk, sale.id, $ctrl.ticket.shipped)"
|
ng-click="itemDescriptor.show($event, sale.itemFk, sale.id, $ctrl.ticket.shipped)"
|
||||||
class="link">
|
class="link">
|
||||||
{{sale.itemFk | zeroFill:6}}
|
{{sale.itemFk}}
|
||||||
</span>
|
</span>
|
||||||
</vn-td>
|
</vn-td>
|
||||||
<vn-td number shrink>
|
<vn-td number shrink>
|
||||||
|
@ -312,7 +312,7 @@
|
||||||
ng-show="::request.saleFk"
|
ng-show="::request.saleFk"
|
||||||
ng-click="itemDescriptor.show($event, request.sale.itemFk, request.sale.id)"
|
ng-click="itemDescriptor.show($event, request.sale.itemFk, request.sale.id)"
|
||||||
class="link">
|
class="link">
|
||||||
{{request.sale.itemFk | zeroFill:6}}
|
{{request.sale.itemFk}}
|
||||||
</span>
|
</span>
|
||||||
</vn-td>
|
</vn-td>
|
||||||
<vn-td number>
|
<vn-td number>
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
<span
|
<span
|
||||||
ng-click="itemDescriptor.show($event, sale.itemFk, sale.id)"
|
ng-click="itemDescriptor.show($event, sale.itemFk, sale.id)"
|
||||||
class="link">
|
class="link">
|
||||||
{{sale.itemFk | zeroFill:6}}
|
{{sale.itemFk}}
|
||||||
</span>
|
</span>
|
||||||
</vn-td>
|
</vn-td>
|
||||||
<vn-td vn-fetched-tags>
|
<vn-td vn-fetched-tags>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "salix-back",
|
"name": "salix-back",
|
||||||
"version": "23.06.01",
|
"version": "23.08.01",
|
||||||
"author": "Verdnatura Levante SL",
|
"author": "Verdnatura Levante SL",
|
||||||
"description": "Salix backend",
|
"description": "Salix backend",
|
||||||
"license": "GPL-3.0",
|
"license": "GPL-3.0",
|
||||||
|
|
|
@ -4,5 +4,4 @@ require('./uppercase');
|
||||||
require('./currency');
|
require('./currency');
|
||||||
require('./percentage');
|
require('./percentage');
|
||||||
require('./number');
|
require('./number');
|
||||||
require('./zerofill');
|
|
||||||
|
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
import zerofill from '../zerofill.js';
|
|
||||||
|
|
||||||
describe('zerofill filter', () => {
|
|
||||||
const superDuperNumber = 1984;
|
|
||||||
|
|
||||||
it('should filter the number filling it with zeros up to 6 characters length', () => {
|
|
||||||
expect(zerofill(superDuperNumber, '000000')).toEqual('001984');
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,10 +0,0 @@
|
||||||
const Vue = require('vue');
|
|
||||||
|
|
||||||
const zerofill = function(value, pad) {
|
|
||||||
const valueStr = String(value);
|
|
||||||
return pad.substring(0, pad.length - valueStr.length) + valueStr;
|
|
||||||
};
|
|
||||||
|
|
||||||
Vue.filter('zerofill', zerofill);
|
|
||||||
|
|
||||||
module.exports = zerofill;
|
|
|
@ -17,8 +17,8 @@
|
||||||
</p>
|
</p>
|
||||||
<h4 style="text-align: center; margin-top: 10%">{{$t('Agree') | uppercase}}</h4>
|
<h4 style="text-align: center; margin-top: 10%">{{$t('Agree') | uppercase}}</h4>
|
||||||
<p style="margin-top: 8%; text-align: justify">
|
<p style="margin-top: 8%; text-align: justify">
|
||||||
{{$t('Date')}} {{formatDate(client.payed, '%d-%m-%Y')}} {{$t('Compensate')}} {{client.amountPaid}} €
|
{{$t('Date')}} {{client.payed | date('%d-%m-%Y')}} {{$t('Compensate')}} {{client.amountPaid}} €
|
||||||
{{$t('From client')}} {{client.name}} {{$t('Toclient')}} {{company.name}}.
|
{{$t('From client')}} {{client.name}} {{$t('Against the balance of')}}: {{client.invoiceFk}}.
|
||||||
</p>
|
</p>
|
||||||
<p style="margin-top: 8%">
|
<p style="margin-top: 8%">
|
||||||
{{$t('Reception')}} <span style="color: blue">administracion@verdnatura.es</span>
|
{{$t('Reception')}} <span style="color: blue">administracion@verdnatura.es</span>
|
||||||
|
|
|
@ -11,6 +11,6 @@ Agree: Acuerdan
|
||||||
Date: En fecha de
|
Date: En fecha de
|
||||||
Compensate: se ha compensado el saldo de
|
Compensate: se ha compensado el saldo de
|
||||||
From client: del cliente/proveedor
|
From client: del cliente/proveedor
|
||||||
To client: con el cliente/proveedor
|
Against the balance of: contra el saldo de
|
||||||
Reception: Por favor, rogamos confirmen la recepción de esta compensación al email
|
Reception: Por favor, rogamos confirmen la recepción de esta compensación al email
|
||||||
Greetings: Saludos cordiales,
|
Greetings: Saludos cordiales,
|
|
@ -4,6 +4,7 @@ SELECT
|
||||||
c.street,
|
c.street,
|
||||||
c.fi,
|
c.fi,
|
||||||
c.city,
|
c.city,
|
||||||
|
r.invoiceFk,
|
||||||
r.amountPaid,
|
r.amountPaid,
|
||||||
r.payed
|
r.payed
|
||||||
FROM client c
|
FROM client c
|
||||||
|
|
|
@ -45,7 +45,7 @@
|
||||||
</thead>
|
</thead>
|
||||||
<tbody v-for="sale in sales">
|
<tbody v-for="sale in sales">
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{sale.itemFk | zerofill('000000')}}</td>
|
<td>{{sale.itemFk}}</td>
|
||||||
<td class="number">{{Math.trunc(sale.subtotal)}}</td>
|
<td class="number">{{Math.trunc(sale.subtotal)}}</td>
|
||||||
<td width="50%">{{sale.concept}}</td>
|
<td width="50%">{{sale.concept}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="font gray uppercase">{{$t('date')}}</td>
|
<td class="font gray uppercase">{{$t('date')}}</td>
|
||||||
<th>{{formatDate(new Date(), '%d-%m-%Y');}}</th>
|
<th>{{formatDate(new Date(), '%d-%m-%Y')}}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
@ -44,7 +44,7 @@
|
||||||
</thead>
|
</thead>
|
||||||
<tbody v-for="sale in sales" :key="sale.id">
|
<tbody v-for="sale in sales" :key="sale.id">
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{formatDate(sale.issued, '%d-%m-%Y');}}</td>
|
<td>{{formatDate(sale.issued, '%d-%m-%Y')}}</td>
|
||||||
<td>{{sale.ref}}</td>
|
<td>{{sale.ref}}</td>
|
||||||
<td class="number">{{sale.debtOut}}</td>
|
<td class="number">{{sale.debtOut}}</td>
|
||||||
<td class="number">{{sale.debtIn}}</td>
|
<td class="number">{{sale.debtIn}}</td>
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
<td id="outline" class="ellipsize">{{labelData.code == 'V' ? (labelData.size || 0) + 'cm' : (labelData.volume || 0) + 'm³'}}</td>
|
<td id="outline" class="ellipsize">{{labelData.code == 'V' ? (labelData.size || 0) + 'cm' : (labelData.volume || 0) + 'm³'}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><div id="agencyDescripton" class="ellipsize">{{labelData.agencyDescription ? labelData.agencyDescription.toUpperCase() : '---'}}</div></td>
|
<td><div id="agencyDescripton" class="ellipsize">{{getAgencyDescripton(labelData)}}</div></td>
|
||||||
<td id="bold">{{labelData.lineCount || 0}}</td>
|
<td id="bold">{{labelData.lineCount || 0}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
|
|
@ -59,5 +59,17 @@ module.exports = {
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
},
|
},
|
||||||
|
getAgencyDescripton(labelData) {
|
||||||
|
let value;
|
||||||
|
if (labelData.agencyDescription)
|
||||||
|
value = labelData.agencyDescription.toUpperCase().substring(0, 11);
|
||||||
|
else
|
||||||
|
value = '---';
|
||||||
|
|
||||||
|
if (labelData.routeFk)
|
||||||
|
value = `${value} [${labelData.routeFk.toString().substring(0, 3)}]`;
|
||||||
|
|
||||||
|
return value;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,7 +14,8 @@ SELECT c.itemPackingTypeFk code,
|
||||||
DATE_FORMAT(t.shipped, '%d/%m/%y') shipped,
|
DATE_FORMAT(t.shipped, '%d/%m/%y') shipped,
|
||||||
tt.labelCount,
|
tt.labelCount,
|
||||||
t.nickName,
|
t.nickName,
|
||||||
COUNT(*) lineCount
|
COUNT(*) lineCount,
|
||||||
|
rm.routeFk
|
||||||
FROM vn.ticket t
|
FROM vn.ticket t
|
||||||
JOIN vn.ticketCollection tc ON tc.ticketFk = t.id
|
JOIN vn.ticketCollection tc ON tc.ticketFk = t.id
|
||||||
JOIN vn.collection c ON c.id = tc.collectionFk
|
JOIN vn.collection c ON c.id = tc.collectionFk
|
||||||
|
|
|
@ -66,7 +66,7 @@
|
||||||
</thead>
|
</thead>
|
||||||
<tbody v-for="sale in sales" class="no-page-break">
|
<tbody v-for="sale in sales" class="no-page-break">
|
||||||
<tr>
|
<tr>
|
||||||
<td width="5%">{{sale.itemFk | zerofill('000000')}}</td>
|
<td width="5%">{{sale.itemFk}}</td>
|
||||||
<td class="number">{{sale.quantity}}</td>
|
<td class="number">{{sale.quantity}}</td>
|
||||||
<td width="50%">{{sale.concept}}</td>
|
<td width="50%">{{sale.concept}}</td>
|
||||||
<td class="number" v-if="showPrices">{{sale.price | currency('EUR', $i18n.locale)}}</td>
|
<td class="number" v-if="showPrices">{{sale.price | currency('EUR', $i18n.locale)}}</td>
|
||||||
|
@ -145,7 +145,7 @@
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="packaging in packagings">
|
<tr v-for="packaging in packagings">
|
||||||
<td>{{packaging.itemFk | zerofill('000000')}}</td>
|
<td>{{packaging.itemFk}}</td>
|
||||||
<td class="number">{{packaging.quantity}}</td>
|
<td class="number">{{packaging.quantity}}</td>
|
||||||
<td width="85%">{{packaging.name}}</td>
|
<td width="85%">{{packaging.name}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
|
@ -13,7 +13,7 @@ module.exports = {
|
||||||
this.sales = await this.rawSqlFromDef('sales', [this.id]);
|
this.sales = await this.rawSqlFromDef('sales', [this.id]);
|
||||||
this.address = await this.findOneFromDef(`address`, [this.id]);
|
this.address = await this.findOneFromDef(`address`, [this.id]);
|
||||||
this.services = await this.rawSqlFromDef('services', [this.id]);
|
this.services = await this.rawSqlFromDef('services', [this.id]);
|
||||||
this.taxes = await this.rawSqlFromDef('taxes', [this.id]);
|
this.taxes = await this.findOneFromDef('taxes', [this.id]);
|
||||||
this.packagings = await this.rawSqlFromDef('packagings', [this.id]);
|
this.packagings = await this.rawSqlFromDef('packagings', [this.id]);
|
||||||
this.signature = await this.findOneFromDef('signature', [this.id]);
|
this.signature = await this.findOneFromDef('signature', [this.id]);
|
||||||
},
|
},
|
||||||
|
|
|
@ -96,7 +96,7 @@
|
||||||
</thead>
|
</thead>
|
||||||
<tbody v-for="sale in ticket.sales" class="no-page-break">
|
<tbody v-for="sale in ticket.sales" class="no-page-break">
|
||||||
<tr>
|
<tr>
|
||||||
<td width="5%">{{sale.itemFk | zerofill('000000')}}</td>
|
<td width="5%">{{sale.itemFk}}</td>
|
||||||
<td class="number">{{sale.quantity}}</td>
|
<td class="number">{{sale.quantity}}</td>
|
||||||
<td width="50%">{{sale.concept}}</td>
|
<td width="50%">{{sale.concept}}</td>
|
||||||
<td class="number">{{sale.price | currency('EUR', $i18n.locale)}}</td>
|
<td class="number">{{sale.price | currency('EUR', $i18n.locale)}}</td>
|
||||||
|
@ -203,7 +203,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="size100 no-page-break" v-if="intrastat.length > 0">
|
<div class="size100 no-page-break" v-if="hasIntrastat">
|
||||||
<h2>{{$t('intrastat')}}</h2>
|
<h2>{{$t('intrastat')}}</h2>
|
||||||
<table class="column-oriented">
|
<table class="column-oriented">
|
||||||
<thead>
|
<thead>
|
||||||
|
|
|
@ -10,7 +10,8 @@ module.exports = {
|
||||||
this.checkMainEntity(this.invoice);
|
this.checkMainEntity(this.invoice);
|
||||||
this.client = await this.findOneFromDef('client', [this.reference]);
|
this.client = await this.findOneFromDef('client', [this.reference]);
|
||||||
this.taxes = await this.rawSqlFromDef(`taxes`, [this.reference]);
|
this.taxes = await this.rawSqlFromDef(`taxes`, [this.reference]);
|
||||||
this.intrastat = await this.rawSqlFromDef(`intrastat`, [this.reference, this.reference, this.reference]);
|
this.hasIntrastat = await this.findValueFromDef(`hasIntrastat`, [this.reference]);
|
||||||
|
this.intrastat = await this.rawSqlFromDef(`intrastat`, [this.reference, this.reference, this.reference, this.reference]);
|
||||||
this.rectified = await this.rawSqlFromDef(`rectified`, [this.reference]);
|
this.rectified = await this.rawSqlFromDef(`rectified`, [this.reference]);
|
||||||
this.hasIncoterms = await this.findValueFromDef(`hasIncoterms`, [this.reference]);
|
this.hasIncoterms = await this.findValueFromDef(`hasIncoterms`, [this.reference]);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
SELECT taxAreaFk != 'NATIONAL'
|
||||||
|
FROM vn.invoiceOutSerial ios
|
||||||
|
JOIN vn.invoiceOut io ON io.serial = ios.code
|
||||||
|
WHERE io.ref = ?;
|
|
@ -1,26 +1,36 @@
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM invoiceOut io
|
FROM (
|
||||||
JOIN invoiceOutSerial ios ON io.serial = ios.code
|
SELECT i.intrastatFk code,
|
||||||
JOIN(
|
it.description,
|
||||||
SELECT ir.id code,
|
CAST(SUM(ROUND((s.quantity * s.price * (100 - s.discount) / 100 ) , 2))AS DECIMAL(10, 2)) subtotal,
|
||||||
ir.description,
|
SUM(IFNULL(i.stems, 1) * s.quantity) stems,
|
||||||
iii.stems,
|
CAST(SUM(IFNULL(i.stems, 1)
|
||||||
iii.net netKg,
|
* s.quantity
|
||||||
iii.amount subtotal
|
* IF(ic.grams, ic.grams, IFNULL(i.weightByPiece, 0)) / 1000)
|
||||||
FROM vn.invoiceInIntrastat iii
|
* IF(sub.totalWeight, sub.totalWeight / vn.invoiceOut_getWeight(?), 1)
|
||||||
LEFT JOIN vn.invoiceIn ii ON ii.id = iii.invoiceInFk
|
AS DECIMAL(10,2)) netKg
|
||||||
LEFT JOIN vn.invoiceOut io ON io.ref = ii.supplierRef
|
FROM sale s
|
||||||
LEFT JOIN vn.intrastat ir ON ir.id = iii.intrastatFk
|
JOIN ticket t ON s.ticketFk = t.id
|
||||||
WHERE io.`ref` = ?
|
JOIN supplier su ON su.id = t.companyFk
|
||||||
|
JOIN item i ON i.id = s.itemFk
|
||||||
|
JOIN intrastat it ON it.id = i.intrastatFk
|
||||||
|
LEFT JOIN itemCost ic ON ic.itemFk = i.id AND ic.warehouseFk = t.warehouseFk
|
||||||
|
LEFT JOIN (
|
||||||
|
SELECT SUM(weight)totalWeight
|
||||||
|
FROM vn.ticket
|
||||||
|
WHERE refFk = ?
|
||||||
|
AND weight
|
||||||
|
) sub ON TRUE
|
||||||
|
WHERE t.refFk =?
|
||||||
|
GROUP BY i.intrastatFk
|
||||||
UNION ALL
|
UNION ALL
|
||||||
SELECT NULL code,
|
SELECT NULL ,
|
||||||
'Servicios' description,
|
IF((SUM((ts.quantity * ts.price))), 'Servicios', NULL),
|
||||||
0 stems,
|
IFNULL(CAST(SUM((ts.quantity * ts.price)) AS DECIMAL(10,2)), 0),
|
||||||
0 netKg,
|
0 ,
|
||||||
IF(CAST(SUM((ts.quantity * ts.price)) AS DECIMAL(10,2)), CAST(SUM((ts.quantity * ts.price)) AS DECIMAL(10,2)), 0) subtotal
|
0
|
||||||
FROM vn.ticketService ts
|
FROM vn.ticketService ts
|
||||||
JOIN vn.ticket t ON ts.ticketFk = t.id
|
JOIN vn.ticket t ON ts.ticketFk = t.id
|
||||||
WHERE t.refFk = ?
|
WHERE t.refFk = ?
|
||||||
) sub
|
) sub2
|
||||||
WHERE io.ref = ? AND ios.isCEE
|
WHERE `description` IS NOT NULL;
|
||||||
ORDER BY sub.code;
|
|
||||||
|
|
Loading…
Reference in New Issue