232201_test_to_master #1582
35
CHANGELOG.md
35
CHANGELOG.md
|
@ -5,17 +5,48 @@ All notable changes to this project will be documented in this file.
|
||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
## [2316.01] - 2023-05-04
|
## [2322.01] - 2023-06-08
|
||||||
|
|
||||||
|
### Added
|
||||||
|
-
|
||||||
|
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
-
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
-
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [2320.01] - 2023-05-25
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- (Tickets -> Crear Factura) Al facturar se envia automáticamente el pdf al cliente
|
||||||
|
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- (Trabajadores -> Nuevo trabajador) Los clientes se crean sin 'TR' pero se añade tipo de negocio 'Trabajador'
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
-
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## [2318.01] - 2023-05-08
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
- (Usuarios -> Histórico) Nueva sección
|
- (Usuarios -> Histórico) Nueva sección
|
||||||
- (Roles -> Histórico) Nueva sección
|
- (Roles -> Histórico) Nueva sección
|
||||||
|
- (General -> Traducciones) Correo de bienvenida a clientes al portugués y al francés
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- (Artículo -> Precio fijado) Modificado el buscador superior por uno lateral
|
- (Artículo -> Precio fijado) Modificado el buscador superior por uno lateral
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
-
|
- (Ticket -> Boxing) Arreglado selección de horas
|
||||||
|
- (Cesta -> Índice) Optimizada búsqueda
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [2314.01] - 2023-04-20
|
## [2314.01] - 2023-04-20
|
||||||
|
|
|
@ -34,6 +34,8 @@ async function test() {
|
||||||
app.boot(bootOptions,
|
app.boot(bootOptions,
|
||||||
err => err ? reject(err) : resolve());
|
err => err ? reject(err) : resolve());
|
||||||
});
|
});
|
||||||
|
// FIXME: Workaround to wait for loopback to be ready
|
||||||
|
await app.models.Application.status();
|
||||||
|
|
||||||
const Jasmine = require('jasmine');
|
const Jasmine = require('jasmine');
|
||||||
const jasmine = new Jasmine();
|
const jasmine = new Jasmine();
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
UPDATE vn.supplier s
|
|
||||||
JOIN vn.country c ON c.id = s.countryFk
|
|
||||||
SET s.nif = MID(REPLACE(s.nif, ' ', ''), 3, LENGTH(REPLACE(s.nif, ' ', '')) - 1)
|
|
||||||
WHERE s.isVies = TRUE
|
|
||||||
AND c.code = LEFT(REPLACE(s.nif, ' ', ''), 2);
|
|
|
@ -1,5 +0,0 @@
|
||||||
UPDATE IGNORE vn.client c
|
|
||||||
JOIN vn.country co ON co.id = c.countryFk
|
|
||||||
SET c.fi = MID(REPLACE(c.fi, ' ', ''), 3, LENGTH(REPLACE(c.fi, ' ', '')) - 1)
|
|
||||||
WHERE c.isVies = TRUE
|
|
||||||
AND co.code = LEFT(REPLACE(c.fi, ' ', ''), 2);
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
CREATE OR REPLACE
|
||||||
|
ALGORITHM = UNDEFINED VIEW `vn`.`zoneEstimatedDelivery` AS
|
||||||
|
select
|
||||||
|
`t`.`zoneFk` AS `zoneFk`,
|
||||||
|
cast(`util`.`VN_CURDATE`() + interval hour(ifnull(`zc`.`hour`, `z`.`hour`)) * 60 + minute(ifnull(`zc`.`hour`, `z`.`hour`)) minute as time) AS `hourTheoretical`,
|
||||||
|
cast(sum(`sv`.`volume`) as decimal(5, 1)) AS `totalVolume`,
|
||||||
|
cast(sum(if(`s`.`alertLevel` < 2, `sv`.`volume`, 0)) as decimal(5, 1)) AS `remainingVolume`,
|
||||||
|
greatest(
|
||||||
|
ifnull(`lhp`.`m3`, 0),
|
||||||
|
ifnull(`dl`.`minSpeed`, 0)
|
||||||
|
) AS `speed`,
|
||||||
|
cast(`zc`.`hour` + interval -sum(if(`s`.`alertLevel` < 2, `sv`.`volume`, 0)) * 60 / greatest(ifnull(`lhp`.`m3`, 0), ifnull(`dl`.`minSpeed`, 0)) minute as time) AS `hourEffective`,
|
||||||
|
floor(-sum(if(`s`.`alertLevel` < 2, `sv`.`volume`, 0)) * 60 / greatest(ifnull(`lhp`.`m3`, 0), ifnull(`dl`.`minSpeed`, 0))) AS `minutesLess`,
|
||||||
|
cast(`zc`.`hour` + interval -sum(if(`s`.`alertLevel` < 2, `sv`.`volume`, 0)) * 60 / greatest(ifnull(`lhp`.`m3`, 0), ifnull(`dl`.`minSpeed`, 0)) minute as time) AS `etc`
|
||||||
|
from
|
||||||
|
(
|
||||||
|
(
|
||||||
|
(
|
||||||
|
(
|
||||||
|
(
|
||||||
|
(
|
||||||
|
(
|
||||||
|
(
|
||||||
|
(
|
||||||
|
`vn`.`ticket` `t`
|
||||||
|
join `vn`.`ticketStateToday` `tst` on
|
||||||
|
(
|
||||||
|
`tst`.`ticket` = `t`.`id`
|
||||||
|
)
|
||||||
|
)
|
||||||
|
join `vn`.`state` `s` on
|
||||||
|
(
|
||||||
|
`s`.`id` = `tst`.`state`
|
||||||
|
)
|
||||||
|
)
|
||||||
|
join `vn`.`saleVolume` `sv` on
|
||||||
|
(
|
||||||
|
`sv`.`ticketFk` = `t`.`id`
|
||||||
|
)
|
||||||
|
)
|
||||||
|
left join `vn`.`lastHourProduction` `lhp` on
|
||||||
|
(
|
||||||
|
`lhp`.`warehouseFk` = `t`.`warehouseFk`
|
||||||
|
)
|
||||||
|
)
|
||||||
|
join `vn`.`warehouse` `w` on
|
||||||
|
(
|
||||||
|
`w`.`id` = `t`.`warehouseFk`
|
||||||
|
)
|
||||||
|
)
|
||||||
|
join `vn`.`warehouseAlias` `wa` on
|
||||||
|
(
|
||||||
|
`wa`.`id` = `w`.`aliasFk`
|
||||||
|
)
|
||||||
|
)
|
||||||
|
straight_join `vn`.`zone` `z` on
|
||||||
|
(
|
||||||
|
`z`.`id` = `t`.`zoneFk`
|
||||||
|
)
|
||||||
|
)
|
||||||
|
left join `vn`.`zoneClosure` `zc` on
|
||||||
|
(
|
||||||
|
`zc`.`zoneFk` = `t`.`zoneFk`
|
||||||
|
and `zc`.`dated` = `util`.`VN_CURDATE`()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
left join `cache`.`departure_limit` `dl` on
|
||||||
|
(
|
||||||
|
`dl`.`warehouse_id` = `t`.`warehouseFk`
|
||||||
|
and `dl`.`fecha` = `util`.`VN_CURDATE`()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
where
|
||||||
|
`w`.`hasProduction` <> 0
|
||||||
|
and cast(`t`.`shipped` as date) = `util`.`VN_CURDATE`()
|
||||||
|
group by
|
||||||
|
`t`.`zoneFk`;
|
|
@ -0,0 +1,5 @@
|
||||||
|
UPDATE `vn`.`supplier` s
|
||||||
|
JOIN `vn`.`country` c ON c.id = s.countryFk
|
||||||
|
SET s.nif = MID(REPLACE(s.nif, ' ', ''), 3, LENGTH(REPLACE(s.nif, ' ', '')) - 1)
|
||||||
|
WHERE s.isVies = TRUE
|
||||||
|
AND c.code = LEFT(REPLACE(s.nif, ' ', ''), 2);
|
|
@ -0,0 +1,5 @@
|
||||||
|
UPDATE IGNORE `vn`.`client` c
|
||||||
|
JOIN `vn`.`country` co ON co.id = c.countryFk
|
||||||
|
SET c.fi = MID(REPLACE(c.fi, ' ', ''), 3, LENGTH(REPLACE(c.fi, ' ', '')) - 1)
|
||||||
|
WHERE c.isVies = TRUE
|
||||||
|
AND co.code = LEFT(REPLACE(c.fi, ' ', ''), 2);
|
|
@ -0,0 +1,12 @@
|
||||||
|
-- vn.companyL10n source
|
||||||
|
|
||||||
|
CREATE OR REPLACE
|
||||||
|
ALGORITHM = UNDEFINED VIEW `vn`.`companyL10n` AS
|
||||||
|
select
|
||||||
|
`c`.`id` AS `id`,
|
||||||
|
ifnull(`ci`.`footnotes`, `c`.`footnotes`) AS `footnotes`
|
||||||
|
from
|
||||||
|
(`vn`.`company` `c`
|
||||||
|
left join `vn`.`companyI18n` `ci` on
|
||||||
|
(`ci`.`companyFk` = `c`.`id`
|
||||||
|
and `ci`.`lang` = `util`.`LANG`()));
|
|
@ -0,0 +1,73 @@
|
||||||
|
DELIMITER $$
|
||||||
|
CREATE OR REPLACE DEFINER=`root`@`localhost` PROCEDURE `vn`.`clientCreate`(
|
||||||
|
vFirstname VARCHAR(50),
|
||||||
|
vSurnames VARCHAR(50),
|
||||||
|
vFi VARCHAR(9),
|
||||||
|
vAddress TEXT,
|
||||||
|
vPostcode CHAR(5),
|
||||||
|
vCity VARCHAR(25),
|
||||||
|
vProvinceFk SMALLINT(5),
|
||||||
|
vCompanyFk SMALLINT(5),
|
||||||
|
vPhone VARCHAR(11),
|
||||||
|
vEmail VARCHAR(255),
|
||||||
|
vUserFk INT)
|
||||||
|
BEGIN
|
||||||
|
/**
|
||||||
|
* Create new client
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
DECLARE vPayMethodFk INT DEFAULT 4;
|
||||||
|
DECLARE vDueDay INT DEFAULT 5;
|
||||||
|
DECLARE vDefaultCredit DECIMAL(10, 2) DEFAULT 300.00;
|
||||||
|
DECLARE vIsTaxDataChecked TINYINT(1) DEFAULT 1;
|
||||||
|
DECLARE vHasCoreVnl BOOLEAN DEFAULT TRUE;
|
||||||
|
DECLARE vMandateTypeFk INT DEFAULT 2;
|
||||||
|
|
||||||
|
INSERT INTO `client` (
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
street,
|
||||||
|
fi,
|
||||||
|
phone,
|
||||||
|
email,
|
||||||
|
provinceFk,
|
||||||
|
city,
|
||||||
|
postcode,
|
||||||
|
socialName,
|
||||||
|
payMethodFk,
|
||||||
|
dueDay,
|
||||||
|
credit,
|
||||||
|
isTaxDataChecked,
|
||||||
|
hasCoreVnl,
|
||||||
|
isEqualizated)
|
||||||
|
VALUES (
|
||||||
|
vUserFk,
|
||||||
|
CONCAT(vFirstname, ' ', vSurnames),
|
||||||
|
vAddress,
|
||||||
|
TRIM(vFi),
|
||||||
|
vPhone,
|
||||||
|
vEmail,
|
||||||
|
vProvinceFk,
|
||||||
|
vCity,
|
||||||
|
vPostcode,
|
||||||
|
CONCAT(vSurnames, ' ', vFirstname),
|
||||||
|
vPayMethodFk,
|
||||||
|
vDueDay,
|
||||||
|
vDefaultCredit,
|
||||||
|
vIsTaxDataChecked,
|
||||||
|
vHasCoreVnl,
|
||||||
|
FALSE
|
||||||
|
) ON duplicate key update
|
||||||
|
payMethodFk = vPayMethodFk,
|
||||||
|
dueDay = vDueDay,
|
||||||
|
credit = vDefaultCredit,
|
||||||
|
isTaxDataChecked = vIsTaxDataChecked,
|
||||||
|
hasCoreVnl = vHasCoreVnl,
|
||||||
|
isActive = TRUE;
|
||||||
|
|
||||||
|
IF (SELECT COUNT(*) FROM mandate WHERE clientFk = vUserFk AND companyFk = vCompanyFk AND mandateTypeFk = vMandateTypeFk) = 0 THEN
|
||||||
|
INSERT INTO mandate (clientFk, companyFk, mandateTypeFk)
|
||||||
|
VALUES (vUserFk, vCompanyFk, vMandateTypeFk);
|
||||||
|
END IF;
|
||||||
|
END$$
|
||||||
|
DELIMITER ;
|
|
@ -0,0 +1,14 @@
|
||||||
|
INSERT INTO `vn`.`businessType` (`code`, `description`)
|
||||||
|
VALUES ('worker','Trabajador');
|
||||||
|
|
||||||
|
ALTER TABLE `vn`.`workerConfig` ADD businessTypeFk varchar(100) NULL
|
||||||
|
COMMENT 'Tipo de negocio por defecto al dar de alta un trabajador nuevo';
|
||||||
|
|
||||||
|
UPDATE `vn`.`workerConfig`
|
||||||
|
SET businessTypeFk = 'worker'
|
||||||
|
WHERE id = 1;
|
||||||
|
|
||||||
|
UPDATE `vn`.`client` c
|
||||||
|
JOIN `vn`.`worker` w ON w.id = c.id
|
||||||
|
SET c.name = REPLACE(c.name, 'TR ', ''),
|
||||||
|
c.businessTypeFk = 'worker';
|
|
@ -0,0 +1,254 @@
|
||||||
|
DROP PROCEDURE IF EXISTS `vn`.`invoiceOut_new`;
|
||||||
|
|
||||||
|
DELIMITER $$
|
||||||
|
$$
|
||||||
|
CREATE DEFINER=`root`@`localhost` PROCEDURE `vn`.`invoiceOut_new`(
|
||||||
|
vSerial VARCHAR(255),
|
||||||
|
vInvoiceDate DATE,
|
||||||
|
vTaxArea VARCHAR(25),
|
||||||
|
OUT vNewInvoiceId INT)
|
||||||
|
BEGIN
|
||||||
|
/**
|
||||||
|
* Creación de facturas emitidas.
|
||||||
|
* requiere previamente tabla tmp.ticketToInvoice(id).
|
||||||
|
*
|
||||||
|
* @param vSerial serie a la cual se hace la factura
|
||||||
|
* @param vInvoiceDate fecha de la factura
|
||||||
|
* @param vTaxArea tipo de iva en relacion a la empresa y al cliente
|
||||||
|
* @param vNewInvoiceId id de la factura que se acaba de generar
|
||||||
|
* @return vNewInvoiceId
|
||||||
|
*/
|
||||||
|
DECLARE vIsAnySaleToInvoice BOOL;
|
||||||
|
DECLARE vIsAnyServiceToInvoice BOOL;
|
||||||
|
DECLARE vNewRef VARCHAR(255);
|
||||||
|
DECLARE vWorker INT DEFAULT account.myUser_getId();
|
||||||
|
DECLARE vCompanyFk INT;
|
||||||
|
DECLARE vInterCompanyFk INT;
|
||||||
|
DECLARE vClientFk INT;
|
||||||
|
DECLARE vCplusStandardInvoiceTypeFk INT DEFAULT 1;
|
||||||
|
DECLARE vCplusCorrectingInvoiceTypeFk INT DEFAULT 6;
|
||||||
|
DECLARE vCplusSimplifiedInvoiceTypeFk INT DEFAULT 2;
|
||||||
|
DECLARE vCorrectingSerial VARCHAR(1) DEFAULT 'R';
|
||||||
|
DECLARE vSimplifiedSerial VARCHAR(1) DEFAULT 'S';
|
||||||
|
DECLARE vNewInvoiceInFk INT;
|
||||||
|
DECLARE vIsInterCompany BOOL DEFAULT FALSE;
|
||||||
|
DECLARE vIsCEESerial BOOL DEFAULT FALSE;
|
||||||
|
DECLARE vIsCorrectInvoiceDate BOOL;
|
||||||
|
DECLARE vMaxShipped DATE;
|
||||||
|
|
||||||
|
SET vInvoiceDate = IFNULL(vInvoiceDate, util.VN_CURDATE());
|
||||||
|
|
||||||
|
SELECT t.clientFk,
|
||||||
|
t.companyFk,
|
||||||
|
MAX(DATE(t.shipped)),
|
||||||
|
DATE(vInvoiceDate) >= invoiceOut_getMaxIssued(
|
||||||
|
vSerial,
|
||||||
|
t.companyFk,
|
||||||
|
YEAR(vInvoiceDate))
|
||||||
|
INTO vClientFk,
|
||||||
|
vCompanyFk,
|
||||||
|
vMaxShipped,
|
||||||
|
vIsCorrectInvoiceDate
|
||||||
|
FROM tmp.ticketToInvoice tt
|
||||||
|
JOIN ticket t ON t.id = tt.id;
|
||||||
|
|
||||||
|
IF(vMaxShipped > vInvoiceDate) THEN
|
||||||
|
CALL util.throw("Invoice date can't be less than max date");
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
IF NOT vIsCorrectInvoiceDate THEN
|
||||||
|
CALL util.throw('Exists an invoice with a previous date');
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
-- Eliminem de tmp.ticketToInvoice els tickets que no han de ser facturats
|
||||||
|
DELETE ti.*
|
||||||
|
FROM tmp.ticketToInvoice ti
|
||||||
|
JOIN ticket t ON t.id = ti.id
|
||||||
|
JOIN sale s ON s.ticketFk = t.id
|
||||||
|
JOIN item i ON i.id = s.itemFk
|
||||||
|
JOIN supplier su ON su.id = t.companyFk
|
||||||
|
JOIN client c ON c.id = t.clientFk
|
||||||
|
LEFT JOIN itemTaxCountry itc ON itc.itemFk = i.id AND itc.countryFk = su.countryFk
|
||||||
|
WHERE (YEAR(t.shipped) < 2001 AND t.isDeleted)
|
||||||
|
OR c.isTaxDataChecked = FALSE
|
||||||
|
OR t.isDeleted
|
||||||
|
OR c.hasToInvoice = FALSE
|
||||||
|
OR itc.id IS NULL;
|
||||||
|
|
||||||
|
SELECT SUM(s.quantity * s.price * (100 - s.discount)/100) <> 0
|
||||||
|
INTO vIsAnySaleToInvoice
|
||||||
|
FROM tmp.ticketToInvoice t
|
||||||
|
JOIN sale s ON s.ticketFk = t.id;
|
||||||
|
|
||||||
|
SELECT COUNT(*) > 0 INTO vIsAnyServiceToInvoice
|
||||||
|
FROM tmp.ticketToInvoice t
|
||||||
|
JOIN ticketService ts ON ts.ticketFk = t.id;
|
||||||
|
|
||||||
|
IF (vIsAnySaleToInvoice OR vIsAnyServiceToInvoice)
|
||||||
|
AND (vCorrectingSerial = vSerial OR NOT hasAnyNegativeBase())
|
||||||
|
THEN
|
||||||
|
|
||||||
|
-- el trigger añade el siguiente Id_Factura correspondiente a la vSerial
|
||||||
|
INSERT INTO invoiceOut(
|
||||||
|
ref,
|
||||||
|
serial,
|
||||||
|
issued,
|
||||||
|
clientFk,
|
||||||
|
dued,
|
||||||
|
companyFk,
|
||||||
|
cplusInvoiceType477Fk
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
1,
|
||||||
|
vSerial,
|
||||||
|
vInvoiceDate,
|
||||||
|
vClientFk,
|
||||||
|
getDueDate(vInvoiceDate, dueDay),
|
||||||
|
vCompanyFk,
|
||||||
|
IF(vSerial = vCorrectingSerial,
|
||||||
|
vCplusCorrectingInvoiceTypeFk,
|
||||||
|
IF(vSerial = vSimplifiedSerial,
|
||||||
|
vCplusSimplifiedInvoiceTypeFk,
|
||||||
|
vCplusStandardInvoiceTypeFk))
|
||||||
|
FROM client
|
||||||
|
WHERE id = vClientFk;
|
||||||
|
|
||||||
|
SET vNewInvoiceId = LAST_INSERT_ID();
|
||||||
|
|
||||||
|
SELECT `ref`
|
||||||
|
INTO vNewRef
|
||||||
|
FROM invoiceOut
|
||||||
|
WHERE id = vNewInvoiceId;
|
||||||
|
|
||||||
|
UPDATE ticket t
|
||||||
|
JOIN tmp.ticketToInvoice ti ON ti.id = t.id
|
||||||
|
SET t.refFk = vNewRef;
|
||||||
|
|
||||||
|
DROP TEMPORARY TABLE IF EXISTS tmp.updateInter;
|
||||||
|
CREATE TEMPORARY TABLE tmp.updateInter ENGINE = MEMORY
|
||||||
|
SELECT s.id,ti.id ticket_id,vWorker Id_Trabajador
|
||||||
|
FROM tmp.ticketToInvoice ti
|
||||||
|
LEFT JOIN ticketState ts ON ti.id = ts.ticket
|
||||||
|
JOIN state s
|
||||||
|
WHERE IFNULL(ts.alertLevel,0) < 3 and s.`code` = getAlert3State(ti.id);
|
||||||
|
|
||||||
|
INSERT INTO ticketTracking(stateFk,ticketFk,workerFk)
|
||||||
|
SELECT * FROM tmp.updateInter;
|
||||||
|
|
||||||
|
CALL invoiceExpenceMake(vNewInvoiceId);
|
||||||
|
CALL invoiceTaxMake(vNewInvoiceId,vTaxArea);
|
||||||
|
|
||||||
|
UPDATE invoiceOut io
|
||||||
|
JOIN (
|
||||||
|
SELECT SUM(amount) total
|
||||||
|
FROM invoiceOutExpence
|
||||||
|
WHERE invoiceOutFk = vNewInvoiceId
|
||||||
|
) base
|
||||||
|
JOIN (
|
||||||
|
SELECT SUM(vat) total
|
||||||
|
FROM invoiceOutTax
|
||||||
|
WHERE invoiceOutFk = vNewInvoiceId
|
||||||
|
) vat
|
||||||
|
SET io.amount = base.total + vat.total
|
||||||
|
WHERE io.id = vNewInvoiceId;
|
||||||
|
|
||||||
|
DROP TEMPORARY TABLE tmp.updateInter;
|
||||||
|
|
||||||
|
SELECT COUNT(*), id
|
||||||
|
INTO vIsInterCompany, vInterCompanyFk
|
||||||
|
FROM company
|
||||||
|
WHERE clientFk = vClientFk;
|
||||||
|
|
||||||
|
IF (vIsInterCompany) THEN
|
||||||
|
|
||||||
|
INSERT INTO invoiceIn(supplierFk, supplierRef, issued, companyFk)
|
||||||
|
SELECT vCompanyFk, vNewRef, vInvoiceDate, vInterCompanyFk;
|
||||||
|
|
||||||
|
SET vNewInvoiceInFk = LAST_INSERT_ID();
|
||||||
|
|
||||||
|
DROP TEMPORARY TABLE IF EXISTS tmp.ticket;
|
||||||
|
CREATE TEMPORARY TABLE tmp.ticket
|
||||||
|
(KEY (ticketFk))
|
||||||
|
ENGINE = MEMORY
|
||||||
|
SELECT id ticketFk
|
||||||
|
FROM tmp.ticketToInvoice;
|
||||||
|
|
||||||
|
CALL `ticket_getTax`('NATIONAL');
|
||||||
|
|
||||||
|
SET @vTaxableBaseServices := 0.00;
|
||||||
|
SET @vTaxCodeGeneral := NULL;
|
||||||
|
|
||||||
|
INSERT INTO invoiceInTax(invoiceInFk, taxableBase, expenceFk, taxTypeSageFk, transactionTypeSageFk)
|
||||||
|
SELECT vNewInvoiceInFk,
|
||||||
|
@vTaxableBaseServices,
|
||||||
|
sub.expenceFk,
|
||||||
|
sub.taxTypeSageFk,
|
||||||
|
sub.transactionTypeSageFk
|
||||||
|
FROM (
|
||||||
|
SELECT @vTaxableBaseServices := SUM(tst.taxableBase) taxableBase,
|
||||||
|
i.expenceFk,
|
||||||
|
i.taxTypeSageFk,
|
||||||
|
i.transactionTypeSageFk,
|
||||||
|
@vTaxCodeGeneral := i.taxClassCodeFk
|
||||||
|
FROM tmp.ticketServiceTax tst
|
||||||
|
JOIN invoiceOutTaxConfig i ON i.taxClassCodeFk = tst.code
|
||||||
|
WHERE i.isService
|
||||||
|
HAVING taxableBase
|
||||||
|
) sub;
|
||||||
|
|
||||||
|
INSERT INTO invoiceInTax(invoiceInFk, taxableBase, expenceFk, taxTypeSageFk, transactionTypeSageFk)
|
||||||
|
SELECT vNewInvoiceInFk,
|
||||||
|
SUM(tt.taxableBase) - IF(tt.code = @vTaxCodeGeneral,
|
||||||
|
@vTaxableBaseServices, 0) taxableBase,
|
||||||
|
i.expenceFk,
|
||||||
|
i.taxTypeSageFk ,
|
||||||
|
i.transactionTypeSageFk
|
||||||
|
FROM tmp.ticketTax tt
|
||||||
|
JOIN invoiceOutTaxConfig i ON i.taxClassCodeFk = tt.code
|
||||||
|
WHERE !i.isService
|
||||||
|
GROUP BY tt.pgcFk
|
||||||
|
HAVING taxableBase
|
||||||
|
ORDER BY tt.priority;
|
||||||
|
|
||||||
|
CALL invoiceInDueDay_calculate(vNewInvoiceInFk);
|
||||||
|
|
||||||
|
SELECT COUNT(*) INTO vIsCEESerial
|
||||||
|
FROM invoiceOutSerial
|
||||||
|
WHERE code = vSerial;
|
||||||
|
|
||||||
|
IF vIsCEESerial THEN
|
||||||
|
|
||||||
|
INSERT INTO invoiceInIntrastat (
|
||||||
|
invoiceInFk,
|
||||||
|
intrastatFk,
|
||||||
|
amount,
|
||||||
|
stems,
|
||||||
|
countryFk,
|
||||||
|
net)
|
||||||
|
SELECT
|
||||||
|
vNewInvoiceInFk,
|
||||||
|
i.intrastatFk,
|
||||||
|
SUM(CAST((s.quantity * s.price * (100 - s.discount) / 100 ) AS DECIMAL(10, 2))),
|
||||||
|
SUM(CAST(IFNULL(i.stems, 1) * s.quantity AS DECIMAL(10, 2))),
|
||||||
|
su.countryFk,
|
||||||
|
CAST(SUM(IFNULL(i.stems, 1)
|
||||||
|
* s.quantity
|
||||||
|
* IF(ic.grams, ic.grams, IFNULL(i.weightByPiece, 0)) / 1000) AS DECIMAL(10, 2))
|
||||||
|
FROM sale s
|
||||||
|
JOIN ticket t ON s.ticketFk = t.id
|
||||||
|
JOIN supplier su ON su.id = t.companyFk
|
||||||
|
JOIN item i ON i.id = s.itemFk
|
||||||
|
LEFT JOIN itemCost ic ON ic.itemFk = i.id AND ic.warehouseFk = t.warehouseFk
|
||||||
|
WHERE t.refFk = vNewRef
|
||||||
|
GROUP BY i.intrastatFk;
|
||||||
|
|
||||||
|
END IF;
|
||||||
|
DROP TEMPORARY TABLE tmp.ticket;
|
||||||
|
DROP TEMPORARY TABLE tmp.ticketAmount;
|
||||||
|
DROP TEMPORARY TABLE tmp.ticketTax;
|
||||||
|
DROP TEMPORARY TABLE tmp.ticketServiceTax;
|
||||||
|
END IF;
|
||||||
|
END IF;
|
||||||
|
DROP TEMPORARY TABLE `tmp`.`ticketToInvoice`;
|
||||||
|
END$$
|
||||||
|
DELIMITER ;
|
|
@ -2801,9 +2801,9 @@ INSERT INTO `vn`.`payDemDetail` (`id`, `detail`)
|
||||||
VALUES
|
VALUES
|
||||||
(1, 1);
|
(1, 1);
|
||||||
|
|
||||||
INSERT INTO `vn`.`workerConfig` (`id`, `businessUpdated`, `roleFk`)
|
INSERT INTO `vn`.`workerConfig` (`id`, `businessUpdated`, `roleFk`, `businessTypeFk`)
|
||||||
VALUES
|
VALUES
|
||||||
(1, NULL, 1);
|
(1, NULL, 1, 'worker');
|
||||||
|
|
||||||
INSERT INTO `vn`.`ticketRefund`(`refundTicketFk`, `originalTicketFk`)
|
INSERT INTO `vn`.`ticketRefund`(`refundTicketFk`, `originalTicketFk`)
|
||||||
VALUES
|
VALUES
|
||||||
|
|
|
@ -285,21 +285,6 @@ export default {
|
||||||
clientMandate: {
|
clientMandate: {
|
||||||
firstMandateText: 'vn-client-mandate vn-card vn-table vn-tbody > vn-tr'
|
firstMandateText: 'vn-client-mandate vn-card vn-table vn-tbody > vn-tr'
|
||||||
},
|
},
|
||||||
clientBalance: {
|
|
||||||
company: 'vn-client-balance-index vn-autocomplete[ng-model="$ctrl.companyId"]',
|
|
||||||
newPaymentButton: `vn-float-button`,
|
|
||||||
newPaymentBank: '.vn-dialog.shown vn-autocomplete[ng-model="$ctrl.bankFk"]',
|
|
||||||
newPaymentAmount: '.vn-dialog.shown vn-input-number[ng-model="$ctrl.amountPaid"]',
|
|
||||||
newDescription: 'vn-textfield[ng-model="$ctrl.receipt.description"]',
|
|
||||||
deliveredAmount: '.vn-dialog vn-input-number[ng-model="$ctrl.deliveredAmount"]',
|
|
||||||
refundAmount: '.vn-dialog vn-input-number[ng-model="$ctrl.amountToReturn"]',
|
|
||||||
saveButton: '.vn-dialog.shown [response="accept"]',
|
|
||||||
anyBalanceLine: 'vn-client-balance-index vn-tbody > vn-tr',
|
|
||||||
firstLineBalance: 'vn-client-balance-index vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(8)',
|
|
||||||
firstLineReference: 'vn-client-balance-index vn-tbody > vn-tr:nth-child(1) > vn-td-editable',
|
|
||||||
firstLineReferenceInput: 'vn-client-balance-index vn-tbody > vn-tr:nth-child(1) > vn-td-editable > div > field > vn-textfield',
|
|
||||||
compensationButton: 'vn-client-balance-index vn-icon-button[vn-dialog="send_compensation"]'
|
|
||||||
},
|
|
||||||
webPayment: {
|
webPayment: {
|
||||||
confirmFirstPaymentButton: 'vn-client-web-payment vn-tr:nth-child(1) vn-icon-button[icon="done_all"]',
|
confirmFirstPaymentButton: 'vn-client-web-payment vn-tr:nth-child(1) vn-icon-button[icon="done_all"]',
|
||||||
firstPaymentConfirmed: 'vn-client-web-payment vn-tr:nth-child(1) vn-icon[icon="check"]'
|
firstPaymentConfirmed: 'vn-client-web-payment vn-tr:nth-child(1) vn-icon[icon="check"]'
|
||||||
|
@ -841,15 +826,6 @@ export default {
|
||||||
landedDatePicker: 'vn-date-picker[label="Landed"]',
|
landedDatePicker: 'vn-date-picker[label="Landed"]',
|
||||||
createButton: 'button[type=submit]'
|
createButton: 'button[type=submit]'
|
||||||
},
|
},
|
||||||
orderSummary: {
|
|
||||||
id: 'vn-order-summary vn-one:nth-child(1) > vn-label-value:nth-child(1) span',
|
|
||||||
alias: 'vn-order-summary vn-one:nth-child(1) > vn-label-value:nth-child(2) span',
|
|
||||||
consignee: 'vn-order-summary vn-one:nth-child(2) > vn-label-value:nth-child(6) span',
|
|
||||||
subtotal: 'vn-order-summary vn-one.taxes > p:nth-child(1)',
|
|
||||||
vat: 'vn-order-summary vn-one.taxes > p:nth-child(2)',
|
|
||||||
total: 'vn-order-summary vn-one.taxes > p:nth-child(3)',
|
|
||||||
sale: 'vn-order-summary vn-tbody > vn-tr',
|
|
||||||
},
|
|
||||||
orderCatalog: {
|
orderCatalog: {
|
||||||
plantRealmButton: 'vn-order-catalog > vn-side-menu vn-icon[icon="icon-plant"]',
|
plantRealmButton: 'vn-order-catalog > vn-side-menu vn-icon[icon="icon-plant"]',
|
||||||
type: 'vn-order-catalog vn-autocomplete[data="$ctrl.itemTypes"]',
|
type: 'vn-order-catalog vn-autocomplete[data="$ctrl.itemTypes"]',
|
||||||
|
|
|
@ -29,19 +29,16 @@ describe('Client Add greuge path', () => {
|
||||||
expect(message.text).toContain('Some fields are invalid');
|
expect(message.text).toContain('Some fields are invalid');
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`should create a new greuge with all its data`, async() => {
|
it(`should create a new greuge with all its data and confirm the greuge was added to the list`, async() => {
|
||||||
await page.write(selectors.clientGreuge.amount, '999');
|
await page.write(selectors.clientGreuge.amount, '999');
|
||||||
await page.waitForTextInField(selectors.clientGreuge.amount, '999');
|
await page.waitForTextInField(selectors.clientGreuge.amount, '999');
|
||||||
await page.write(selectors.clientGreuge.description, 'new armor for Batman!');
|
await page.write(selectors.clientGreuge.description, 'new armor for Batman!');
|
||||||
await page.waitToClick(selectors.clientGreuge.saveButton);
|
await page.waitToClick(selectors.clientGreuge.saveButton);
|
||||||
const message = await page.waitForSnackbar();
|
const message = await page.waitForSnackbar();
|
||||||
|
|
||||||
expect(message.text).toContain('Data saved!');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should confirm the greuge was added to the list', async() => {
|
|
||||||
const result = await page.waitToGetProperty(selectors.clientGreuge.firstGreugeText, 'innerText');
|
const result = await page.waitToGetProperty(selectors.clientGreuge.firstGreugeText, 'innerText');
|
||||||
|
|
||||||
|
expect(message.text).toContain('Data saved!');
|
||||||
expect(result).toContain(999);
|
expect(result).toContain(999);
|
||||||
expect(result).toContain('new armor for Batman!');
|
expect(result).toContain('new armor for Batman!');
|
||||||
expect(result).toContain('Diff');
|
expect(result).toContain('Diff');
|
||||||
|
|
|
@ -1,6 +1,17 @@
|
||||||
import selectors from '../../helpers/selectors';
|
import selectors from '../../helpers/selectors';
|
||||||
import getBrowser from '../../helpers/puppeteer';
|
import getBrowser from '../../helpers/puppeteer';
|
||||||
|
|
||||||
|
const $ = {
|
||||||
|
company: 'vn-client-balance-index vn-autocomplete[ng-model="$ctrl.companyId"]',
|
||||||
|
newPaymentButton: `vn-float-button`,
|
||||||
|
newPayment: '.vn-dialog.shown',
|
||||||
|
refundAmount: '.vn-dialog.shown [vn-name="amountToReturn"]',
|
||||||
|
saveButton: '.vn-dialog.shown [response="accept"]',
|
||||||
|
firstLineBalance: 'vn-client-balance-index vn-tbody > vn-tr:nth-child(1) > vn-td:nth-child(8)',
|
||||||
|
firstLineReference: 'vn-client-balance-index vn-tbody > vn-tr:nth-child(1) > vn-td-editable',
|
||||||
|
firstLineReferenceInput: 'vn-client-balance-index vn-tbody > vn-tr:nth-child(1) > vn-td-editable vn-textfield',
|
||||||
|
};
|
||||||
|
|
||||||
describe('Client balance path', () => {
|
describe('Client balance path', () => {
|
||||||
let browser;
|
let browser;
|
||||||
let page;
|
let page;
|
||||||
|
@ -18,125 +29,100 @@ describe('Client balance path', () => {
|
||||||
it('should now edit the local user config data', async() => {
|
it('should now edit the local user config data', async() => {
|
||||||
await page.waitToClick(selectors.globalItems.userMenuButton);
|
await page.waitToClick(selectors.globalItems.userMenuButton);
|
||||||
await page.autocompleteSearch(selectors.globalItems.userLocalCompany, 'CCs');
|
await page.autocompleteSearch(selectors.globalItems.userLocalCompany, 'CCs');
|
||||||
const message = await page.waitForSnackbar();
|
const companyMessage = await page.waitForSnackbar();
|
||||||
|
|
||||||
expect(message.text).toContain('Data saved!');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should access to the balance section to check the data shown matches the local settings', async() => {
|
|
||||||
await page.accessToSection('client.card.balance.index');
|
await page.accessToSection('client.card.balance.index');
|
||||||
let result = await page.waitToGetProperty(selectors.clientBalance.company, 'value');
|
const company = await page.getValue($.company);
|
||||||
|
|
||||||
expect(result).toEqual('CCs');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should now clear the user local settings', async() => {
|
|
||||||
await page.waitToClick(selectors.globalItems.userMenuButton);
|
await page.waitToClick(selectors.globalItems.userMenuButton);
|
||||||
await page.clearInput(selectors.globalItems.userConfigThirdAutocomplete);
|
await page.clearInput(selectors.globalItems.userConfigThirdAutocomplete);
|
||||||
const message = await page.waitForSnackbar();
|
const message = await page.waitForSnackbar();
|
||||||
|
|
||||||
expect(message.text).toContain('Data saved!');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should reload the section', async() => {
|
|
||||||
await page.closePopup();
|
await page.closePopup();
|
||||||
await page.reloadSection('client.card.balance.index');
|
await page.reloadSection('client.card.balance.index');
|
||||||
|
|
||||||
|
expect(companyMessage.isSuccess).toBeTrue();
|
||||||
|
expect(company).toEqual('CCs');
|
||||||
|
expect(message.isSuccess).toBeTrue();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create a new payment that clears the debt', async() => {
|
it('should create a new payment that clears the debt', async() => {
|
||||||
await page.closePopup();
|
await page.waitToClick($.newPaymentButton);
|
||||||
await page.waitToClick(selectors.clientBalance.newPaymentButton);
|
await page.fillForm($.newPayment, {
|
||||||
await page.autocompleteSearch(selectors.clientBalance.newPaymentBank, 'Cash');
|
bank: 'Cash',
|
||||||
await page.clearInput(selectors.clientBalance.newDescription);
|
description: 'Description',
|
||||||
await page.write(selectors.clientBalance.newDescription, 'Description');
|
viewReceipt: false
|
||||||
await page.waitToClick(selectors.clientBalance.saveButton);
|
});
|
||||||
|
await page.respondToDialog('accept');
|
||||||
const message = await page.waitForSnackbar();
|
const message = await page.waitForSnackbar();
|
||||||
|
|
||||||
expect(message.text).toContain('Data saved!');
|
expect(message.isSuccess).toBeTrue();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should edit the 1st line reference', async() => {
|
it('should edit the 1st line reference and check data', async() => {
|
||||||
await page.waitToClick(selectors.clientBalance.firstLineReference);
|
await page.waitToClick($.firstLineReference);
|
||||||
await page.write(selectors.clientBalance.firstLineReferenceInput, 'Miscellaneous payment');
|
await page.write($.firstLineReferenceInput, 'Miscellaneous payment');
|
||||||
await page.keyboard.press('Enter');
|
await page.keyboard.press('Enter');
|
||||||
const message = await page.waitForSnackbar();
|
const message = await page.waitForSnackbar();
|
||||||
|
|
||||||
expect(message.text).toContain('Data saved!');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should check balance is now 0, the reference was saved and the company is now VNL becouse the user local settings were removed', async() => {
|
|
||||||
await page.waitForSpinnerLoad();
|
await page.waitForSpinnerLoad();
|
||||||
let company = await page
|
let company = await page.getValue($.company);
|
||||||
.waitToGetProperty(selectors.clientBalance.company, 'value');
|
let reference = await page.innerText($.firstLineReference);
|
||||||
|
let firstBalanceLine = await page.innerText($.firstLineBalance);
|
||||||
let reference = await page
|
|
||||||
.waitToGetProperty(selectors.clientBalance.firstLineReference, 'innerText');
|
|
||||||
|
|
||||||
let firstBalanceLine = await page
|
|
||||||
.waitToGetProperty(selectors.clientBalance.firstLineBalance, 'innerText');
|
|
||||||
|
|
||||||
|
expect(message.isSuccess).toBeTrue();
|
||||||
expect(company).toEqual('VNL');
|
expect(company).toEqual('VNL');
|
||||||
expect(reference).toEqual('Miscellaneous payment');
|
expect(reference).toEqual('Miscellaneous payment');
|
||||||
expect(firstBalanceLine).toContain('0.00');
|
expect(firstBalanceLine).toContain('0.00');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create a new payment and check the cash comparison works correctly', async() => {
|
it('should create a new payment, check the cash comparison works correctly and balance value is -100', async() => {
|
||||||
const amountPaid = '100';
|
await page.waitToClick($.newPaymentButton);
|
||||||
const cashHanded = '500';
|
await page.fillForm($.newPayment, {
|
||||||
const expectedRefund = '400';
|
amountPaid: 100,
|
||||||
|
description: 'Payment',
|
||||||
await page.waitToClick(selectors.clientBalance.newPaymentButton);
|
deliveredAmount: 500,
|
||||||
await page.write(selectors.clientBalance.newPaymentAmount, amountPaid);
|
viewReceipt: false
|
||||||
await page.clearInput(selectors.clientBalance.newDescription);
|
});
|
||||||
await page.write(selectors.clientBalance.newDescription, 'Payment');
|
const refund = await page.getValue($.refundAmount);
|
||||||
await page.write(selectors.clientBalance.deliveredAmount, cashHanded);
|
await page.respondToDialog('accept');
|
||||||
const refund = await page.waitToGetProperty(selectors.clientBalance.refundAmount, 'value');
|
|
||||||
await page.waitToClick(selectors.clientBalance.saveButton);
|
|
||||||
const message = await page.waitForSnackbar();
|
const message = await page.waitForSnackbar();
|
||||||
|
|
||||||
expect(refund).toEqual(expectedRefund);
|
const result = await page.innerText($.firstLineBalance);
|
||||||
expect(message.text).toContain('Data saved!');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should check the balance value is now -100', async() => {
|
|
||||||
let result = await page
|
|
||||||
.waitToGetProperty(selectors.clientBalance.firstLineBalance, 'innerText');
|
|
||||||
|
|
||||||
|
expect(refund).toEqual('400');
|
||||||
|
expect(message.isSuccess).toBeTrue();
|
||||||
expect(result).toContain('-€100.00');
|
expect(result).toContain('-€100.00');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create a new payment and check the cash exceeded the maximum', async() => {
|
it('should create a new payment and check the cash exceeded the maximum', async() => {
|
||||||
const amountPaid = '1001';
|
await page.waitToClick($.newPaymentButton);
|
||||||
|
await page.fillForm($.newPayment, {
|
||||||
await page.closePopup();
|
bank: 'Cash',
|
||||||
await page.waitToClick(selectors.clientBalance.newPaymentButton);
|
amountPaid: 1001,
|
||||||
await page.autocompleteSearch(selectors.clientBalance.newPaymentBank, 'Cash');
|
description: 'Payment'
|
||||||
await page.write(selectors.clientBalance.newPaymentAmount, amountPaid);
|
});
|
||||||
await page.clearInput(selectors.clientBalance.newDescription);
|
await page.waitToClick($.saveButton);
|
||||||
await page.write(selectors.clientBalance.newDescription, 'Payment');
|
|
||||||
await page.waitToClick(selectors.clientBalance.saveButton);
|
|
||||||
const message = await page.waitForSnackbar();
|
const message = await page.waitForSnackbar();
|
||||||
|
|
||||||
expect(message.text).toContain('Amount exceeded');
|
expect(message.text).toContain('Amount exceeded');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create a new payment that sets the balance back to the original negative value', async() => {
|
it('should create a new payment that sets the balance back to negative value and check it', async() => {
|
||||||
await page.closePopup();
|
await page.closePopup();
|
||||||
await page.waitToClick(selectors.clientBalance.newPaymentButton);
|
await page.waitToClick($.newPaymentButton);
|
||||||
await page.autocompleteSearch(selectors.clientBalance.newPaymentBank, 'Pay on receipt');
|
|
||||||
await page.overwrite(selectors.clientBalance.newPaymentAmount, '-150');
|
await page.fillForm($.newPayment, {
|
||||||
await page.clearInput(selectors.clientBalance.newDescription);
|
bank: 'Pay on receipt',
|
||||||
await page.write(selectors.clientBalance.newDescription, 'Description');
|
amountPaid: -150,
|
||||||
await page.waitToClick(selectors.clientBalance.saveButton);
|
description: 'Description'
|
||||||
|
});
|
||||||
|
await page.respondToDialog('accept');
|
||||||
const message = await page.waitForSnackbar();
|
const message = await page.waitForSnackbar();
|
||||||
|
|
||||||
expect(message.text).toContain('Data saved!');
|
const result = await page.innerText($.firstLineBalance);
|
||||||
});
|
|
||||||
|
|
||||||
it('should check balance is now 50', async() => {
|
|
||||||
let result = await page
|
|
||||||
.waitToGetProperty(selectors.clientBalance.firstLineBalance, 'innerText');
|
|
||||||
|
|
||||||
|
expect(message.isSuccess).toBeTrue();
|
||||||
expect(result).toEqual('€50.00');
|
expect(result).toEqual('€50.00');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -149,12 +135,9 @@ describe('Client balance path', () => {
|
||||||
await page.waitForState('client.index');
|
await page.waitForState('client.index');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should now search for the user Petter Parker', async() => {
|
it('should now search for the user Petter Parker not check the payment button is not present', async() => {
|
||||||
await page.accessToSearchResult('Petter Parker');
|
await page.accessToSearchResult('Petter Parker');
|
||||||
await page.accessToSection('client.card.balance.index');
|
await page.accessToSection('client.card.balance.index');
|
||||||
});
|
await page.waitForSelector($.newPaymentButton, {hidden: true});
|
||||||
|
|
||||||
it('should not be able to click the new payment button as it isnt present', async() => {
|
|
||||||
await page.waitForSelector(selectors.clientBalance.newPaymentButton, {hidden: true});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
import selectors from '../../helpers/selectors';
|
|
||||||
import getBrowser from '../../helpers/puppeteer';
|
import getBrowser from '../../helpers/puppeteer';
|
||||||
|
|
||||||
|
const $ = {
|
||||||
|
company: 'vn-client-balance-index vn-autocomplete[ng-model="$ctrl.companyId"]',
|
||||||
|
compensationButton: 'vn-client-balance-index vn-icon-button[vn-dialog="send_compensation"]',
|
||||||
|
saveButton: '.vn-dialog.shown [response="accept"]'
|
||||||
|
};
|
||||||
|
|
||||||
describe('Client Send balance compensation', () => {
|
describe('Client Send balance compensation', () => {
|
||||||
let browser;
|
let browser;
|
||||||
let page;
|
let page;
|
||||||
|
@ -17,9 +22,9 @@ describe('Client Send balance compensation', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`should click on send compensation button`, async() => {
|
it(`should click on send compensation button`, async() => {
|
||||||
await page.autocompleteSearch(selectors.clientBalance.company, 'VNL');
|
await page.autocompleteSearch($.company, 'VNL');
|
||||||
await page.waitToClick(selectors.clientBalance.compensationButton);
|
await page.waitToClick($.compensationButton);
|
||||||
await page.waitToClick(selectors.clientBalance.saveButton);
|
await page.waitToClick($.saveButton);
|
||||||
const message = await page.waitForSnackbar();
|
const message = await page.waitForSnackbar();
|
||||||
|
|
||||||
expect(message.text).toContain('Notification sent!');
|
expect(message.text).toContain('Notification sent!');
|
||||||
|
|
|
@ -50,6 +50,7 @@ describe('Item Edit basic data path', () => {
|
||||||
|
|
||||||
it(`should create a new intrastat and save it`, async() => {
|
it(`should create a new intrastat and save it`, async() => {
|
||||||
await page.click($.newIntrastatButton);
|
await page.click($.newIntrastatButton);
|
||||||
|
await page.waitForSelector($.intrastatForm);
|
||||||
await page.fillForm($.intrastatForm, {
|
await page.fillForm($.intrastatForm, {
|
||||||
id: '588420239',
|
id: '588420239',
|
||||||
description: 'Tropical Flowers'
|
description: 'Tropical Flowers'
|
||||||
|
|
|
@ -53,12 +53,4 @@ describe('Item edit tax path', () => {
|
||||||
|
|
||||||
expect(firstVatType).toEqual('Reduced VAT');
|
expect(firstVatType).toEqual('Reduced VAT');
|
||||||
});
|
});
|
||||||
|
|
||||||
// # #2680 Undo changes button bugs
|
|
||||||
xit(`should now click the undo changes button and see the form is restored`, async() => {
|
|
||||||
await page.waitToClick(selectors.itemTax.undoChangesButton);
|
|
||||||
const firstVatType = await page.waitToGetProperty(selectors.itemTax.firstClass, 'value');
|
|
||||||
|
|
||||||
expect(firstVatType).toEqual('General VAT');
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -316,7 +316,7 @@ describe('Ticket Edit sale path', () => {
|
||||||
it('should confirm the transfered quantity is the correct one', async() => {
|
it('should confirm the transfered quantity is the correct one', async() => {
|
||||||
const result = await page.waitToGetProperty(selectors.ticketSales.secondSaleQuantityCell, 'innerText');
|
const result = await page.waitToGetProperty(selectors.ticketSales.secondSaleQuantityCell, 'innerText');
|
||||||
|
|
||||||
expect(result).toContain('20');
|
expect(result).toContain('10');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should go back to the original ticket sales section', async() => {
|
it('should go back to the original ticket sales section', async() => {
|
||||||
|
@ -425,20 +425,6 @@ describe('Ticket Edit sale path', () => {
|
||||||
expect(result).toBeFalsy();
|
expect(result).toBeFalsy();
|
||||||
});
|
});
|
||||||
|
|
||||||
// tickets no longer update their totals instantly, a task performed ever 5-10 mins does it. disabled this test until it changes.
|
|
||||||
xit('should update all sales discount', async() => {
|
|
||||||
await page.closePopup();
|
|
||||||
await page.waitToClick(selectors.ticketSales.moreMenu);
|
|
||||||
await page.waitToClick(selectors.ticketSales.moreMenuUpdateDiscount);
|
|
||||||
await page.waitForSelector(selectors.ticketSales.moreMenuUpdateDiscountInput);
|
|
||||||
await page.type(selectors.ticketSales.moreMenuUpdateDiscountInput, '100');
|
|
||||||
await page.keyboard.press('Enter');
|
|
||||||
await page.waitForTextInElement(selectors.ticketSales.totalImport, '0.00');
|
|
||||||
const result = await page.waitToGetProperty(selectors.ticketSales.totalImport, 'innerText');
|
|
||||||
|
|
||||||
expect(result).toContain('0.00');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should log in as Production role and go to a target ticket summary', async() => {
|
it('should log in as Production role and go to a target ticket summary', async() => {
|
||||||
await page.loginAndModule('production', 'ticket');
|
await page.loginAndModule('production', 'ticket');
|
||||||
await page.accessToSearchResult('13');
|
await page.accessToSearchResult('13');
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
import selectors from '../../helpers/selectors.js';
|
import selectors from '../../helpers/selectors.js';
|
||||||
import getBrowser from '../../helpers/puppeteer';
|
import getBrowser from '../../helpers/puppeteer';
|
||||||
|
const $ = {
|
||||||
|
newPayment: '.vn-dialog.shown',
|
||||||
|
anyBalanceLine: 'vn-client-balance-index vn-tbody > vn-tr',
|
||||||
|
firstLineReference: 'vn-client-balance-index vn-tbody > vn-tr:nth-child(1) > vn-td-editable'
|
||||||
|
};
|
||||||
|
|
||||||
describe('Ticket index payout path', () => {
|
describe('Ticket index payout path', () => {
|
||||||
let browser;
|
let browser;
|
||||||
|
@ -8,17 +13,14 @@ describe('Ticket index payout path', () => {
|
||||||
beforeAll(async() => {
|
beforeAll(async() => {
|
||||||
browser = await getBrowser();
|
browser = await getBrowser();
|
||||||
page = browser.page;
|
page = browser.page;
|
||||||
|
await page.loginAndModule('administrative', 'ticket');
|
||||||
|
await page.waitForState('ticket.index');
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async() => {
|
afterAll(async() => {
|
||||||
await browser.close();
|
await browser.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should navigate to the ticket index', async() => {
|
|
||||||
await page.loginAndModule('administrative', 'ticket');
|
|
||||||
await page.waitForState('ticket.index');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should check the second ticket from a client and 1 of another', async() => {
|
it('should check the second ticket from a client and 1 of another', async() => {
|
||||||
await page.waitToClick(selectors.globalItems.searchButton);
|
await page.waitToClick(selectors.globalItems.searchButton);
|
||||||
await page.waitToClick(selectors.ticketsIndex.thirdTicketCheckbox);
|
await page.waitToClick(selectors.ticketsIndex.thirdTicketCheckbox);
|
||||||
|
@ -42,27 +44,27 @@ describe('Ticket index payout path', () => {
|
||||||
await page.waitForSelector(selectors.ticketsIndex.payoutCompany);
|
await page.waitForSelector(selectors.ticketsIndex.payoutCompany);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should fill the company and bank to perform a payout', async() => {
|
it('should fill the company and bank to perform a payout and check a new balance line was entered', async() => {
|
||||||
await page.autocompleteSearch(selectors.ticketsIndex.payoutCompany, 'VNL');
|
await page.fillForm($.newPayment, {
|
||||||
await page.autocompleteSearch(selectors.ticketsIndex.payoutBank, 'cash');
|
company: 'VNL',
|
||||||
await page.write(selectors.clientBalance.newPaymentAmount, '100');
|
bank: 'cash',
|
||||||
await page.write(selectors.ticketsIndex.payoutDescription, 'Payment');
|
amountPaid: 100,
|
||||||
await page.waitToClick(selectors.ticketsIndex.submitPayout);
|
description: 'Payment',
|
||||||
|
viewReceipt: false
|
||||||
|
});
|
||||||
|
await page.respondToDialog('accept');
|
||||||
const message = await page.waitForSnackbar();
|
const message = await page.waitForSnackbar();
|
||||||
|
|
||||||
expect(message.text).toContain('Data saved!');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should navigate to the client balance section and check a new balance line was entered', async() => {
|
|
||||||
await page.waitToClick(selectors.globalItems.homeButton);
|
await page.waitToClick(selectors.globalItems.homeButton);
|
||||||
await page.selectModule('client');
|
await page.selectModule('client');
|
||||||
await page.accessToSearchResult('1101');
|
await page.accessToSearchResult('1101');
|
||||||
await page.accessToSection('client.card.balance.index');
|
await page.accessToSection('client.card.balance.index');
|
||||||
await page.waitForSelector(selectors.clientBalance.anyBalanceLine);
|
await page.waitForSelector($.anyBalanceLine);
|
||||||
const count = await page.countElement(selectors.clientBalance.anyBalanceLine);
|
const count = await page.countElement($.anyBalanceLine);
|
||||||
const reference = await page.waitToGetProperty(selectors.clientBalance.firstLineReference, 'innerText');
|
const reference = await page.innerText($.firstLineReference);
|
||||||
|
|
||||||
|
expect(message.isSuccess).toBeTrue();
|
||||||
expect(count).toEqual(4);
|
expect(count).toEqual(4);
|
||||||
expect(reference).toContain('Cash, Albaran: 7, 8Payment');
|
expect(reference).toContain('Payment');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,15 @@
|
||||||
import selectors from '../../helpers/selectors.js';
|
|
||||||
import getBrowser from '../../helpers/puppeteer';
|
import getBrowser from '../../helpers/puppeteer';
|
||||||
|
|
||||||
|
const $ = {
|
||||||
|
id: 'vn-order-summary vn-one:nth-child(1) > vn-label-value:nth-child(1) span',
|
||||||
|
alias: 'vn-order-summary vn-one:nth-child(1) > vn-label-value:nth-child(2) span',
|
||||||
|
consignee: 'vn-order-summary vn-one:nth-child(2) > vn-label-value:nth-child(6) span',
|
||||||
|
subtotal: 'vn-order-summary vn-one.taxes > p:nth-child(1)',
|
||||||
|
vat: 'vn-order-summary vn-one.taxes > p:nth-child(2)',
|
||||||
|
total: 'vn-order-summary vn-one.taxes > p:nth-child(3)',
|
||||||
|
sale: 'vn-order-summary vn-tbody > vn-tr',
|
||||||
|
};
|
||||||
|
|
||||||
describe('Order summary path', () => {
|
describe('Order summary path', () => {
|
||||||
let browser;
|
let browser;
|
||||||
let page;
|
let page;
|
||||||
|
@ -15,49 +24,23 @@ describe('Order summary path', () => {
|
||||||
await browser.close();
|
await browser.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should reach the order summary section', async() => {
|
it('should reach the order summary section and check data', async() => {
|
||||||
await page.waitForState('order.card.summary');
|
await page.waitForState('order.card.summary');
|
||||||
});
|
|
||||||
|
|
||||||
it('should check the summary contains the order id', async() => {
|
const id = await page.innerText($.id);
|
||||||
const result = await page.waitToGetProperty(selectors.orderSummary.id, 'innerText');
|
const alias = await page.innerText($.alias);
|
||||||
|
const consignee = await page.innerText($.consignee);
|
||||||
|
const subtotal = await page.innerText($.subtotal);
|
||||||
|
const vat = await page.innerText($.vat);
|
||||||
|
const total = await page.innerText($.total);
|
||||||
|
const sale = await page.countElement($.sale);
|
||||||
|
|
||||||
expect(result).toEqual('16');
|
expect(id).toEqual('16');
|
||||||
});
|
expect(alias).toEqual('Many places');
|
||||||
|
expect(consignee).toEqual('address 26 - Gotham (Province one)');
|
||||||
it('should check the summary contains the order alias', async() => {
|
expect(subtotal.length).toBeGreaterThan(1);
|
||||||
const result = await page.waitToGetProperty(selectors.orderSummary.alias, 'innerText');
|
expect(vat.length).toBeGreaterThan(1);
|
||||||
|
expect(total.length).toBeGreaterThan(1);
|
||||||
expect(result).toEqual('Many places');
|
expect(sale).toBeGreaterThan(0);
|
||||||
});
|
|
||||||
|
|
||||||
it('should check the summary contains the order consignee', async() => {
|
|
||||||
const result = await page.waitToGetProperty(selectors.orderSummary.consignee, 'innerText');
|
|
||||||
|
|
||||||
expect(result).toEqual('address 26 - Gotham (Province one)');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should check the summary contains the order subtotal', async() => {
|
|
||||||
const result = await page.waitToGetProperty(selectors.orderSummary.subtotal, 'innerText');
|
|
||||||
|
|
||||||
expect(result.length).toBeGreaterThan(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should check the summary contains the order vat', async() => {
|
|
||||||
const result = await page.waitToGetProperty(selectors.orderSummary.vat, 'innerText');
|
|
||||||
|
|
||||||
expect(result.length).toBeGreaterThan(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should check the summary contains the order total', async() => {
|
|
||||||
const result = await page.waitToGetProperty(selectors.orderSummary.total, 'innerText');
|
|
||||||
|
|
||||||
expect(result.length).toBeGreaterThan(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should check the summary contains the order sales', async() => {
|
|
||||||
const result = await page.countElement(selectors.orderSummary.sale);
|
|
||||||
|
|
||||||
expect(result).toBeGreaterThan(0);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -57,11 +57,4 @@ describe('Route tickets path', () => {
|
||||||
it('should now count how many tickets are in route to find one less', async() => {
|
it('should now count how many tickets are in route to find one less', async() => {
|
||||||
await page.waitForNumberOfElements(selectors.routeTickets.anyTicket, 0);
|
await page.waitForNumberOfElements(selectors.routeTickets.anyTicket, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
// #2862 updateVolume() route descriptor no actualiza volumen
|
|
||||||
xit('should confirm the route volume on the descriptor has been updated by the changes made', async() => {
|
|
||||||
const result = await page.waitToGetProperty(selectors.routeDescriptor.volume, 'innerText');
|
|
||||||
|
|
||||||
expect(result).toEqual('0 / 50 m³');
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -42,20 +42,6 @@ describe('Entry lastest buys path', () => {
|
||||||
expect(httpRequests.find(req => req.includes(('typeFk')))).toBeDefined();
|
expect(httpRequests.find(req => req.includes(('typeFk')))).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should filter by from date', async() => {
|
|
||||||
await page.pickDate(selectors.entryLatestBuys.fromInput, new Date());
|
|
||||||
await page.waitToClick(selectors.entryLatestBuys.chip);
|
|
||||||
|
|
||||||
expect(httpRequests.find(req => req.includes(('from')))).toBeDefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should filter by to date', async() => {
|
|
||||||
await page.pickDate(selectors.entryLatestBuys.toInput, new Date());
|
|
||||||
await page.waitToClick(selectors.entryLatestBuys.chip);
|
|
||||||
|
|
||||||
expect(httpRequests.find(req => req.includes(('to')))).toBeDefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should filter by sales person', async() => {
|
it('should filter by sales person', async() => {
|
||||||
await page.autocompleteSearch(selectors.entryLatestBuys.salesPersonInput, 'buyerNick');
|
await page.autocompleteSearch(selectors.entryLatestBuys.salesPersonInput, 'buyerNick');
|
||||||
await page.waitToClick(selectors.entryLatestBuys.chip);
|
await page.waitToClick(selectors.entryLatestBuys.chip);
|
||||||
|
|
|
@ -7,11 +7,10 @@ export default class DataViewer {
|
||||||
}
|
}
|
||||||
|
|
||||||
get status() {
|
get status() {
|
||||||
if (this.model)
|
|
||||||
return this.model.status;
|
|
||||||
|
|
||||||
if (this.isLoading)
|
if (this.isLoading)
|
||||||
return 'loading';
|
return 'loading';
|
||||||
|
if (this.model)
|
||||||
|
return this.model.status;
|
||||||
if (!this.data)
|
if (!this.data)
|
||||||
return 'clear';
|
return 'clear';
|
||||||
if (this.data.length)
|
if (this.data.length)
|
||||||
|
|
|
@ -36,30 +36,6 @@ describe('Component vnPopover', () => {
|
||||||
|
|
||||||
expect(controller.emit).not.toHaveBeenCalledWith('open');
|
expect(controller.emit).not.toHaveBeenCalledWith('open');
|
||||||
});
|
});
|
||||||
|
|
||||||
// #1615 migrar karma a jest (this doesn't work anymore, needs fixing)
|
|
||||||
xit(`should check that popover is visible into the screen`, () => {
|
|
||||||
$parent.css({
|
|
||||||
backgroundColor: 'red',
|
|
||||||
position: 'absolute',
|
|
||||||
width: '50px',
|
|
||||||
height: '50px',
|
|
||||||
top: '0',
|
|
||||||
left: '100px'
|
|
||||||
});
|
|
||||||
controller.show($parent[0]);
|
|
||||||
|
|
||||||
let rect = controller.popover.getBoundingClientRect();
|
|
||||||
let style = controller.window.getComputedStyle(controller.element);
|
|
||||||
|
|
||||||
expect(style.visibility).toEqual('visible');
|
|
||||||
expect(style.display).not.toEqual('none');
|
|
||||||
|
|
||||||
expect(0).toBeLessThanOrEqual(rect.top);
|
|
||||||
expect(0).toBeLessThanOrEqual(rect.left);
|
|
||||||
expect(controller.window.innerHeight).toBeGreaterThan(rect.bottom);
|
|
||||||
expect(controller.window.innerWidth).toBeGreaterThan(rect.right);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('hide()', () => {
|
describe('hide()', () => {
|
||||||
|
|
|
@ -8,18 +8,8 @@ export default class Th {
|
||||||
$element.on('click', () => this.onToggleOrder());
|
$element.on('click', () => this.onToggleOrder());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Changes the order if the cell has a field and defaultOrder property
|
|
||||||
*/
|
|
||||||
$onInit() {
|
$onInit() {
|
||||||
if (!this.field) return;
|
if (!this.field) return;
|
||||||
|
|
||||||
if (this.defaultOrder) {
|
|
||||||
this.order = this.defaultOrder;
|
|
||||||
this.table.applyOrder(this.field, this.order);
|
|
||||||
this.updateArrow();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.updateArrow();
|
this.updateArrow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,9 +72,6 @@ ngModule.vnComponent('vnTh', {
|
||||||
template: require('./index.html'),
|
template: require('./index.html'),
|
||||||
transclude: true,
|
transclude: true,
|
||||||
controller: Th,
|
controller: Th,
|
||||||
bindings: {
|
|
||||||
defaultOrder: '@?'
|
|
||||||
},
|
|
||||||
require: {
|
require: {
|
||||||
table: '^^vnTable'
|
table: '^^vnTable'
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,17 +17,6 @@ describe('Component vnTh', () => {
|
||||||
controller.column.setAttribute('field', 'MyField');
|
controller.column.setAttribute('field', 'MyField');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
describe('onInit()', () => {
|
|
||||||
it(`should define controllers order as per defaultOrder then call setOrder()`, () => {
|
|
||||||
controller.defaultOrder = 'DESC';
|
|
||||||
jest.spyOn(controller.table, 'setOrder');
|
|
||||||
controller.$onInit();
|
|
||||||
|
|
||||||
expect(controller.order).toEqual('DESC');
|
|
||||||
expect(controller.table.setOrder).toHaveBeenCalledWith('MyField', 'DESC');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('toggleOrder()', () => {
|
describe('toggleOrder()', () => {
|
||||||
it(`should change the ordenation to DESC (descendant) if it was ASC (ascendant)`, () => {
|
it(`should change the ordenation to DESC (descendant) if it was ASC (ascendant)`, () => {
|
||||||
controller.order = 'ASC';
|
controller.order = 'ASC';
|
||||||
|
|
|
@ -14,9 +14,12 @@
|
||||||
order="changedModel"
|
order="changedModel"
|
||||||
auto-load="true">
|
auto-load="true">
|
||||||
</vn-crud-model>
|
</vn-crud-model>
|
||||||
<vn-data-viewer model="model" class="vn-w-md vn-px-sm">
|
<vn-data-viewer
|
||||||
|
model="model"
|
||||||
|
is-loading="model.isLoading"
|
||||||
|
class="vn-w-md vn-px-sm">
|
||||||
<div class="change vn-mb-sm" ng-repeat="log in $ctrl.logs">
|
<div class="change vn-mb-sm" ng-repeat="log in $ctrl.logs">
|
||||||
<div class="user-wrapper">
|
<div class="left">
|
||||||
<vn-avatar class="vn-mt-xs"
|
<vn-avatar class="vn-mt-xs"
|
||||||
ng-class="::{system: !log.user}"
|
ng-class="::{system: !log.user}"
|
||||||
val="{{::log.user ? log.user.nickname : 'System'}}"
|
val="{{::log.user ? log.user.nickname : 'System'}}"
|
||||||
|
@ -33,7 +36,7 @@
|
||||||
<div class="header vn-mb-sm">
|
<div class="header vn-mb-sm">
|
||||||
<div
|
<div
|
||||||
class="date text-secondary text-caption"
|
class="date text-secondary text-caption"
|
||||||
title="{{::log.creationDate | date:'dd/MM/yyyy HH:mm'}}">
|
title="{{::log.creationDate | date:'dd/MM/yyyy HH:mm:ss'}}">
|
||||||
{{::$ctrl.relativeDate(log.creationDate)}}
|
{{::$ctrl.relativeDate(log.creationDate)}}
|
||||||
</div>
|
</div>
|
||||||
<span class="chip" ng-class="::$ctrl.actionsClass[log.action]" translate>
|
<span class="chip" ng-class="::$ctrl.actionsClass[log.action]" translate>
|
||||||
|
|
|
@ -4,7 +4,7 @@ vn-log {
|
||||||
.change {
|
.change {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
& > .user-wrapper {
|
& > .left {
|
||||||
position: relative;
|
position: relative;
|
||||||
padding-right: 10px;
|
padding-right: 10px;
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ vn-log {
|
||||||
bottom: -8px;
|
bottom: -8px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&:last-child > .user-wrapper > .line {
|
&:last-child > .left > .line {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
.detail {
|
.detail {
|
||||||
|
|
|
@ -170,5 +170,6 @@
|
||||||
"comercialName": "Comercial",
|
"comercialName": "Comercial",
|
||||||
"Added observation": "Added observation",
|
"Added observation": "Added observation",
|
||||||
"Comment added to client": "Comment added to client",
|
"Comment added to client": "Comment added to client",
|
||||||
"This ticket is already a refund": "This ticket is already a refund"
|
"This ticket is already a refund": "This ticket is already a refund",
|
||||||
|
"A claim with that sale already exists": "A claim with that sale already exists"
|
||||||
}
|
}
|
|
@ -27,7 +27,6 @@ module.exports = Self => {
|
||||||
Object.assign(myOptions, options);
|
Object.assign(myOptions, options);
|
||||||
|
|
||||||
const summaryObj = await getSummary(models.Client, clientFk, myOptions);
|
const summaryObj = await getSummary(models.Client, clientFk, myOptions);
|
||||||
|
|
||||||
summaryObj.mana = await models.Client.getMana(clientFk, myOptions);
|
summaryObj.mana = await models.Client.getMana(clientFk, myOptions);
|
||||||
summaryObj.debt = await models.Client.getDebt(clientFk, myOptions);
|
summaryObj.debt = await models.Client.getDebt(clientFk, myOptions);
|
||||||
summaryObj.averageInvoiced = await models.Client.getAverageInvoiced(clientFk, myOptions);
|
summaryObj.averageInvoiced = await models.Client.getAverageInvoiced(clientFk, myOptions);
|
||||||
|
@ -115,6 +114,12 @@ module.exports = Self => {
|
||||||
fields: ['claimingRate', 'priceIncreasing'],
|
fields: ['claimingRate', 'priceIncreasing'],
|
||||||
limit: 1
|
limit: 1
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
relation: 'businessType',
|
||||||
|
scope: {
|
||||||
|
fields: ['description']
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
where: {id: clientId}
|
where: {id: clientId}
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
<vn-date-picker
|
<vn-date-picker
|
||||||
label="Date"
|
label="Date"
|
||||||
ng-model="$ctrl.receipt.payed"
|
ng-model="$ctrl.receipt.payed"
|
||||||
|
vn-name="payed"
|
||||||
required="true">
|
required="true">
|
||||||
</vn-date-picker>
|
</vn-date-picker>
|
||||||
<vn-autocomplete
|
<vn-autocomplete
|
||||||
|
@ -21,6 +22,7 @@
|
||||||
show-field="code"
|
show-field="code"
|
||||||
value-field="id"
|
value-field="id"
|
||||||
ng-model="$ctrl.companyFk"
|
ng-model="$ctrl.companyFk"
|
||||||
|
vn-name="company"
|
||||||
required="true">
|
required="true">
|
||||||
</vn-autocomplete>
|
</vn-autocomplete>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
|
@ -33,6 +35,7 @@
|
||||||
fields="['accountingTypeFk']"
|
fields="['accountingTypeFk']"
|
||||||
include="{relation: 'accountingType'}"
|
include="{relation: 'accountingType'}"
|
||||||
ng-model="$ctrl.bankFk"
|
ng-model="$ctrl.bankFk"
|
||||||
|
vn-name="bank"
|
||||||
search-function="$ctrl.bankSearchFunc($search)"
|
search-function="$ctrl.bankSearchFunc($search)"
|
||||||
selection="$ctrl.bankSelection"
|
selection="$ctrl.bankSelection"
|
||||||
order="id"
|
order="id"
|
||||||
|
@ -43,6 +46,7 @@
|
||||||
vn-focus
|
vn-focus
|
||||||
label="Amount"
|
label="Amount"
|
||||||
ng-model="$ctrl.amountPaid"
|
ng-model="$ctrl.amountPaid"
|
||||||
|
vn-name="amountPaid"
|
||||||
step="0.01"
|
step="0.01"
|
||||||
required="true"
|
required="true"
|
||||||
max="$ctrl.maxAmount">
|
max="$ctrl.maxAmount">
|
||||||
|
@ -52,6 +56,7 @@
|
||||||
<h6 translate>Compensation</h6>
|
<h6 translate>Compensation</h6>
|
||||||
<vn-textfield
|
<vn-textfield
|
||||||
ng-model="$ctrl.receipt.compensationAccount"
|
ng-model="$ctrl.receipt.compensationAccount"
|
||||||
|
vn-name="compensationAccount"
|
||||||
label="Compensation Account"
|
label="Compensation Account"
|
||||||
on-change="$ctrl.accountShortToStandard(value)">
|
on-change="$ctrl.accountShortToStandard(value)">
|
||||||
</vn-textfield>
|
</vn-textfield>
|
||||||
|
@ -60,6 +65,7 @@
|
||||||
<vn-textfield
|
<vn-textfield
|
||||||
label="Reference"
|
label="Reference"
|
||||||
ng-model="$ctrl.receipt.description"
|
ng-model="$ctrl.receipt.description"
|
||||||
|
vn-name="description"
|
||||||
rule
|
rule
|
||||||
required="true">
|
required="true">
|
||||||
</vn-textfield>
|
</vn-textfield>
|
||||||
|
@ -70,23 +76,27 @@
|
||||||
<vn-input-number
|
<vn-input-number
|
||||||
ng-model="$ctrl.deliveredAmount"
|
ng-model="$ctrl.deliveredAmount"
|
||||||
label="Delivered amount"
|
label="Delivered amount"
|
||||||
step="0.01">
|
step="0.01"
|
||||||
|
vn-name="deliveredAmount">
|
||||||
</vn-input-number>
|
</vn-input-number>
|
||||||
<vn-input-number
|
<vn-input-number
|
||||||
disabled="true"
|
disabled="true"
|
||||||
ng-model="$ctrl.amountToReturn"
|
ng-model="$ctrl.amountToReturn"
|
||||||
label="Amount to return">
|
label="Amount to return"
|
||||||
|
vn-name="amountToReturn">
|
||||||
</vn-input-number>
|
</vn-input-number>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
</vn-vertical>
|
</vn-vertical>
|
||||||
<vn-horizontal ng-show="$ctrl.bankSelection.accountingType.code == 'cash'">
|
<vn-horizontal ng-show="$ctrl.bankSelection.accountingType.code == 'cash'">
|
||||||
<vn-check
|
<vn-check
|
||||||
label="View receipt"
|
label="View receipt"
|
||||||
ng-model="$ctrl.viewReceipt">
|
ng-model="$ctrl.viewReceipt"
|
||||||
|
vn-name="viewReceipt">
|
||||||
</vn-check>
|
</vn-check>
|
||||||
<vn-check
|
<vn-check
|
||||||
label="Send email"
|
label="Send email"
|
||||||
ng-model="$ctrl.sendEmail">
|
ng-model="$ctrl.sendEmail"
|
||||||
|
vn-name="sendEmail">
|
||||||
</vn-check>
|
</vn-check>
|
||||||
</vn-horizontal>
|
</vn-horizontal>
|
||||||
</tpl-body>
|
</tpl-body>
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
<vn-table model="model" auto-load="false">
|
<vn-table model="model" auto-load="false">
|
||||||
<vn-thead>
|
<vn-thead>
|
||||||
<vn-tr>
|
<vn-tr>
|
||||||
<vn-th field="shipped" default-order="DESC" expand>Date</vn-th>
|
<vn-th field="shipped" expand>Date</vn-th>
|
||||||
<vn-th field="userFk">Created by</vn-thfield></vn-th>
|
<vn-th field="userFk">Created by</vn-thfield></vn-th>
|
||||||
<vn-th field="description">Comment</vn-th>
|
<vn-th field="description">Comment</vn-th>
|
||||||
<vn-th field="greugeTypeFk">Type</vn-th>
|
<vn-th field="greugeTypeFk">Type</vn-th>
|
||||||
|
|
|
@ -11,8 +11,7 @@ class Controller extends Section {
|
||||||
scope: {
|
scope: {
|
||||||
fields: ['id', 'name']
|
fields: ['id', 'name']
|
||||||
},
|
},
|
||||||
},
|
}, {
|
||||||
{
|
|
||||||
relation: 'user',
|
relation: 'user',
|
||||||
scope: {
|
scope: {
|
||||||
fields: ['id', 'name']
|
fields: ['id', 'name']
|
||||||
|
@ -24,8 +23,6 @@ class Controller extends Section {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Controller.$inject = ['$element', '$scope'];
|
|
||||||
|
|
||||||
ngModule.vnComponent('vnClientGreugeIndex', {
|
ngModule.vnComponent('vnClientGreugeIndex', {
|
||||||
template: require('./index.html'),
|
template: require('./index.html'),
|
||||||
controller: Controller
|
controller: Controller
|
||||||
|
|
|
@ -64,6 +64,9 @@
|
||||||
<vn-label-value label="Channel"
|
<vn-label-value label="Channel"
|
||||||
value="{{$ctrl.summary.contactChannel.name}}">
|
value="{{$ctrl.summary.contactChannel.name}}">
|
||||||
</vn-label-value>
|
</vn-label-value>
|
||||||
|
<vn-label-value label="Business type"
|
||||||
|
value="{{$ctrl.summary.businessType.description}}">
|
||||||
|
</vn-label-value>
|
||||||
</vn-one>
|
</vn-one>
|
||||||
<vn-one>
|
<vn-one>
|
||||||
<h4 ng-show="$ctrl.isEmployee">
|
<h4 ng-show="$ctrl.isEmployee">
|
||||||
|
|
|
@ -23,3 +23,4 @@ Latest tickets: Últimos tickets
|
||||||
Rating: Clasificación
|
Rating: Clasificación
|
||||||
Value from 1 to 20. The higher the better value: Valor del 1 al 20. Cuanto más alto mejor valoración
|
Value from 1 to 20. The higher the better value: Valor del 1 al 20. Cuanto más alto mejor valoración
|
||||||
Go to grafana: Ir a grafana
|
Go to grafana: Ir a grafana
|
||||||
|
Business type: Tipo de negocio
|
|
@ -141,7 +141,7 @@ module.exports = Self => {
|
||||||
let stmt;
|
let stmt;
|
||||||
|
|
||||||
stmt = new ParameterizedSQL(
|
stmt = new ParameterizedSQL(
|
||||||
`CREATE TEMPORARY TABLE tmp.filter
|
`CREATE OR REPLACE TEMPORARY TABLE tmp.filter
|
||||||
(INDEX (id))
|
(INDEX (id))
|
||||||
ENGINE = MEMORY
|
ENGINE = MEMORY
|
||||||
SELECT
|
SELECT
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
<vn-table model="model">
|
<vn-table model="model">
|
||||||
<vn-thead>
|
<vn-thead>
|
||||||
<vn-tr>
|
<vn-tr>
|
||||||
<vn-th shrink field="itemFk" default-order="ASC" number>Item</vn-th>
|
<vn-th shrink field="itemFk" number>Item</vn-th>
|
||||||
<vn-th>Description</vn-th>
|
<vn-th>Description</vn-th>
|
||||||
<vn-th shrink field="quantity" number>Quantity</vn-th>
|
<vn-th shrink field="quantity" number>Quantity</vn-th>
|
||||||
<vn-th shrink number>m³ per quantity</vn-th>
|
<vn-th shrink number>m³ per quantity</vn-th>
|
||||||
|
|
|
@ -6,9 +6,10 @@ class Controller extends Section {
|
||||||
constructor($element, $) {
|
constructor($element, $) {
|
||||||
super($element, $);
|
super($element, $);
|
||||||
this.filter = {
|
this.filter = {
|
||||||
include: [{
|
include: {
|
||||||
relation: 'item'
|
relation: 'item'
|
||||||
}]
|
},
|
||||||
|
order: 'itemFk'
|
||||||
};
|
};
|
||||||
this.order = {};
|
this.order = {};
|
||||||
this.ticketVolumes = [];
|
this.ticketVolumes = [];
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
const mergeFilters = require('vn-loopback/util/filter').mergeFilters;
|
||||||
module.exports = Self => {
|
module.exports = Self => {
|
||||||
Self.remoteMethodCtx('editableStates', {
|
Self.remoteMethodCtx('editableStates', {
|
||||||
description: 'Gets the editable states according the user role ',
|
description: 'Gets the editable states according the user role ',
|
||||||
|
@ -19,25 +20,16 @@ module.exports = Self => {
|
||||||
Self.editableStates = async(ctx, filter, options) => {
|
Self.editableStates = async(ctx, filter, options) => {
|
||||||
const models = Self.app.models;
|
const models = Self.app.models;
|
||||||
const userId = ctx.req.accessToken.userId;
|
const userId = ctx.req.accessToken.userId;
|
||||||
const myOptions = {};
|
const myOptions = {...(options || {})};
|
||||||
|
|
||||||
if (typeof options == 'object')
|
|
||||||
Object.assign(myOptions, options);
|
|
||||||
|
|
||||||
let statesList = await models.State.find(filter, myOptions);
|
|
||||||
const isProduction = await models.VnUser.hasRole(userId, 'production', myOptions);
|
const isProduction = await models.VnUser.hasRole(userId, 'production', myOptions);
|
||||||
const isSalesPerson = await models.VnUser.hasRole(userId, 'salesPerson', myOptions);
|
|
||||||
const isAdministrative = await models.VnUser.hasRole(userId, 'administrative', myOptions);
|
const isAdministrative = await models.VnUser.hasRole(userId, 'administrative', myOptions);
|
||||||
|
|
||||||
if (isProduction || isAdministrative)
|
if (!isProduction && !isAdministrative)
|
||||||
return statesList;
|
filter = mergeFilters(filter, {where: {alertLevel: 0}});
|
||||||
|
|
||||||
if (isSalesPerson) {
|
const states = await models.State.find(filter, myOptions);
|
||||||
return statesList = statesList.filter(stateList =>
|
|
||||||
stateList.alertLevel === 0 || stateList.code === 'PICKER_DESIGNED'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return statesList.filter(stateList => stateList.alertLevel === 0);
|
return states;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -24,31 +24,6 @@ describe('ticket editableStates()', () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`should return the expected states by a specific role`, async() => {
|
|
||||||
const tx = await models.State.beginTransaction({});
|
|
||||||
|
|
||||||
try {
|
|
||||||
const options = {transaction: tx};
|
|
||||||
|
|
||||||
const productionRole = 18;
|
|
||||||
const ctx = {req: {accessToken: {userId: productionRole}}};
|
|
||||||
|
|
||||||
const editableStates = await models.State.editableStates(ctx, filter, options);
|
|
||||||
|
|
||||||
const deliveredState = editableStates.some(state => state.code == 'DELIVERED');
|
|
||||||
|
|
||||||
const pickerDesignedState = editableStates.some(state => state.code == 'PICKER_DESIGNED');
|
|
||||||
|
|
||||||
expect(deliveredState).toBeFalsy();
|
|
||||||
expect(pickerDesignedState).toBeTruthy();
|
|
||||||
|
|
||||||
await tx.rollback();
|
|
||||||
} catch (e) {
|
|
||||||
await tx.rollback();
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should return again the expected state by a specific role`, async() => {
|
it(`should return again the expected state by a specific role`, async() => {
|
||||||
const tx = await models.State.beginTransaction({});
|
const tx = await models.State.beginTransaction({});
|
||||||
|
|
||||||
|
@ -70,4 +45,25 @@ describe('ticket editableStates()', () => {
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it(`should return the expected state matching with the name`, async() => {
|
||||||
|
const tx = await models.State.beginTransaction({});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const options = {transaction: tx};
|
||||||
|
|
||||||
|
const employeeRole = 1;
|
||||||
|
const ctx = {req: {accessToken: {userId: employeeRole}}};
|
||||||
|
const filter = {where: {name: {like: '%Previa OK%'}}};
|
||||||
|
|
||||||
|
const [editableStates] = await models.State.editableStates(ctx, filter, options);
|
||||||
|
|
||||||
|
expect(editableStates.name).toBe('Previa OK');
|
||||||
|
|
||||||
|
await tx.rollback();
|
||||||
|
} catch (e) {
|
||||||
|
await tx.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -124,6 +124,7 @@ module.exports = Self => {
|
||||||
const isDeliveryBoss = await models.VnUser.hasRole(userId, 'deliveryBoss', myOptions);
|
const isDeliveryBoss = await models.VnUser.hasRole(userId, 'deliveryBoss', myOptions);
|
||||||
if (!isDeliveryBoss) {
|
if (!isDeliveryBoss) {
|
||||||
const zoneShipped = await models.Agency.getShipped(
|
const zoneShipped = await models.Agency.getShipped(
|
||||||
|
ctx,
|
||||||
args.landed,
|
args.landed,
|
||||||
args.addressFk,
|
args.addressFk,
|
||||||
args.agencyModeFk,
|
args.agencyModeFk,
|
||||||
|
|
|
@ -24,7 +24,6 @@ module.exports = function(Self) {
|
||||||
});
|
});
|
||||||
|
|
||||||
Self.makeInvoice = async(ctx, ticketsIds, options) => {
|
Self.makeInvoice = async(ctx, ticketsIds, options) => {
|
||||||
const userId = ctx.req.accessToken.userId;
|
|
||||||
const models = Self.app.models;
|
const models = Self.app.models;
|
||||||
const date = Date.vnNew();
|
const date = Date.vnNew();
|
||||||
date.setHours(0, 0, 0, 0);
|
date.setHours(0, 0, 0, 0);
|
||||||
|
@ -42,6 +41,7 @@ module.exports = function(Self) {
|
||||||
|
|
||||||
let serial;
|
let serial;
|
||||||
let invoiceId;
|
let invoiceId;
|
||||||
|
let invoiceOut;
|
||||||
try {
|
try {
|
||||||
const tickets = await models.Ticket.find({
|
const tickets = await models.Ticket.find({
|
||||||
where: {
|
where: {
|
||||||
|
@ -89,24 +89,14 @@ module.exports = function(Self) {
|
||||||
|
|
||||||
invoiceId = resultInvoice.id;
|
invoiceId = resultInvoice.id;
|
||||||
|
|
||||||
for (let ticket of tickets) {
|
|
||||||
const ticketInvoice = await models.Ticket.findById(ticket.id, {
|
|
||||||
fields: ['refFk']
|
|
||||||
}, myOptions);
|
|
||||||
|
|
||||||
await models.TicketLog.create({
|
|
||||||
originFk: ticket.id,
|
|
||||||
userFk: userId,
|
|
||||||
action: 'insert',
|
|
||||||
changedModel: 'Ticket',
|
|
||||||
changedModelId: ticket.id,
|
|
||||||
newInstance: ticketInvoice
|
|
||||||
}, myOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (serial != 'R' && invoiceId)
|
if (serial != 'R' && invoiceId)
|
||||||
await Self.rawSql('CALL invoiceOutBooking(?)', [invoiceId], myOptions);
|
await Self.rawSql('CALL invoiceOutBooking(?)', [invoiceId], myOptions);
|
||||||
|
|
||||||
|
invoiceOut = await models.InvoiceOut.findById(invoiceId, {
|
||||||
|
include: {
|
||||||
|
relation: 'client'
|
||||||
|
}
|
||||||
|
}, myOptions);
|
||||||
if (tx) await tx.commit();
|
if (tx) await tx.commit();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (tx) await tx.rollback();
|
if (tx) await tx.rollback();
|
||||||
|
@ -116,6 +106,15 @@ module.exports = function(Self) {
|
||||||
if (serial != 'R' && invoiceId)
|
if (serial != 'R' && invoiceId)
|
||||||
await models.InvoiceOut.createPdf(ctx, invoiceId);
|
await models.InvoiceOut.createPdf(ctx, invoiceId);
|
||||||
|
|
||||||
|
if (invoiceId) {
|
||||||
|
ctx.args = {
|
||||||
|
reference: invoiceOut.ref,
|
||||||
|
recipientId: invoiceOut.clientFk,
|
||||||
|
recipient: invoiceOut.client().email
|
||||||
|
};
|
||||||
|
await models.InvoiceOut.invoiceEmail(ctx, invoiceOut.ref);
|
||||||
|
}
|
||||||
|
|
||||||
return {invoiceFk: invoiceId, serial: serial};
|
return {invoiceFk: invoiceId, serial: serial};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -100,7 +100,7 @@ module.exports = Self => {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!args.shipped && args.landed) {
|
if (!args.shipped && args.landed) {
|
||||||
const shippedResult = await models.Agency.getShipped(args.landed,
|
const shippedResult = await models.Agency.getShipped(ctx, args.landed,
|
||||||
address.id, args.agencyModeId, args.warehouseId, myOptions);
|
address.id, args.agencyModeId, args.warehouseId, myOptions);
|
||||||
args.shipped = (shippedResult && shippedResult.shipped) || args.landed;
|
args.shipped = (shippedResult && shippedResult.shipped) || args.landed;
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,6 +81,7 @@ module.exports = Self => {
|
||||||
const isDeliveryBoss = await models.VnUser.hasRole(userId, 'deliveryBoss', myOptions);
|
const isDeliveryBoss = await models.VnUser.hasRole(userId, 'deliveryBoss', myOptions);
|
||||||
if (!isDeliveryBoss) {
|
if (!isDeliveryBoss) {
|
||||||
const zoneShipped = await models.Agency.getShipped(
|
const zoneShipped = await models.Agency.getShipped(
|
||||||
|
ctx,
|
||||||
args.landed,
|
args.landed,
|
||||||
args.addressId,
|
args.addressId,
|
||||||
args.agencyModeId,
|
args.agencyModeId,
|
||||||
|
|
|
@ -6,6 +6,9 @@ describe('ticket makeInvoice()', () => {
|
||||||
const ticketId = 11;
|
const ticketId = 11;
|
||||||
const clientId = 1102;
|
const clientId = 1102;
|
||||||
const activeCtx = {
|
const activeCtx = {
|
||||||
|
getLocale: () => {
|
||||||
|
return 'en';
|
||||||
|
},
|
||||||
accessToken: {userId: userId},
|
accessToken: {userId: userId},
|
||||||
headers: {origin: 'http://localhost:5000'},
|
headers: {origin: 'http://localhost:5000'},
|
||||||
};
|
};
|
||||||
|
@ -67,6 +70,7 @@ describe('ticket makeInvoice()', () => {
|
||||||
it('should invoice a ticket, then try again to fail', async() => {
|
it('should invoice a ticket, then try again to fail', async() => {
|
||||||
const invoiceOutModel = models.InvoiceOut;
|
const invoiceOutModel = models.InvoiceOut;
|
||||||
spyOn(invoiceOutModel, 'createPdf');
|
spyOn(invoiceOutModel, 'createPdf');
|
||||||
|
spyOn(invoiceOutModel, 'invoiceEmail');
|
||||||
|
|
||||||
const tx = await models.Ticket.beginTransaction({});
|
const tx = await models.Ticket.beginTransaction({});
|
||||||
|
|
||||||
|
@ -90,6 +94,7 @@ describe('ticket makeInvoice()', () => {
|
||||||
it('should success to invoice a ticket', async() => {
|
it('should success to invoice a ticket', async() => {
|
||||||
const invoiceOutModel = models.InvoiceOut;
|
const invoiceOutModel = models.InvoiceOut;
|
||||||
spyOn(invoiceOutModel, 'createPdf');
|
spyOn(invoiceOutModel, 'createPdf');
|
||||||
|
spyOn(invoiceOutModel, 'invoiceEmail');
|
||||||
|
|
||||||
const tx = await models.Ticket.beginTransaction({});
|
const tx = await models.Ticket.beginTransaction({});
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<vn-crud-model auto-load="false"
|
<vn-crud-model
|
||||||
|
auto-load="true"
|
||||||
vn-id="model"
|
vn-id="model"
|
||||||
url="sales"
|
url="sales"
|
||||||
filter="::$ctrl.filter"
|
filter="::$ctrl.filter"
|
||||||
|
@ -23,7 +24,7 @@
|
||||||
<vn-thead>
|
<vn-thead>
|
||||||
<vn-tr>
|
<vn-tr>
|
||||||
<vn-th field="itemFk" number>Item</vn-th>
|
<vn-th field="itemFk" number>Item</vn-th>
|
||||||
<vn-th field="concept" default-order="ASC">Description</vn-th>
|
<vn-th field="concept">Description</vn-th>
|
||||||
<vn-th field="itemPackingTypeFk" number>Packing type</vn-th>
|
<vn-th field="itemPackingTypeFk" number>Packing type</vn-th>
|
||||||
<vn-th field="quantity" number>Quantity</vn-th>
|
<vn-th field="quantity" number>Quantity</vn-th>
|
||||||
<vn-th number>m³ per quantity</vn-th>
|
<vn-th number>m³ per quantity</vn-th>
|
||||||
|
|
|
@ -5,9 +5,10 @@ class Controller extends Section {
|
||||||
constructor($element, $) {
|
constructor($element, $) {
|
||||||
super($element, $);
|
super($element, $);
|
||||||
this.filter = {
|
this.filter = {
|
||||||
include: [{
|
include: {
|
||||||
relation: 'item'
|
relation: 'item'
|
||||||
}]
|
},
|
||||||
|
order: 'concept'
|
||||||
};
|
};
|
||||||
|
|
||||||
this.ticketVolumes = [];
|
this.ticketVolumes = [];
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* eslint max-len: ["error", { "code": 130 }]*/
|
/* eslint max-len: ["error", { "code": 150 }]*/
|
||||||
const UserError = require('vn-loopback/util/user-error');
|
const UserError = require('vn-loopback/util/user-error');
|
||||||
|
|
||||||
module.exports = Self => {
|
module.exports = Self => {
|
||||||
|
@ -139,7 +139,7 @@ module.exports = Self => {
|
||||||
|
|
||||||
if (!client) {
|
if (!client) {
|
||||||
const nickname = args.firstName.concat(' ', args.lastNames);
|
const nickname = args.firstName.concat(' ', args.lastNames);
|
||||||
const workerConfig = await models.WorkerConfig.findOne({fields: ['roleFk']});
|
const workerConfig = await models.WorkerConfig.findOne({fields: ['roleFk', 'businessTypeFk']});
|
||||||
const [randomPassword] = await models.Worker.rawSql(
|
const [randomPassword] = await models.Worker.rawSql(
|
||||||
'SELECT account.passwordGenerate() as password;'
|
'SELECT account.passwordGenerate() as password;'
|
||||||
);
|
);
|
||||||
|
@ -196,7 +196,7 @@ module.exports = Self => {
|
||||||
|
|
||||||
client = await models.Client.findById(
|
client = await models.Client.findById(
|
||||||
user.id,
|
user.id,
|
||||||
{fields: ['id', 'name', 'socialName', 'street', 'city', 'iban', 'bankEntityFk', 'defaultAddressFk', 'fi']},
|
{fields: ['id', 'name', 'socialName', 'street', 'city', 'iban', 'bankEntityFk', 'defaultAddressFk', 'businessTypeFk', 'fi']},
|
||||||
myOptions
|
myOptions
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -205,6 +205,7 @@ module.exports = Self => {
|
||||||
iban: args.iban,
|
iban: args.iban,
|
||||||
bankEntityFk: args.bankEntityFk,
|
bankEntityFk: args.bankEntityFk,
|
||||||
defaultAddressFk: address.id,
|
defaultAddressFk: address.id,
|
||||||
|
businessTypeFk: workerConfig.businessTypeFk,
|
||||||
},
|
},
|
||||||
myOptions
|
myOptions
|
||||||
);
|
);
|
||||||
|
|
|
@ -14,6 +14,9 @@
|
||||||
},
|
},
|
||||||
"roleFk": {
|
"roleFk": {
|
||||||
"type": "number"
|
"type": "number"
|
||||||
|
},
|
||||||
|
"businessTypeFk": {
|
||||||
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"acls": [
|
"acls": [
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
|
const ParameterizedSQL = require('loopback-connector').ParameterizedSQL;
|
||||||
|
|
||||||
module.exports = Self => {
|
module.exports = Self => {
|
||||||
Self.remoteMethod('getShipped', {
|
Self.remoteMethodCtx('getShipped', {
|
||||||
description: 'Returns the first shipped possible for params',
|
description: 'Returns the first shipped possible for params',
|
||||||
accessType: 'READ',
|
accessType: 'READ',
|
||||||
accepts: [{
|
accepts: [{
|
||||||
|
@ -34,18 +34,22 @@ module.exports = Self => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Self.getShipped = async(landed, addressFk, agencyModeFk, warehouseFk, options) => {
|
Self.getShipped = async(ctx, landed, addressFk, agencyModeFk, warehouseFk, options) => {
|
||||||
const myOptions = {};
|
const myOptions = {};
|
||||||
|
|
||||||
if (typeof options == 'object')
|
if (typeof options == 'object')
|
||||||
Object.assign(myOptions, options);
|
Object.assign(myOptions, options);
|
||||||
|
|
||||||
const stmts = [];
|
const stmts = [];
|
||||||
|
const userId = ctx.req.accessToken.userId;
|
||||||
|
const models = Self.app.models;
|
||||||
|
const isProductionAssistant = await models.VnUser.hasRole(userId, 'productionAssi', myOptions);
|
||||||
stmts.push(new ParameterizedSQL(
|
stmts.push(new ParameterizedSQL(
|
||||||
`CALL vn.zone_getShipped(?, ?, ?, TRUE)`, [
|
`CALL vn.zone_getShipped(?, ?, ?, ?)`, [
|
||||||
landed,
|
landed,
|
||||||
addressFk,
|
addressFk,
|
||||||
agencyModeFk
|
agencyModeFk,
|
||||||
|
isProductionAssistant
|
||||||
]
|
]
|
||||||
));
|
));
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
const {models} = require('vn-loopback/server/server');
|
const models = require('vn-loopback/server/server').models;
|
||||||
|
|
||||||
describe('agency getShipped()', () => {
|
describe('agency getShipped()', () => {
|
||||||
|
const employeeId = 1;
|
||||||
|
const ctx = {req: {accessToken: {userId: employeeId}}};
|
||||||
|
|
||||||
it('should return a shipment date', async() => {
|
it('should return a shipment date', async() => {
|
||||||
const landed = Date.vnNew();
|
const landed = Date.vnNew();
|
||||||
landed.setDate(landed.getDate() + 1);
|
landed.setDate(landed.getDate() + 1);
|
||||||
|
@ -12,8 +15,7 @@ describe('agency getShipped()', () => {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const options = {transaction: tx};
|
const options = {transaction: tx};
|
||||||
|
const result = await models.Agency.getShipped(ctx, landed, addressFk, agencyModeFk, warehouseFk, options);
|
||||||
const result = await models.Agency.getShipped(landed, addressFk, agencyModeFk, warehouseFk, options);
|
|
||||||
|
|
||||||
expect(result).toBeDefined();
|
expect(result).toBeDefined();
|
||||||
|
|
||||||
|
@ -37,7 +39,7 @@ describe('agency getShipped()', () => {
|
||||||
try {
|
try {
|
||||||
const options = {transaction: tx};
|
const options = {transaction: tx};
|
||||||
|
|
||||||
const result = await models.Agency.getShipped(landed, addressFk, agencyModeFk, warehouseFk, options);
|
const result = await models.Agency.getShipped(ctx, landed, addressFk, agencyModeFk, warehouseFk, options);
|
||||||
|
|
||||||
expect(result).toBeUndefined();
|
expect(result).toBeUndefined();
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "salix-back",
|
"name": "salix-back",
|
||||||
"version": "23.16.01",
|
"version": "23.22.01",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "salix-back",
|
"name": "salix-back",
|
||||||
"version": "23.16.01",
|
"version": "23.22.01",
|
||||||
"author": "Verdnatura Levante SL",
|
"author": "Verdnatura Levante SL",
|
||||||
"description": "Salix backend",
|
"description": "Salix backend",
|
||||||
"license": "GPL-3.0",
|
"license": "GPL-3.0",
|
||||||
|
|
|
@ -4,13 +4,14 @@ const db = require('../../database');
|
||||||
module.exports = {
|
module.exports = {
|
||||||
name: 'report-footer',
|
name: 'report-footer',
|
||||||
async serverPrefetch() {
|
async serverPrefetch() {
|
||||||
this.company = await db.findOne(
|
this.company = await db.findOne(`
|
||||||
`SELECT
|
SELECT IFNULL(ci.footnotes, cl.footnotes) as footnotes
|
||||||
ci.footnotes
|
FROM company c
|
||||||
FROM companyI18n ci
|
LEFT JOIN companyL10n cl ON c.id = cl.id
|
||||||
JOIN company c ON c.id = ci.companyFk
|
LEFT JOIN companyI18n ci ON ci.companyFk = cl.id
|
||||||
WHERE c.code = ? AND ci.lang = (SELECT lang FROM account.user WHERE id = ?)`,
|
AND ci.lang = (SELECT lang FROM account.user where id = ?)
|
||||||
[this.companyCode, this.recipientId]);
|
WHERE c.code = ?`,
|
||||||
|
[this.recipientId, this.companyCode]);
|
||||||
},
|
},
|
||||||
|
|
||||||
props: ['leftText', 'companyCode', 'recipientId', 'centerText']
|
props: ['leftText', 'companyCode', 'recipientId', 'centerText']
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
subject: Weekly time log
|
subject: Weekly time log
|
||||||
title: Record of hours week {0} year {1}
|
title: Record of hours week {0} year {1}
|
||||||
dear: Dear worker
|
dear: Dear worker
|
||||||
description: Access the following link:<br/><br/>
|
Acceda al siguiente enlace: Access the following link:<br/>
|
||||||
{0} <br/><br/>
|
description:
|
||||||
Click 'SATISFIED' if you agree with the hours worked. Otherwise, press 'NOT SATISFIED', detailing the cause of the disagreement.
|
Click 'SATISFIED' if you agree with the hours worked. Otherwise, press 'NOT SATISFIED', detailing the cause of the disagreement.
|
||||||
|
Hours: Hours
|
|
@ -1,6 +1,7 @@
|
||||||
subject: Registro de horas semanal
|
subject: Registro de horas semanal
|
||||||
title: Registro de horas semana {0} año {1}
|
title: Registro de horas semana {0} año {1}
|
||||||
dear: Estimado trabajador
|
dear: Estimado trabajador
|
||||||
description: Acceda al siguiente enlace:<br/><br/>
|
toaccess: Acceda al siguiente enlace:<br/>
|
||||||
{0} <br/><br/>
|
description:
|
||||||
Pulse 'CONFORME' si esta de acuerdo con las horas trabajadas. En caso contrario pulse 'NO CONFORME', detallando la causa de la disconformidad.
|
Pulse 'CONFORME' si esta de acuerdo con las horas trabajadas. En caso contrario pulse 'NO CONFORME', detallando la causa de la disconformidad.
|
||||||
|
Hours: Horas
|
|
@ -3,7 +3,9 @@
|
||||||
<div class="grid-block vn-pa-ml">
|
<div class="grid-block vn-pa-ml">
|
||||||
<h1>{{ $t('title', [week, year]) }}</h1>
|
<h1>{{ $t('title', [week, year]) }}</h1>
|
||||||
<p>{{$t('dear')}},</p>
|
<p>{{$t('dear')}},</p>
|
||||||
<p v-html="$t('description', [url])"></p>
|
<p v-html="$t('toaccess')"></p>
|
||||||
|
<a :href="url"><button>{{$t('Hours')}}</button></a>
|
||||||
|
<p>{{$t('description')}}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</email-body>
|
</email-body>
|
||||||
|
|
Loading…
Reference in New Issue