Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix into 4856-worker.time-control
gitea/salix/pipeline/head There was a failure building this commit
Details
gitea/salix/pipeline/head There was a failure building this commit
Details
This commit is contained in:
commit
1c1e4cc176
15
CHANGELOG.md
15
CHANGELOG.md
|
@ -5,17 +5,30 @@ 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/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [2306.01] - 2023-02-23
|
||||
## [2308.01] - 2023-03-09
|
||||
|
||||
### Added
|
||||
-
|
||||
|
||||
### Changed
|
||||
-
|
||||
|
||||
### Fixed
|
||||
-
|
||||
|
||||
## [2306.01] - 2023-02-23
|
||||
|
||||
### Added
|
||||
- (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
|
||||
- (General -> Inicio) Ahora permite recuperar la contraseña tanto con el correo de recuperación como el usuario
|
||||
|
||||
### Fixed
|
||||
- (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
|
||||
- (Artículos) El disponible en la vista previa se muestra correctamente
|
||||
|
||||
## [2304.01] - 2023-02-09
|
||||
|
||||
|
|
|
@ -74,10 +74,13 @@ module.exports = Self => {
|
|||
const container = await models.ImageContainer.getContainer(collection);
|
||||
const rootPath = container.client.root;
|
||||
const fileSrc = path.join(rootPath, collection, size);
|
||||
|
||||
const ext = image.name.substring((image.name.length - 4));
|
||||
const fileName = ext !== '.png' ? `${image.name}.png` : image.name;
|
||||
const file = {
|
||||
path: `${fileSrc}/${image.name}.png`,
|
||||
path: `${fileSrc}/${fileName}`,
|
||||
contentType: 'image/png',
|
||||
name: `${image.name}.png`
|
||||
name: image.name
|
||||
};
|
||||
|
||||
if (!fs.existsSync(file.path)) return [];
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
const UserError = require('vn-loopback/util/user-error');
|
||||
const fs = require('fs-extra');
|
||||
const path = require('path');
|
||||
const uuid = require('uuid');
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethodCtx('upload', {
|
||||
|
@ -18,12 +19,6 @@ module.exports = Self => {
|
|||
type: 'string',
|
||||
description: 'The collection name',
|
||||
required: true
|
||||
},
|
||||
{
|
||||
arg: 'fileName',
|
||||
type: 'string',
|
||||
description: 'The file name',
|
||||
required: true
|
||||
}],
|
||||
returns: {
|
||||
type: 'Object',
|
||||
|
@ -56,10 +51,12 @@ module.exports = Self => {
|
|||
const [uploadedFile] = Object.values(uploaded.files).map(file => {
|
||||
return file[0];
|
||||
});
|
||||
|
||||
const file = await TempContainer.getFile(tempContainer.name, uploadedFile.name);
|
||||
srcFile = path.join(file.client.root, file.container, file.name);
|
||||
|
||||
await models.Image.registerImage(args.collection, srcFile, args.fileName, args.id);
|
||||
const fileName = `${uuid.v4()}.png`;
|
||||
await models.Image.registerImage(args.collection, srcFile, fileName, args.id);
|
||||
} catch (e) {
|
||||
if (fs.existsSync(srcFile))
|
||||
await fs.unlink(srcFile);
|
||||
|
|
|
@ -20,10 +20,9 @@
|
|||
"type": "date"
|
||||
}
|
||||
},
|
||||
|
||||
"scope": {
|
||||
"where" :{
|
||||
"expired": null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -84,9 +84,8 @@ module.exports = Self => {
|
|||
const container = await models.ImageContainer.container(collectionName);
|
||||
const rootPath = container.client.root;
|
||||
const collectionDir = path.join(rootPath, collectionName);
|
||||
const file = `${fileName}.png`;
|
||||
const dstDir = path.join(collectionDir, 'full');
|
||||
const dstFile = path.join(dstDir, file);
|
||||
const dstFile = path.join(dstDir, fileName);
|
||||
|
||||
const buffer = readChunk.sync(srcFilePath, 0, 12);
|
||||
const type = imageType(buffer);
|
||||
|
@ -120,7 +119,7 @@ module.exports = Self => {
|
|||
const sizes = collection.sizes();
|
||||
for (let size of sizes) {
|
||||
const dstDir = path.join(collectionDir, `${size.width}x${size.height}`);
|
||||
const dstFile = path.join(dstDir, file);
|
||||
const dstFile = path.join(dstDir, fileName);
|
||||
const resizeOpts = {
|
||||
withoutEnlargement: true,
|
||||
fit: size.crop ? 'cover' : 'inside'
|
||||
|
|
|
@ -1,2 +1,173 @@
|
|||
DELETE FROM `salix`.`ACL` WHERE model="SaleChecked";
|
||||
DROP TABLE IF EXISTS `vn`.`saleChecked`;
|
||||
DROP PROCEDURE IF EXISTS `vn`.`clean`;
|
||||
|
||||
DELIMITER $$
|
||||
$$
|
||||
CREATE DEFINER=`root`@`localhost` PROCEDURE `vn`.`clean`()
|
||||
BEGIN
|
||||
DECLARE vDateShort DATETIME;
|
||||
DECLARE vOneYearAgo DATE;
|
||||
DECLARE vFourYearsAgo DATE;
|
||||
DECLARE v18Month DATE;
|
||||
DECLARE v26Month DATE;
|
||||
DECLARE v3Month DATE;
|
||||
DECLARE vTrashId VARCHAR(15);
|
||||
|
||||
SET vDateShort = util.VN_CURDATE() - INTERVAL 2 MONTH;
|
||||
SET vOneYearAgo = util.VN_CURDATE() - INTERVAL 1 YEAR;
|
||||
SET vFourYearsAgo = util.VN_CURDATE() - INTERVAL 4 YEAR;
|
||||
SET v18Month = util.VN_CURDATE() - INTERVAL 18 MONTH;
|
||||
SET v26Month = util.VN_CURDATE() - INTERVAL 26 MONTH;
|
||||
SET v3Month = util.VN_CURDATE() - INTERVAL 3 MONTH;
|
||||
|
||||
DELETE FROM ticketParking WHERE created < vDateShort;
|
||||
DELETE FROM routesMonitor WHERE dated < vDateShort;
|
||||
DELETE FROM workerTimeControlLog WHERE created < vDateShort;
|
||||
DELETE FROM `message` WHERE sendDate < vDateShort;
|
||||
DELETE FROM messageInbox WHERE sendDate < vDateShort;
|
||||
DELETE FROM messageInbox WHERE sendDate < vDateShort;
|
||||
DELETE FROM workerTimeControl WHERE timed < vFourYearsAgo;
|
||||
DELETE FROM itemShelving WHERE created < util.VN_CURDATE() AND visible = 0;
|
||||
DELETE FROM ticketDown WHERE created < TIMESTAMPADD(DAY,-1,util.VN_CURDATE());
|
||||
DELETE FROM entryLog WHERE creationDate < vDateShort;
|
||||
DELETE IGNORE FROM expedition WHERE created < v26Month;
|
||||
DELETE FROM sms WHERE created < v18Month;
|
||||
DELETE FROM saleTracking WHERE created < vOneYearAgo;
|
||||
DELETE FROM ticketTracking WHERE created < v18Month;
|
||||
DELETE tobs FROM ticketObservation tobs
|
||||
JOIN ticket t ON tobs.ticketFk = t.id WHERE t.shipped < TIMESTAMPADD(YEAR,-2,util.VN_CURDATE());
|
||||
DELETE sc.* FROM saleCloned sc JOIN sale s ON s.id = sc.saleClonedFk JOIN ticket t ON t.id = s.ticketFk WHERE t.shipped < vOneYearAgo;
|
||||
DELETE FROM sharingCart where ended < vDateShort;
|
||||
DELETE FROM sharingClient where ended < vDateShort;
|
||||
DELETE tw.* FROM ticketWeekly tw
|
||||
LEFT JOIN sale s ON s.ticketFk = tw.ticketFk WHERE s.itemFk IS NULL;
|
||||
DELETE FROM claim WHERE ticketCreated < vFourYearsAgo;
|
||||
DELETE FROM message WHERE sendDate < vDateShort;
|
||||
-- Robert ubicacion anterior de trevelLog comentario para debug
|
||||
DELETE FROM zoneEvent WHERE `type` = 'day' AND dated < v3Month;
|
||||
DELETE bm
|
||||
FROM buyMark bm
|
||||
JOIN buy b ON b.id = bm.id
|
||||
JOIN entry e ON e.id = b.entryFk
|
||||
JOIN travel t ON t.id = e.travelFk
|
||||
WHERE t.landed <= vDateShort;
|
||||
DELETE FROM vn.buy WHERE created < vDateShort AND entryFk = 9200;
|
||||
DELETE FROM vn.itemShelvingLog WHERE created < vDateShort;
|
||||
DELETE FROM vn.stockBuyed WHERE creationDate < vDateShort;
|
||||
DELETE FROM vn.itemCleanLog WHERE created < util.VN_NOW() - INTERVAL 1 YEAR;
|
||||
DELETE FROM printQueue WHERE statusCode = 'printed' AND created < vDateShort;
|
||||
|
||||
-- Equipos duplicados
|
||||
DELETE w.*
|
||||
FROM workerTeam w
|
||||
JOIN (SELECT id, team, workerFk, COUNT(*) - 1 as duplicated
|
||||
FROM workerTeam
|
||||
GROUP BY team,workerFk
|
||||
HAVING duplicated
|
||||
) d ON d.team = w.team AND d.workerFk = w.workerFk AND d.id != w.id;
|
||||
|
||||
DELETE sc
|
||||
FROM saleComponent sc
|
||||
JOIN sale s ON s.id= sc.saleFk
|
||||
JOIN ticket t ON t.id= s.ticketFk
|
||||
WHERE t.shipped < v18Month;
|
||||
|
||||
DELETE c
|
||||
FROM vn.claim c
|
||||
JOIN vn.claimState cs ON cs.id = c.claimStateFk
|
||||
WHERE cs.description = "Anulado" AND
|
||||
c.created < vDateShort;
|
||||
DELETE
|
||||
FROM vn.expeditionTruck
|
||||
WHERE ETD < v3Month;
|
||||
|
||||
-- borrar travels sin entradas
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp.thermographToDelete;
|
||||
CREATE TEMPORARY TABLE tmp.thermographToDelete
|
||||
SELECT th.id,th.dmsFk
|
||||
FROM vn.travel t
|
||||
LEFT JOIN vn.entry e ON e.travelFk = t.id
|
||||
JOIN vn.travelThermograph th ON th.travelFk = t.id
|
||||
WHERE t.shipped < TIMESTAMPADD(MONTH, -3, util.VN_CURDATE()) AND e.travelFk IS NULL;
|
||||
|
||||
SELECT dt.id INTO vTrashId
|
||||
FROM vn.dmsType dt
|
||||
WHERE dt.code = 'trash';
|
||||
|
||||
UPDATE tmp.thermographToDelete th
|
||||
JOIN vn.dms d ON d.id = th.dmsFk
|
||||
SET d.dmsTypeFk = vTrashId;
|
||||
|
||||
DELETE th
|
||||
FROM tmp.thermographToDelete tmp
|
||||
JOIN vn.travelThermograph th ON th.id = tmp.id;
|
||||
|
||||
DELETE t
|
||||
FROM vn.travel t
|
||||
LEFT JOIN vn.entry e ON e.travelFk = t.id
|
||||
WHERE t.shipped < TIMESTAMPADD(MONTH, -3, util.VN_CURDATE()) AND e.travelFk IS NULL;
|
||||
|
||||
UPDATE dms d
|
||||
JOIN dmsType dt ON dt.id = d.dmsTypeFk
|
||||
SET d.dmsTypeFk = vTrashId
|
||||
WHERE created < TIMESTAMPADD(MONTH, -dt.monthToDelete, util.VN_CURDATE());
|
||||
|
||||
-- borrar entradas sin compras
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp.entryToDelete;
|
||||
CREATE TEMPORARY TABLE tmp.entryToDelete
|
||||
SELECT e.*
|
||||
FROM vn.entry e
|
||||
LEFT JOIN vn.buy b ON b.entryFk = e.id
|
||||
JOIN vn.entryConfig ec ON e.id != ec.defaultEntry
|
||||
WHERE e.dated < TIMESTAMPADD(MONTH, -3, util.VN_CURDATE()) AND b.entryFK IS NULL;
|
||||
|
||||
DELETE e
|
||||
FROM vn.entry e
|
||||
JOIN tmp.entryToDelete tmp ON tmp.id = e.id;
|
||||
|
||||
-- borrar de route registros menores a 4 años
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp.routeToDelete;
|
||||
CREATE TEMPORARY TABLE tmp.routeToDelete
|
||||
SELECT *
|
||||
FROM vn.route r
|
||||
WHERE created < TIMESTAMPADD(YEAR,-4,util.VN_CURDATE());
|
||||
|
||||
UPDATE tmp.routeToDelete tmp
|
||||
JOIN vn.dms d ON d.id = tmp.gestdocFk
|
||||
SET d.dmsTypeFk = vTrashId;
|
||||
|
||||
DELETE r
|
||||
FROM tmp.routeToDelete tmp
|
||||
JOIN vn.route r ON r.id = tmp.id;
|
||||
|
||||
-- borrar registros de dua y awb menores a 2 años
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp.duaToDelete;
|
||||
CREATE TEMPORARY TABLE tmp.duaToDelete
|
||||
SELECT *
|
||||
FROM vn.dua
|
||||
WHERE operated < TIMESTAMPADD(YEAR,-2,util.VN_CURDATE());
|
||||
|
||||
UPDATE tmp.duaToDelete tm
|
||||
JOIN vn.dms d ON d.id = tm.gestdocFk
|
||||
SET d.dmsTypeFk = vTrashId;
|
||||
|
||||
DELETE d
|
||||
FROM tmp.duaToDelete tmp
|
||||
JOIN vn.dua d ON d.id = tmp.id;
|
||||
|
||||
DELETE FROM vn.awb WHERE created < TIMESTAMPADD(YEAR,-2,util.VN_CURDATE());
|
||||
|
||||
-- Borra los registros de collection y ticketcollection
|
||||
DELETE FROM vn.collection WHERE created < vDateShort;
|
||||
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp.thermographToDelete;
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp.entryToDelete;
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp.duaToDelete;
|
||||
|
||||
DELETE FROM travelLog WHERE creationDate < v3Month;
|
||||
|
||||
CALL shelving_clean;
|
||||
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
|
|
@ -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 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';
|
||||
|
||||
INSERT INTO `salix`.`ACL`
|
||||
(model, property, accessType, permission, principalType, principalId)
|
||||
VALUES('ItemConfig', '*', 'READ', 'ALLOW', 'ROLE', 'buyer');
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
ALTER TABLE `vn`.`itemConfig` ADD defaultTag INT DEFAULT 56 NOT NULL;
|
||||
ALTER TABLE `vn`.`itemConfig` ADD CONSTRAINT itemConfig_FK FOREIGN KEY (defaultTag) REFERENCES vn.tag(id);
|
||||
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`.`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';
|
|
@ -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;
|
|
@ -0,0 +1,3 @@
|
|||
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
|
||||
VALUES
|
||||
('ItemConfig', '*', '*', 'ALLOW', 'ROLE', 'employee');
|
|
@ -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()),
|
||||
(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()),
|
||||
(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`)
|
||||
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()),
|
||||
(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()),
|
||||
(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`)
|
||||
VALUES
|
||||
|
@ -2744,9 +2747,9 @@ INSERT INTO `vn`.`collection` (`id`, `created`, `workerFk`, `stateFk`, `itemPack
|
|||
VALUES
|
||||
(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
|
||||
(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`)
|
||||
VALUES
|
||||
|
|
|
@ -26286,6 +26286,7 @@ CREATE TABLE `entry` (
|
|||
`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',
|
||||
`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`),
|
||||
KEY `Id_Proveedor` (`supplierFk`),
|
||||
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_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_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';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
/*!50003 SET @saved_cs_client = @@character_set_client */ ;
|
||||
|
|
|
@ -778,18 +778,16 @@ export default {
|
|||
ipt: 'vn-autocomplete[label="Destination IPT"]',
|
||||
tableIpt: 'vn-autocomplete[name="ipt"]',
|
||||
tableFutureIpt: 'vn-autocomplete[name="futureIpt"]',
|
||||
futureState: 'vn-check[label="Pending Origin"]',
|
||||
state: 'vn-check[label="Pending Destination"]',
|
||||
isFullMovable: 'vn-check[ng-model="filter.isFullMovable"]',
|
||||
warehouseFk: 'vn-autocomplete[label="Warehouse"]',
|
||||
tableButtonSearch: 'vn-button[vn-tooltip="Search"]',
|
||||
moveButton: 'vn-button[vn-tooltip="Advance tickets"]',
|
||||
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"]',
|
||||
tableFutureId: 'vn-textfield[name="futureId"]',
|
||||
tableLiters: 'vn-textfield[name="liters"]',
|
||||
tableLines: 'vn-textfield[name="lines"]',
|
||||
tableStock: 'vn-textfield[name="hasStock"]',
|
||||
submit: 'vn-submit[label="Search"]',
|
||||
table: 'tbody > tr:not(.empty-rows)'
|
||||
},
|
||||
|
|
|
@ -55,7 +55,7 @@ describe('Ticket Summary path', () => {
|
|||
let result = await page
|
||||
.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() => {
|
||||
|
|
|
@ -63,6 +63,6 @@ describe('Ticket index payout path', () => {
|
|||
const reference = await page.waitToGetProperty(selectors.clientBalance.firstLineReference, 'innerText');
|
||||
|
||||
expect(count).toEqual(4);
|
||||
expect(reference).toContain('Cash, Albaran: 7, 8Payment');
|
||||
expect(reference).toContain('Cash,Albaran: 7, 8Payment');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -4,12 +4,17 @@ import getBrowser from '../../helpers/puppeteer';
|
|||
describe('Ticket Advance path', () => {
|
||||
let browser;
|
||||
let page;
|
||||
const httpRequests = [];
|
||||
|
||||
beforeAll(async() => {
|
||||
browser = await getBrowser();
|
||||
page = browser.page;
|
||||
await page.loginAndModule('employee', 'ticket');
|
||||
await page.accessToSection('ticket.advance');
|
||||
page.on('request', req => {
|
||||
if (req.url().includes(`Tickets/getTicketsAdvance`))
|
||||
httpRequests.push(req.url());
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(async() => {
|
||||
|
@ -43,91 +48,74 @@ describe('Ticket Advance path', () => {
|
|||
it('should search with the required data', async() => {
|
||||
await page.waitToClick(selectors.ticketAdvance.openAdvancedSearchButton);
|
||||
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() => {
|
||||
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.autocompleteSearch(selectors.ticketAdvance.futureIpt, 'Horizontal');
|
||||
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.clearInput(selectors.ticketAdvance.futureIpt);
|
||||
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.futureState);
|
||||
await page.autocompleteSearch(selectors.ticketAdvance.ipt, 'Horizontal');
|
||||
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.futureState);
|
||||
await page.clearInput(selectors.ticketAdvance.ipt);
|
||||
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() => {
|
||||
await page.waitToClick(selectors.ticketAdvance.tableButtonSearch);
|
||||
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.openAdvancedSearchButton);
|
||||
await page.waitToClick(selectors.ticketAdvance.submit);
|
||||
await page.waitForNumberOfElements(selectors.ticketAdvance.table, 1);
|
||||
});
|
||||
|
||||
it('should search in smart-table with an IPT Destination', async() => {
|
||||
await page.waitToClick(selectors.ticketAdvance.tableButtonSearch);
|
||||
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.openAdvancedSearchButton);
|
||||
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() => {
|
||||
await page.waitToClick(selectors.ticketAdvance.multiCheck);
|
||||
it('should check the first ticket and move to the present', async() => {
|
||||
await page.waitToClick(selectors.ticketAdvance.firstCheck);
|
||||
await page.waitToClick(selectors.ticketAdvance.moveButton);
|
||||
await page.waitToClick(selectors.ticketAdvance.acceptButton);
|
||||
const message = await page.waitForSnackbar();
|
||||
|
|
|
@ -45,7 +45,7 @@ describe('Claim summary path', () => {
|
|||
it('should display the claimed line(s)', async() => {
|
||||
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() => {
|
||||
|
|
|
@ -82,8 +82,6 @@
|
|||
}
|
||||
&[type=time],
|
||||
&[type=date] {
|
||||
clip-path: inset(0 20px 0 0);
|
||||
|
||||
&::-webkit-inner-spin-button,
|
||||
&::-webkit-clear-button {
|
||||
display: none;
|
||||
|
@ -99,7 +97,7 @@
|
|||
}
|
||||
&[type=number] {
|
||||
-moz-appearance: textfield;
|
||||
|
||||
|
||||
&::-webkit-outer-spin-button,
|
||||
&::-webkit-inner-spin-button {
|
||||
-webkit-appearance: none;
|
||||
|
|
|
@ -3,5 +3,4 @@ import './ucwords';
|
|||
import './dash-if-empty';
|
||||
import './percentage';
|
||||
import './currency';
|
||||
import './zero-fill';
|
||||
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);
|
|
@ -32,6 +32,9 @@
|
|||
.icon-100:before {
|
||||
content: "\e95a";
|
||||
}
|
||||
.icon-clientUnpaid:before {
|
||||
content: "\e95b";
|
||||
}
|
||||
.icon-history:before {
|
||||
content: "\e968";
|
||||
}
|
||||
|
@ -337,6 +340,9 @@
|
|||
.icon-solunion:before {
|
||||
content: "\e94e";
|
||||
}
|
||||
.icon-stowaway:before {
|
||||
content: "\e94f";
|
||||
}
|
||||
.icon-splitline:before {
|
||||
content: "\e93e";
|
||||
}
|
||||
|
|
Binary file not shown.
|
@ -82,9 +82,11 @@
|
|||
<glyph unicode="" glyph-name="linesprepaired" d="M870.4 857.6h-213.333c-21.333 59.733-76.8 102.4-145.067 102.4s-123.733-42.667-145.067-102.4h-213.333c-55.467 0-102.4-46.933-102.4-102.4v-716.8c0-55.467 46.933-102.4 102.4-102.4h716.8c55.467 0 102.4 46.933 102.4 102.4v716.8c0 55.467-46.933 102.4-102.4 102.4zM512 857.6c29.867 0 51.2-21.333 51.2-51.2s-21.333-51.2-51.2-51.2-51.2 21.333-51.2 51.2 21.333 51.2 51.2 51.2zM614.4 140.8h-358.4v102.4h358.4v-102.4zM768 345.6h-512v102.4h512v-102.4zM768 550.4h-512v102.4h512v-102.4z" />
|
||||
<glyph unicode="" glyph-name="control" d="M418.133 315.733l-128-123.733 256-256 469.333 469.333-128 128-341.333-341.333zM546.133 311.467l34.133 34.133h-68.267zM230.4 128l-59.733 64 153.6 153.6h-68.267v102.4h426.667l204.8 204.8 85.333-85.333v187.733c0 55.467-46.933 102.4-102.4 102.4h-213.333c-21.333 59.733-76.8 102.4-145.067 102.4s-123.733-42.667-145.067-102.4h-213.333c-55.467 0-102.4-46.933-102.4-102.4v-716.8c0-55.467 46.933-102.4 102.4-102.4h273.067l-196.267 192zM512 857.6c29.867 0 51.2-21.333 51.2-51.2s-21.333-51.2-51.2-51.2-51.2 21.333-51.2 51.2c0 29.867 21.333 51.2 51.2 51.2zM256 652.8h512v-102.4h-512v102.4zM665.6-64h204.8c55.467 0 102.4 46.933 102.4 102.4v204.8l-307.2-307.2z" />
|
||||
<glyph unicode="" glyph-name="revision" d="M358.4 140.8h-102.4v102.4h81.067c0 0 0 4.267 0 4.267 0 34.133 8.533 68.267 21.333 98.133h-102.4v102.4h170.667c51.2 51.2 123.733 85.333 200.533 102.4h-371.2v102.4h512v-93.867c76.8-8.533 149.333-34.133 204.8-72.533v268.8c0 55.467-46.933 102.4-102.4 102.4h-213.333c-21.333 59.733-76.8 102.4-145.067 102.4s-123.733-42.667-145.067-102.4h-213.333c-55.467 0-102.4-46.933-102.4-102.4v-716.8c0-55.467 46.933-102.4 102.4-102.4h546.133c-157.867 8.533-290.133 89.6-341.333 204.8zM512 857.6c29.867 0 51.2-21.333 51.2-51.2s-21.333-51.2-51.2-51.2-51.2 21.333-51.2 51.2c0 29.867 21.333 51.2 51.2 51.2zM721.067 452.267c-136.533 0-251.733-85.333-302.933-204.8 46.933-119.467 162.133-204.8 302.933-204.8s251.733 85.333 302.933 204.8c-46.933 119.467-162.133 204.8-302.933 204.8zM721.067 110.933c-76.8 0-136.533 59.733-136.533 136.533s64 136.533 136.533 136.533 136.533-64 136.533-136.533-59.733-136.533-136.533-136.533zM721.067 328.533c-46.933 0-81.067-38.4-81.067-81.067s38.4-81.067 81.067-81.067c46.933 0 81.067 38.4 81.067 81.067s-34.133 81.067-81.067 81.067z" />
|
||||
<glyph unicode="" glyph-name="deaulter" d="M677.973-64c-30.72 35.84-61.867 70.827-91.307 107.52-40.96 51.2-80.64 103.253-121.173 154.88-16.64 21.333-21.76 20.48-30.72-4.693-13.227-36.693-25.6-73.387-40.107-109.653-5.12-12.8-13.227-26.88-24.32-34.56-51.627-34.987-104.107-69.12-157.867-100.693-10.667-6.4-30.72-5.547-41.813 0.853-8.107 4.693-12.373 23.893-11.093 35.84 0.853 8.96 11.093 19.627 19.627 25.6 39.253 26.453 78.933 51.627 119.040 76.8 18.347 11.52 30.293 26.027 35.84 47.787 12.373 48.213 27.307 95.573 39.253 143.36 8.533 33.707 26.88 58.88 56.32 77.227 40.533 25.173 80.64 52.053 120.747 78.507 6.4 4.267 10.24 11.52 15.36 17.493-7.253 2.56-14.933 7.253-22.187 6.827-75.52-6.4-151.467-13.227-226.987-20.48-2.133 0-4.693-0.853-6.827-0.853-22.613-1.707-39.253 10.24-40.96 29.867s12.373 33.707 35.413 35.84c45.227 4.267 90.88 8.96 136.107 12.8 65.707 5.547 131.84 10.667 197.547 15.36 26.027 1.707 53.76-21.76 67.413-55.467 9.813-23.893 5.12-46.080-18.347-65.28-49.92-40.107-100.693-78.933-151.040-118.187-23.040-17.92-23.893-23.467-6.4-46.507 58.453-78.080 116.48-156.587 174.933-234.667 27.307-36.693 25.173-50.773-12.373-75.52-5.12 0-9.813 0-14.080 0zM791.893 649.813c-43.093 1.28-76.373-31.573-77.227-75.52-0.853-44.373 29.44-76.8 72.107-77.653 45.227-1.28 77.653 29.44 78.080 73.813 0.427 45.227-29.44 78.080-72.96 79.36zM671.147 737.707c0-72.107-34.133-136.107-87.467-176.64l-235.52-21.76c-72.107 36.693-122.027 111.787-122.027 198.4 0 122.88 99.84 222.293 222.72 222.293 122.453 0 222.293-99.413 222.293-222.293zM592.213 680.533l-50.347 18.347c-2.133-8.533-5.12-16.213-9.813-22.613-5.12-6.4-10.24-11.947-16.213-17.067-5.973-4.267-12.373-8.107-19.2-11.093s-13.653-4.693-20.053-5.547c-17.92-2.987-33.707-0.427-48.64 6.827s-26.88 18.347-36.693 32.853l76.373 12.373 7.253 32.427-97.28-15.787c-1.28 5.547-2.987 11.093-3.84 16.64l-0.853 4.267 99.413 16.213 7.253 32.427-106.667-17.493c0.853 9.387 2.987 17.493 6.4 26.027 3.84 8.533 8.107 16.213 14.080 23.040 5.547 6.827 12.8 12.373 21.333 17.067s17.92 8.107 28.587 9.813c6.827 1.28 13.227 1.707 20.907 1.28s14.507-1.707 21.333-3.84c6.827-2.133 13.653-5.973 20.053-10.24 5.973-4.693 11.947-11.093 17.493-18.773l38.827 37.973c-13.227 17.92-30.293 31.147-52.053 39.253-21.76 8.533-46.080 10.667-73.387 6.4-19.627-2.987-36.267-9.387-51.2-17.92-14.507-8.533-26.88-19.2-37.547-32-10.667-12.373-18.773-26.027-23.893-40.96-5.547-14.507-8.96-29.867-9.813-45.653l-21.76-3.84-7.253-32.427 29.013 4.693 0.427-2.987c1.28-6.827 2.56-12.8 4.267-18.347l-23.467-3.84-8.107-32.427 43.52 7.253c6.827-13.653 15.787-26.027 26.027-36.693 10.24-11.52 22.187-20.48 35.413-27.733 13.227-7.68 27.307-12.8 42.667-15.787s31.573-3.413 47.36-0.853c12.373 2.133 24.32 5.12 35.84 10.667s22.613 11.52 32.853 19.2c10.24 8.107 18.347 16.64 26.027 26.453 6.827 9.387 12.373 20.48 15.36 32.427z" />
|
||||
<glyph unicode="" glyph-name="defaulter" d="M677.973-64c-30.72 35.84-61.867 70.827-91.307 107.52-40.96 51.2-80.64 103.253-121.173 154.88-16.64 21.333-21.76 20.48-30.72-4.693-13.227-36.693-25.6-73.387-40.107-109.653-5.12-12.8-13.227-26.88-24.32-34.56-51.627-34.987-104.107-69.12-157.867-100.693-10.667-6.4-30.72-5.547-41.813 0.853-8.107 4.693-12.373 23.893-11.093 35.84 0.853 8.96 11.093 19.627 19.627 25.6 39.253 26.453 78.933 51.627 119.040 76.8 18.347 11.52 30.293 26.027 35.84 47.787 12.373 48.213 27.307 95.573 39.253 143.36 8.533 33.707 26.88 58.88 56.32 77.227 40.533 25.173 80.64 52.053 120.747 78.507 6.4 4.267 10.24 11.52 15.36 17.493-7.253 2.56-14.933 7.253-22.187 6.827-75.52-6.4-151.467-13.227-226.987-20.48-2.133 0-4.693-0.853-6.827-0.853-22.613-1.707-39.253 10.24-40.96 29.867s12.373 33.707 35.413 35.84c45.227 4.267 90.88 8.96 136.107 12.8 65.707 5.547 131.84 10.667 197.547 15.36 26.027 1.707 53.76-21.76 67.413-55.467 9.813-23.893 5.12-46.080-18.347-65.28-49.92-40.107-100.693-78.933-151.040-118.187-23.040-17.92-23.893-23.467-6.4-46.507 58.453-78.080 116.48-156.587 174.933-234.667 27.307-36.693 25.173-50.773-12.373-75.52-5.12 0-9.813 0-14.080 0zM791.893 649.813c-43.093 1.28-76.373-31.573-77.227-75.52-0.853-44.373 29.44-76.8 72.107-77.653 45.227-1.28 77.653 29.44 78.080 73.813 0.427 45.227-29.44 78.080-72.96 79.36zM671.147 737.707c0-72.107-34.133-136.107-87.467-176.64l-235.52-21.76c-72.107 36.693-122.027 111.787-122.027 198.4 0 122.88 99.84 222.293 222.72 222.293 122.453 0 222.293-99.413 222.293-222.293zM592.213 680.533l-50.347 18.347c-2.133-8.533-5.12-16.213-9.813-22.613-5.12-6.4-10.24-11.947-16.213-17.067-5.973-4.267-12.373-8.107-19.2-11.093s-13.653-4.693-20.053-5.547c-17.92-2.987-33.707-0.427-48.64 6.827s-26.88 18.347-36.693 32.853l76.373 12.373 7.253 32.427-97.28-15.787c-1.28 5.547-2.987 11.093-3.84 16.64l-0.853 4.267 99.413 16.213 7.253 32.427-106.667-17.493c0.853 9.387 2.987 17.493 6.4 26.027 3.84 8.533 8.107 16.213 14.080 23.040 5.547 6.827 12.8 12.373 21.333 17.067s17.92 8.107 28.587 9.813c6.827 1.28 13.227 1.707 20.907 1.28s14.507-1.707 21.333-3.84c6.827-2.133 13.653-5.973 20.053-10.24 5.973-4.693 11.947-11.093 17.493-18.773l38.827 37.973c-13.227 17.92-30.293 31.147-52.053 39.253-21.76 8.533-46.080 10.667-73.387 6.4-19.627-2.987-36.267-9.387-51.2-17.92-14.507-8.533-26.88-19.2-37.547-32-10.667-12.373-18.773-26.027-23.893-40.96-5.547-14.507-8.96-29.867-9.813-45.653l-21.76-3.84-7.253-32.427 29.013 4.693 0.427-2.987c1.28-6.827 2.56-12.8 4.267-18.347l-23.467-3.84-8.107-32.427 43.52 7.253c6.827-13.653 15.787-26.027 26.027-36.693 10.24-11.52 22.187-20.48 35.413-27.733 13.227-7.68 27.307-12.8 42.667-15.787s31.573-3.413 47.36-0.853c12.373 2.133 24.32 5.12 35.84 10.667s22.613 11.52 32.853 19.2c10.24 8.107 18.347 16.64 26.027 26.453 6.827 9.387 12.373 20.48 15.36 32.427z" />
|
||||
<glyph unicode="" glyph-name="services" d="M951.467 217.6c0 8.533 0 21.333 0 29.867s0 21.333-4.267 29.867l64 51.2c4.267 4.267 8.533 12.8 4.267 21.333l-64 106.667c-4.267 8.533-12.8 8.533-17.067 8.533l-76.8-29.867c-17.067 12.8-34.133 21.333-51.2 29.867l-12.8 81.067c0 8.533-8.533 12.8-17.067 12.8h-123.733c-8.533 0-12.8-4.267-17.067-12.8l-12.8-81.067c-17.067-8.533-38.4-17.067-51.2-29.867l-76.8 29.867c-8.533 4.267-17.067 0-17.067-8.533l-64-106.667c-4.267-8.533-4.267-17.067 4.267-21.333l64-51.2c0-8.533-4.267-21.333-4.267-29.867s0-21.333 4.267-29.867l-55.467-51.2c-4.267-4.267-8.533-12.8-4.267-21.333l64-106.667c4.267-8.533 12.8-8.533 17.067-8.533l76.8 29.867c17.067-12.8 34.133-21.333 51.2-29.867l12.8-81.067c0-8.533 8.533-12.8 17.067-12.8h123.733c8.533 0 12.8 4.267 17.067 12.8l12.8 81.067c17.067 8.533 38.4 17.067 51.2 29.867l76.8-29.867c8.533-4.267 17.067 0 17.067 8.533l64 106.667c4.267 8.533 4.267 17.067-4.267 21.333 0 0-68.267 51.2-68.267 51.2zM721.067 132.267c-64 0-115.2 51.2-115.2 115.2s51.2 115.2 115.2 115.2 115.2-51.2 115.2-115.2c0-64-51.2-115.2-115.2-115.2zM345.6 174.933h-89.6v102.4h81.067c4.267 34.133 8.533 68.267 21.333 102.4h-102.4v102.4h162.133c34.133 42.667 72.533 76.8 119.467 102.4h-281.6v102.4h520.533v-59.733c51.2-8.533 102.4-25.6 145.067-51.2v281.6c0 55.467-46.933 102.4-102.4 102.4h-622.933c-55.467 0-102.4-46.933-102.4-102.4v-819.2c0-55.467 46.933-102.4 102.4-102.4h302.933c-81.067 55.467-136.533 140.8-153.6 238.933z" />
|
||||
<glyph unicode="" glyph-name="albaran" d="M819.2 960h-622.933c-55.467 0-102.4-46.933-102.4-102.4v-819.2c0-55.467 46.933-102.4 102.4-102.4h622.933c55.467 0 102.4 46.933 102.4 102.4v819.2c0 55.467-46.933 102.4-102.4 102.4zM358.4 174.933h-102.4v102.4h503.467v-102.4h-401.067zM256 379.733v102.4h503.467v-102.4h-503.467zM759.467 584.533h-503.467v102.4h503.467v-102.4z" />
|
||||
<glyph unicode="" glyph-name="solunion" d="M759.467 870.4v-136.533h-601.6c0 0-128-341.333 106.667-341.333s469.333 0 469.333 0 34.133 0 34.133-34.133-8.533-98.133-8.533-98.133h-541.867c0 0-247.467 29.867-204.8 320 0 0 8.533 140.8 72.533 298.667 0 0 21.333-8.533 85.333-8.533h588.8zM853.333 25.6c64 0 85.333-8.533 85.333-8.533 64 153.6 72.533 298.667 72.533 298.667 42.667 290.133-204.8 320-204.8 320h-541.867c0 0-8.533-64-8.533-98.133s34.133-34.133 34.133-34.133 238.933 0 469.333 0 106.667-341.333 106.667-341.333h-601.6v-136.533h588.8z" />
|
||||
<glyph unicode="" glyph-name="stowaway" d="M1006.933 452.267l-260.267 106.667 29.867 29.867c4.267 4.267 4.267 12.8 4.267 17.067-4.267 4.267-8.533 8.533-12.8 8.533h-157.867c0 93.867 76.8 157.867 174.933 157.867 4.267 0 8.533 4.267 12.8 8.533s4.267 8.533 0 17.067l-81.067 153.6c-4.267 0-12.8 4.267-17.067 4.267-46.933 0-93.867-17.067-132.267-42.667-21.333-17.067-42.667-38.4-55.467-59.733-12.8 21.333-29.867 42.667-55.467 59.733-34.133 12.8-81.067 34.133-128 34.133-4.267 0-12.8-4.267-12.8-8.533l-85.333-153.6c-4.267-4.267-4.267-4.267 0-12.8 4.267-4.267 8.533-8.533 12.8-8.533 98.133 0 174.933-59.733 174.933-153.6v0h-140.8c-4.267 0-12.8-4.267-12.8-8.533-8.533-4.267-4.267-17.067 0-21.333l21.333-21.333-277.333-110.933c-8.533-8.533-12.8-12.8-8.533-21.333 0-8.533 8.533-12.8 17.067-12.8v0l98.133 4.267-81.067-85.333c0-4.267-4.267-8.533 0-12.8 0-4.267 4.267-8.533 8.533-8.533l85.333-34.133v-179.2c0-8.533 4.267-12.8 8.533-12.8l358.4-145.067h8.533l358.4 145.067c4.267 4.267 8.533 8.533 8.533 12.8v179.2l85.333 34.133c4.267 0 8.533 4.267 8.533 8.533s0 8.533-4.267 12.8l-68.267 98.133 102.4-4.267c8.533 0 12.8 4.267 17.067 12.8 8.533 0 4.267 4.267-4.267 12.8zM110.933 456.533l196.267 76.8 8.533-8.533-166.4-64-38.4-4.267zM153.6 285.867v0l-68.267 34.133 68.267 98.133 328.533-132.267-68.267-98.133-260.267 98.133zM490.667-29.867l-328.533 132.267v153.6l243.2-98.133h12.8c0 0 0 0 4.267 0v0c0 0 4.267 0 4.267 4.267l64 85.333c0-4.267 0-277.333 0-277.333zM490.667 324.267l-298.667 115.2 149.333 64 153.6-157.867v-17.067h-4.267zM529.067 337.067l157.867 157.867 140.8-55.467-298.667-115.2c0 0 0 12.8 0 12.8zM849.067 102.4l-328.533-132.267v281.6l64-85.333c0 0 0-4.267 4.267-4.267v0h17.067l243.2 98.133v-157.867zM938.667 324.267l-324.267-132.267-68.267 98.133 328.533 132.267 64-98.133zM870.4 460.8l-157.867 64 12.8 8.533 187.733-76.8-42.667 4.267z" />
|
||||
<glyph unicode="" glyph-name="agency-term" d="M789.333 266.667c-55.467 0-102.4-46.933-102.4-102.4s46.933-102.4 102.4-102.4c55.467 0 102.4 46.933 102.4 102.4 0 59.733-46.933 102.4-102.4 102.4zM789.333 113.067c-29.867 0-51.2 21.333-51.2 51.2s21.333 51.2 51.2 51.2c29.867 0 51.2-21.333 51.2-51.2 0-25.6-25.6-51.2-51.2-51.2zM251.733 266.667c-55.467 0-102.4-46.933-102.4-102.4s46.933-102.4 102.4-102.4 102.4 46.933 102.4 102.4c0 59.733-46.933 102.4-102.4 102.4zM251.733 113.067c-29.867 0-51.2 21.333-51.2 51.2s21.333 51.2 51.2 51.2 51.2-21.333 51.2-51.2c0-25.6-25.6-51.2-51.2-51.2zM1006.933 539.733l-196.267 192c-12.8 12.8-29.867 17.067-46.933 17.067h-98.133v38.4c0 25.6-21.333 51.2-51.2 51.2h-563.2c-29.867 0-51.2-21.333-51.2-51.2v-554.667c0-29.867 25.6-51.2 51.2-51.2h68.267c8.533 64 64 115.2 132.267 115.2 64 0 123.733-51.2 132.267-115.2h268.8c8.533 64 64 115.2 132.267 115.2s128-51.2 136.533-115.2h51.2c29.867 0 51.2 25.6 51.2 51.2v260.267c0 17.067-8.533 34.133-17.067 46.933v0zM725.333 684.8c0 4.267 4.267 8.533 8.533 8.533h34.133c0 0 4.267 0 4.267-4.267l153.6-145.067c4.267 0 0-12.8-4.267-12.8h-187.733c-8.533 0-8.533 4.267-8.533 8.533v145.067zM509.013 556.373c0-113.92-92.16-206.080-206.080-206.080s-206.080 92.16-206.080 206.080 92.16 206.507 206.080 206.507 206.080-92.587 206.080-206.507zM342.613 494.080h-87.893l-15.36-40.107h-78.933l100.693 230.827h76.373l100.693-230.827h-80.213l-15.36 40.107zM321.28 550.4l-22.613 58.027-22.187-58.027h44.8z" />
|
||||
<glyph unicode="" glyph-name="apps" d="M0 704h256v256h-256v-256zM384-64h256v256h-256v-256zM0-64h256v256h-256v-256zM0 320h256v256h-256v-256zM384 320h256v256h-256v-256zM768 960v-256h256v256h-256zM384 704h256v256h-256v-256zM768 320h256v256h-256v-256zM768-64h256v256h-256v-256z" />
|
||||
<glyph unicode="" glyph-name="info" d="M512 960c-281.6 0-512-230.4-512-512s230.4-512 512-512 512 230.4 512 512-230.4 512-512 512zM563.2 192h-102.4v307.2h102.4v-307.2zM563.2 601.6h-102.4v102.4h102.4v-102.4z" />
|
||||
|
@ -96,6 +98,7 @@
|
|||
<glyph unicode="" glyph-name="headercol" d="M362.667-64h302.933v678.4h-302.933v-678.4zM0-64h302.933v678.4h-302.933v-678.4zM721.067 614.4v-678.4h302.933v678.4h-302.933zM362.667 678.4h302.933v281.6h-302.933v-281.6zM0 678.4h302.933v281.6h-302.933v-281.6zM721.067 960v-281.6h302.933v281.6h-302.933z" />
|
||||
<glyph unicode="" glyph-name="reserva" d="M841.6 864c48 0 86.4-38.4 86.4-86.4v-662.4c0-48-38.4-86.4-86.4-86.4h-659.2c-48 3.2-86.4 41.6-86.4 89.6v659.2c0 48 38.4 86.4 86.4 86.4h659.2zM841.6 960h-659.2c-99.2 0-182.4-83.2-182.4-182.4v-662.4c0-96 83.2-179.2 182.4-179.2h662.4c99.2 0 182.4 83.2 182.4 182.4v659.2c-3.2 99.2-86.4 182.4-185.6 182.4v0zM611.2 192l-99.2 144h-108.8v-144h-118.4v512h220.8c44.8 0 83.2-6.4 118.4-22.4 32-16 57.6-35.2 76.8-64s25.6-60.8 25.6-99.2c0-38.4-9.6-70.4-28.8-99.2s-44.8-48-76.8-64l115.2-163.2h-124.8zM582.4 585.6c-19.2 16-44.8 22.4-80 22.4h-96v-179.2h96c35.2 0 64 6.4 80 22.4 19.2 16 28.8 38.4 28.8 67.2-3.2 28.8-9.6 51.2-28.8 67.2z" />
|
||||
<glyph unicode="" glyph-name="100" d="M640 38.4l-17.067-17.067h-213.333v153.6h-153.6v102.4h200.533l102.4 102.4h-302.933v102.4h405.333l102.4 102.4h-507.733v102.4h520.533v-89.6l72.533 72.533c17.067 17.067 42.667 29.867 68.267 29.867 4.267 0 8.533 0 8.533 0v157.867c0 55.467-46.933 102.4-102.4 102.4h-627.2c-55.467 0-102.4-46.933-102.4-102.4v-819.2c0-55.467 46.933-102.4 102.4-102.4h627.2c55.467 0 102.4 46.933 102.4 102.4v285.867l-285.867-285.867zM917.333 635.733c8.533 0 17.067-4.267 21.333-8.533l76.8-76.8c12.8-12.8 12.8-34.133 0-46.933l-64-64-119.467 119.467 64 64c4.267 8.533 12.8 12.8 21.333 12.8zM797.867 529.067l119.467-123.733-320-320h-123.733v119.467l324.267 324.267z" />
|
||||
<glyph unicode="" glyph-name="clientUnpaid" horiz-adv-x="1135" d="M1135.22-64v47.845h-84.359v927.41l8.574 0.42c3.118 0.18 6.295 0.36 9.473 0.36h23.683c14.21 0.060 28.36 0.060 42.569 0.060v47.905c-314.713-0.18-629.485-0.24-944.258-0.24h-190.902v-47.726h83.16s0-928.069 0-928.069h-83.16v-47.726h140.898c331.44 0 662.881 0 994.321-0.24zM821.526 911.255h180.17v-926.93h-180.17v926.93zM591.892 911.735h180.11v-926.93h-180.11v926.87zM362.258 911.735h180.17v-926.93h-180.17v926.93zM132.624 911.255h180.17v-926.93h-180.17v926.93zM748.139 719.694c4.916-1.079 9.653-2.578 14.27-4.197v142.157c-7.555 1.739-15.169 3.358-22.963 4.737-16.668 2.818-33.576 4.437-50.364 6.595h-52.642c-2.938-0.48-5.876-1.199-8.814-1.439-8.754-0.719-17.507-1.679-26.141-2.998v-144.735c47.785 14.569 97.19 10.732 146.654-0.060zM878.545 627.6c27.82 34.775 55.94 69.969 84.179 105.284-38.072 44.428-81.661 78.543-131.605 101.447v-162.842c16.368-13.61 31.357-28.899 47.426-43.828zM467.003 283.809c-0.3 0.6 0 1.559 0 3.058h65.892v101.806h-97.43c-6.535 32.437-3.477 64.693-4.257 97.849h101.687v101.866h-74.706c0.060 1.439 0 2.039 0.18 2.458 18.107 37.653 42.509 69.43 74.526 93.652v161.403c-3.298-1.379-6.655-2.818-9.893-4.317-60.496-28.599-111.34-66.012-151.091-113.438v-564.612c37.953-46.646 86.997-82.8 147.194-108.342 4.557-1.919 9.173-3.717 13.79-5.456v153.489c-26.921 20.505-48.445 48.085-65.832 80.702zM297.925 591.806c-1.919-6.056-4.617-7.794-10.852-7.734-35.075 0.3-70.149 0.18-105.224 0.18h-9.293v-93.652h100.787c0.899-33.156 1.799-65.233 2.758-98.149h-103.605v-101.746h9.293c36.693 0 73.447-0.36 110.14 0.24 5.276 0.12 8.694-0.839 11.212-3.238v319.389c-1.799-5.036-3.657-10.073-5.276-15.289zM736.688 286.866v101.806h-135.202v-101.806h135.202zM736.808 588.329h-135.322v-101.866h135.322v101.866zM954.27 163.236c-28.419 34.055-56.539 67.811-83.999 100.727-13.31-10.972-26.201-21.884-39.152-32.556v-169.258c13.49 6.415 26.681 13.79 39.571 22.304 32.257 21.345 59.777 47.726 83.58 78.783zM615.215 167.493c-4.677 0.839-9.233 1.799-13.73 2.938v-138.68c32.017-5.036 64.633-5.816 97.789-3.178 21.524 1.739 42.629 4.916 63.134 9.773v145.695c-45.447-21.524-95.031-25.781-147.194-16.548z" />
|
||||
<glyph unicode="" glyph-name="sign" d="M725.333 960c72.533-72.533 145.067-145.067 217.6-217.6-4.267-4.267-8.533-12.8-17.067-17.067-179.2-179.2-358.4-362.667-537.6-541.867-8.533-8.533-25.6-17.067-38.4-21.333-81.067-21.333-166.4-42.667-247.467-64-4.267 0-12.8-4.267-21.333-4.267 0 8.533 0 17.067 4.267 21.333 21.333 85.333 42.667 166.4 64 251.733 4.267 8.533 8.533 21.333 17.067 25.6 183.467 187.733 371.2 371.2 554.667 554.667 0 8.533 0 12.8 4.267 12.8zM849.067 25.6c-25.6-21.333-46.933-42.667-72.533-59.733-29.867-17.067-59.733-25.6-89.6-29.867-21.333-4.267-42.667 0-55.467 12.8-12.8 8.533-25.6 46.933-38.4 51.2-4.267 0-12.8 0-17.067-4.267-68.267-25.6-145.067-55.467-221.867-55.467-106.667 0-209.067 0-315.733 0-4.267 0-8.533 0-12.8 0-4.267 4.267-12.8 8.533-12.8 12.8s8.533 12.8 12.8 17.067c4.267 4.267 12.8 0 21.333 0 102.4 0 204.8 0 307.2 4.267 76.8 0 153.6 25.6 221.867 64 8.533 4.267 12.8 12.8 12.8 21.333 4.267 55.467 12.8 106.667 42.667 153.6 17.067 29.867 42.667 51.2 81.067 55.467 55.467 0 85.333-38.4 64-89.6-17.067-34.133-42.667-64-64-89.6-21.333-21.333-51.2-38.4-72.533-55.467-4.267-4.267-8.533-17.067-8.533-21.333 8.533-34.133 29.867-51.2 59.733-42.667 29.867 4.267 59.733 17.067 81.067 34.133 25.6 17.067 46.933 42.667 72.533 64 8.533 8.533 17.067 21.333 29.867 25.6 8.533 4.267 21.333 8.533 29.867 4.267 4.267-4.267 8.533-21.333 4.267-29.867-8.533-21.333-17.067-42.667-25.6-64-4.267-8.533-8.533-25.6 0-34.133s29.867-4.267 38.4 4.267c25.6 17.067 51.2 34.133 72.533 55.467 8.533 8.533 17.067 17.067 25.6 8.533 4.267-4.267 4.267-21.333 0-29.867-25.6-34.133-59.733-59.733-102.4-72.533-46.933-12.8-76.8 17.067-68.267 64-4.267 12.8-4.267 17.067 0 25.6zM618.667 72.533c0 0 0-4.267 0-4.267s4.267 0 4.267 0c29.867 25.6 59.733 51.2 85.333 81.067 12.8 12.8 21.333 34.133 29.867 51.2 8.533 21.333 0 34.133-21.333 38.4-25.6 4.267-42.667-8.533-55.467-25.6-29.867-46.933-38.4-93.867-42.667-140.8z" />
|
||||
<glyph unicode="" glyph-name="polizon" d="M1011.2 456.533l-264.533 106.667 29.867 29.867c4.267 4.267 4.267 12.8 4.267 17.067-4.267 4.267-8.533 8.533-12.8 8.533h-157.867c0 93.867 76.8 157.867 174.933 157.867 4.267 0 8.533 4.267 12.8 8.533s4.267 8.533 0 17.067l-81.067 153.6c-4.267 0-12.8 4.267-17.067 4.267-46.933 0-93.867-17.067-132.267-42.667-25.6-17.067-42.667-38.4-55.467-59.733-12.8 25.6-29.867 42.667-55.467 59.733-38.4 25.6-85.333 42.667-132.267 42.667-4.267 0-12.8-4.267-12.8-8.533l-81.067-153.6c-4.267-4.267-4.267-8.533 0-17.067 4.267-4.267 8.533-8.533 12.8-8.533 98.133 0 174.933-59.733 174.933-153.6v0h-140.8c-4.267 0-12.8-4.267-12.8-8.533-4.267-4.267 0-12.8 4.267-17.067l21.333-21.333-277.333-110.933c-8.533-8.533-12.8-12.8-8.533-21.333 0-8.533 8.533-12.8 17.067-12.8 0 0 0 0 0 0l98.133 4.267-76.8-98.133c0-4.267-4.267-8.533 0-12.8 0-4.267 4.267-8.533 8.533-8.533l85.333-34.133v-179.2c0-8.533 4.267-12.8 8.533-12.8l362.667-145.067c0 0 4.267 0 4.267 0s4.267 0 4.267 0l362.667 145.067c4.267 4.267 8.533 8.533 8.533 12.8v179.2l85.333 34.133c4.267 0 8.533 4.267 8.533 8.533s0 8.533-4.267 12.8l-72.533 98.133 102.4-4.267c8.533 0 12.8 4.267 17.067 12.8 0 8.533-4.267 12.8-12.8 17.067zM110.933 460.8l200.533 81.067 8.533-8.533-170.667-68.267-38.4-4.267zM153.6 294.4v4.267l-72.533 29.867 72.533 98.133 328.533-132.267-72.533-98.133-256 102.4v-4.267zM494.933-25.6l-328.533 132.267v153.6l243.2-98.133c0 0 4.267 0 4.267 0h4.267c0 0 4.267 0 4.267 0v0c0 0 0 0 4.267 0v0c0 0 4.267 0 4.267 4.267l64 85.333v-277.333zM494.933 328.533l-302.933 119.467 149.333 59.733 153.6-162.133v-17.067zM529.067 345.6l162.133 157.867 140.8-55.467-302.933-119.467v17.067zM857.6 106.667l-328.533-132.267v281.6l64-85.333c0 0 0-4.267 4.267-4.267v0c0 0 4.267 0 4.267 0v0c0 0 4.267 0 4.267 0v0 0c0 0 4.267 0 4.267 0l243.2 98.133v-157.867zM942.933 328.533l-328.533-132.267-72.533 98.133 328.533 132.267 72.533-98.133zM874.667 465.067l-162.133 64 12.8 8.533 187.733-76.8-38.4 4.267z" />
|
||||
<glyph unicode="" glyph-name="solclaim" d="M1024 917.333v-938.667h-938.667v68.267h234.667v51.2h38.4c8.533-4.267 17.067-4.267 29.867-4.267h298.667c42.667 0 76.8 34.133 76.8 76.8 0 0 0 0 0 0 29.867 12.8 46.933 38.4 46.933 72.533 0 0 0 0 0 0 29.867 12.8 46.933 38.4 46.933 72.533s-21.333 59.733-46.933 72.533c0 0 0 0 0 0 0 42.667-34.133 76.8-76.8 76.8h-106.667c21.333 21.333 29.867 55.467 17.067 89.6-12.8 25.6-38.4 42.667-68.267 42.667-12.8 0-21.333-4.267-34.133-8.533l-217.6-98.133v29.867h-238.933v396.8h362.667v-209.067h209.067v209.067h366.933zM0 89.6h281.6v51.2h89.6c4.267-4.267 12.8-4.267 17.067-4.267h298.667c21.333 0 34.133 12.8 34.133 34.133s-12.8 34.133-34.133 34.133h-136.533v12.8h183.467c21.333 0 34.133 12.8 34.133 29.867 0 21.333-12.8 29.867-34.133 29.867h-179.2v12.8h234.667c21.333 0 34.133 8.533 34.133 29.867s-12.8 29.867-34.133 29.867h-230.4v12.8h183.467c21.333 0 29.867 12.8 29.867 34.133s-12.8 34.133-34.133 34.133h-230.4l93.867 64c12.8 8.533 21.333 29.867 12.8 46.933s-29.867 25.6-51.2 17.067l-251.733-119.467c-4.267 0-4.267-4.267-8.533-4.267-4.267-4.267-8.533-8.533-12.8-12.8h-8.533v55.467h-281.6v-388.267z" />
|
||||
|
@ -128,4 +131,4 @@
|
|||
<glyph unicode="" glyph-name="grid" d="M0 704h256v256h-256v-256zM384-64h256v256h-256v-256zM0-64h256v256h-256v-256zM0 320h256v256h-256v-256zM384 320h256v256h-256v-256zM768 960v-256h256v256h-256zM384 704h256v256h-256v-256zM768 320h256v256h-256v-256zM768-64h256v256h-256v-256z" />
|
||||
<glyph unicode="" glyph-name="web" d="M827.733 533.333c-29.867 145.067-157.867 256-315.733 256-123.733 0-230.4-68.267-285.867-170.667-128-17.067-226.133-123.733-226.133-256 0-140.8 115.2-256 256-256h554.667c119.467 0 213.333 93.867 213.333 213.333 0 110.933-85.333 204.8-196.267 213.333z" />
|
||||
<glyph unicode="" glyph-name="dfiscales" d="M140.8 520.533v-341.333h149.333v341.333h-149.333zM439.467 520.533v-341.333h149.333v341.333h-149.333zM38.4-64h942.933v145.067h-942.933v-145.067zM733.867 520.533v-341.333h149.333v341.333h-149.333zM512 960l-473.6-243.2v-98.133h942.933v98.133l-469.333 243.2z" />
|
||||
</font></defs></svg>
|
||||
</font></defs></svg>
|
||||
|
|
Before Width: | Height: | Size: 157 KiB After Width: | Height: | Size: 162 KiB |
Binary file not shown.
Binary file not shown.
|
@ -1,8 +1,8 @@
|
|||
|
||||
<vn-dialog
|
||||
vn-id="instanceLog">
|
||||
<tpl-body>
|
||||
<vn-log
|
||||
class="vn-instance-log"
|
||||
url="{{$ctrl.url}}"
|
||||
origin-id="$ctrl.originId"
|
||||
changed-model="$ctrl.changedModel"
|
||||
|
|
|
@ -1,13 +1,9 @@
|
|||
.vn-dialog {
|
||||
& > .window:not(:has(.empty-rows)) {
|
||||
width:60%;
|
||||
vn-log {
|
||||
vn-card {
|
||||
visibility: hidden;
|
||||
& > * {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
vn-log.vn-instance-log {
|
||||
vn-card {
|
||||
width: 900px;
|
||||
visibility: hidden;
|
||||
& > * {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,14 +69,6 @@
|
|||
value-field="code">
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-textfield
|
||||
vn-one
|
||||
label="File name"
|
||||
ng-model="$ctrl.newPhoto.fileName"
|
||||
required="true">
|
||||
</vn-input-file>
|
||||
</vn-horizontal>
|
||||
</vn-one>
|
||||
</vn-horizontal>
|
||||
</tpl-body>
|
||||
|
|
|
@ -64,8 +64,7 @@ export default class UploadPhoto extends Component {
|
|||
this.editor = null;
|
||||
this.newPhoto = {
|
||||
id: id,
|
||||
collection: collection,
|
||||
fileName: id
|
||||
collection: collection
|
||||
};
|
||||
this.$.dialog.show();
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
require('../methods/application/status')(Self);
|
||||
require('../methods/application/post')(Self);
|
||||
};
|
||||
|
|
|
@ -7,6 +7,12 @@
|
|||
"principalType": "ROLE",
|
||||
"principalId": "$everyone",
|
||||
"permission": "ALLOW"
|
||||
}
|
||||
},
|
||||
{
|
||||
"property": "post",
|
||||
"principalType": "ROLE",
|
||||
"principalId": "$everyone",
|
||||
"permission": "ALLOW"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ module.exports = () => {
|
|||
if (!env || env === 'development')
|
||||
return new Date(Date.UTC(2001, 0, 1, 11));
|
||||
|
||||
return new Date(Date.UTC());
|
||||
return new Date();
|
||||
};
|
||||
|
||||
Date.vnNew = () => {
|
||||
|
|
|
@ -101,7 +101,7 @@
|
|||
<vn-span
|
||||
ng-click="itemDescriptor.show($event, saleClaimed.itemFk)"
|
||||
class="link">
|
||||
{{::saleClaimed.itemFk | zeroFill:6}}
|
||||
{{::saleClaimed.itemFk}}
|
||||
</vn-span>
|
||||
</td>
|
||||
<td number>
|
||||
|
|
|
@ -115,7 +115,7 @@
|
|||
<span
|
||||
ng-click="itemDescriptor.show($event, saleClaimed.sale.itemFk, saleClaimed.sale.id)"
|
||||
class="link">
|
||||
{{::saleClaimed.sale.itemFk | zeroFill:6}}
|
||||
{{::saleClaimed.sale.itemFk}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td expand>{{::saleClaimed.sale.ticket.landed | date: 'dd/MM/yyyy'}}</vn-td>
|
||||
|
@ -241,7 +241,7 @@
|
|||
<span
|
||||
ng-click="itemDescriptor.show($event, action.sale.itemFk, action.sale.id)"
|
||||
class="link">
|
||||
{{::action.sale.itemFk | zeroFill:6}}
|
||||
{{::action.sale.itemFk}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td number>
|
||||
|
|
|
@ -67,7 +67,7 @@ module.exports = function(Self) {
|
|||
|
||||
try {
|
||||
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 bank = await models.Bank.findById(args.bankFk, null, myOptions);
|
||||
const accountingType = await models.AccountingType.findById(bank.accountingTypeFk, null, myOptions);
|
||||
|
@ -76,23 +76,8 @@ module.exports = function(Self) {
|
|||
if (!args.compensationAccount)
|
||||
throw new UserError('Compensation account is empty');
|
||||
|
||||
const supplierCompensation = await models.Supplier.findOne({
|
||||
where: {
|
||||
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');
|
||||
// Check compensation account exists
|
||||
await models.Client.getClientOrSupplierReference(args.compensationAccount, myOptions);
|
||||
|
||||
await Self.rawSql(
|
||||
`CALL vn.ledger_doCompensation(?, ?, ?, ?, ?, ?, ?)`,
|
||||
|
@ -151,7 +136,7 @@ module.exports = function(Self) {
|
|||
myOptions
|
||||
);
|
||||
}
|
||||
|
||||
const newReceipt = await models.Receipt.create(args, myOptions);
|
||||
if (tx) await tx.commit();
|
||||
|
||||
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;
|
||||
};
|
||||
};
|
|
@ -0,0 +1,76 @@
|
|||
const UserError = require('vn-loopback/util/user-error');
|
||||
const base64url = require('base64url');
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethod('confirm', {
|
||||
description: 'Confirms electronic payment transaction',
|
||||
accessType: 'WRITE',
|
||||
accepts: [
|
||||
{
|
||||
arg: 'Ds_SignatureVersion',
|
||||
type: 'string',
|
||||
required: false,
|
||||
}, {
|
||||
arg: 'Ds_MerchantParameters',
|
||||
type: 'string',
|
||||
required: true,
|
||||
}, {
|
||||
arg: 'Ds_Signature',
|
||||
type: 'string',
|
||||
required: true,
|
||||
}
|
||||
],
|
||||
returns: {
|
||||
type: 'Boolean',
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/confirm`,
|
||||
verb: 'POST'
|
||||
}
|
||||
});
|
||||
|
||||
Self.confirm = async(signatureVersion, merchantParameters, signature) => {
|
||||
const $ = Self.app.models;
|
||||
|
||||
const decodedParams = JSON.parse(
|
||||
base64url.decode(merchantParameters, 'utf8'));
|
||||
const params = {};
|
||||
|
||||
for (const param in decodedParams)
|
||||
params[param] = decodeURIComponent(decodedParams[param]);
|
||||
|
||||
const orderId = params['Ds_Order'];
|
||||
const merchantId = parseInt(params['Ds_MerchantCode']);
|
||||
|
||||
if (!orderId)
|
||||
throw new UserError('Order id not found');
|
||||
if (!merchantId)
|
||||
throw new UserError('Mechant id not found');
|
||||
|
||||
const merchant = await $.TpvMerchant.findById(merchantId, {
|
||||
fields: ['id', 'secretKey']
|
||||
});
|
||||
|
||||
const base64hmac = Self.createSignature(
|
||||
orderId,
|
||||
merchant.secretKey,
|
||||
merchantParameters
|
||||
);
|
||||
|
||||
if (base64hmac !== base64url.toBase64(signature))
|
||||
throw new UserError('Invalid signature');
|
||||
|
||||
await Self.rawSql(
|
||||
'CALL hedera.tpvTransaction_confirm(?, ?, ?, ?, ?, ?)', [
|
||||
params['Ds_Amount'],
|
||||
orderId,
|
||||
merchantId,
|
||||
params['Ds_Currency'],
|
||||
params['Ds_Response'],
|
||||
params['Ds_ErrorCode']
|
||||
]);
|
||||
|
||||
return true;
|
||||
};
|
||||
};
|
|
@ -0,0 +1,39 @@
|
|||
const UserError = require('vn-loopback/util/user-error');
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethodCtx('end', {
|
||||
description: 'Ends electronic payment transaction',
|
||||
accessType: 'WRITE',
|
||||
accepts: [
|
||||
{
|
||||
arg: 'orderId',
|
||||
type: 'string',
|
||||
required: true,
|
||||
}, {
|
||||
arg: 'status',
|
||||
type: 'string',
|
||||
required: true,
|
||||
}
|
||||
],
|
||||
http: {
|
||||
path: `/end`,
|
||||
verb: 'POST'
|
||||
}
|
||||
});
|
||||
|
||||
Self.end = async(ctx, orderId, status) => {
|
||||
const userId = ctx.req.accessToken.userId;
|
||||
const transaction = await Self.findById(orderId, {
|
||||
fields: ['id', 'clientFk']
|
||||
});
|
||||
|
||||
if (transaction?.clientFk != userId)
|
||||
throw new UserError('Transaction not owned by user');
|
||||
|
||||
await Self.rawSql(
|
||||
'CALL hedera.tpvTransaction_end(?, ?)', [
|
||||
orderId,
|
||||
status
|
||||
]);
|
||||
};
|
||||
};
|
|
@ -0,0 +1,85 @@
|
|||
const UserError = require('vn-loopback/util/user-error');
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethodCtx('start', {
|
||||
description: 'Starts electronic payment transaction',
|
||||
accessType: 'WRITE',
|
||||
accepts: [
|
||||
{
|
||||
arg: 'amount',
|
||||
type: 'Number',
|
||||
required: true,
|
||||
}, {
|
||||
arg: 'companyId',
|
||||
type: 'Number',
|
||||
required: false,
|
||||
}, {
|
||||
arg: 'urlOk',
|
||||
type: 'String',
|
||||
required: false,
|
||||
}, {
|
||||
arg: 'urlKo',
|
||||
type: 'String',
|
||||
required: false,
|
||||
}
|
||||
],
|
||||
returns: {
|
||||
type: 'Object',
|
||||
root: true
|
||||
},
|
||||
http: {
|
||||
path: `/start`,
|
||||
verb: 'POST'
|
||||
}
|
||||
});
|
||||
|
||||
Self.start = async(ctx, amount, companyId, urlOk, urlKo) => {
|
||||
const userId = ctx.req.accessToken.userId;
|
||||
const [[row]] = await Self.rawSql(
|
||||
'CALL hedera.tpvTransaction_start(?, ?, ?)', [
|
||||
amount,
|
||||
companyId,
|
||||
userId
|
||||
]);
|
||||
|
||||
if (!row)
|
||||
throw new UserError('Transaction error');
|
||||
|
||||
const orderId = row.transactionId.padStart(12, '0');
|
||||
const merchantUrl = row.merchantUrl ? row.merchantUrl : '';
|
||||
urlOk = urlOk ? urlOk.replace('_transactionId_', orderId) : '';
|
||||
urlKo = urlKo ? urlKo.replace('_transactionId_', orderId) : '';
|
||||
|
||||
const params = {
|
||||
'Ds_Merchant_Amount': amount,
|
||||
'Ds_Merchant_Order': orderId,
|
||||
'Ds_Merchant_MerchantCode': row.merchant,
|
||||
'Ds_Merchant_Currency': row.currency,
|
||||
'Ds_Merchant_TransactionType': row.transactionType,
|
||||
'Ds_Merchant_Terminal': row.terminal,
|
||||
'Ds_Merchant_MerchantURL': merchantUrl,
|
||||
'Ds_Merchant_UrlOK': urlOk,
|
||||
'Ds_Merchant_UrlKO': urlKo
|
||||
};
|
||||
for (const param in params)
|
||||
params[param] = encodeURIComponent(params[param]);
|
||||
|
||||
const json = JSON.stringify(params);
|
||||
const merchantParameters = Buffer.from(json).toString('base64');
|
||||
|
||||
const signature = Self.createSignature(
|
||||
orderId,
|
||||
row.secretKey,
|
||||
merchantParameters
|
||||
);
|
||||
|
||||
return {
|
||||
url: row.url,
|
||||
postValues: {
|
||||
'Ds_SignatureVersion': 'HMAC_SHA256_V1',
|
||||
'Ds_MerchantParameters': merchantParameters,
|
||||
'Ds_Signature': signature
|
||||
}
|
||||
};
|
||||
};
|
||||
};
|
|
@ -47,4 +47,5 @@ module.exports = Self => {
|
|||
require('../methods/client/incotermsAuthorizationEmail')(Self);
|
||||
require('../methods/client/consumptionSendQueued')(Self);
|
||||
require('../methods/client/filter')(Self);
|
||||
require('../methods/client/getClientOrSupplierReference')(Self);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
const crypto = require('crypto');
|
||||
|
||||
module.exports = Self => {
|
||||
require('../methods/tpv-transaction/confirm')(Self);
|
||||
require('../methods/tpv-transaction/start')(Self);
|
||||
require('../methods/tpv-transaction/end')(Self);
|
||||
|
||||
Self.createSignature = function(orderId, secretKey, merchantParameters) {
|
||||
secretKey = Buffer.from(secretKey, 'base64');
|
||||
const iv = Buffer.alloc(8, 0);
|
||||
|
||||
const cipher = crypto.createCipheriv('des-ede3-cbc', secretKey, iv);
|
||||
cipher.setAutoPadding(false);
|
||||
const orderKey = Buffer.concat([
|
||||
cipher.update(zeroPad(orderId, 8)),
|
||||
cipher.final()
|
||||
]);
|
||||
|
||||
return crypto.createHmac('sha256', orderKey)
|
||||
.update(merchantParameters)
|
||||
.digest('base64');
|
||||
};
|
||||
|
||||
function zeroPad(buf, blocksize) {
|
||||
const buffer = typeof buf === 'string' ? Buffer.from(buf, 'utf8') : buf;
|
||||
const pad = Buffer.alloc((blocksize - (buffer.length % blocksize)) % blocksize, 0);
|
||||
return Buffer.concat([buffer, pad]);
|
||||
}
|
||||
};
|
|
@ -11,7 +11,7 @@
|
|||
</vn-crud-model>
|
||||
<vn-horizontal>
|
||||
<vn-date-picker
|
||||
label="Date"
|
||||
label="Date"
|
||||
ng-model="$ctrl.receipt.payed"
|
||||
required="true">
|
||||
</vn-date-picker>
|
||||
|
@ -48,6 +48,14 @@
|
|||
max="$ctrl.maxAmount">
|
||||
</vn-input-number>
|
||||
</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-textfield
|
||||
label="Reference"
|
||||
|
@ -71,17 +79,9 @@
|
|||
</vn-input-number>
|
||||
</vn-horizontal>
|
||||
</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-check
|
||||
label="View receipt"
|
||||
<vn-check
|
||||
label="View receipt"
|
||||
ng-model="$ctrl.viewReceipt">
|
||||
</vn-check>
|
||||
</vn-horizontal>
|
||||
|
@ -89,4 +89,4 @@
|
|||
<tpl-buttons>
|
||||
<input type="button" response="cancel" translate-attr="{value: 'Cancel'}"/>
|
||||
<button response="accept" translate vn-focus>Accept</button>
|
||||
</tpl-buttons>
|
||||
</tpl-buttons>
|
||||
|
|
|
@ -4,7 +4,6 @@ import Dialog from 'core/components/dialog';
|
|||
class Controller extends Dialog {
|
||||
constructor($element, $, $transclude, vnReport) {
|
||||
super($element, $, $transclude);
|
||||
this.viewReceipt = true;
|
||||
this.vnReport = vnReport;
|
||||
this.receipt = {};
|
||||
}
|
||||
|
@ -61,12 +60,16 @@ class Controller extends Dialog {
|
|||
const accountingType = value.accountingType;
|
||||
|
||||
this.receipt.description = [];
|
||||
if (accountingType.receiptDescription != null && accountingType.receiptDescription != '')
|
||||
this.receipt.description.push(accountingType.receiptDescription);
|
||||
if (this.originalDescription)
|
||||
this.receipt.description.push(this.originalDescription);
|
||||
this.receipt.description.join(', ');
|
||||
|
||||
this.viewReceipt = accountingType.code == 'cash';
|
||||
if (accountingType.code == 'compensation')
|
||||
this.receipt.description = '';
|
||||
else {
|
||||
if (accountingType.receiptDescription != null && accountingType.receiptDescription != '')
|
||||
this.receipt.description.push(accountingType.receiptDescription);
|
||||
if (this.originalDescription)
|
||||
this.receipt.description.push(this.originalDescription);
|
||||
this.receipt.description.join(', ');
|
||||
}
|
||||
this.maxAmount = accountingType && accountingType.maxAmount;
|
||||
|
||||
this.receipt.payed = Date.vnNew();
|
||||
|
@ -112,7 +115,25 @@ class Controller extends Dialog {
|
|||
}
|
||||
|
||||
accountShortToStandard(value) {
|
||||
this.receipt.compensationAccount = value.replace('.', '0'.repeat(11 - value.length));
|
||||
if (value) {
|
||||
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() {
|
||||
|
|
|
@ -75,7 +75,6 @@ describe('Client', () => {
|
|||
jest.spyOn(controller.vnReport, 'show');
|
||||
|
||||
controller.$params = {id: 1101};
|
||||
controller.viewReceipt = false;
|
||||
|
||||
$httpBackend.expect('POST', `Clients/1101/createReceipt`).respond({id: 1});
|
||||
controller.responseHandler('accept');
|
||||
|
|
|
@ -1,2 +1,4 @@
|
|||
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 => {
|
||||
require('../methods/entry/filter')(Self);
|
||||
require('../methods/entry/getEntry')(Self);
|
||||
|
@ -7,4 +8,41 @@ module.exports = Self => {
|
|||
require('../methods/entry/importBuysPreview')(Self);
|
||||
require('../methods/entry/lastItemBuys')(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": {
|
||||
"type": "number",
|
||||
"required": true
|
||||
},
|
||||
"observationEditorFk": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
|
@ -99,6 +102,11 @@
|
|||
"type": "belongsTo",
|
||||
"model": "Currency",
|
||||
"foreignKey": "currencyFk"
|
||||
},
|
||||
"observationEditor": {
|
||||
"type": "belongsTo",
|
||||
"model": "Account",
|
||||
"foreignKey": "observationEditorFk"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@
|
|||
ng-if="buy.id"
|
||||
ng-click="itemDescriptor.show($event, buy.item.id)"
|
||||
class="link">
|
||||
{{::buy.item.id | zeroFill:6}}
|
||||
{{::buy.item.id}}
|
||||
</span>
|
||||
<vn-autocomplete ng-if="!buy.id" class="dense"
|
||||
vn-focus
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
ng-model="$ctrl.filter.typeFk"
|
||||
fields="['categoryFk']"
|
||||
include="'category'"
|
||||
on-change="$ctrl.applyFilters()">
|
||||
on-change="$ctrl.addFilters()">
|
||||
<tpl-item>
|
||||
<div>{{name}}</div>
|
||||
<div class="text-caption text-secondary">
|
||||
|
@ -60,7 +60,7 @@
|
|||
value-field="id"
|
||||
where="{role: {inq: ['logistic', 'buyer']}}"
|
||||
label="Buyer"
|
||||
on-change="$ctrl.applyFilters()">
|
||||
on-change="$ctrl.addFilters()">
|
||||
</vn-autocomplete>
|
||||
<vn-autocomplete
|
||||
vn-id="supplier"
|
||||
|
@ -71,7 +71,7 @@
|
|||
search-function="{or: [{nickname: {like: '%'+ $search +'%'}}, {name: {like: '%'+ $search +'%'}}]}"
|
||||
show-field="name"
|
||||
value-field="id"
|
||||
on-change="$ctrl.applyFilters()">
|
||||
on-change="$ctrl.addFilters()">
|
||||
<tpl-item>{{name}}: {{nickname}}</tpl-item>
|
||||
</vn-autocomplete>
|
||||
</vn-horizontal>
|
||||
|
@ -79,12 +79,12 @@
|
|||
<vn-date-picker
|
||||
label="From"
|
||||
ng-model="$ctrl.filter.from"
|
||||
on-change="$ctrl.applyFilters()">
|
||||
on-change="$ctrl.addFilters()">
|
||||
</vn-date-picker>
|
||||
<vn-date-picker
|
||||
label="To"
|
||||
ng-model="$ctrl.filter.to"
|
||||
on-change="$ctrl.applyFilters()">
|
||||
on-change="$ctrl.addFilters()">
|
||||
</vn-date-picker>
|
||||
</vn-vertical>
|
||||
<vn-horizontal class="checks">
|
||||
|
@ -92,19 +92,19 @@
|
|||
label="Is active"
|
||||
ng-model="$ctrl.filter.active"
|
||||
triple-state="true"
|
||||
ng-click="$ctrl.applyFilters()">
|
||||
ng-click="$ctrl.addFilters()">
|
||||
</vn-check>
|
||||
<vn-check
|
||||
label="Is visible"
|
||||
ng-model="$ctrl.filter.visible"
|
||||
triple-state="true"
|
||||
ng-click="$ctrl.applyFilters()">
|
||||
ng-click="$ctrl.addFilters()">
|
||||
</vn-check>
|
||||
<vn-check
|
||||
label="Is floramondo"
|
||||
ng-model="$ctrl.filter.floramondo"
|
||||
triple-state="true"
|
||||
ng-click="$ctrl.applyFilters()">
|
||||
ng-click="$ctrl.addFilters()">
|
||||
</vn-check>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal class="tags">
|
||||
|
@ -139,7 +139,7 @@
|
|||
ng-model="itemTag.value"
|
||||
show-field="value"
|
||||
value-field="value"
|
||||
on-change="$ctrl.applyFilters()">
|
||||
on-change="$ctrl.addFilters()">
|
||||
</vn-autocomplete>
|
||||
<vn-icon-button
|
||||
vn-none
|
||||
|
|
|
@ -17,33 +17,33 @@ class Controller extends SearchPanel {
|
|||
changeCategory(id) {
|
||||
if (this.filter.categoryFk != id) {
|
||||
this.filter.categoryFk = id;
|
||||
this.applyFilters();
|
||||
this.addFilters();
|
||||
}
|
||||
}
|
||||
|
||||
removeItemFilter(param) {
|
||||
this.filter[param] = null;
|
||||
if (param == 'categoryFk') this.filter['typeFk'] = null;
|
||||
this.applyFilters();
|
||||
this.addFilters();
|
||||
}
|
||||
|
||||
removeTag(tag) {
|
||||
const index = this.filter.tags.indexOf(tag);
|
||||
if (index > -1) this.filter.tags.splice(index, 1);
|
||||
this.applyFilters();
|
||||
this.addFilters();
|
||||
}
|
||||
|
||||
onKeyPress($event) {
|
||||
if ($event.key === 'Enter')
|
||||
this.applyFilters();
|
||||
this.addFilters();
|
||||
}
|
||||
|
||||
applyFilters() {
|
||||
addFilters() {
|
||||
for (let i = 0; i < this.filter.tags.length; i++) {
|
||||
if (!this.filter.tags[i].value)
|
||||
this.filter.tags.splice(i, 1);
|
||||
}
|
||||
return this.model.applyFilter({}, this.filter);
|
||||
return this.model.addFilter({}, this.filter);
|
||||
}
|
||||
|
||||
showTagInfo(itemTag) {
|
||||
|
|
|
@ -10,7 +10,7 @@ describe('Entry', () => {
|
|||
beforeEach(angular.mock.inject($componentController => {
|
||||
$element = angular.element(`<vn-latest-buys-search-panel></vn-latest-buys-search-panel>`);
|
||||
controller = $componentController('vnLatestBuysSearchPanel', {$element});
|
||||
controller.model = {applyFilter: () => {}};
|
||||
controller.model = {addFilter: () => {}};
|
||||
}));
|
||||
|
||||
describe('removeItemFilter()', () => {
|
||||
|
|
|
@ -148,7 +148,7 @@
|
|||
<span
|
||||
ng-click="itemDescriptor.show($event, line.item.id)"
|
||||
class="link">
|
||||
{{::line.item.id | zeroFill:6}}
|
||||
{{::line.item.id}}
|
||||
</span>
|
||||
</td>
|
||||
<td number shrink>
|
||||
|
|
|
@ -94,11 +94,6 @@
|
|||
"model": "Supplier",
|
||||
"foreignKey": "supplierFk"
|
||||
},
|
||||
"supplierContact": {
|
||||
"type": "hasMany",
|
||||
"model": "SupplierContact",
|
||||
"foreignKey": "supplierFk"
|
||||
},
|
||||
"currency": {
|
||||
"type": "belongsTo",
|
||||
"model": "Currency",
|
||||
|
|
|
@ -6,13 +6,15 @@ class Controller extends ModuleCard {
|
|||
const filter = {
|
||||
include: [
|
||||
{
|
||||
relation: 'supplier'
|
||||
},
|
||||
{
|
||||
relation: 'supplierContact',
|
||||
relation: 'supplier',
|
||||
scope: {
|
||||
where: {
|
||||
email: {neq: null}
|
||||
include: {
|
||||
relation: 'contacts',
|
||||
scope: {
|
||||
where: {
|
||||
email: {neq: null},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
</vn-item>
|
||||
<vn-item
|
||||
ng-if="$ctrl.isAgricultural()"
|
||||
ng-click="sendPdfConfirmation.show({email: $ctrl.entity.supplierContact[0].email})"
|
||||
ng-click="sendPdfConfirmation.show({email: $ctrl.entity.supplier.contacts[0].email})"
|
||||
translate>
|
||||
Send agricultural receipt as PDF
|
||||
</vn-item>
|
||||
|
|
|
@ -47,7 +47,7 @@
|
|||
show-field="description"
|
||||
rule
|
||||
vn-focus>
|
||||
<tpl-item>{{id | zeroFill:8}}: {{description}}</tpl-item>
|
||||
<tpl-item>{{id}}: {{description}}</tpl-item>
|
||||
</vn-autocomplete>
|
||||
<vn-input-number
|
||||
label="Amount"
|
||||
|
|
|
@ -141,7 +141,7 @@
|
|||
</vn-thead>
|
||||
<vn-tbody>
|
||||
<vn-tr ng-repeat="intrastat in $ctrl.summary.invoiceInIntrastat">
|
||||
<vn-td>{{::intrastat.intrastatFk | zeroFill:8}}: {{::intrastat.intrastat.description}}</vn-td>
|
||||
<vn-td>{{::intrastat.intrastatFk}}: {{::intrastat.intrastat.description}}</vn-td>
|
||||
<vn-td>{{::intrastat.amount | currency: 'EUR':2}}</vn-td>
|
||||
<vn-td>{{::intrastat.net}}</vn-td>
|
||||
<vn-td>{{::intrastat.stems}}</vn-td>
|
||||
|
|
|
@ -35,8 +35,7 @@ module.exports = Self => {
|
|||
const tickets = await models.Ticket.find(filter, myOptions);
|
||||
|
||||
const ticketsIds = tickets.map(ticket => ticket.id);
|
||||
|
||||
const refundedTickets = await models.Ticket.refund(ticketsIds, myOptions);
|
||||
const refundedTickets = await models.Ticket.refund(ticketsIds, true, myOptions);
|
||||
|
||||
if (tx) await tx.commit();
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ describe('InvoiceOut refund()', () => {
|
|||
try {
|
||||
const result = await models.InvoiceOut.refund('T1111111', options);
|
||||
|
||||
expect(result.length).toEqual(2);
|
||||
expect(result.length).toEqual(1);
|
||||
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
||||
|
|
|
@ -72,4 +72,45 @@ describe('upsertFixedPrice()', () => {
|
|||
throw e;
|
||||
}
|
||||
});
|
||||
|
||||
it(`should recalculate rate2 if change rate3`, async() => {
|
||||
const tx = await models.FixedPrice.beginTransaction({});
|
||||
|
||||
const tomorrow = new Date(now);
|
||||
tomorrow.setDate(tomorrow.getDate() + 1);
|
||||
|
||||
const rate2 = 2;
|
||||
const firstRate3 = 1;
|
||||
const secondRate3 = 2;
|
||||
try {
|
||||
const options = {transaction: tx};
|
||||
const ctx = {args: {
|
||||
id: undefined,
|
||||
itemFk: 1,
|
||||
warehouseFk: 1,
|
||||
started: tomorrow,
|
||||
ended: tomorrow,
|
||||
rate2: rate2,
|
||||
rate3: firstRate3,
|
||||
minPrice: 0,
|
||||
hasMinPrice: false
|
||||
}};
|
||||
|
||||
// create new fixed price
|
||||
const newFixedPrice = await models.FixedPrice.upsertFixedPrice(ctx, options);
|
||||
|
||||
// change rate3 to same fixed price id
|
||||
ctx.args.id = newFixedPrice.id;
|
||||
ctx.args.rate3 = secondRate3;
|
||||
|
||||
const result = await models.FixedPrice.upsertFixedPrice(ctx, options);
|
||||
|
||||
expect(result.rate2).not.toEqual(rate2);
|
||||
|
||||
await tx.rollback();
|
||||
} catch (e) {
|
||||
await tx.rollback();
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -72,6 +72,16 @@ module.exports = Self => {
|
|||
|
||||
try {
|
||||
delete args.ctx; // removed unwanted data
|
||||
|
||||
if (args.id) {
|
||||
const beforeFixedPrice = await models.FixedPrice.findById(args.id, {fields: ['rate3']}, myOptions);
|
||||
const [result] = await Self.rawSql(`SELECT vn.priceFixed_getRate2(?, ?) as rate2`,
|
||||
[args.id, args.rate3], myOptions);
|
||||
|
||||
if (beforeFixedPrice.rate3 != args.rate3 && result && result.rate2)
|
||||
args.rate2 = result.rate2;
|
||||
}
|
||||
|
||||
const fixedPrice = await models.FixedPrice.upsert(args, myOptions);
|
||||
const targetItem = await models.Item.findById(args.itemFk, null, myOptions);
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
const https = require('https');
|
||||
const fs = require('fs-extra');
|
||||
const path = require('path');
|
||||
const uuid = require('uuid');
|
||||
|
||||
module.exports = Self => {
|
||||
Self.remoteMethod('downloadImages', {
|
||||
|
@ -46,10 +47,8 @@ module.exports = Self => {
|
|||
|
||||
if (!image) return;
|
||||
|
||||
const srcFile = image.url;
|
||||
const fileName = srcFile.replace(/\.|\/|:|\?|\\|=|%/g, '');
|
||||
const file = `${fileName}.png`;
|
||||
const filePath = path.join(tempPath, file);
|
||||
const fileName = `${uuid.v4()}.png`;
|
||||
const filePath = path.join(tempPath, fileName);
|
||||
const imageUrl = image.url.replace('http://', 'https://');
|
||||
|
||||
https.get(imageUrl, async response => {
|
||||
|
|
|
@ -98,9 +98,8 @@ module.exports = Self => {
|
|||
summary.tags = res[1];
|
||||
[summary.botanical] = res[2];
|
||||
|
||||
const userConfig = await models.UserConfig.getUserConfig(ctx, myOptions);
|
||||
|
||||
res = await models.Item.getVisibleAvailable(summary.item.id, userConfig.warehouseFk, null, myOptions);
|
||||
const itemConfig = await models.ItemConfig.findOne(null, myOptions);
|
||||
res = await models.Item.getVisibleAvailable(summary.item.id, itemConfig.warehouseFk, undefined, myOptions);
|
||||
|
||||
summary.available = res.available;
|
||||
summary.visible = res.visible;
|
||||
|
|
|
@ -12,7 +12,7 @@ describe('item getVisibleAvailable()', () => {
|
|||
|
||||
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);
|
||||
|
||||
await tx.rollback();
|
||||
|
|
|
@ -25,6 +25,9 @@
|
|||
},
|
||||
"defaultTag": {
|
||||
"type": "int"
|
||||
},
|
||||
"warehouseFk": {
|
||||
"type": "int"
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<vn-portal slot="menu">
|
||||
<vn-item-descriptor
|
||||
warehouse-fk="$ctrl.vnConfig.warehouseFk"
|
||||
<vn-item-descriptor
|
||||
warehouse-fk="$ctrl.warehouseFk"
|
||||
item="$ctrl.item"
|
||||
card-reload="$ctrl.reload()"></vn-item-descriptor>
|
||||
<vn-left-menu source="card"></vn-left-menu>
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
<slot-before>
|
||||
<div class="photo" text-center>
|
||||
<img vn-id="photo"
|
||||
ng-src="{{$root.imagePath('catalog', '200x200', $ctrl.item.id)}}"
|
||||
ng-src="{{$root.imagePath('catalog', '200x200', $ctrl.item.id)}}"
|
||||
zoom-image="{{$root.imagePath('catalog', '1600x900', $ctrl.item.id)}}"
|
||||
on-error-src/>
|
||||
<vn-float-button ng-click="uploadPhoto.show('catalog', $ctrl.item.id)"
|
||||
|
@ -36,13 +36,23 @@
|
|||
<p translate>Available</p>
|
||||
<p>{{$ctrl.available | dashIfEmpty}}</p>
|
||||
</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>
|
||||
</slot-before>
|
||||
<slot-body>
|
||||
<div class="attributes">
|
||||
<vn-label-value
|
||||
label="Buyer">
|
||||
<span
|
||||
<span
|
||||
ng-click="workerDescriptor.show($event, $ctrl.item.itemType.worker.userFk)"
|
||||
class="link">
|
||||
{{$ctrl.item.itemType.worker.user.name}}
|
||||
|
@ -50,22 +60,22 @@
|
|||
</vn-label-value>
|
||||
<vn-label-value
|
||||
label="{{$ctrl.item.tag5}}"
|
||||
ng-if="$ctrl.item.value5"
|
||||
ng-if="$ctrl.item.value5"
|
||||
value="{{$ctrl.item.value5}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value
|
||||
label="{{$ctrl.item.tag6}}"
|
||||
ng-if="$ctrl.item.value6"
|
||||
label="{{$ctrl.item.tag6}}"
|
||||
ng-if="$ctrl.item.value6"
|
||||
value="{{$ctrl.item.value6}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value
|
||||
label="{{$ctrl.item.tag7}}"
|
||||
ng-if="$ctrl.item.value7"
|
||||
label="{{$ctrl.item.tag7}}"
|
||||
ng-if="$ctrl.item.value7"
|
||||
value="{{$ctrl.item.value7}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value
|
||||
label="{{$ctrl.item.tag8}}"
|
||||
ng-if="$ctrl.item.value8"
|
||||
label="{{$ctrl.item.tag8}}"
|
||||
ng-if="$ctrl.item.value8"
|
||||
value="{{$ctrl.item.value8}}">
|
||||
</vn-label-value>
|
||||
</div>
|
||||
|
@ -112,7 +122,7 @@
|
|||
question="Do you want to clone this item?"
|
||||
message="All it's properties will be copied">
|
||||
</vn-confirm>
|
||||
<vn-worker-descriptor-popover
|
||||
<vn-worker-descriptor-popover
|
||||
vn-id="workerDescriptor">
|
||||
</vn-worker-descriptor-popover>
|
||||
<vn-popup vn-id="summary">
|
||||
|
@ -120,7 +130,7 @@
|
|||
</vn-popup>
|
||||
|
||||
<!-- Upload photo dialog -->
|
||||
<vn-upload-photo
|
||||
vn-id="uploadPhoto"
|
||||
<vn-upload-photo
|
||||
vn-id="uploadPhoto"
|
||||
on-response="$ctrl.onUploadResponse()">
|
||||
</vn-upload-photo>
|
||||
</vn-upload-photo>
|
||||
|
|
|
@ -30,7 +30,10 @@ class Controller extends Descriptor {
|
|||
|
||||
set warehouseFk(value) {
|
||||
this._warehouseFk = value;
|
||||
if (value) this.updateStock();
|
||||
if (value) {
|
||||
this.updateStock();
|
||||
this.getWarehouseName(value);
|
||||
}
|
||||
}
|
||||
|
||||
loadData() {
|
||||
|
@ -89,6 +92,22 @@ class Controller extends Descriptor {
|
|||
this.$.photo.setAttribute('src', newSrc);
|
||||
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'];
|
||||
|
@ -100,6 +119,6 @@ ngModule.vnComponent('vnItemDescriptor', {
|
|||
item: '<',
|
||||
dated: '<',
|
||||
cardReload: '&',
|
||||
warehouseFk: '<?'
|
||||
warehouseFk: '<'
|
||||
}
|
||||
});
|
||||
|
|
|
@ -37,6 +37,7 @@ class Controller extends Section {
|
|||
set warehouseFk(value) {
|
||||
if (value && value != this._warehouseFk) {
|
||||
this._warehouseFk = value;
|
||||
this.card.warehouseFk = value;
|
||||
|
||||
this.$state.go(this.$state.current.name, {
|
||||
warehouseFk: value
|
||||
|
@ -76,5 +77,8 @@ ngModule.vnComponent('vnItemDiary', {
|
|||
controller: Controller,
|
||||
bindings: {
|
||||
item: '<'
|
||||
},
|
||||
require: {
|
||||
card: '?^vnItemCard'
|
||||
}
|
||||
});
|
||||
|
|
|
@ -14,6 +14,7 @@ describe('Item', () => {
|
|||
controller = $componentController('vnItemDiary', {$element, $scope});
|
||||
controller.$.model = crudModel;
|
||||
controller.$params = {id: 1};
|
||||
controller.card = {};
|
||||
}));
|
||||
|
||||
describe('set item()', () => {
|
||||
|
|
|
@ -131,7 +131,7 @@
|
|||
class="dense"
|
||||
vn-focus
|
||||
ng-model="price.rate3"
|
||||
on-change="$ctrl.upsertPrice(price); $ctrl.recalculateRate2(price)"
|
||||
on-change="$ctrl.upsertPrice(price);"
|
||||
step="0.01"s>
|
||||
</vn-input-number>
|
||||
</field>
|
||||
|
|
|
@ -113,24 +113,6 @@ export default class Controller extends Section {
|
|||
return {[param]: value};
|
||||
}
|
||||
}
|
||||
|
||||
recalculateRate2(price) {
|
||||
if (!price.id || !price.rate3) return;
|
||||
|
||||
const query = 'FixedPrices/getRate2';
|
||||
const params = {
|
||||
fixedPriceId: price.id,
|
||||
rate3: price.rate3
|
||||
};
|
||||
this.$http.get(query, {params})
|
||||
.then(res => {
|
||||
const rate2 = res.data.rate2;
|
||||
if (rate2) {
|
||||
price.rate2 = rate2;
|
||||
this.upsertPrice(price);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.vnComponent('vnFixedPrice', {
|
||||
|
|
|
@ -85,25 +85,5 @@ describe('fixed price', () => {
|
|||
expect(controller.$.model.remove).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('recalculateRate2()', () => {
|
||||
it(`should rate2 recalculate`, () => {
|
||||
jest.spyOn(controller.vnApp, 'showSuccess');
|
||||
const price = {
|
||||
id: 1,
|
||||
itemFk: 1,
|
||||
rate2: 2,
|
||||
rate3: 2
|
||||
};
|
||||
const response = {rate2: 1};
|
||||
controller.recalculateRate2(price);
|
||||
|
||||
const query = `FixedPrices/getRate2?fixedPriceId=${price.id}&rate3=${price.rate3}`;
|
||||
$httpBackend.expectGET(query).respond(response);
|
||||
$httpBackend.flush();
|
||||
|
||||
expect(price.rate2).toEqual(response.rate2);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
<vn-card class="vn-w-md vn-pa-md">
|
||||
<vn-horizontal>
|
||||
<vn-date-picker class="vn-pa-xs"
|
||||
vn-one
|
||||
label="Since"
|
||||
vn-one
|
||||
label="Since"
|
||||
ng-model="$ctrl.dateFrom">
|
||||
|
@ -35,7 +37,7 @@
|
|||
<vn-th field="warehouseFk">Warehouse</vn-th>
|
||||
<vn-th field="landed">Landed</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>Packing</vn-th>
|
||||
<vn-th number>Grouping</vn-th>
|
||||
|
@ -64,7 +66,7 @@
|
|||
{{::entry.entryFk | dashIfEmpty}}
|
||||
</span>
|
||||
</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}}
|
||||
</vn-td>
|
||||
<vn-td number class="expendable">{{entry.stickers | dashIfEmpty}}</vn-td>
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<vn-horizontal>
|
||||
<vn-one>
|
||||
<img style="width: 100%; display: block;"
|
||||
ng-src="{{$root.imagePath('catalog', '200x200', $ctrl.item.id)}}"
|
||||
ng-src="{{$root.imagePath('catalog', '200x200', $ctrl.item.id)}}"
|
||||
zoom-image="{{$root.imagePath('catalog', '1600x900', $ctrl.item.id)}}" on-error-src/>
|
||||
<vn-horizontal class="item-state">
|
||||
<vn-one>
|
||||
|
@ -22,44 +22,54 @@
|
|||
<p translate>Available</p>
|
||||
<p>{{$ctrl.summary.available}}</p>
|
||||
</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-one>
|
||||
<vn-one name="basicData">
|
||||
<h4 ng-show="$ctrl.isBuyer">
|
||||
<a
|
||||
<a
|
||||
ui-sref="item.card.basicData({id:$ctrl.item.id})"
|
||||
target="_self">
|
||||
<span translate vn-tooltip="Go to">Basic data</span>
|
||||
</a>
|
||||
</h4>
|
||||
<h4
|
||||
translate
|
||||
translate
|
||||
ng-show="!$ctrl.isBuyer">
|
||||
Basic data
|
||||
</h4>
|
||||
<vn-label-value label="Name"
|
||||
value="{{$ctrl.summary.item.name}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value label="Full name"
|
||||
<vn-label-value label="Full name"
|
||||
value="{{$ctrl.summary.item.longName}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value label="Item family"
|
||||
<vn-label-value label="Item family"
|
||||
value="{{$ctrl.summary.item.itemType.name}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value label="Size"
|
||||
<vn-label-value label="Size"
|
||||
value="{{$ctrl.summary.item.size}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value label="Origin"
|
||||
<vn-label-value label="Origin"
|
||||
value="{{$ctrl.summary.item.origin.name}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value label="stems"
|
||||
<vn-label-value label="stems"
|
||||
value="{{$ctrl.summary.item.stems}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value label="Multiplier"
|
||||
<vn-label-value label="Multiplier"
|
||||
value="{{$ctrl.summary.item.stemMultiplier}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value label="Buyer">
|
||||
<span
|
||||
<span
|
||||
ng-click="workerDescriptor.show($event, $ctrl.summary.item.itemType.worker.userFk)"
|
||||
class="link">
|
||||
{{$ctrl.summary.item.itemType.worker.user.name}}
|
||||
|
@ -68,45 +78,45 @@
|
|||
</vn-one>
|
||||
<vn-one name="otherData">
|
||||
<h4 ng-show="$ctrl.isBuyer">
|
||||
<a
|
||||
<a
|
||||
ui-sref="item.card.basicData({id:$ctrl.item.id})"
|
||||
target="_self">
|
||||
<span translate vn-tooltip="Go to">Other data</span>
|
||||
</a>
|
||||
</h4>
|
||||
<h4
|
||||
translate
|
||||
translate
|
||||
ng-show="!$ctrl.isBuyer">
|
||||
Other data
|
||||
</h4>
|
||||
<vn-label-value label="Intrastat code"
|
||||
<vn-label-value label="Intrastat code"
|
||||
value="{{$ctrl.summary.item.intrastat.id}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value label="Intrastat"
|
||||
<vn-label-value label="Intrastat"
|
||||
value="{{$ctrl.summary.item.intrastat.description}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value label="Reference"
|
||||
<vn-label-value label="Reference"
|
||||
value="{{$ctrl.summary.item.comment}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value label="Relevancy"
|
||||
<vn-label-value label="Relevancy"
|
||||
value="{{$ctrl.summary.item.relevancy}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value label="Weight/Piece"
|
||||
<vn-label-value label="Weight/Piece"
|
||||
value="{{$ctrl.summary.item.weightByPiece}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value label="Expense"
|
||||
<vn-label-value label="Expense"
|
||||
value="{{$ctrl.summary.item.expense.name}}">
|
||||
</vn-label-value>
|
||||
</vn-one>
|
||||
<vn-one name="tags">
|
||||
<h4 ng-show="$ctrl.isBuyer || $ctrl.isReplenisher">
|
||||
<a
|
||||
<a
|
||||
ui-sref="item.card.tags({id:$ctrl.item.id})"
|
||||
target="_self">
|
||||
<span translate vn-tooltip="Go to">Tags</span>
|
||||
</a>
|
||||
</h4>
|
||||
<h4
|
||||
<h4
|
||||
translate
|
||||
ng-show="!$ctrl.isBuyer && !$ctrl.isReplenisher">
|
||||
Tags
|
||||
|
@ -119,14 +129,14 @@
|
|||
</vn-one>
|
||||
<vn-one name="description" ng-if="$ctrl.summary.item.description">
|
||||
<h4 ng-show="$ctrl.isBuyer">
|
||||
<a
|
||||
<a
|
||||
ui-sref="item.card.basicData({id:$ctrl.item.id})"
|
||||
target="_self">
|
||||
<span translate vn-tooltip="Go to">Description</span>
|
||||
</a>
|
||||
</h4>
|
||||
<h4
|
||||
translate
|
||||
translate
|
||||
ng-show="!$ctrl.isBuyer">
|
||||
Description
|
||||
</h4>
|
||||
|
@ -136,13 +146,13 @@
|
|||
</vn-one>
|
||||
<vn-one name="tax">
|
||||
<h4 ng-show="$ctrl.isBuyer || $ctrl.isAdministrative">
|
||||
<a
|
||||
<a
|
||||
ui-sref="item.card.tax({id:$ctrl.item.id})"
|
||||
target="_self">
|
||||
<span translate vn-tooltip="Go to">Tax</span>
|
||||
</a>
|
||||
</h4>
|
||||
<h4
|
||||
<h4
|
||||
translate
|
||||
ng-show="!$ctrl.isBuyer && !$ctrl.isAdministrative">
|
||||
Tax
|
||||
|
@ -154,33 +164,33 @@
|
|||
</vn-one>
|
||||
<vn-one name="botanical">
|
||||
<h4 ng-show="$ctrl.isBuyer">
|
||||
<a
|
||||
<a
|
||||
ui-sref="item.card.botanical({id:$ctrl.item.id})"
|
||||
target="_self">
|
||||
<span translate vn-tooltip="Go to">Botanical</span>
|
||||
</a>
|
||||
</h4>
|
||||
<h4
|
||||
<h4
|
||||
translate
|
||||
ng-show="!$ctrl.isBuyer">
|
||||
Botanical
|
||||
</h4>
|
||||
<vn-label-value label="Genus"
|
||||
<vn-label-value label="Genus"
|
||||
value="{{$ctrl.summary.botanical.genus.name}}">
|
||||
</vn-label-value>
|
||||
<vn-label-value label="Specie"
|
||||
<vn-label-value label="Specie"
|
||||
value="{{$ctrl.summary.botanical.specie.name}}">
|
||||
</vn-label-value>
|
||||
</vn-one>
|
||||
<vn-one name="barcode">
|
||||
<h4 ng-show="$ctrl.isBuyer || $ctrl.isReplenisher">
|
||||
<a
|
||||
<a
|
||||
ui-sref="item.card.itemBarcode({id:$ctrl.item.id})"
|
||||
target="_self">
|
||||
<span translate vn-tooltip="Go to">Barcode</span>
|
||||
</a>
|
||||
</h4>
|
||||
<h4
|
||||
<h4
|
||||
translate
|
||||
ng-show="!$ctrl.isBuyer && !$ctrl.isReplenisher">
|
||||
Barcode
|
||||
|
@ -191,6 +201,6 @@
|
|||
</vn-one>
|
||||
</vn-horizontal>
|
||||
</vn-card>
|
||||
<vn-worker-descriptor-popover
|
||||
<vn-worker-descriptor-popover
|
||||
vn-id="workerDescriptor">
|
||||
</vn-worker-descriptor-popover>
|
||||
</vn-worker-descriptor-popover>
|
||||
|
|
|
@ -7,6 +7,24 @@ class Controller extends Summary {
|
|||
this.$http.get(`Items/${this.item.id}/getSummary`).then(response => {
|
||||
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() {
|
||||
|
@ -37,4 +55,7 @@ ngModule.vnComponent('vnItemSummary', {
|
|||
bindings: {
|
||||
item: '<',
|
||||
},
|
||||
require: {
|
||||
card: '?^vnItemCard'
|
||||
}
|
||||
});
|
||||
|
|
|
@ -14,12 +14,15 @@ describe('Item', () => {
|
|||
const $element = angular.element('<vn-item-summary></vn-item-summary>');
|
||||
controller = $componentController('vnItemSummary', {$element, $scope});
|
||||
controller.item = {id: 1};
|
||||
controller.card = {};
|
||||
}));
|
||||
|
||||
describe('getSummary()', () => {
|
||||
it('should perform a query to set summary', () => {
|
||||
let data = {id: 1, name: 'Gem of mind'};
|
||||
$httpBackend.expect('GET', `Items/1/getSummary`).respond(200, data);
|
||||
$httpBackend.expect('GET', `ItemConfigs/findOne`).respond({});
|
||||
$httpBackend.expect('GET', `Warehouses/findOne`).respond({});
|
||||
controller.getSummary();
|
||||
$httpBackend.flush();
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
WarehouseFk: Calculated on the warehouse of {{ warehouseName }}
|
|
@ -1,3 +1,4 @@
|
|||
Barcode: Códigos de barras
|
||||
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 }}
|
||||
|
|
|
@ -29,7 +29,11 @@ vn-item-summary {
|
|||
padding: 0;
|
||||
|
||||
&: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.$.watcher.notifySaved();
|
||||
this.$.watcher.updateOriginalData();
|
||||
this.card.reload();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,11 @@ module.exports = Self => {
|
|||
type: 'string',
|
||||
required: true,
|
||||
description: `The old version number`
|
||||
}, {
|
||||
arg: 'description',
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: `The description of changes`
|
||||
}, {
|
||||
arg: 'unlock',
|
||||
type: 'boolean',
|
||||
|
@ -42,8 +47,7 @@ module.exports = Self => {
|
|||
verb: 'POST'
|
||||
}
|
||||
});
|
||||
|
||||
Self.upload = async(ctx, appName, toVersion, branch, fromVersion, unlock, options) => {
|
||||
Self.upload = async(ctx, options) => {
|
||||
const models = Self.app.models;
|
||||
const myOptions = {};
|
||||
const $t = ctx.req.__; // $translate
|
||||
|
@ -51,6 +55,12 @@ module.exports = Self => {
|
|||
const AccessContainer = models.AccessContainer;
|
||||
const fileOptions = {};
|
||||
let tx;
|
||||
const appName = ctx.args.appName;
|
||||
const toVersion = ctx.args.toVersion;
|
||||
const branch = ctx.args.branch;
|
||||
const fromVersion = ctx.args.fromVersion;
|
||||
let description = ctx.args.description;
|
||||
const unlock = ctx.args.unlock;
|
||||
|
||||
if (typeof options == 'object')
|
||||
Object.assign(myOptions, options);
|
||||
|
@ -132,13 +142,46 @@ module.exports = Self => {
|
|||
await fs.symlink(rootRelative, destinationRoot);
|
||||
}
|
||||
}
|
||||
if (description) {
|
||||
let formatDesc;
|
||||
const mainBranches = new Set(['master', 'test', 'dev']);
|
||||
if (mainBranches.has(branch))
|
||||
formatDesc = `> :branch_${branch}: `;
|
||||
else
|
||||
formatDesc = `> :branch: `;
|
||||
|
||||
formatDesc += `*${appName.toUpperCase()}* v.${toVersion} `;
|
||||
|
||||
const oldVersion = await models.MdbVersionTree.findOne({
|
||||
where: {version: fromVersion},
|
||||
fields: ['branchFk']
|
||||
}, myOptions);
|
||||
|
||||
if (branch == oldVersion.branchFk)
|
||||
formatDesc += `[*${branch}*]: `;
|
||||
else
|
||||
formatDesc += `[*${oldVersion.branchFk}* » *${branch}*]: `;
|
||||
|
||||
const params = await models.MdbConfig.findOne(myOptions);
|
||||
const issueTrackerUrl = params.issueTrackerUrl;
|
||||
const issueNumberRegex = params.issueNumberRegex;
|
||||
const chatDestination = params.chatDestination;
|
||||
|
||||
const regex = new RegExp(issueNumberRegex, 'g');
|
||||
formatDesc += description.replace(regex, (match, issueId) => {
|
||||
const newUrl = issueTrackerUrl.replace('{index}', issueId);
|
||||
return `[#${issueId}](${newUrl})`;
|
||||
});
|
||||
|
||||
await models.Chat.send(ctx, chatDestination, formatDesc, myOptions);
|
||||
}
|
||||
await models.MdbVersionTree.create({
|
||||
app: appName,
|
||||
version: toVersion,
|
||||
branchFk: branch,
|
||||
fromVersion,
|
||||
userFk: userId
|
||||
userFk: userId,
|
||||
description,
|
||||
}, myOptions);
|
||||
|
||||
await models.MdbVersion.upsert({
|
||||
|
|
|
@ -11,6 +11,9 @@
|
|||
"MdbVersionTree": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"MdbConfig": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"AccessContainer": {
|
||||
"dataSource": "accessStorage"
|
||||
}
|
||||
|
|
|
@ -11,6 +11,11 @@
|
|||
"id": true,
|
||||
"type": "string",
|
||||
"description": "Identifier"
|
||||
},
|
||||
"dsName": {
|
||||
"id": true,
|
||||
"type": "string",
|
||||
"description": "ODBC name"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"name": "MdbConfig",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "mdbConfig"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string",
|
||||
"id": true
|
||||
},
|
||||
"issueTrackerUrl": {
|
||||
"type": "string"
|
||||
},
|
||||
"issueNumberRegex": {
|
||||
"type": "string"
|
||||
},
|
||||
"chatDestination": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,6 +23,9 @@
|
|||
},
|
||||
"userFk": {
|
||||
"type": "number"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
<vn-td number>
|
||||
<span ng-click="itemDescriptor.show($event, row.itemFk)"
|
||||
class="link">
|
||||
{{::row.itemFk | zeroFill:6}}
|
||||
{{::row.itemFk}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td vn-fetched-tags>
|
||||
|
|
|
@ -95,7 +95,7 @@
|
|||
<span
|
||||
ng-click="itemDescriptor.show($event, row.itemFk)"
|
||||
class="link">
|
||||
{{::row.itemFk | zeroFill:6}}
|
||||
{{::row.itemFk}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td vn-fetched-tags>
|
||||
|
|
|
@ -29,5 +29,12 @@
|
|||
"pickingOrder": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
"saleGroup": {
|
||||
"type": "hasMany",
|
||||
"model": "saleGroup",
|
||||
"foreignKey": "parkingFk"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,3 +21,5 @@ companyFk: empresa
|
|||
agencyModeFk: agencia
|
||||
ticketFk: ticket
|
||||
mergedTicket: ticket fusionado
|
||||
withWarningAccept: aviso negativos
|
||||
isWithoutNegatives: sin negativos
|
||||
|
|
|
@ -12,6 +12,11 @@ module.exports = Self => {
|
|||
arg: 'servicesIds',
|
||||
type: ['number']
|
||||
},
|
||||
{
|
||||
arg: 'createSingleTicket',
|
||||
type: 'boolean',
|
||||
required: false
|
||||
}
|
||||
],
|
||||
returns: {
|
||||
type: ['number'],
|
||||
|
@ -23,7 +28,7 @@ module.exports = Self => {
|
|||
}
|
||||
});
|
||||
|
||||
Self.refund = async(salesIds, servicesIds, options) => {
|
||||
Self.refund = async(salesIds, servicesIds, createSingleTicket = false, options) => {
|
||||
const models = Self.app.models;
|
||||
const myOptions = {};
|
||||
let tx;
|
||||
|
@ -63,38 +68,37 @@ module.exports = Self => {
|
|||
const ticketsIds = [...new Set(sales.map(sale => sale.ticketFk))];
|
||||
|
||||
const refundTickets = [];
|
||||
|
||||
const now = Date.vnNew();
|
||||
const mappedTickets = new Map();
|
||||
const now = Date.vnNew();
|
||||
|
||||
for (let ticketId of ticketsIds) {
|
||||
const filter = {include: {relation: 'address'}};
|
||||
const ticket = await models.Ticket.findById(ticketId, filter, myOptions);
|
||||
|
||||
const refundTicket = await models.Ticket.create({
|
||||
clientFk: ticket.clientFk,
|
||||
shipped: now,
|
||||
addressFk: ticket.address().id,
|
||||
agencyModeFk: refundAgencyMode.id,
|
||||
nickname: ticket.address().nickname,
|
||||
warehouseFk: ticket.warehouseFk,
|
||||
companyFk: ticket.companyFk,
|
||||
landed: now,
|
||||
zoneFk: refoundZoneId
|
||||
}, myOptions);
|
||||
|
||||
refundTickets.push(refundTicket);
|
||||
|
||||
mappedTickets.set(ticketId, refundTicket.id);
|
||||
|
||||
await models.TicketRefund.create({
|
||||
refundTicketFk: refundTicket.id,
|
||||
originalTicketFk: ticket.id,
|
||||
}, myOptions);
|
||||
const [firstTicketId] = ticketsIds;
|
||||
if (createSingleTicket) {
|
||||
await createTicketRefund(
|
||||
firstTicketId,
|
||||
refundTickets,
|
||||
mappedTickets,
|
||||
now,
|
||||
refundAgencyMode,
|
||||
refoundZoneId,
|
||||
myOptions
|
||||
);
|
||||
} else {
|
||||
for (let ticketId of ticketsIds) {
|
||||
await createTicketRefund(
|
||||
ticketId,
|
||||
refundTickets,
|
||||
mappedTickets,
|
||||
now,
|
||||
refundAgencyMode,
|
||||
refoundZoneId,
|
||||
myOptions
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for (const sale of sales) {
|
||||
const refundTicketId = mappedTickets.get(sale.ticketFk);
|
||||
const refundTicketId = await getTicketRefundId(createSingleTicket, sale.ticketFk, refundTickets, mappedTickets);
|
||||
|
||||
const createdSale = await models.Sale.create({
|
||||
ticketFk: refundTicketId,
|
||||
itemFk: sale.itemFk,
|
||||
|
@ -118,7 +122,7 @@ module.exports = Self => {
|
|||
const services = await models.TicketService.find(servicesFilter, myOptions);
|
||||
|
||||
for (const service of services) {
|
||||
const refundTicketId = mappedTickets.get(service.ticketFk);
|
||||
const refundTicketId = await getTicketRefundId(createSingleTicket, service.ticketFk, refundTickets, mappedTickets);
|
||||
|
||||
await models.TicketService.create({
|
||||
description: service.description,
|
||||
|
@ -139,4 +143,47 @@ module.exports = Self => {
|
|||
throw e;
|
||||
}
|
||||
};
|
||||
|
||||
async function createTicketRefund(
|
||||
ticketId,
|
||||
refundTickets,
|
||||
mappedTickets,
|
||||
now,
|
||||
refundAgencyMode,
|
||||
refoundZoneId,
|
||||
myOptions
|
||||
) {
|
||||
const models = Self.app.models;
|
||||
|
||||
const filter = {include: {relation: 'address'}};
|
||||
const ticket = await models.Ticket.findById(ticketId, filter, myOptions);
|
||||
|
||||
const refundTicket = await models.Ticket.create({
|
||||
clientFk: ticket.clientFk,
|
||||
shipped: now,
|
||||
addressFk: ticket.address().id,
|
||||
agencyModeFk: refundAgencyMode.id,
|
||||
nickname: ticket.address().nickname,
|
||||
warehouseFk: ticket.warehouseFk,
|
||||
companyFk: ticket.companyFk,
|
||||
landed: now,
|
||||
zoneFk: refoundZoneId
|
||||
}, myOptions);
|
||||
|
||||
refundTickets.push(refundTicket);
|
||||
|
||||
mappedTickets.set(ticketId, refundTicket.id);
|
||||
|
||||
await models.TicketRefund.create({
|
||||
refundTicketFk: refundTicket.id,
|
||||
originalTicketFk: ticket.id,
|
||||
}, myOptions);
|
||||
}
|
||||
|
||||
async function getTicketRefundId(createSingleTicket, ticketId, refundTickets, mappedTickets) {
|
||||
if (createSingleTicket) {
|
||||
const [firstRefundTicket] = refundTickets;
|
||||
return firstRefundTicket.id;
|
||||
} else return mappedTickets.get(ticketId);
|
||||
}
|
||||
};
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue